minor-ref
This commit is contained in:
parent
cd436dd34d
commit
7c614c66d9
|
@ -6,8 +6,8 @@ import { useLocalize } from '~/context/localize'
|
||||||
import { useReactions } from '~/context/reactions'
|
import { useReactions } from '~/context/reactions'
|
||||||
import { useSession } from '~/context/session'
|
import { useSession } from '~/context/session'
|
||||||
import { Author, Reaction, ReactionKind, ReactionSort } from '~/graphql/schema/core.gen'
|
import { Author, Reaction, ReactionKind, ReactionSort } from '~/graphql/schema/core.gen'
|
||||||
import { byCreated, byStat } from '~/lib/sort'
|
|
||||||
import { SortFunction } from '~/types/common'
|
import { SortFunction } from '~/types/common'
|
||||||
|
import { byCreated, byStat } from '~/utils/sort'
|
||||||
import { Button } from '../_shared/Button'
|
import { Button } from '../_shared/Button'
|
||||||
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
|
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
|
||||||
import styles from './Article.module.scss'
|
import styles from './Article.module.scss'
|
||||||
|
|
|
@ -5,8 +5,8 @@ import { Icon } from '~/components/_shared/Icon'
|
||||||
import { useFeed } from '~/context/feed'
|
import { useFeed } from '~/context/feed'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import type { Shout } from '~/graphql/schema/core.gen'
|
import type { Shout } from '~/graphql/schema/core.gen'
|
||||||
import { byScore } from '~/lib/sort'
|
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
||||||
|
import { byScore } from '~/utils/sort'
|
||||||
import { FEED_PAGE_SIZE } from '../Views/Feed/Feed'
|
import { FEED_PAGE_SIZE } from '../Views/Feed/Feed'
|
||||||
import styles from './SearchModal.module.scss'
|
import styles from './SearchModal.module.scss'
|
||||||
import { SearchResultItem } from './SearchResultItem'
|
import { SearchResultItem } from './SearchResultItem'
|
||||||
|
@ -23,7 +23,7 @@ const getSearchCoincidences = ({ str, intersection }: { str: string; intersectio
|
||||||
)}</span>`
|
)}</span>`
|
||||||
|
|
||||||
const prepareSearchResults = (list: Shout[], searchValue: string) =>
|
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,
|
...article,
|
||||||
id: index,
|
id: index,
|
||||||
title: article.title
|
title: article.title
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Icon } from '~/components/_shared/Icon'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useTopics } from '~/context/topics'
|
import { useTopics } from '~/context/topics'
|
||||||
import type { Topic } from '~/graphql/schema/core.gen'
|
import type { Topic } from '~/graphql/schema/core.gen'
|
||||||
import { getRandomTopicsFromArray } from '~/lib/getRandomTopicsFromArray'
|
import { getRandomItemsFromArray } from '~/utils/random'
|
||||||
import styles from './TopicsNav.module.scss'
|
import styles from './TopicsNav.module.scss'
|
||||||
|
|
||||||
export const RandomTopics = () => {
|
export const RandomTopics = () => {
|
||||||
|
@ -17,11 +17,11 @@ export const RandomTopics = () => {
|
||||||
createEffect(
|
createEffect(
|
||||||
on(sortedTopics, (ttt: Topic[]) => {
|
on(sortedTopics, (ttt: Topic[]) => {
|
||||||
if (ttt?.length) {
|
if (ttt?.length) {
|
||||||
setRandomTopics(getRandomTopicsFromArray(ttt))
|
setRandomTopics(getRandomItemsFromArray(ttt))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
onMount(() => sortedTopics() && getRandomTopicsFromArray(sortedTopics()))
|
onMount(() => sortedTopics() && getRandomItemsFromArray(sortedTopics()))
|
||||||
return (
|
return (
|
||||||
<ul class="nodash">
|
<ul class="nodash">
|
||||||
<Show when={randomTopics().length > 0}>
|
<Show when={randomTopics().length > 0}>
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { SearchField } from '~/components/_shared/SearchField'
|
||||||
import { useAuthors } from '~/context/authors'
|
import { useAuthors } from '~/context/authors'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import type { Author } from '~/graphql/schema/core.gen'
|
import type { Author } from '~/graphql/schema/core.gen'
|
||||||
|
import { dummyFilter } from '~/intl/dummyFilter'
|
||||||
import { authorLetterReduce, translateAuthor } from '~/intl/translate'
|
import { authorLetterReduce, translateAuthor } from '~/intl/translate'
|
||||||
import { dummyFilter } from '~/lib/dummyFilter'
|
|
||||||
// import { byFirstChar, byStat } from '~/lib/sort'
|
// import { byFirstChar, byStat } from '~/lib/sort'
|
||||||
import { scrollHandler } from '~/utils/scroll'
|
import { scrollHandler } from '~/utils/scroll'
|
||||||
import styles from './AllAuthors.module.scss'
|
import styles from './AllAuthors.module.scss'
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { SearchField } from '~/components/_shared/SearchField'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useTopics } from '~/context/topics'
|
import { useTopics } from '~/context/topics'
|
||||||
import type { Topic } from '~/graphql/schema/core.gen'
|
import type { Topic } from '~/graphql/schema/core.gen'
|
||||||
import { dummyFilter } from '~/lib/dummyFilter'
|
import { dummyFilter } from '~/intl/dummyFilter'
|
||||||
import { scrollHandler } from '~/utils/scroll'
|
import { scrollHandler } from '~/utils/scroll'
|
||||||
import { TopicBadge } from '../../Topic/TopicBadge'
|
import { TopicBadge } from '../../Topic/TopicBadge'
|
||||||
import styles from './AllTopics.module.scss'
|
import styles from './AllTopics.module.scss'
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { graphqlClientCreate } from '~/graphql/client'
|
||||||
import getAuthorFollowersQuery from '~/graphql/query/core/author-followers'
|
import getAuthorFollowersQuery from '~/graphql/query/core/author-followers'
|
||||||
import getAuthorFollowsQuery from '~/graphql/query/core/author-follows'
|
import getAuthorFollowsQuery from '~/graphql/query/core/author-follows'
|
||||||
import type { Author, Reaction, Shout, Topic } from '~/graphql/schema/core.gen'
|
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 stylesArticle from '../../Article/Article.module.scss'
|
||||||
import { Comment } from '../../Article/Comment'
|
import { Comment } from '../../Article/Comment'
|
||||||
import { AuthorCard } from '../../Author/AuthorCard'
|
import { AuthorCard } from '../../Author/AuthorCard'
|
||||||
|
|
|
@ -17,8 +17,8 @@ import { useUI } from '~/context/ui'
|
||||||
import { loadUnratedShouts } from '~/graphql/api/private'
|
import { loadUnratedShouts } from '~/graphql/api/private'
|
||||||
import { graphqlClientCreate } from '~/graphql/client'
|
import { graphqlClientCreate } from '~/graphql/client'
|
||||||
import type { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
|
import type { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
|
||||||
import { byCreated } from '~/lib/sort'
|
|
||||||
import { FeedSearchParams } from '~/routes/feed/[...order]'
|
import { FeedSearchParams } from '~/routes/feed/[...order]'
|
||||||
|
import { byCreated } from '~/utils/sort'
|
||||||
import { CommentDate } from '../../Article/CommentDate'
|
import { CommentDate } from '../../Article/CommentDate'
|
||||||
import { getShareUrl } from '../../Article/SharePopup'
|
import { getShareUrl } from '../../Article/SharePopup'
|
||||||
import { AuthorBadge } from '../../Author/AuthorBadge'
|
import { AuthorBadge } from '../../Author/AuthorBadge'
|
||||||
|
|
|
@ -21,7 +21,6 @@ import { useSnackbar, useUI } from '~/context/ui'
|
||||||
import { InputMaybe, ProfileInput } from '~/graphql/schema/core.gen'
|
import { InputMaybe, ProfileInput } from '~/graphql/schema/core.gen'
|
||||||
import { getImageUrl } from '~/lib/getThumbUrl'
|
import { getImageUrl } from '~/lib/getThumbUrl'
|
||||||
import { handleImageUpload } from '~/lib/handleImageUpload'
|
import { handleImageUpload } from '~/lib/handleImageUpload'
|
||||||
import { profileSocialLinks } from '~/lib/profileSocialLinks'
|
|
||||||
import { clone } from '~/utils/clone'
|
import { clone } from '~/utils/clone'
|
||||||
import { validateUrl } from '~/utils/validate'
|
import { validateUrl } from '~/utils/validate'
|
||||||
import { ProfileSettingsNavigation } from '../../ProfileNav'
|
import { ProfileSettingsNavigation } from '../../ProfileNav'
|
||||||
|
@ -33,6 +32,7 @@ import { Modal } from '../../_shared/Modal'
|
||||||
import { Popover } from '../../_shared/Popover'
|
import { Popover } from '../../_shared/Popover'
|
||||||
import { SocialNetworkInput } from '../../_shared/SocialNetworkInput'
|
import { SocialNetworkInput } from '../../_shared/SocialNetworkInput'
|
||||||
import styles from './Settings.module.scss'
|
import styles from './Settings.module.scss'
|
||||||
|
import { profileSocialLinks } from './profileSocialLinks'
|
||||||
|
|
||||||
const SimplifiedEditor = lazy(() => import('~/components/Editor/SimplifiedEditor'))
|
const SimplifiedEditor = lazy(() => import('~/components/Editor/SimplifiedEditor'))
|
||||||
const GrowingTextarea = lazy(() => import('~/components/_shared/GrowingTextarea/GrowingTextarea'))
|
const GrowingTextarea = lazy(() => import('~/components/_shared/GrowingTextarea/GrowingTextarea'))
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { SearchField } from '~/components/_shared/SearchField'
|
||||||
import { FollowsFilter, useFollowing } from '~/context/following'
|
import { FollowsFilter, useFollowing } from '~/context/following'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Author, Topic } from '~/graphql/schema/core.gen'
|
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 stylesSettings from '../../../styles/FeedSettings.module.scss'
|
||||||
import { AuthorBadge } from '../../Author/AuthorBadge'
|
import { AuthorBadge } from '../../Author/AuthorBadge'
|
||||||
import { ProfileSettingsNavigation } from '../../ProfileNav'
|
import { ProfileSettingsNavigation } from '../../ProfileNav'
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { JSX, Show, createEffect, createSignal, on, onMount } from 'solid-js'
|
||||||
import { Button } from '~/components/_shared/Button'
|
import { Button } from '~/components/_shared/Button'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
|
import { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
|
||||||
import { byCreated } from '~/lib/sort'
|
|
||||||
import { SortFunction } from '~/types/common'
|
import { SortFunction } from '~/types/common'
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
||||||
|
import { byCreated } from '~/utils/sort'
|
||||||
|
|
||||||
export type LoadMoreItems = Shout[] | Author[] | Reaction[]
|
export type LoadMoreItems = Shout[] | Author[] | Reaction[]
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ import {
|
||||||
Shout,
|
Shout,
|
||||||
Topic
|
Topic
|
||||||
} from '~/graphql/schema/core.gen'
|
} from '~/graphql/schema/core.gen'
|
||||||
import { byStat } from '~/lib/sort'
|
|
||||||
import { FilterFunction, SortFunction } from '~/types/common'
|
import { FilterFunction, SortFunction } from '~/types/common'
|
||||||
|
import { byStat } from '~/utils/sort'
|
||||||
import { useFeed } from './feed'
|
import { useFeed } from './feed'
|
||||||
|
|
||||||
const TOP_AUTHORS_COUNT = 5
|
const TOP_AUTHORS_COUNT = 5
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
Topic
|
Topic
|
||||||
} from '~/graphql/schema/core.gen'
|
} from '~/graphql/schema/core.gen'
|
||||||
import { graphqlClientCreate } from '../graphql/client'
|
import { graphqlClientCreate } from '../graphql/client'
|
||||||
import { byStat } from '../lib/sort'
|
import { byStat } from '../utils/sort'
|
||||||
import { useSession } from './session'
|
import { useSession } from './session'
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 5
|
export const PRERENDERED_ARTICLES_COUNT = 5
|
||||||
|
|
|
@ -12,8 +12,8 @@ import {
|
||||||
} from 'solid-js'
|
} from 'solid-js'
|
||||||
import { loadTopics } from '~/graphql/api/public'
|
import { loadTopics } from '~/graphql/api/public'
|
||||||
import { Topic } from '~/graphql/schema/core.gen'
|
import { Topic } from '~/graphql/schema/core.gen'
|
||||||
import { getRandomTopicsFromArray } from '~/lib/getRandomTopicsFromArray'
|
import { getRandomItemsFromArray } from '~/utils/random'
|
||||||
import { byTopicStatDesc } from '../lib/sort'
|
import { byTopicStatDesc } from '../utils/sort'
|
||||||
|
|
||||||
type TopicsContextType = {
|
type TopicsContextType = {
|
||||||
topicEntities: Accessor<{ [topicSlug: string]: Topic }>
|
topicEntities: Accessor<{ [topicSlug: string]: Topic }>
|
||||||
|
@ -198,7 +198,7 @@ export const TopicsProvider = (props: { children: JSX.Element }) => {
|
||||||
const topics = isCacheValid ? req : await loadAllTopics()
|
const topics = isCacheValid ? req : await loadAllTopics()
|
||||||
console.info(`[context.topics] got ${(topics as Topic[]).length || 0} topics from idb`)
|
console.info(`[context.topics] got ${(topics as Topic[]).length || 0} topics from idb`)
|
||||||
addTopics(topics as Topic[])
|
addTopics(topics as Topic[])
|
||||||
setRandomTopic(getRandomTopicsFromArray(topics || [], 1).pop())
|
setRandomTopic(getRandomItemsFromArray(topics || [], 1).pop())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ defer: true }
|
{ defer: true }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Author, Topic } from '~/graphql/schema/core.gen'
|
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 prepareQuery = (searchQuery: string, lang: string) => {
|
||||||
const q = searchQuery.toLowerCase()
|
const q = searchQuery.toLowerCase()
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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<number> } | 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
|
|
||||||
}
|
|
||||||
}
|
|
8
src/utils/random.ts
Normal file
8
src/utils/random.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export const getRandomItemsFromArray = <T>(items: T[], count = 10): T[] => {
|
||||||
|
if (!Array.isArray(items)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const shuffledItems = [...items].sort(() => 0.5 - Math.random())
|
||||||
|
return shuffledItems.slice(0, count)
|
||||||
|
}
|
57
src/utils/sort.ts
Normal file
57
src/utils/sort.ts
Normal file
|
@ -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<number> } | undefined | null }
|
||||||
|
type WithScore = { score: number }
|
||||||
|
|
||||||
|
export const byFirstChar = <T extends WithNameOrTitle>(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 = <T extends WithCreatedAt>(a: T, b: T) => {
|
||||||
|
return (a?.created_at || 0) - (b?.created_at || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const byPublished = <T extends WithPublishedAt>(a: T, b: T) => {
|
||||||
|
return (a?.published_at || 0) - (b?.published_at || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const byLength = <T>(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 <T extends WithStat>(a: T, b: T) => {
|
||||||
|
const aStat = a.stat?.[metric] ?? 0
|
||||||
|
const bStat = b.stat?.[metric] ?? 0
|
||||||
|
return aStat - bStat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const byTopicStatDesc = <T extends WithStat>(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 = <T extends WithScore>(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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user