webapp/src/components/Views/Home.tsx

192 lines
5.6 KiB
TypeScript
Raw Normal View History

import { createMemo, createSignal, For, onMount, Show } from 'solid-js'
2022-09-09 11:53:35 +00:00
import Banner from '../Discours/Banner'
2022-09-22 09:37:49 +00:00
import { NavTopics } from '../Nav/Topics'
import { Row5 } from '../Feed/Row5'
import { Row3 } from '../Feed/Row3'
import { Row2 } from '../Feed/Row2'
import { Row1 } from '../Feed/Row1'
2022-09-09 11:53:35 +00:00
import Hero from '../Discours/Hero'
import { Beside } from '../Feed/Beside'
2022-09-09 11:53:35 +00:00
import RowShort from '../Feed/RowShort'
import Slider from '../Feed/Slider'
import Group from '../Feed/Group'
import type { Shout, Topic } from '../../graphql/types.gen'
2022-11-14 17:41:05 +00:00
import { Icon } from '../_shared/Icon'
2022-09-09 11:53:35 +00:00
import { t } from '../../utils/intl'
import { useTopicsStore } from '../../stores/zine/topics'
2022-09-22 09:37:49 +00:00
import {
loadPublishedArticles,
loadTopArticles,
loadTopMonthArticles,
useArticlesStore
} from '../../stores/zine/articles'
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
2022-09-23 23:42:19 +00:00
import { locale } from '../../stores/ui'
2022-09-29 14:40:11 +00:00
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
import { splitToPages } from '../../utils/splitToPages'
2022-09-22 09:37:49 +00:00
2022-09-09 11:53:35 +00:00
type HomeProps = {
randomTopics: Topic[]
recentPublishedArticles: Shout[]
}
export const PRERENDERED_ARTICLES_COUNT = 5
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
2022-09-22 09:37:49 +00:00
export const HomeView = (props: HomeProps) => {
2022-09-13 09:59:04 +00:00
const {
2022-09-28 20:16:44 +00:00
sortedArticles,
topArticles,
topMonthArticles,
topViewedArticles,
topCommentedArticles,
articlesByLayout
2022-09-13 09:59:04 +00:00
} = useArticlesStore({
2022-09-22 09:37:49 +00:00
sortedArticles: props.recentPublishedArticles
2022-09-13 08:05:11 +00:00
})
2022-09-28 20:16:44 +00:00
const { randomTopics, topTopics } = useTopicsStore({
2022-09-13 09:59:04 +00:00
randomTopics: props.randomTopics
})
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
2022-09-09 11:53:35 +00:00
2022-09-28 20:16:44 +00:00
const { topAuthors } = useTopAuthorsStore()
2022-09-13 09:59:04 +00:00
onMount(async () => {
2022-09-22 09:37:49 +00:00
loadTopArticles()
loadTopMonthArticles()
2022-09-29 14:40:11 +00:00
if (sortedArticles().length < PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT) {
const { hasMore } = await loadPublishedArticles({
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-09 11:53:35 +00:00
2022-09-22 09:37:49 +00:00
const randomLayout = createMemo(() => {
2022-09-28 20:16:44 +00:00
const filledLayouts = Object.keys(articlesByLayout()).filter(
2022-09-22 09:37:49 +00:00
// FIXME: is 7 ok? or more complex logic needed?
2022-09-28 20:16:44 +00:00
(layout) => articlesByLayout()[layout].length > 7
2022-09-22 09:37:49 +00:00
)
2022-09-09 11:53:35 +00:00
2022-09-28 20:16:44 +00:00
const selectedRandomLayout =
2022-09-22 09:37:49 +00:00
filledLayouts.length > 0 ? filledLayouts[Math.floor(Math.random() * filledLayouts.length)] : ''
return (
2022-09-28 20:16:44 +00:00
<Show when={Boolean(selectedRandomLayout)}>
2022-09-09 11:53:35 +00:00
<Group
2022-09-28 20:16:44 +00:00
articles={articlesByLayout()[selectedRandomLayout]}
2022-09-09 11:53:35 +00:00
header={
<div class="layout-icon">
2022-09-28 20:16:44 +00:00
<Icon name={selectedRandomLayout} />
2022-09-09 11:53:35 +00:00
</div>
}
/>
2022-09-22 09:37:49 +00:00
</Show>
)
})
2022-09-29 14:40:11 +00:00
const loadMore = async () => {
saveScrollPosition()
const { hasMore } = await loadPublishedArticles({
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 (
2022-10-05 15:11:14 +00:00
<Show when={locale() && sortedArticles().length > 0}>
2022-09-28 20:16:44 +00:00
<NavTopics topics={randomTopics()} />
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Row5 articles={sortedArticles().slice(0, 5)} />
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'}
2022-09-09 11:53:35 +00:00
/>
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Row3 articles={sortedArticles().slice(6, 9)} />
2022-09-29 14:40:11 +00:00
<Beside
beside={sortedArticles()[9]}
title={t('Top authors')}
values={topAuthors()}
wrapper={'author'}
/>
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Slider title={t('Top month articles')} articles={topMonthArticles()} />
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Row2 articles={sortedArticles().slice(10, 12)} />
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<RowShort articles={sortedArticles().slice(12, 16)} />
2022-09-22 09:37:49 +00:00
2022-09-29 14:40:11 +00:00
<Row1 article={sortedArticles()[16]} />
2022-09-28 20:16:44 +00:00
<Row3 articles={sortedArticles().slice(17, 20)} />
2022-09-29 14:40:11 +00:00
<Row3 articles={topCommentedArticles().slice(0, 3)} header={<h2>{t('Top commented')}</h2>} />
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
{randomLayout()}
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Slider title={t('Favorite')} articles={topArticles()} />
2022-09-22 09:37:49 +00:00
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}
/>
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Row3 articles={sortedArticles().slice(21, 24)} />
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
<Banner />
<Row2 articles={sortedArticles().slice(24, 26)} />
<Row3 articles={sortedArticles().slice(26, 29)} />
<Row2 articles={sortedArticles().slice(29, 31)} />
<Row3 articles={sortedArticles().slice(31, 34)} />
</Show>
2022-09-22 09:37:49 +00:00
2022-09-29 14:40:11 +00:00
<For each={pages()}>
{(page) => (
<>
<Row1 article={page[0]} />
<Row3 articles={page.slice(1, 4)} />
<Row2 articles={page.slice(4, 6)} />
<Beside values={page.slice(6, 9)} beside={page[9]} wrapper="article" />
<Row1 article={page[10]} />
<Row2 articles={page.slice(11, 13)} />
<Row3 articles={page.slice(13, 16)} />
</>
)}
</For>
2022-09-22 09:37:49 +00:00
<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
)
}