diff --git a/src/components/Topic/Full.tsx b/src/components/Topic/Full.tsx index 874f45d5..5449a211 100644 --- a/src/components/Topic/Full.tsx +++ b/src/components/Topic/Full.tsx @@ -1,7 +1,7 @@ import type { Author, Topic } from '~/graphql/schema/core.gen' import { clsx } from 'clsx' -import { Show, createEffect, createMemo, createSignal } from 'solid-js' +import { Show, createEffect, createSignal, on } from 'solid-js' import { useFollowing } from '~/context/following' import { useLocalize } from '~/context/localize' @@ -25,16 +25,18 @@ export const FullTopic = (props: Props) => { const { follows, changeFollowing } = useFollowing() const { requireAuthentication } = useSession() const [followed, setFollowed] = createSignal() + const [title, setTitle] = createSignal('') - const title = createMemo(() => { + createEffect(on(() => props.topic, (tpc) => { + if (!tpc) return /* FIXME: use title translation*/ + setTitle((_) => tpc?.title || '') return `#${capitalize( - lang() === 'en' - ? props.topic.slug.replace(/-/, ' ') - : props.topic.title || props.topic.slug.replace(/-/, ' '), + lang() === 'en' ? tpc.slug.replace(/-/, ' ') : tpc.title || tpc.slug.replace(/-/, ' '), true )}` - }) + }, {} )) + createEffect(() => { if (follows?.topics?.length !== 0) { const items = follows.topics || [] diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index 75fd0ef0..468a7ad5 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -1,6 +1,6 @@ import { useSearchParams } from '@solidjs/router' import { clsx } from 'clsx' -import { For, Show, Suspense, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' +import { For, Show, Suspense, createEffect, createMemo, createSignal, on } from 'solid-js' import { useAuthors } from '~/context/authors' import { useFeed } from '~/context/feed' import { useLocalize } from '~/context/localize' @@ -17,6 +17,7 @@ import { Row1 } from '../Feed/Row1' import { Row2 } from '../Feed/Row2' import { Row3 } from '../Feed/Row3' import { FullTopic } from '../Topic/Full' +import { LoadMoreItems, LoadMoreWrapper } from '../_shared/LoadMoreWrapper' import { Loading } from '../_shared/Loading' import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper' @@ -40,17 +41,28 @@ export const TopicView = (props: Props) => { const { topicEntities } = useTopics() const { authorsByTopic } = useAuthors() const [searchParams, changeSearchParams] = useSearchParams<{ by: TopicFeedSortBy }>() - const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [favoriteTopArticles, setFavoriteTopArticles] = createSignal([]) const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal([]) const [topic, setTopic] = createSignal() const [followers, setFollowers] = createSignal(props.followers || []) - const sortedFeed = createMemo(() => feedByTopic()[topic()?.slug || ''] || []) // TODO: filter + sort + + // TODO: filter + sort + const [sortedFeed, setSortedFeed] = createSignal([] as Shout[]) + createEffect(on(([feedByTopic, () => props.topicSlug, topicEntities]), ([feed, slug, ttt]) => { + if (Object.values(ttt).length === 0) return + const sss = (feed[slug] || []) as Shout[] + sss && setSortedFeed(sss) + console.debug('topic slug loaded', slug) + const tpc = ttt[slug] + console.debug('topics loaded', ttt) + tpc && setTopic(tpc) + }, {})) const loadTopicFollowers = async () => { const topicFollowersFetcher = loadFollowersByTopic(props.topicSlug) const topicFollowers = await topicFollowersFetcher() topicFollowers && setFollowers(topicFollowers) + console.debug('loadTopicFollowers', topicFollowers) } const [topicAuthors, setTopicAuthors] = createSignal([]) @@ -59,6 +71,7 @@ export const TopicView = (props: Props) => { const topicAuthorsFetcher = await loadAuthors({ by, limit: 10, offset: 0 }) const result = await topicAuthorsFetcher() result && setTopicAuthors(result) + console.debug('loadTopicAuthors', result) } const loadFavoriteTopArticles = async () => { @@ -70,6 +83,7 @@ export const TopicView = (props: Props) => { const topicRandomShoutsFetcher = loadShouts(options) const result = await topicRandomShoutsFetcher() result && setFavoriteTopArticles(result) + console.debug('loadFavoriteTopArticles', result) } const loadReactedTopMonthArticles = async () => { @@ -85,27 +99,18 @@ export const TopicView = (props: Props) => { const reactedTopMonthShoutsFetcher = loadShouts(options) const result = await reactedTopMonthShoutsFetcher() result && setReactedTopMonthArticles(result) + console.debug('loadReactedTopMonthArticles', result) } // второй этап начальной загрузки данных - createEffect( - on( - topicEntities, - (ttt: Record) => { - if (props.topicSlug in ttt) { - Promise.all([ - loadFavoriteTopArticles(), - loadReactedTopMonthArticles(), - loadTopicAuthors(), - loadTopicFollowers() - ]).finally(() => { - setTopic(ttt[props.topicSlug]) - }) - } - }, - { defer: true } - ) - ) + createEffect(on(topic, (tpc) => { + console.debug('topic loaded', tpc) + if (!tpc) return + loadFavoriteTopArticles() + loadReactedTopMonthArticles() + loadTopicAuthors() + loadTopicFollowers() + }, { defer: true })) // дозагрузка const loadMore = async () => { @@ -117,19 +122,11 @@ export const TopicView = (props: Props) => { offset: amountBefore }) const result = await topicShoutsFetcher() - if (result) { - addFeed(result) - const amountAfter = feedByTopic()[props.topicSlug].length - setIsLoadMoreButtonVisible(amountBefore !== amountAfter) - } + result && addFeed(result) restoreScrollPosition() + return result as LoadMoreItems } - onMount(() => { - if (sortedFeed() || [].length === PRERENDERED_ARTICLES_COUNT) { - loadMore() - } - }) /* const selectionTitle = createMemo(() => { const m = searchParams?.by @@ -139,15 +136,14 @@ export const TopicView = (props: Props) => { return t('Top recent') }) */ + const pages = createMemo(() => paginate(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) ) return (
}> - - - +
@@ -226,23 +222,17 @@ export const TopicView = (props: Props) => { - - {(page) => ( - <> - - - - - )} - - - -

- -

-
+ + + {(page) => ( + <> + + + + + )} + +
) diff --git a/src/components/_shared/LoadMoreWrapper.tsx b/src/components/_shared/LoadMoreWrapper.tsx index 9bb7887d..dc5f5c0c 100644 --- a/src/components/_shared/LoadMoreWrapper.tsx +++ b/src/components/_shared/LoadMoreWrapper.tsx @@ -36,7 +36,6 @@ export const LoadMoreWrapper = (props: LoadMoreProps) => { saveScrollPosition() const newItems = await props.loadFunction(offset()) if (!Array.isArray(newItems)) return - console.debug('[_share] load more items', newItems) setItems( (prev) => Array.from(new Set([...prev, ...newItems])).sort( diff --git a/src/routes/(main).tsx b/src/routes/(main).tsx index 437bed88..9a43ac0c 100644 --- a/src/routes/(main).tsx +++ b/src/routes/(main).tsx @@ -79,7 +79,7 @@ export default function HomePage(props: RouteSectionProps) { topFeed: topRatedFeed } = useFeed() - // load more faetured shouts + // load more featured shouts const loadMoreFeatured = async (offset?: number) => { const shoutsLoader = featuredLoader(offset) const loaded = await shoutsLoader() diff --git a/src/routes/topic/[slug]/[...tab].tsx b/src/routes/topic/[slug]/[...tab].tsx index bea7d491..aa33a40b 100644 --- a/src/routes/topic/[slug]/[...tab].tsx +++ b/src/routes/topic/[slug]/[...tab].tsx @@ -1,6 +1,6 @@ import { RouteSectionProps, createAsync } from '@solidjs/router' import { HttpStatusCode } from '@solidjs/start' -import { Show, Suspense, createEffect, createMemo, createSignal } from 'solid-js' +import { Show, Suspense, createEffect, createSignal, on } from 'solid-js' import { FourOuFourView } from '~/components/Views/FourOuFour' import { TopicFeedSortBy, TopicView } from '~/components/Views/Topic' import { Loading } from '~/components/_shared/Loading' @@ -21,6 +21,7 @@ const fetchTopicShouts = async (slug: string, offset?: number) => { const fetchAllTopics = async () => { const topicsFetcher = loadTopics() + console.debug('all topics fetched') return await topicsFetcher() } @@ -38,62 +39,53 @@ export type TopicPageProps = { articles?: Shout[]; topics: Topic[]; authors?: Au export default function TopicPage(props: RouteSectionProps) { const { t } = useLocalize() - const { addTopics, sortedTopics } = useTopics() - const [loadingError, setLoadingError] = createSignal(false) - - const topic = createAsync(async () => { - try { - let ttt: Topic[] = sortedTopics() - if (!ttt) { - ttt = props.data.topics || (await fetchAllTopics()) || [] - addTopics(ttt) - console.debug('[route.topic] all topics loaded') - } - const t = ttt.find((x) => x.slug === props.params.slug) - return t - } catch (_error) { - setLoadingError(true) - return null - } + const { addTopics } = useTopics() + const topics = createAsync(async () => props.data.topics || (await fetchAllTopics()) || []) + const articles = createAsync(async () => { + const result = (await props.data).articles || (await fetchTopicShouts(props.params.slug)) + setShoutsLoaded(true) + return result || [] }) - - const articles = createAsync( - async () => props.data.articles || (await fetchTopicShouts(props.params.slug)) || [] - ) - - const title = createMemo(() => `${t('Discours')}${topic()?.title ? ` :: ${topic()?.title}` : ''}`) - - createEffect(() => { - if (topic() && window) { - window?.gtag?.('event', 'page_view', { - page_title: topic()?.title, - page_location: window?.location.href, - page_path: window?.location.pathname - }) + const [topic, setTopic] = createSignal() + const [title, setTitle] = createSignal('') + const [desc, setDesc] = createSignal('') + const [cover, setCover] = createSignal('') + const [shoutsLoaded, setShoutsLoaded] = createSignal(false) + createEffect(on([topics, () => window], ([ttt, win]) => { + if (ttt) { + // console.debug('all topics:', ttt) + ttt && addTopics(ttt) + const tpc = ttt.find((x) => x.slug === props.params.slug) + if (!tpc) return + setTopic(tpc) + setTitle(() => `${t('Discours')}${topic()?.title ? ` :: ${topic()?.title}` : ''}`) + setDesc(() => + topic()?.body + ? descFromBody(topic()?.body || '') + : t('The most interesting publications on the topic', { topicName: title() }) + ) + setCover(() => + topic()?.pic ? getImageUrl(topic()?.pic || '', { width: 1200 }) : '/logo.png' + ) + if (win) window?.gtag?.('event', 'page_view', { + page_title: tpc.title, + page_location: window?.location.href, + page_path: window?.location.pathname + }) } - }) - - const desc = createMemo(() => - topic()?.body - ? descFromBody(topic()?.body || '') - : t('The most interesting publications on the topic', { topicName: title() }) - ) - - const cover = createMemo(() => - topic()?.pic ? getImageUrl(topic()?.pic || '', { width: 1200 }) : '/logo.png' - ) + }, { defer: true })) return ( - }> - - - - - } - > + + + + + } + > + }> ) { selectedTab={props.params.tab as TopicFeedSortBy} /> - - + + ) }