topic+author-loadmore-fix
This commit is contained in:
parent
22f44ee0ec
commit
f808bd2394
|
@ -1,6 +1,6 @@
|
||||||
import { A, useLocation, useParams } from '@solidjs/router'
|
import { A, useLocation, useParams } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
|
import { For, Match, Show, Switch, createEffect, createMemo, createSignal } from 'solid-js'
|
||||||
import { Loading } from '~/components/_shared/Loading'
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
import { coreApiUrl } from '~/config'
|
import { coreApiUrl } from '~/config'
|
||||||
import { useAuthors } from '~/context/authors'
|
import { useAuthors } from '~/context/authors'
|
||||||
|
@ -12,7 +12,6 @@ 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 '~/lib/sort'
|
||||||
import { paginate } from '~/utils/paginate'
|
|
||||||
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'
|
||||||
|
@ -25,20 +24,19 @@ import styles from './Author.module.scss'
|
||||||
|
|
||||||
type AuthorViewProps = {
|
type AuthorViewProps = {
|
||||||
authorSlug: string
|
authorSlug: string
|
||||||
selectedTab: string
|
shouts: Shout[]
|
||||||
shouts?: Shout[]
|
|
||||||
author?: Author
|
author?: Author
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 12
|
export const PRERENDERED_ARTICLES_COUNT = 12
|
||||||
const LOAD_MORE_PAGE_SIZE = 9
|
// const LOAD_MORE_PAGE_SIZE = 9
|
||||||
|
|
||||||
export const AuthorView = (props: AuthorViewProps) => {
|
export const AuthorView = (props: AuthorViewProps) => {
|
||||||
// contexts
|
// contexts
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const loc = useLocation()
|
const loc = useLocation()
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const [currentTab, setCurrentTab] = createSignal<string>(props.selectedTab)
|
const [currentTab, setCurrentTab] = createSignal<string>(params.tab)
|
||||||
|
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
const client = createMemo(() => graphqlClientCreate(coreApiUrl, session()?.access_token))
|
const client = createMemo(() => graphqlClientCreate(coreApiUrl, session()?.access_token))
|
||||||
|
@ -56,21 +54,11 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
|
|
||||||
// derivatives
|
// derivatives
|
||||||
const me = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
|
const me = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
|
||||||
const pages = createMemo<Shout[][]>(() =>
|
|
||||||
paginate((props.shouts || []).slice(1), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Переход по табам
|
// Переход по табам
|
||||||
createEffect(
|
createEffect(() => {
|
||||||
on(
|
setCurrentTab(params.tab)
|
||||||
() => params.tab,
|
})
|
||||||
(tab: string) => {
|
|
||||||
// Обновляем текущую вкладку
|
|
||||||
setCurrentTab(tab || '')
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Объединенный эффект для загрузки автора и его подписок
|
// Объединенный эффект для загрузки автора и его подписок
|
||||||
createEffect(async () => {
|
createEffect(async () => {
|
||||||
|
@ -171,7 +159,6 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
||||||
<Match when={currentTab() === 'about'}>
|
<Match when={currentTab() === 'about'}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -198,7 +185,6 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
</Match>
|
</Match>
|
||||||
|
|
||||||
<Match when={currentTab() === 'comments'}>
|
<Match when={currentTab() === 'comments'}>
|
||||||
|
|
||||||
<Show when={me()?.slug === props.authorSlug && !me().stat?.comments}>
|
<Show when={me()?.slug === props.authorSlug && !me().stat?.comments}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<Placeholder type={loc?.pathname} mode="profile" />
|
<Placeholder type={loc?.pathname} mode="profile" />
|
||||||
|
@ -232,36 +218,29 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={Array.isArray(props.shouts) && props.shouts.length > 0 && props.shouts[0]}>
|
<Show when={Array.isArray(props.shouts) && props.shouts.length > 0}>
|
||||||
<Row1 article={props.shouts?.[0] as Shout} noauthor={true} nodate={true} />
|
<For each={props.shouts.filter((_, i) => i % 3 === 0)}>
|
||||||
|
{(_shout, index) => {
|
||||||
<Show when={props.shouts && props.shouts.length > 1}>
|
const articles = props.shouts.slice(index() * 3, index() * 3 + 3);
|
||||||
<Switch>
|
return (
|
||||||
<Match when={props.shouts && props.shouts.length === 2}>
|
<>
|
||||||
<Row2 articles={props.shouts as Shout[]} isEqual={true} noauthor={true} nodate={true} />
|
<Switch>
|
||||||
</Match>
|
<Match when={articles.length === 1}>
|
||||||
<Match when={props.shouts && props.shouts.length === 3}>
|
<Row1 article={articles[0]} noauthor={true} nodate={true} />
|
||||||
<Row3 articles={props.shouts as Shout[]} noauthor={true} nodate={true} />
|
</Match>
|
||||||
</Match>
|
<Match when={articles.length === 2}>
|
||||||
<Match when={props.shouts && props.shouts.length > 3}>
|
<Row2 articles={articles} noauthor={true} nodate={true} isEqual={true} />
|
||||||
<For each={pages()}>
|
</Match>
|
||||||
{(page) => (
|
<Match when={articles.length === 3}>
|
||||||
<>
|
<Row3 articles={articles} noauthor={true} nodate={true} />
|
||||||
<Row1 article={page[0]} noauthor={true} nodate={true} />
|
</Match>
|
||||||
<Row2 articles={page.slice(1, 3)} isEqual={true} noauthor={true} />
|
</Switch>
|
||||||
<Row1 article={page[3]} noauthor={true} nodate={true} />
|
</>
|
||||||
<Row2 articles={page.slice(4, 6)} isEqual={true} noauthor={true} />
|
);
|
||||||
<Row1 article={page[6]} noauthor={true} nodate={true} />
|
}}
|
||||||
<Row2 articles={page.slice(7, 9)} isEqual={true} noauthor={true} />
|
</For>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
</Show>
|
|
||||||
</Show>
|
</Show>
|
||||||
</Match>
|
</Match>
|
||||||
|
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, Suspense, createEffect, createMemo, createSignal, on } from 'solid-js'
|
import { For, Match, Show, Suspense, Switch, createEffect, createSignal, on } from 'solid-js'
|
||||||
import { useAuthors } from '~/context/authors'
|
import { useAuthors } from '~/context/authors'
|
||||||
import { useFeed } from '~/context/feed'
|
import { useFeed } from '~/context/feed'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
@ -9,7 +9,6 @@ import { loadAuthors, loadFollowersByTopic, loadShouts } from '~/graphql/api/pub
|
||||||
import { Author, AuthorsBy, LoadShoutsOptions, Shout, Topic } from '~/graphql/schema/core.gen'
|
import { Author, AuthorsBy, LoadShoutsOptions, Shout, Topic } from '~/graphql/schema/core.gen'
|
||||||
import { SHOUTS_PER_PAGE } from '~/routes/(main)'
|
import { SHOUTS_PER_PAGE } from '~/routes/(main)'
|
||||||
import { getUnixtime } from '~/utils/date'
|
import { getUnixtime } from '~/utils/date'
|
||||||
import { paginate } from '~/utils/paginate'
|
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
||||||
import styles from '../../styles/Topic.module.scss'
|
import styles from '../../styles/Topic.module.scss'
|
||||||
import { Beside } from '../Feed/Beside'
|
import { Beside } from '../Feed/Beside'
|
||||||
|
@ -21,7 +20,6 @@ import { LoadMoreItems, LoadMoreWrapper } from '../_shared/LoadMoreWrapper'
|
||||||
import { Loading } from '../_shared/Loading'
|
import { Loading } from '../_shared/Loading'
|
||||||
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
|
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
|
||||||
|
|
||||||
// FIXME: should be 'last_comment' and 'comments_stat' or just one?
|
|
||||||
export type TopicFeedSortBy = 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'last_comment'
|
export type TopicFeedSortBy = 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'last_comment'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -33,7 +31,7 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 28
|
export const PRERENDERED_ARTICLES_COUNT = 28
|
||||||
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
|
// const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
|
||||||
|
|
||||||
export const TopicView = (props: Props) => {
|
export const TopicView = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
@ -49,13 +47,13 @@ export const TopicView = (props: Props) => {
|
||||||
// TODO: filter + sort
|
// TODO: filter + sort
|
||||||
const [sortedFeed, setSortedFeed] = createSignal([] as Shout[])
|
const [sortedFeed, setSortedFeed] = createSignal([] as Shout[])
|
||||||
createEffect(on(([feedByTopic, () => props.topicSlug, topicEntities]), ([feed, slug, ttt]) => {
|
createEffect(on(([feedByTopic, () => props.topicSlug, topicEntities]), ([feed, slug, ttt]) => {
|
||||||
if (Object.values(ttt).length === 0) return
|
if (Object.values(ttt).length === 0) return
|
||||||
const sss = (feed[slug] || []) as Shout[]
|
const sss = (feed[slug] || []) as Shout[]
|
||||||
sss && setSortedFeed(sss)
|
sss && setSortedFeed(sss)
|
||||||
console.debug('topic slug loaded', slug)
|
console.debug('topic slug loaded', slug)
|
||||||
const tpc = ttt[slug]
|
const tpc = ttt[slug]
|
||||||
console.debug('topics loaded', ttt)
|
console.debug('topics loaded', ttt)
|
||||||
tpc && setTopic(tpc)
|
tpc && setTopic(tpc)
|
||||||
}, {}))
|
}, {}))
|
||||||
|
|
||||||
const loadTopicFollowers = async () => {
|
const loadTopicFollowers = async () => {
|
||||||
|
@ -104,12 +102,12 @@ export const TopicView = (props: Props) => {
|
||||||
|
|
||||||
// второй этап начальной загрузки данных
|
// второй этап начальной загрузки данных
|
||||||
createEffect(on(topic, (tpc) => {
|
createEffect(on(topic, (tpc) => {
|
||||||
console.debug('topic loaded', tpc)
|
console.debug('topic loaded', tpc)
|
||||||
if (!tpc) return
|
if (!tpc) return
|
||||||
loadFavoriteTopArticles()
|
loadFavoriteTopArticles()
|
||||||
loadReactedTopMonthArticles()
|
loadReactedTopMonthArticles()
|
||||||
loadTopicAuthors()
|
loadTopicAuthors()
|
||||||
loadTopicFollowers()
|
loadTopicFollowers()
|
||||||
}, { defer: true }))
|
}, { defer: true }))
|
||||||
|
|
||||||
// дозагрузка
|
// дозагрузка
|
||||||
|
@ -137,9 +135,6 @@ export const TopicView = (props: Props) => {
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const pages = createMemo<Shout[][]>(() =>
|
|
||||||
paginate(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
|
|
||||||
)
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.topicPage}>
|
<div class={styles.topicPage}>
|
||||||
<Suspense fallback={<Loading />}>
|
<Suspense fallback={<Loading />}>
|
||||||
|
@ -223,15 +218,26 @@ export const TopicView = (props: Props) => {
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<LoadMoreWrapper loadFunction={loadMore} pageSize={SHOUTS_PER_PAGE}>
|
<LoadMoreWrapper loadFunction={loadMore} pageSize={SHOUTS_PER_PAGE}>
|
||||||
<For each={pages()}>
|
<For each={sortedFeed().slice(19).filter((_, i) => i % 3 === 0)}>
|
||||||
{(page) => (
|
{(_shout, index) => {
|
||||||
|
const articles = sortedFeed().slice(19).slice(index() * 3, index() * 3 + 3);
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<Row3 articles={page.slice(0, 3)} />
|
<Switch>
|
||||||
<Row3 articles={page.slice(3, 6)} />
|
<Match when={articles.length === 1}>
|
||||||
<Row3 articles={page.slice(6, 9)} />
|
<Row1 article={articles[0]} noauthor={true} nodate={true} />
|
||||||
|
</Match>
|
||||||
|
<Match when={articles.length === 2}>
|
||||||
|
<Row2 articles={articles} noauthor={true} nodate={true} isEqual={true} />
|
||||||
|
</Match>
|
||||||
|
<Match when={articles.length === 3}>
|
||||||
|
<Row3 articles={articles} noauthor={true} nodate={true} />
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
</>
|
</>
|
||||||
)}
|
);
|
||||||
</For>
|
}}
|
||||||
|
</For>
|
||||||
</LoadMoreWrapper>
|
</LoadMoreWrapper>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -138,9 +138,8 @@ export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
||||||
>
|
>
|
||||||
<AuthorView
|
<AuthorView
|
||||||
author={author() as Author}
|
author={author() as Author}
|
||||||
selectedTab={props.params.tab}
|
|
||||||
authorSlug={props.params.slug}
|
authorSlug={props.params.slug}
|
||||||
shouts={authorShouts()}
|
shouts={authorShouts() || []}
|
||||||
/>
|
/>
|
||||||
</LoadMoreWrapper>
|
</LoadMoreWrapper>
|
||||||
</ReactionsProvider>
|
</ReactionsProvider>
|
||||||
|
|
|
@ -62,34 +62,38 @@ export default function TopicPage(props: RouteSectionProps<TopicPageProps>) {
|
||||||
const [desc, setDesc] = createSignal<string>('')
|
const [desc, setDesc] = createSignal<string>('')
|
||||||
const [cover, setCover] = createSignal<string>('')
|
const [cover, setCover] = createSignal<string>('')
|
||||||
const [viewed, setViewed] = createSignal(false)
|
const [viewed, setViewed] = createSignal(false)
|
||||||
createEffect(on([topics, () => window], ([ttt, win]) => {
|
createEffect(
|
||||||
if (ttt && win) {
|
on(
|
||||||
// console.debug('all topics:', ttt)
|
[topics, () => window],
|
||||||
ttt && addTopics(ttt)
|
([ttt, win]) => {
|
||||||
const tpc = ttt.find((x) => x.slug === props.params.slug)
|
if (ttt && win) {
|
||||||
if (!tpc) return
|
// console.debug('all topics:', ttt)
|
||||||
setTopic(tpc)
|
ttt && addTopics(ttt)
|
||||||
setTitle(() => `${t('Discours')}${topic()?.title ? ` :: ${topic()?.title}` : ''}`)
|
const tpc = ttt.find((x) => x.slug === props.params.slug)
|
||||||
setDesc(() =>
|
if (!tpc) return
|
||||||
topic()?.body
|
setTopic(tpc)
|
||||||
? descFromBody(topic()?.body || '')
|
setTitle(() => `${t('Discours')}${topic()?.title ? ` :: ${topic()?.title}` : ''}`)
|
||||||
: t('The most interesting publications on the topic', { topicName: title() })
|
setDesc(() =>
|
||||||
)
|
topic()?.body
|
||||||
setCover(() =>
|
? descFromBody(topic()?.body || '')
|
||||||
topic()?.pic ? getImageUrl(topic()?.pic || '', { width: 1200 }) : '/logo.png'
|
: t('The most interesting publications on the topic', { topicName: title() })
|
||||||
)
|
)
|
||||||
|
setCover(() => (topic()?.pic ? getImageUrl(topic()?.pic || '', { width: 1200 }) : '/logo.png'))
|
||||||
|
|
||||||
// views google counter increment
|
// views google counter increment
|
||||||
if (viewed()) {
|
if (!viewed()) {
|
||||||
window?.gtag?.('event', 'page_view', {
|
window?.gtag?.('event', 'page_view', {
|
||||||
page_title: tpc.title,
|
page_title: tpc.title,
|
||||||
page_location: window?.location.href,
|
page_location: window?.location.href,
|
||||||
page_path: window?.location.pathname
|
page_path: window?.location.pathname
|
||||||
})
|
})
|
||||||
setViewed(true)
|
setViewed(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {}))
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show
|
||||||
|
|
Loading…
Reference in New Issue
Block a user