webapp/src/components/Views/Expo/Expo.tsx

179 lines
6.3 KiB
TypeScript
Raw Normal View History

import { getPagePath } from '@nanostores/router'
import { clsx } from 'clsx'
2023-10-10 15:38:02 +00:00
import { createEffect, createMemo, createSignal, For, on, onCleanup, onMount, Show } from 'solid-js'
2023-10-10 15:38:02 +00:00
import { useLocalize } from '../../../context/localize'
import { LoadShoutsOptions, Shout } from '../../../graphql/types.gen'
2023-10-10 15:38:02 +00:00
import { LayoutType } from '../../../pages/types'
import { router, useRouter } from '../../../stores/router'
2023-10-10 15:38:02 +00:00
import { loadShouts, resetSortedArticles, useArticlesStore } from '../../../stores/zine/articles'
import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll'
import { splitToPages } from '../../../utils/splitToPages'
import { Button } from '../../_shared/Button'
2023-10-10 15:38:02 +00:00
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
import { Loading } from '../../_shared/Loading'
import { ArticleCard } from '../../Feed/ArticleCard'
import styles from './Expo.module.scss'
2023-10-10 15:38:02 +00:00
type Props = {
shouts: Shout[]
}
export const PRERENDERED_ARTICLES_COUNT = 28
const LOAD_MORE_PAGE_SIZE = 16
export const Expo = (props: Props) => {
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.shouts))
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const { t } = useLocalize()
const { page: getPage } = useRouter()
const getLayout = createMemo<LayoutType>(() => getPage().params['layout'] as LayoutType)
const { sortedArticles } = useArticlesStore({
shouts: isLoaded() ? props.shouts : [],
2023-10-10 15:38:02 +00:00
})
const loadMore = async (count) => {
saveScrollPosition()
const options: LoadShoutsOptions = {
limit: count,
offset: sortedArticles().length,
2023-10-10 15:38:02 +00:00
}
2023-11-17 09:00:00 +00:00
options.filters = getLayout() ? { layout: getLayout() } : { exclude_layout: 'article' }
2023-10-10 15:38:02 +00:00
const { hasMore } = await loadShouts(options)
setIsLoadMoreButtonVisible(hasMore)
restoreScrollPosition()
}
const pages = createMemo<Shout[][]>(() =>
splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE),
2023-10-10 15:38:02 +00:00
)
onMount(() => {
if (isLoaded()) {
return
}
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
setIsLoaded(true)
})
onMount(() => {
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
loadMore(LOAD_MORE_PAGE_SIZE)
}
})
createEffect(
on(
() => getLayout(),
() => {
resetSortedArticles()
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
},
{ defer: true },
),
2023-10-10 15:38:02 +00:00
)
onCleanup(() => {
resetSortedArticles()
})
const handleLoadMoreClick = () => {
loadMore(LOAD_MORE_PAGE_SIZE)
}
return (
<div class={styles.Expo}>
<Show when={sortedArticles().length > 0} fallback={<Loading />}>
<div class="wide-container">
<ul class={clsx('view-switcher', styles.navigation)}>
<li class={clsx({ 'view-switcher__item--selected': !getLayout() })}>
<ConditionalWrapper
condition={Boolean(getLayout())}
wrapper={(children) => <a href={getPagePath(router, 'expo')}>{children}</a>}
>
<span class={clsx('linkReplacement')}>{t('All')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'literature' })}>
<ConditionalWrapper
condition={getLayout() !== 'literature'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'literature' })}>{children}</a>
)}
>
<span class={clsx('linkReplacement')}>{t('Literature')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'music' })}>
<ConditionalWrapper
condition={getLayout() !== 'music'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'music' })}>{children}</a>
)}
>
<span class={clsx('linkReplacement')}>{t('Music')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'image' })}>
<ConditionalWrapper
condition={getLayout() !== 'image'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'image' })}>{children}</a>
)}
>
<span class={clsx('linkReplacement')}>{t('Gallery')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'video' })}>
<ConditionalWrapper
condition={getLayout() !== 'video'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'video' })}>{children}</a>
)}
>
<span class={clsx('cursorPointer linkReplacement')}>{t('Video')}</span>
</ConditionalWrapper>
</li>
</ul>
<div class="row">
<For each={sortedArticles().slice(0, PRERENDERED_ARTICLES_COUNT)}>
{(shout) => (
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
<ArticleCard
article={shout}
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
desktopCoverSize="XS"
2023-10-10 15:38:02 +00:00
/>
</div>
)}
</For>
<For each={pages()}>
{(page) => (
<For each={page}>
{(shout) => (
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
<ArticleCard
article={shout}
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
desktopCoverSize="XS"
2023-10-10 15:38:02 +00:00
/>
</div>
)}
</For>
)}
</For>
</div>
<Show when={isLoadMoreButtonVisible()}>
<div class={styles.showMore}>
<Button size="L" onClick={handleLoadMoreClick} value={t('Load more')} />
</div>
</Show>
</div>
</Show>
</div>
)
}