diff --git a/src/components/Author/Card.tsx b/src/components/Author/Card.tsx
index feb02cb4..0f75c65d 100644
--- a/src/components/Author/Card.tsx
+++ b/src/components/Author/Card.tsx
@@ -9,6 +9,7 @@ import { locale } from '../../stores/ui'
import { follow, unfollow } from '../../stores/zine/common'
import { clsx } from 'clsx'
import { useSession } from '../../context/session'
+import { StatMetrics } from '../_shared/StatMetrics'
interface AuthorCardProps {
caption?: string
@@ -69,9 +70,11 @@ export const AuthorCard = (props: AuthorCardProps) => {
{props.isAuthorsList}
-
- {bio()}
-
+
diff --git a/src/components/Topic/Card.tsx b/src/components/Topic/Card.tsx
index 8067171e..6cdc394a 100644
--- a/src/components/Topic/Card.tsx
+++ b/src/components/Topic/Card.tsx
@@ -1,14 +1,14 @@
-import { capitalize, plural } from '../../utils'
+import { capitalize } from '../../utils'
import styles from './Card.module.scss'
import { createMemo, Show } from 'solid-js'
import type { Topic } from '../../graphql/types.gen'
import { FollowingEntity } from '../../graphql/types.gen'
import { t } from '../../utils/intl'
-import { locale } from '../../stores/ui'
import { follow, unfollow } from '../../stores/zine/common'
import { getLogger } from '../../utils/logger'
import { clsx } from 'clsx'
import { useSession } from '../../context/session'
+import { StatMetrics } from '../_shared/StatMetrics'
const log = getLogger('TopicCard')
@@ -74,54 +74,6 @@ export const TopicCard = (props: TopicProps) => {
{props.topic.body}
-
-
-
-
-
- {props.topic.stat?.shouts +
- ' ' +
- t('post') +
- plural(
- props.topic.stat?.shouts || 0,
- locale() === 'ru' ? ['ов', '', 'а'] : ['s', '', 's']
- )}
-
-
-
-
- {props.topic.stat?.authors +
- ' ' +
- t('author') +
- plural(
- props.topic.stat?.authors || 0,
- locale() === 'ru' ? ['ов', '', 'а'] : ['s', '', 's']
- )}
-
-
- {props.topic.stat?.followers +
- ' ' +
- t('follower') +
- plural(
- props.topic.stat?.followers || 0,
- locale() === 'ru' ? ['ов', '', 'а'] : ['s', '', 's']
- )}
-
- {/*FIXME*/}
- {/**/}
- {/* */}
- {/* {topic().stat?.viewed +*/}
- {/* ' ' +*/}
- {/* t('view') +*/}
- {/* plural(*/}
- {/* topic().stat?.viewed || 0,*/}
- {/* locale() === 'ru' ? ['ов', '', 'а'] : ['s', '', 's']*/}
- {/* )}*/}
- {/* */}
- {/**/}
-
-
-
{
- const { sortedAuthors } = useAuthorsStore({ authors: props.authors })
const [limit, setLimit] = createSignal(PAGE_SIZE)
+ const { searchParams, changeSearchParam } = useRouter
()
+ const { sortedAuthors } = useAuthorsStore({
+ authors: props.authors,
+ sortBy: searchParams().by || 'shouts'
+ })
const { session } = useSession()
+ onMount(() => changeSearchParam('by', 'shouts'))
createEffect(() => {
setAuthorsSort(searchParams().by || 'shouts')
+ setLimit(PAGE_SIZE)
})
const subscribed = (s) => Boolean(session()?.news?.authors && session()?.news?.authors?.includes(s || ''))
- const { searchParams, changeSearchParam } = useRouter()
-
const byLetter = createMemo<{ [letter: string]: Author[] }>(() => {
return sortedAuthors().reduce((acc, author) => {
let letter = author.name.trim().split(' ').pop().at(0).toUpperCase()
- if (!/[А-Я]/i.test(letter) && locale() === 'ru') letter = '@'
+ if (!/[А-я]/i.test(letter) && locale() === 'ru') letter = '@'
if (!acc[letter]) acc[letter] = []
acc[letter].push(author)
return acc
@@ -64,8 +69,8 @@ export const AllAuthorsView = (props: Props) => {
{t('By shouts')}
-
- {t('By rating')}
+
+ {t('By rating')}
{t('By name')}
@@ -167,15 +172,18 @@ export const AllAuthorsView = (props: Props) => {
0}>
{(author) => (
-
+ <>
+
+
+ >
)}
@@ -185,15 +193,18 @@ export const AllAuthorsView = (props: Props) => {
{(author) => (
-
+ <>
+
+
+ >
)}
diff --git a/src/components/Views/AllTopics.tsx b/src/components/Views/AllTopics.tsx
index a28c71da..d6bce589 100644
--- a/src/components/Views/AllTopics.tsx
+++ b/src/components/Views/AllTopics.tsx
@@ -1,4 +1,4 @@
-import { createEffect, createMemo, createSignal, For, Show } from 'solid-js'
+import { createEffect, createMemo, createSignal, For, onMount, Show } from 'solid-js'
import type { Topic } from '../../graphql/types.gen'
import { t } from '../../utils/intl'
import { setTopicsSort, useTopicsStore } from '../../stores/zine/topics'
@@ -11,6 +11,7 @@ import { translit } from '../../utils/ru2en'
import styles from '../../styles/AllTopics.module.scss'
import { SearchField } from '../_shared/SearchField'
import { scrollHandler } from '../../utils/scroll'
+import { StatMetrics } from '../_shared/StatMetrics'
type AllTopicsPageSearchParams = {
by: 'shouts' | 'authors' | 'title' | ''
@@ -34,6 +35,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => {
const { session } = useSession()
+ onMount(() => changeSearchParam('by', 'shouts'))
createEffect(() => {
setTopicsSort(searchParams().by || 'shouts')
setLimit(PAGE_SIZE)
@@ -182,12 +184,15 @@ export const AllTopicsView = (props: AllTopicsViewProps) => {
{(topic) => (
-
+ <>
+
+
+ >
)}
diff --git a/src/components/_shared/Stat.module.scss b/src/components/_shared/Stat.module.scss
new file mode 100644
index 00000000..183bea64
--- /dev/null
+++ b/src/components/_shared/Stat.module.scss
@@ -0,0 +1,34 @@
+.statMetrics {
+ @include font-size(1.7rem);
+
+ color: #9fa1a7;
+ display: flex;
+ margin-bottom: 1em;
+
+ @include media-breakpoint-down(md) {
+ flex-wrap: wrap;
+ }
+}
+
+.statMetricsItem {
+ @include font-size(1.5rem);
+
+ margin-right: 1.6rem;
+ white-space: nowrap;
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ &.compact {
+ font-size: small;
+ }
+
+ &.followers {
+ word-break: keep-all;
+ }
+
+ &.button {
+ float: right;
+ }
+}
diff --git a/src/components/_shared/StatMetrics.tsx b/src/components/_shared/StatMetrics.tsx
new file mode 100644
index 00000000..fd60946c
--- /dev/null
+++ b/src/components/_shared/StatMetrics.tsx
@@ -0,0 +1,35 @@
+import { For } from 'solid-js'
+import type { Stat, TopicStat } from '../../graphql/types.gen'
+import { locale } from '../../stores/ui'
+import { plural } from '../../utils'
+import { t } from '../../utils/intl'
+import styles from './Stat.module.scss'
+
+interface StatMetricsProps {
+ fields?: string[]
+ stat: Stat | TopicStat
+ compact?: boolean
+}
+
+const pseudonames = {
+ comments: 'discussions'
+}
+
+const nos = (s) => s.slice(0, s.length - 1)
+
+export const StatMetrics = (props: StatMetricsProps) => {
+ return (
+
+
+ {(entity: string) => (
+
+ {props.stat[entity] +
+ ' ' +
+ t(nos(pseudonames[entity] || entity)) +
+ plural(props.stat[entity] || 0, locale() === 'ru' ? ['ов', '', 'а'] : ['s', '', 's'])}
+
+ )}
+
+
+ )
+}
diff --git a/src/graphql/query/authors-all.ts b/src/graphql/query/authors-all.ts
index dd9ff818..1a1813ba 100644
--- a/src/graphql/query/authors-all.ts
+++ b/src/graphql/query/authors-all.ts
@@ -13,6 +13,7 @@ export default gql`
stat {
shouts
followers
+ comments: commented
}
}
}
diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts
index a57bc253..e199e4cf 100644
--- a/src/graphql/types.gen.ts
+++ b/src/graphql/types.gen.ts
@@ -35,10 +35,10 @@ export type Author = {
}
export type AuthorStat = {
+ rating?: Maybe
commented?: Maybe
followers?: Maybe
followings?: Maybe
- rating?: Maybe
shouts?: Maybe
}
@@ -615,6 +615,8 @@ export type Stat = {
rating?: Maybe
reacted?: Maybe
viewed?: Maybe
+ shouts?: Maybe
+ followers?: Maybe
}
export type Subscription = {
diff --git a/src/locales/ru.json b/src/locales/ru.json
index dce9e981..d65efc8b 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -178,5 +178,7 @@
"topics": "темы",
"user already exist": "пользователь уже существует",
"view": "просмотр",
- "zine": "журнал"
+ "zine": "журнал",
+ "shout": "пост",
+ "discussion": "дискурс"
}
diff --git a/src/stores/zine/authors.ts b/src/stores/zine/authors.ts
index 49d8b53c..c133b8ec 100644
--- a/src/stores/zine/authors.ts
+++ b/src/stores/zine/authors.ts
@@ -2,8 +2,9 @@ import { apiClient } from '../../utils/apiClient'
import type { Author } from '../../graphql/types.gen'
import { createSignal } from 'solid-js'
import { createLazyMemo } from '@solid-primitives/memo'
+import { byStat } from '../../utils/sortby'
-export type AuthorsSortBy = 'shouts' | 'name' | 'rating'
+export type AuthorsSortBy = 'shouts' | 'name' | 'followers'
const [sortAllBy, setSortAllBy] = createSignal('shouts')
@@ -15,21 +16,15 @@ const [authorsByTopic, setAuthorsByTopic] = createSignal<{ [topicSlug: string]:
const sortedAuthors = createLazyMemo(() => {
const authors = Object.values(authorEntities())
switch (sortAllBy()) {
- // case 'created': {
- // log.debug('sorted by created')
- // authors.sort(byCreated)
- // break
- // }
- case 'rating': {
- // TODO:
+ case 'followers': {
+ authors.sort(byStat('followers'))
break
}
case 'shouts': {
- // TODO:
+ authors.sort(byStat('shouts'))
break
}
case 'name': {
- console.debug('sorted by name')
authors.sort((a, b) => a.name.localeCompare(b.name))
break
}
@@ -84,9 +79,13 @@ export const loadAllAuthors = async (): Promise => {
type InitialState = {
authors?: Author[]
+ sortBy?: AuthorsSortBy
}
export const useAuthorsStore = (initialState: InitialState = {}) => {
+ if (initialState.sortBy) {
+ setSortAllBy(initialState.sortBy)
+ }
addAuthors([...(initialState.authors || [])])
return { authorEntities, sortedAuthors, authorsByTopic }
diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts
index f263cb3d..7ea0c301 100644
--- a/src/utils/apiClient.ts
+++ b/src/utils/apiClient.ts
@@ -260,9 +260,7 @@ export const apiClient = {
},
getReactionsBy: async ({ by, limit = REACTIONS_AMOUNT_PER_PAGE, offset = 0 }) => {
const resp = await publicGraphQLClient.query(reactionsLoadBy, { by, limit, offset }).toPromise()
-
- console.log('resactions response', resp)
-
+ resp.error ?? console.error(resp.error)
return resp.data.loadReactionsBy
},
diff --git a/src/utils/sortby.ts b/src/utils/sortby.ts
index 9d001037..4b03fdaee 100644
--- a/src/utils/sortby.ts
+++ b/src/utils/sortby.ts
@@ -27,7 +27,6 @@ export const byLength = (
return 0
}
-// TODO more typing
export const byStat = (metric: keyof Stat) => {
return (a, b) => {
const x = (a?.stat && a.stat[metric]) || 0