expo-showup
This commit is contained in:
parent
a52ee5a90f
commit
22575cc7fa
|
@ -1,6 +1,7 @@
|
||||||
import { A } from '@solidjs/router'
|
import { A } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
||||||
|
|
||||||
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
||||||
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
||||||
import { Loading } from '~/components/_shared/Loading'
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
|
@ -13,6 +14,8 @@ import getRandomTopShoutsQuery from '~/graphql/query/core/articles-load-random-t
|
||||||
import { LoadShoutsFilters, LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
import { LoadShoutsFilters, LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
||||||
import { LayoutType } from '~/types/common'
|
import { LayoutType } from '~/types/common'
|
||||||
import { getUnixtime } from '~/utils/date'
|
import { getUnixtime } from '~/utils/date'
|
||||||
|
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
||||||
|
import { byCreated } from '~/utils/sort'
|
||||||
import { ArticleCard } from '../../Feed/ArticleCard'
|
import { ArticleCard } from '../../Feed/ArticleCard'
|
||||||
|
|
||||||
import styles from './Expo.module.scss'
|
import styles from './Expo.module.scss'
|
||||||
|
@ -33,21 +36,9 @@ export const Expo = (props: Props) => {
|
||||||
|
|
||||||
const [favoriteTopArticles, setFavoriteTopArticles] = createSignal<Shout[]>([])
|
const [favoriteTopArticles, setFavoriteTopArticles] = createSignal<Shout[]>([])
|
||||||
const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal<Shout[]>([])
|
const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal<Shout[]>([])
|
||||||
const [expoShouts, setExpoShouts] = createSignal<Shout[]>([])
|
|
||||||
const { feedByLayout, expoFeed, setExpoFeed } = useFeed()
|
const { feedByLayout, expoFeed, setExpoFeed } = useFeed()
|
||||||
const layouts = createMemo<LayoutType[]>(() => (props.layout ? [props.layout] : EXPO_LAYOUTS))
|
const layouts = createMemo<LayoutType[]>(() => (props.layout ? [props.layout] : EXPO_LAYOUTS))
|
||||||
|
|
||||||
const loadMoreFiltered = async () => {
|
|
||||||
const limit = SHOUTS_PER_PAGE
|
|
||||||
const offset = (props.layout ? feedByLayout()[props.layout] : expoFeed())?.length
|
|
||||||
const filters: LoadShoutsFilters = { layouts: layouts(), featured: true }
|
|
||||||
const options: LoadShoutsOptions = { filters, limit, offset }
|
|
||||||
const shoutsFetcher = loadShouts(options)
|
|
||||||
const result = await shoutsFetcher()
|
|
||||||
result && setExpoFeed(result)
|
|
||||||
return result as LoadMoreItems
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadRandomTopArticles = async () => {
|
const loadRandomTopArticles = async () => {
|
||||||
const options: LoadShoutsOptions = {
|
const options: LoadShoutsOptions = {
|
||||||
filters: { layouts: layouts(), featured: true },
|
filters: { layouts: layouts(), featured: true },
|
||||||
|
@ -76,20 +67,15 @@ export const Expo = (props: Props) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
on(
|
on(layouts, (lll) => {
|
||||||
() => props.layout,
|
console.debug('layouts changed', lll)
|
||||||
() => {
|
|
||||||
setExpoShouts([])
|
|
||||||
setFavoriteTopArticles([])
|
|
||||||
setReactedTopMonthArticles([])
|
|
||||||
loadRandomTopArticles()
|
loadRandomTopArticles()
|
||||||
loadRandomTopMonthArticles()
|
loadRandomTopMonthArticles()
|
||||||
}
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
setExpoShouts([])
|
setExpoFeed([])
|
||||||
})
|
})
|
||||||
const ExpoTabs = () => (
|
const ExpoTabs = () => (
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
|
@ -134,10 +120,10 @@ export const Expo = (props: Props) => {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
const ExpoGrid = () => (
|
const ExpoGrid = (props: Props) => (
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<For each={props.shouts.slice(0, LOAD_MORE_PAGE_SIZE)}>
|
<For each={expoFeed()?.slice(0, LOAD_MORE_PAGE_SIZE) || []}>
|
||||||
{(shout) => (
|
{(shout) => (
|
||||||
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
||||||
<ArticleCard
|
<ArticleCard
|
||||||
|
@ -167,7 +153,7 @@ export const Expo = (props: Props) => {
|
||||||
<Show when={favoriteTopArticles()?.length > 0} keyed={true}>
|
<Show when={favoriteTopArticles()?.length > 0} keyed={true}>
|
||||||
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
||||||
</Show>
|
</Show>
|
||||||
<For each={props.topRatedShouts?.slice(LOAD_MORE_PAGE_SIZE * 2, expoShouts().length)}>
|
<For each={props.topRatedShouts?.slice(LOAD_MORE_PAGE_SIZE * 2, expoFeed()?.length || 0)}>
|
||||||
{(shout) => (
|
{(shout) => (
|
||||||
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
||||||
<ArticleCard
|
<ArticleCard
|
||||||
|
@ -183,13 +169,32 @@ export const Expo = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const [loadMoreVisible, setLoadMoreVisible] = createSignal(false)
|
||||||
|
|
||||||
|
// дозагрузка
|
||||||
|
const loadMore = async () => {
|
||||||
|
saveScrollPosition()
|
||||||
|
const limit = SHOUTS_PER_PAGE
|
||||||
|
const offset = (props.layout ? feedByLayout()[props.layout] : expoFeed())?.length
|
||||||
|
const filters: LoadShoutsFilters = { layouts: layouts(), featured: true }
|
||||||
|
const options: LoadShoutsOptions = { filters, limit, offset }
|
||||||
|
const shoutsFetcher = loadShouts(options)
|
||||||
|
const result = await shoutsFetcher()
|
||||||
|
setLoadMoreVisible(Boolean(result?.length))
|
||||||
|
const expoFeedUpdater = (layout?: LayoutType) => (prev: Shout[]) =>
|
||||||
|
Array.from(new Set((layout ? prev || [] : expoFeed())?.concat(result || [])))?.sort(byCreated)
|
||||||
|
result && setExpoFeed(expoFeedUpdater(props.layout))
|
||||||
|
restoreScrollPosition()
|
||||||
|
return result as LoadMoreItems
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.Expo}>
|
<div class={styles.Expo}>
|
||||||
<ExpoTabs />
|
<ExpoTabs />
|
||||||
|
|
||||||
<Show when={expoShouts().length > 0} fallback={<Loading />}>
|
<Show when={expoFeed()} fallback={<Loading />}>
|
||||||
<LoadMoreWrapper loadFunction={loadMoreFiltered} pageSize={LOAD_MORE_PAGE_SIZE}>
|
<LoadMoreWrapper loadFunction={loadMore} pageSize={LOAD_MORE_PAGE_SIZE} hidden={!loadMoreVisible()}>
|
||||||
<ExpoGrid />
|
<ExpoGrid {...props} />
|
||||||
</LoadMoreWrapper>
|
</LoadMoreWrapper>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Params, RouteSectionProps, createAsync } from '@solidjs/router'
|
import { Params, RouteSectionProps, createAsync } from '@solidjs/router'
|
||||||
import { Show, createEffect, createMemo, on } from 'solid-js'
|
import { Show, onMount } from 'solid-js'
|
||||||
import { TopicsNav } from '~/components/TopicsNav'
|
import { TopicsNav } from '~/components/TopicsNav'
|
||||||
import { Expo } from '~/components/Views/Expo'
|
import { Expo } from '~/components/Views/Expo'
|
||||||
import { PageLayout } from '~/components/_shared/PageLayout'
|
import { PageLayout } from '~/components/_shared/PageLayout'
|
||||||
|
@ -32,9 +32,9 @@ export default (props: RouteSectionProps<Shout[]>) => {
|
||||||
async () =>
|
async () =>
|
||||||
props.data || (await fetchExpoShouts(props.params.layout ? [props.params.layout] : EXPO_LAYOUTS))
|
props.data || (await fetchExpoShouts(props.params.layout ? [props.params.layout] : EXPO_LAYOUTS))
|
||||||
)
|
)
|
||||||
const layout = createMemo(() => props.params.layout)
|
|
||||||
const title = createMemo(() => {
|
const getTitle = (l: string) => {
|
||||||
switch (layout()) {
|
switch (l) {
|
||||||
case 'audio': {
|
case 'audio': {
|
||||||
return t('Audio')
|
return t('Audio')
|
||||||
}
|
}
|
||||||
|
@ -51,15 +51,21 @@ export default (props: RouteSectionProps<Shout[]>) => {
|
||||||
return t('Art')
|
return t('Art')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
document.title = getTitle(props.params.layout || '')
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(on(title, (ttl) => (document.title = ttl), { defer: true }))
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout withPadding={true} zeroBottomPadding={true} title={`${t('Discours')} :: ${title()}`}>
|
<PageLayout
|
||||||
|
withPadding={true}
|
||||||
|
zeroBottomPadding={true}
|
||||||
|
title={`${t('Discours')} :: ${getTitle(props.params.layout || '')}`}
|
||||||
|
>
|
||||||
<TopicsNav />
|
<TopicsNav />
|
||||||
<Show when={shouts()} keyed>
|
<Show when={shouts()} keyed>
|
||||||
{(sss) => <Expo shouts={sss} layout={layout() as LayoutType} />}
|
{(sss) => <Expo shouts={sss} layout={props.params.layout as LayoutType} />}
|
||||||
</Show>
|
</Show>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user