webapp/src/components/Views/Home.tsx

183 lines
6.3 KiB
TypeScript
Raw Normal View History

import { getPagePath } from '@nanostores/router'
2024-05-05 16:13:48 +00:00
import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
import { useLocalize } from '../../context/localize'
2024-05-06 23:44:25 +00:00
import { useTopics } from '../../context/topics'
2023-12-24 12:56:30 +00:00
import { Shout, Topic } from '../../graphql/schema/core.gen'
import { router } from '../../stores/router'
import {
loadShouts,
loadTopArticles,
loadTopMonthArticles,
useArticlesStore,
} from '../../stores/zine/articles'
2022-09-22 09:37:49 +00:00
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
2023-12-25 15:07:12 +00:00
import { capitalize } from '../../utils/capitalize'
2022-09-29 14:40:11 +00:00
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
import { splitToPages } from '../../utils/splitToPages'
import Banner from '../Discours/Banner'
import Hero from '../Discours/Hero'
import { Beside } from '../Feed/Beside'
import Group from '../Feed/Group'
import { Row1 } from '../Feed/Row1'
import { Row2 } from '../Feed/Row2'
import { Row3 } from '../Feed/Row3'
import { Row5 } from '../Feed/Row5'
import RowShort from '../Feed/RowShort'
import { Topics } from '../Nav/Topics'
2024-02-04 11:25:21 +00:00
import { Icon } from '../_shared/Icon'
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
2022-09-22 09:37:49 +00:00
import styles from './Home.module.scss'
type Props = {
2022-11-15 14:24:50 +00:00
shouts: Shout[]
2022-09-09 11:53:35 +00:00
}
export const PRERENDERED_ARTICLES_COUNT = 5
2022-11-22 03:02:11 +00:00
export const RANDOM_TOPICS_COUNT = 12
export const RANDOM_TOPIC_SHOUTS_COUNT = 7
2022-09-29 14:40:11 +00:00
const CLIENT_LOAD_ARTICLES_COUNT = 29
const LOAD_MORE_PAGE_SIZE = 16 // Row1 + Row3 + Row2 + Beside (3 + 1) + Row1 + Row 2 + Row3
2022-09-13 09:59:04 +00:00
export const HomeView = (props: Props) => {
const { sortedArticles, topArticles, topCommentedArticles, topMonthArticles, topViewedArticles } =
useArticlesStore({
shouts: props.shouts,
})
2024-05-06 23:44:25 +00:00
const { topTopics } = useTopics()
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
2022-09-28 20:16:44 +00:00
const { topAuthors } = useTopAuthorsStore()
2023-02-17 09:21:02 +00:00
const { t } = useLocalize()
2022-09-13 09:59:04 +00:00
2024-05-05 16:13:48 +00:00
const [randomTopic, _setRandomTopic] = createSignal<Topic>(null)
const [randomTopicArticles, _setRandomTopicArticles] = createSignal<Shout[]>([])
onMount(async () => {
loadTopArticles()
loadTopMonthArticles()
2022-09-29 14:40:11 +00:00
if (sortedArticles().length < PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT) {
2022-11-18 02:23:04 +00:00
const { hasMore } = await loadShouts({
filters: { featured: true },
limit: CLIENT_LOAD_ARTICLES_COUNT,
offset: sortedArticles().length,
})
setIsLoadMoreButtonVisible(hasMore)
2022-09-29 14:40:11 +00:00
}
2022-09-22 09:37:49 +00:00
})
2022-09-29 14:40:11 +00:00
const loadMore = async () => {
saveScrollPosition()
2022-11-18 02:23:04 +00:00
const { hasMore } = await loadShouts({
filters: { featured: true },
limit: LOAD_MORE_PAGE_SIZE,
offset: sortedArticles().length,
})
setIsLoadMoreButtonVisible(hasMore)
2022-09-29 14:40:11 +00:00
restoreScrollPosition()
2022-09-22 09:37:49 +00:00
}
2022-09-09 11:53:35 +00:00
const pages = createMemo<Shout[][]>(() =>
splitToPages(
sortedArticles(),
PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT,
LOAD_MORE_PAGE_SIZE,
),
)
2022-09-29 14:40:11 +00:00
2022-09-22 09:37:49 +00:00
return (
2023-02-17 09:21:02 +00:00
<Show when={sortedArticles().length > 0}>
2023-10-10 15:38:02 +00:00
<Topics />
2023-01-24 22:15:29 +00:00
<Row5 articles={sortedArticles().slice(0, 5)} nodate={true} />
2022-09-22 09:37:49 +00:00
<Hero />
2022-10-05 11:42:13 +00:00
<Show when={sortedArticles().length > PRERENDERED_ARTICLES_COUNT}>
2022-09-09 11:53:35 +00:00
<Beside
2022-09-28 20:16:44 +00:00
beside={sortedArticles()[5]}
title={t('Top viewed')}
values={topViewedArticles().slice(0, 5)}
wrapper={'top-article'}
2023-01-24 22:15:29 +00:00
nodate={true}
2022-09-09 11:53:35 +00:00
/>
2023-01-24 22:15:29 +00:00
<Row3 articles={sortedArticles().slice(6, 9)} nodate={true} />
2022-09-29 14:40:11 +00:00
<Beside
beside={sortedArticles()[9]}
title={t('Top authors')}
values={topAuthors()}
wrapper={'author'}
2023-01-24 22:15:29 +00:00
nodate={true}
2022-09-29 14:40:11 +00:00
/>
<Show when={topMonthArticles()}>
2024-05-06 23:44:25 +00:00
<ArticleCardSwiper title={t('Top month')} slides={topMonthArticles()} />
</Show>
2023-01-24 22:15:29 +00:00
<Row2 articles={sortedArticles().slice(10, 12)} nodate={true} />
2022-09-28 20:16:44 +00:00
<RowShort articles={sortedArticles().slice(12, 16)} />
2023-01-24 22:15:29 +00:00
<Row1 article={sortedArticles()[16]} nodate={true} />
<Row3 articles={sortedArticles().slice(17, 20)} nodate={true} />
<Row3
articles={topCommentedArticles().slice(0, 3)}
header={<h2>{t('Top commented')}</h2>}
nodate={true}
/>
<Show when={randomTopic()}>
<Group
articles={randomTopicArticles()}
header={
<div class={styles.randomTopicHeaderContainer}>
2023-12-25 15:07:12 +00:00
<div class={styles.randomTopicHeader}>{capitalize(randomTopic().title, true)}</div>
<div>
<a
class={styles.randomTopicHeaderLink}
href={getPagePath(router, 'topic', { slug: randomTopic().slug })}
>
{t('All articles')} <Icon class={styles.icon} name="arrow-right" />
</a>
</div>
</div>
}
/>
</Show>
<Show when={topArticles()}>
<ArticleCardSwiper title={t('Favorite')} slides={topArticles()} />
</Show>
2022-09-28 20:16:44 +00:00
<Beside
beside={sortedArticles()[20]}
title={t('Top topics')}
values={topTopics().slice(0, 5)}
wrapper={'topic'}
isTopicCompact={true}
2023-01-24 22:15:29 +00:00
nodate={true}
2022-09-28 20:16:44 +00:00
/>
<Row3 articles={sortedArticles().slice(21, 24)} nodate={true} />
2022-09-28 20:16:44 +00:00
<Banner />
2023-01-24 22:15:29 +00:00
<Row2 articles={sortedArticles().slice(24, 26)} nodate={true} />
<Row3 articles={sortedArticles().slice(26, 29)} nodate={true} />
<Row2 articles={sortedArticles().slice(29, 31)} nodate={true} />
<Row3 articles={sortedArticles().slice(31, 34)} nodate={true} />
2022-09-28 20:16:44 +00:00
</Show>
2022-09-29 14:40:11 +00:00
<For each={pages()}>
{(page) => (
<>
2023-01-24 22:15:29 +00:00
<Row1 article={page[0]} nodate={true} />
<Row3 articles={page.slice(1, 4)} nodate={true} />
<Row2 articles={page.slice(4, 6)} nodate={true} />
<Beside values={page.slice(6, 9)} beside={page[9]} wrapper="article" nodate={true} />
<Row1 article={page[10]} nodate={true} />
<Row2 articles={page.slice(11, 13)} nodate={true} />
<Row3 articles={page.slice(13, 16)} nodate={true} />
2022-09-29 14:40:11 +00:00
</>
)}
</For>
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
</Show>
2022-09-23 23:42:19 +00:00
</Show>
2022-09-09 11:53:35 +00:00
)
}