diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx
index 13fffae5..299c62a1 100644
--- a/src/components/Article/CommentsTree.tsx
+++ b/src/components/Article/CommentsTree.tsx
@@ -6,8 +6,8 @@ import { useLocalize } from '~/context/localize'
import { useReactions } from '~/context/reactions'
import { useSession } from '~/context/session'
import { Author, Reaction, ReactionKind, ReactionSort } from '~/graphql/schema/core.gen'
-import { byCreated, byStat } from '~/lib/sort'
import { SortFunction } from '~/types/common'
+import { byCreated, byStat } from '~/utils/sort'
import { Button } from '../_shared/Button'
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
import styles from './Article.module.scss'
diff --git a/src/components/SearchModal/SearchModal.tsx b/src/components/SearchModal/SearchModal.tsx
index 5545f1c2..b0ef9644 100644
--- a/src/components/SearchModal/SearchModal.tsx
+++ b/src/components/SearchModal/SearchModal.tsx
@@ -5,8 +5,8 @@ import { Icon } from '~/components/_shared/Icon'
import { useFeed } from '~/context/feed'
import { useLocalize } from '~/context/localize'
import type { Shout } from '~/graphql/schema/core.gen'
-import { byScore } from '~/lib/sort'
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
+import { byScore } from '~/utils/sort'
import { FEED_PAGE_SIZE } from '../Views/Feed/Feed'
import styles from './SearchModal.module.scss'
import { SearchResultItem } from './SearchResultItem'
@@ -23,7 +23,7 @@ const getSearchCoincidences = ({ str, intersection }: { str: string; intersectio
)}`
const prepareSearchResults = (list: Shout[], searchValue: string) =>
- list.sort(byScore() as (a: Shout, b: Shout) => number).map((article, index) => ({
+ list.sort(byScore as (a: Shout, b: Shout) => number).map((article, index) => ({
...article,
id: index,
title: article.title
diff --git a/src/components/TopicsNav/TopicsNav.tsx b/src/components/TopicsNav/TopicsNav.tsx
index 2a4f5395..c6f1801a 100644
--- a/src/components/TopicsNav/TopicsNav.tsx
+++ b/src/components/TopicsNav/TopicsNav.tsx
@@ -5,7 +5,7 @@ import { Icon } from '~/components/_shared/Icon'
import { useLocalize } from '~/context/localize'
import { useTopics } from '~/context/topics'
import type { Topic } from '~/graphql/schema/core.gen'
-import { getRandomTopicsFromArray } from '~/lib/getRandomTopicsFromArray'
+import { getRandomItemsFromArray } from '~/utils/random'
import styles from './TopicsNav.module.scss'
export const RandomTopics = () => {
@@ -17,11 +17,11 @@ export const RandomTopics = () => {
createEffect(
on(sortedTopics, (ttt: Topic[]) => {
if (ttt?.length) {
- setRandomTopics(getRandomTopicsFromArray(ttt))
+ setRandomTopics(getRandomItemsFromArray(ttt))
}
})
)
- onMount(() => sortedTopics() && getRandomTopicsFromArray(sortedTopics()))
+ onMount(() => sortedTopics() && getRandomItemsFromArray(sortedTopics()))
return (
0}>
diff --git a/src/components/Views/AllAuthors/AllAuthors.tsx b/src/components/Views/AllAuthors/AllAuthors.tsx
index a611cd81..d32dc0d9 100644
--- a/src/components/Views/AllAuthors/AllAuthors.tsx
+++ b/src/components/Views/AllAuthors/AllAuthors.tsx
@@ -9,8 +9,8 @@ import { SearchField } from '~/components/_shared/SearchField'
import { useAuthors } from '~/context/authors'
import { useLocalize } from '~/context/localize'
import type { Author } from '~/graphql/schema/core.gen'
+import { dummyFilter } from '~/intl/dummyFilter'
import { authorLetterReduce, translateAuthor } from '~/intl/translate'
-import { dummyFilter } from '~/lib/dummyFilter'
// import { byFirstChar, byStat } from '~/lib/sort'
import { scrollHandler } from '~/utils/scroll'
import styles from './AllAuthors.module.scss'
diff --git a/src/components/Views/AllTopics/AllTopics.tsx b/src/components/Views/AllTopics/AllTopics.tsx
index 270e6f63..e29a4e77 100644
--- a/src/components/Views/AllTopics/AllTopics.tsx
+++ b/src/components/Views/AllTopics/AllTopics.tsx
@@ -6,7 +6,7 @@ import { SearchField } from '~/components/_shared/SearchField'
import { useLocalize } from '~/context/localize'
import { useTopics } from '~/context/topics'
import type { Topic } from '~/graphql/schema/core.gen'
-import { dummyFilter } from '~/lib/dummyFilter'
+import { dummyFilter } from '~/intl/dummyFilter'
import { scrollHandler } from '~/utils/scroll'
import { TopicBadge } from '../../Topic/TopicBadge'
import styles from './AllTopics.module.scss'
diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx
index 5be0e61e..26bc5ffa 100644
--- a/src/components/Views/Author/Author.tsx
+++ b/src/components/Views/Author/Author.tsx
@@ -11,7 +11,7 @@ import { graphqlClientCreate } from '~/graphql/client'
import getAuthorFollowersQuery from '~/graphql/query/core/author-followers'
import getAuthorFollowsQuery from '~/graphql/query/core/author-follows'
import type { Author, Reaction, Shout, Topic } from '~/graphql/schema/core.gen'
-import { byCreated } from '~/lib/sort'
+import { byCreated } from '~/utils/sort'
import stylesArticle from '../../Article/Article.module.scss'
import { Comment } from '../../Article/Comment'
import { AuthorCard } from '../../Author/AuthorCard'
diff --git a/src/components/Views/Feed/Feed.tsx b/src/components/Views/Feed/Feed.tsx
index a9d84ff1..42d30bc6 100644
--- a/src/components/Views/Feed/Feed.tsx
+++ b/src/components/Views/Feed/Feed.tsx
@@ -17,8 +17,8 @@ import { useUI } from '~/context/ui'
import { loadUnratedShouts } from '~/graphql/api/private'
import { graphqlClientCreate } from '~/graphql/client'
import type { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
-import { byCreated } from '~/lib/sort'
import { FeedSearchParams } from '~/routes/feed/[...order]'
+import { byCreated } from '~/utils/sort'
import { CommentDate } from '../../Article/CommentDate'
import { getShareUrl } from '../../Article/SharePopup'
import { AuthorBadge } from '../../Author/AuthorBadge'
diff --git a/src/components/Views/Profile/ProfileSettings.tsx b/src/components/Views/Profile/ProfileSettings.tsx
index 7b13d808..8b049d5e 100644
--- a/src/components/Views/Profile/ProfileSettings.tsx
+++ b/src/components/Views/Profile/ProfileSettings.tsx
@@ -21,7 +21,6 @@ import { useSnackbar, useUI } from '~/context/ui'
import { InputMaybe, ProfileInput } from '~/graphql/schema/core.gen'
import { getImageUrl } from '~/lib/getThumbUrl'
import { handleImageUpload } from '~/lib/handleImageUpload'
-import { profileSocialLinks } from '~/lib/profileSocialLinks'
import { clone } from '~/utils/clone'
import { validateUrl } from '~/utils/validate'
import { ProfileSettingsNavigation } from '../../ProfileNav'
@@ -33,6 +32,7 @@ import { Modal } from '../../_shared/Modal'
import { Popover } from '../../_shared/Popover'
import { SocialNetworkInput } from '../../_shared/SocialNetworkInput'
import styles from './Settings.module.scss'
+import { profileSocialLinks } from './profileSocialLinks'
const SimplifiedEditor = lazy(() => import('~/components/Editor/SimplifiedEditor'))
const GrowingTextarea = lazy(() => import('~/components/_shared/GrowingTextarea/GrowingTextarea'))
diff --git a/src/components/Views/Profile/ProfileSubscriptions.tsx b/src/components/Views/Profile/ProfileSubscriptions.tsx
index f460f278..0cda14da 100644
--- a/src/components/Views/Profile/ProfileSubscriptions.tsx
+++ b/src/components/Views/Profile/ProfileSubscriptions.tsx
@@ -5,7 +5,7 @@ import { SearchField } from '~/components/_shared/SearchField'
import { FollowsFilter, useFollowing } from '~/context/following'
import { useLocalize } from '~/context/localize'
import { Author, Topic } from '~/graphql/schema/core.gen'
-import { dummyFilter } from '~/lib/dummyFilter'
+import { dummyFilter } from '~/intl/dummyFilter'
import stylesSettings from '../../../styles/FeedSettings.module.scss'
import { AuthorBadge } from '../../Author/AuthorBadge'
import { ProfileSettingsNavigation } from '../../ProfileNav'
diff --git a/src/lib/profileSocialLinks.ts b/src/components/Views/Profile/profileSocialLinks.ts
similarity index 100%
rename from src/lib/profileSocialLinks.ts
rename to src/components/Views/Profile/profileSocialLinks.ts
diff --git a/src/components/_shared/LoadMoreWrapper.tsx b/src/components/_shared/LoadMoreWrapper.tsx
index 37498e04..ff53e9bd 100644
--- a/src/components/_shared/LoadMoreWrapper.tsx
+++ b/src/components/_shared/LoadMoreWrapper.tsx
@@ -2,9 +2,9 @@ import { JSX, Show, createEffect, createSignal, on, onMount } from 'solid-js'
import { Button } from '~/components/_shared/Button'
import { useLocalize } from '~/context/localize'
import { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
-import { byCreated } from '~/lib/sort'
import { SortFunction } from '~/types/common'
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
+import { byCreated } from '~/utils/sort'
export type LoadMoreItems = Shout[] | Author[] | Reaction[]
diff --git a/src/context/authors.tsx b/src/context/authors.tsx
index 8287b443..a9118f61 100644
--- a/src/context/authors.tsx
+++ b/src/context/authors.tsx
@@ -17,8 +17,8 @@ import {
Shout,
Topic
} from '~/graphql/schema/core.gen'
-import { byStat } from '~/lib/sort'
import { FilterFunction, SortFunction } from '~/types/common'
+import { byStat } from '~/utils/sort'
import { useFeed } from './feed'
const TOP_AUTHORS_COUNT = 5
diff --git a/src/context/feed.tsx b/src/context/feed.tsx
index 1ef90e07..3e210b5a 100644
--- a/src/context/feed.tsx
+++ b/src/context/feed.tsx
@@ -12,7 +12,7 @@ import {
Topic
} from '~/graphql/schema/core.gen'
import { graphqlClientCreate } from '../graphql/client'
-import { byStat } from '../lib/sort'
+import { byStat } from '../utils/sort'
import { useSession } from './session'
export const PRERENDERED_ARTICLES_COUNT = 5
diff --git a/src/context/topics.tsx b/src/context/topics.tsx
index 17ee753b..5c437b98 100644
--- a/src/context/topics.tsx
+++ b/src/context/topics.tsx
@@ -12,8 +12,8 @@ import {
} from 'solid-js'
import { loadTopics } from '~/graphql/api/public'
import { Topic } from '~/graphql/schema/core.gen'
-import { getRandomTopicsFromArray } from '~/lib/getRandomTopicsFromArray'
-import { byTopicStatDesc } from '../lib/sort'
+import { getRandomItemsFromArray } from '~/utils/random'
+import { byTopicStatDesc } from '../utils/sort'
type TopicsContextType = {
topicEntities: Accessor<{ [topicSlug: string]: Topic }>
@@ -198,7 +198,7 @@ export const TopicsProvider = (props: { children: JSX.Element }) => {
const topics = isCacheValid ? req : await loadAllTopics()
console.info(`[context.topics] got ${(topics as Topic[]).length || 0} topics from idb`)
addTopics(topics as Topic[])
- setRandomTopic(getRandomTopicsFromArray(topics || [], 1).pop())
+ setRandomTopic(getRandomItemsFromArray(topics || [], 1).pop())
}
},
{ defer: true }
diff --git a/src/lib/dummyFilter.ts b/src/intl/dummyFilter.ts
similarity index 96%
rename from src/lib/dummyFilter.ts
rename to src/intl/dummyFilter.ts
index e54c5a43..cde73ba8 100644
--- a/src/lib/dummyFilter.ts
+++ b/src/intl/dummyFilter.ts
@@ -1,5 +1,5 @@
import type { Author, Topic } from '~/graphql/schema/core.gen'
-import { translit } from '../intl/translit'
+import { translit } from './translit'
const prepareQuery = (searchQuery: string, lang: string) => {
const q = searchQuery.toLowerCase()
diff --git a/src/lib/getRandomTopicsFromArray.ts b/src/lib/getRandomTopicsFromArray.ts
deleted file mode 100644
index 8911f253..00000000
--- a/src/lib/getRandomTopicsFromArray.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Topic } from '~/graphql/schema/core.gen'
-import { RANDOM_TOPICS_COUNT } from '../components/Views/Home'
-
-export const getRandomTopicsFromArray = (topics: Topic[], count: number = RANDOM_TOPICS_COUNT): Topic[] => {
- if (!Array.isArray(topics)) return [] as Topic[]
- const shuffledTopics = [...topics].sort(() => 0.5 - Math.random())
- return shuffledTopics.slice(0, count)
-}
diff --git a/src/lib/sort.ts b/src/lib/sort.ts
deleted file mode 100644
index 8c34e79d..00000000
--- a/src/lib/sort.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import type { Author, Maybe, Reaction, Shout, Topic, TopicStat } from '~/graphql/schema/core.gen'
-
-export const byFirstChar = (a: Author | Topic, b: Author | Topic) =>
- ((a as Author).name || (a as Topic).title || '').localeCompare(
- (b as Author).name || (b as Topic).title || ''
- )
-
-export const byCreated = (a: { created_at?: number }, b: { created_at?: number }) => {
- return (a?.created_at || 0) - (b?.created_at || 0)
-}
-
-export const byPublished = (a: Shout, b: Shout) => {
- return (a?.published_at || 0) - (b?.published_at || 0)
-}
-
-export const byLength = (
- a: (Shout | Reaction | Topic | Author)[],
- b: (Shout | Reaction | Topic | Author)[]
-) => {
- const x = a.length
- const y = b.length
-
- if (x > y) return -1
-
- if (x < y) return 1
-
- return 0
-}
-
-export type SomeStat = { [x: string]: Maybe } | undefined | null
-
-export const byStat = (metric: string) => {
- if (metric === 'name' || metric === 'title') return byFirstChar
- return (a: { stat?: SomeStat }, b: { stat?: SomeStat }) => {
- const aStat = a.stat?.[metric] ?? 0
- const bStat = b.stat?.[metric] ?? 0
- return aStat - bStat
- }
-}
-
-export const byTopicStatDesc = (metric: keyof TopicStat) => {
- return (a: Topic, b: Topic) => {
- const x = a.stat?.[metric] || 0
- const y = b.stat?.[metric] || 0
- if (x > y) return -1
- if (x < y) return 1
- return 0
- }
-}
-
-export const byScore = () => {
- return (a: { score: number }, b: { score: number }) => {
- const x = a?.score || 0
- const y = b?.score || 0
- if (x > y) return -1
- if (x < y) return 1
- return 0
- }
-}
diff --git a/src/utils/random.ts b/src/utils/random.ts
new file mode 100644
index 00000000..1105c52b
--- /dev/null
+++ b/src/utils/random.ts
@@ -0,0 +1,8 @@
+export const getRandomItemsFromArray = (items: T[], count = 10): T[] => {
+ if (!Array.isArray(items)) {
+ return []
+ }
+
+ const shuffledItems = [...items].sort(() => 0.5 - Math.random())
+ return shuffledItems.slice(0, count)
+}
diff --git a/src/utils/sort.ts b/src/utils/sort.ts
new file mode 100644
index 00000000..87475dc5
--- /dev/null
+++ b/src/utils/sort.ts
@@ -0,0 +1,57 @@
+import { Maybe } from 'graphql/jsutils/Maybe'
+
+type WithNameOrTitle = { name?: string } | { title?: string }
+type WithCreatedAt = { created_at?: number }
+type WithPublishedAt = { published_at?: number }
+type WithStat = { stat?: { [key: string]: Maybe } | undefined | null }
+type WithScore = { score: number }
+
+export const byFirstChar = (a: T, b: T) => {
+ const aValue = 'name' in a ? a.name : (a as { title?: string }).title || ''
+ const bValue = 'name' in b ? b.name : (b as { title?: string }).title || ''
+
+ return aValue?.localeCompare(bValue || '')
+}
+export const byCreated = (a: T, b: T) => {
+ return (a?.created_at || 0) - (b?.created_at || 0)
+}
+
+export const byPublished = (a: T, b: T) => {
+ return (a?.published_at || 0) - (b?.published_at || 0)
+}
+
+export const byLength = (a: T[], b: T[]) => {
+ const x = a.length
+ const y = b.length
+
+ if (x > y) return -1
+ if (x < y) return 1
+ return 0
+}
+
+export const byStat = (metric: string) => {
+ if (metric === 'name' || metric === 'title') return byFirstChar
+ return (a: T, b: T) => {
+ const aStat = a.stat?.[metric] ?? 0
+ const bStat = b.stat?.[metric] ?? 0
+ return aStat - bStat
+ }
+}
+
+export const byTopicStatDesc = (metric: string) => {
+ return (a: T, b: T) => {
+ const x = a.stat?.[metric] || 0
+ const y = b.stat?.[metric] || 0
+ if (x > y) return -1
+ if (x < y) return 1
+ return 0
+ }
+}
+
+export const byScore = (a: T, b: T) => {
+ const x = a?.score || 0
+ const y = b?.score || 0
+ if (x > y) return -1
+ if (x < y) return 1
+ return 0
+}