expo-fixes
This commit is contained in:
parent
22575cc7fa
commit
a144d7051b
|
@ -3,12 +3,4 @@
|
||||||
background: #fef2f2;
|
background: #fef2f2;
|
||||||
padding: 0 0 4rem;
|
padding: 0 0 4rem;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
|
||||||
.showMore {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
padding: 4rem 0 2rem;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,34 @@
|
||||||
import { A } from '@solidjs/router'
|
import { For, Show, createEffect, createSignal, on } from 'solid-js'
|
||||||
import { clsx } from 'clsx'
|
|
||||||
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
|
||||||
|
|
||||||
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
|
||||||
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
|
||||||
import { Loading } from '~/components/_shared/Loading'
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
import { ArticleCardSwiper } from '~/components/_shared/SolidSwiper/ArticleCardSwiper'
|
import { ArticleCardSwiper } from '~/components/_shared/SolidSwiper/ArticleCardSwiper'
|
||||||
import { EXPO_LAYOUTS, SHOUTS_PER_PAGE, useFeed } from '~/context/feed'
|
import { EXPO_LAYOUTS, SHOUTS_PER_PAGE } from '~/context/feed'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useSession } from '~/context/session'
|
import { useSession } from '~/context/session'
|
||||||
import { loadShouts } from '~/graphql/api/public'
|
|
||||||
import getRandomTopShoutsQuery from '~/graphql/query/core/articles-load-random-top'
|
import getRandomTopShoutsQuery from '~/graphql/query/core/articles-load-random-top'
|
||||||
import { LoadShoutsFilters, LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
import { LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
||||||
import { LayoutType } from '~/types/common'
|
import { ExpoLayoutType } 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'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
topMonthShouts?: Shout[]
|
layout: ExpoLayoutType
|
||||||
topRatedShouts?: Shout[]
|
|
||||||
layout?: LayoutType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 36
|
|
||||||
const LOAD_MORE_PAGE_SIZE = 12
|
|
||||||
|
|
||||||
export const Expo = (props: Props) => {
|
export const Expo = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { client } = useSession()
|
const { client } = useSession()
|
||||||
|
|
||||||
const [favoriteTopArticles, setFavoriteTopArticles] = createSignal<Shout[]>([])
|
const [favoriteTopArticles, setFavoriteTopArticles] = createSignal<Shout[]>([])
|
||||||
const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal<Shout[]>([])
|
const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal<Shout[]>([])
|
||||||
const { feedByLayout, expoFeed, setExpoFeed } = useFeed()
|
|
||||||
const layouts = createMemo<LayoutType[]>(() => (props.layout ? [props.layout] : EXPO_LAYOUTS))
|
|
||||||
|
|
||||||
|
// Функция загрузки случайных избранных статей
|
||||||
const loadRandomTopArticles = async () => {
|
const loadRandomTopArticles = async () => {
|
||||||
|
const layouts = props.layout ? [props.layout] : EXPO_LAYOUTS
|
||||||
const options: LoadShoutsOptions = {
|
const options: LoadShoutsOptions = {
|
||||||
filters: { layouts: layouts(), featured: true },
|
filters: { layouts, featured: true },
|
||||||
limit: 10,
|
limit: 10,
|
||||||
random_limit: 100
|
random_limit: 100
|
||||||
}
|
}
|
||||||
|
@ -49,11 +36,13 @@ export const Expo = (props: Props) => {
|
||||||
setFavoriteTopArticles(resp?.data?.load_shouts_random_top || [])
|
setFavoriteTopArticles(resp?.data?.load_shouts_random_top || [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Функция загрузки популярных статей за последний месяц
|
||||||
const loadRandomTopMonthArticles = async () => {
|
const loadRandomTopMonthArticles = async () => {
|
||||||
|
const layouts = props.layout ? [props.layout] : EXPO_LAYOUTS
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const after = getUnixtime(new Date(now.setMonth(now.getMonth() - 1)))
|
const after = getUnixtime(new Date(now.setMonth(now.getMonth() - 1)))
|
||||||
const options: LoadShoutsOptions = {
|
const options: LoadShoutsOptions = {
|
||||||
filters: { layouts: layouts(), after, reacted: true },
|
filters: { layouts, after, reacted: true },
|
||||||
limit: 10,
|
limit: 10,
|
||||||
random_limit: 10
|
random_limit: 10
|
||||||
}
|
}
|
||||||
|
@ -61,141 +50,46 @@ export const Expo = (props: Props) => {
|
||||||
setReactedTopMonthArticles(resp?.data?.load_shouts_random_top || [])
|
setReactedTopMonthArticles(resp?.data?.load_shouts_random_top || [])
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
// Эффект для загрузки random top при изменении layout
|
||||||
loadRandomTopArticles()
|
|
||||||
loadRandomTopMonthArticles()
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
on(layouts, (lll) => {
|
on(
|
||||||
console.debug('layouts changed', lll)
|
() => props.layout,
|
||||||
loadRandomTopArticles()
|
async (_layout?: ExpoLayoutType) => {
|
||||||
loadRandomTopMonthArticles()
|
await loadRandomTopArticles()
|
||||||
})
|
await loadRandomTopMonthArticles()
|
||||||
)
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
setExpoFeed([])
|
|
||||||
})
|
|
||||||
const ExpoTabs = () => (
|
|
||||||
<div class="wide-container">
|
|
||||||
<ul class={clsx('view-switcher')}>
|
|
||||||
<li class={clsx({ 'view-switcher__item--selected': !props.layout })}>
|
|
||||||
<A href={'/expo'}>
|
|
||||||
<span class={clsx('linkReplacement')}>{t('All')}</span>
|
|
||||||
</A>
|
|
||||||
</li>
|
|
||||||
<li class={clsx({ 'view-switcher__item--selected': props.layout === 'literature' })}>
|
|
||||||
<ConditionalWrapper
|
|
||||||
condition={props.layout !== 'literature'}
|
|
||||||
wrapper={(children) => <A href={'/expo/literature'}>{children}</A>}
|
|
||||||
>
|
|
||||||
<span class={clsx('linkReplacement')}>{t('Literature')}</span>
|
|
||||||
</ConditionalWrapper>
|
|
||||||
</li>
|
|
||||||
<li class={clsx({ 'view-switcher__item--selected': props.layout === 'audio' })}>
|
|
||||||
<ConditionalWrapper
|
|
||||||
condition={props.layout !== 'audio'}
|
|
||||||
wrapper={(children) => <A href={'/expo/audio'}>{children}</A>}
|
|
||||||
>
|
|
||||||
<span class={clsx('linkReplacement')}>{t('Music')}</span>
|
|
||||||
</ConditionalWrapper>
|
|
||||||
</li>
|
|
||||||
<li class={clsx({ 'view-switcher__item--selected': props.layout === 'image' })}>
|
|
||||||
<ConditionalWrapper
|
|
||||||
condition={props.layout !== 'image'}
|
|
||||||
wrapper={(children) => <A href={'/expo/image'}>{children}</A>}
|
|
||||||
>
|
|
||||||
<span class={clsx('linkReplacement')}>{t('Gallery')}</span>
|
|
||||||
</ConditionalWrapper>
|
|
||||||
</li>
|
|
||||||
<li class={clsx({ 'view-switcher__item--selected': props.layout === 'video' })}>
|
|
||||||
<ConditionalWrapper
|
|
||||||
condition={props.layout !== 'video'}
|
|
||||||
wrapper={(children) => <A href={'/expo/video'}>{children}</A>}
|
|
||||||
>
|
|
||||||
<span class={clsx('cursorPointer linkReplacement')}>{t('Video')}</span>
|
|
||||||
</ConditionalWrapper>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
const ExpoGrid = (props: Props) => (
|
|
||||||
<div class="wide-container">
|
|
||||||
<div class="row">
|
|
||||||
<For each={expoFeed()?.slice(0, LOAD_MORE_PAGE_SIZE) || []}>
|
|
||||||
{(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"
|
|
||||||
withAspectRatio={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
<Show when={reactedTopMonthArticles()?.length > 0} keyed={true}>
|
|
||||||
<ArticleCardSwiper title={t('Top month')} slides={reactedTopMonthArticles()} />
|
|
||||||
</Show>
|
|
||||||
<For each={(props.topMonthShouts || []).slice(LOAD_MORE_PAGE_SIZE, LOAD_MORE_PAGE_SIZE * 2)}>
|
|
||||||
{(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"
|
|
||||||
withAspectRatio={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
<Show when={favoriteTopArticles()?.length > 0} keyed={true}>
|
|
||||||
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
|
||||||
</Show>
|
|
||||||
<For each={props.topRatedShouts?.slice(LOAD_MORE_PAGE_SIZE * 2, expoFeed()?.length || 0)}>
|
|
||||||
{(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"
|
|
||||||
withAspectRatio={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</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 />
|
<Show when={props.shouts} fallback={<Loading />} keyed>
|
||||||
|
{(feed: Shout[]) => (
|
||||||
|
<div class="wide-container">
|
||||||
|
<div class="row">
|
||||||
|
<For each={feed.slice(0, SHOUTS_PER_PAGE) || []}>
|
||||||
|
{(shout) => (
|
||||||
|
<div id={`shout-${shout.id}`} 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"
|
||||||
|
withAspectRatio={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Show when={expoFeed()} fallback={<Loading />}>
|
<Show when={reactedTopMonthArticles()?.length > 0}>
|
||||||
<LoadMoreWrapper loadFunction={loadMore} pageSize={LOAD_MORE_PAGE_SIZE} hidden={!loadMoreVisible()}>
|
<ArticleCardSwiper title={t('Top month')} slides={reactedTopMonthArticles()} />
|
||||||
<ExpoGrid {...props} />
|
</Show>
|
||||||
</LoadMoreWrapper>
|
|
||||||
|
<Show when={favoriteTopArticles()?.length > 0}>
|
||||||
|
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
34
src/components/Views/Expo/ExpoNav.tsx
Normal file
34
src/components/Views/Expo/ExpoNav.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { A } from '@solidjs/router'
|
||||||
|
import { clsx } from 'clsx'
|
||||||
|
import { For } from 'solid-js'
|
||||||
|
|
||||||
|
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
||||||
|
import { EXPO_LAYOUTS, EXPO_TITLES } from '~/context/feed'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { ExpoLayoutType } from '~/types/common'
|
||||||
|
|
||||||
|
export const ExpoNav = (props: { layout: ExpoLayoutType | '' }) => {
|
||||||
|
const { t } = useLocalize()
|
||||||
|
return (
|
||||||
|
<div class="wide-container">
|
||||||
|
<ul class={clsx('view-switcher')}>
|
||||||
|
<For each={[...EXPO_LAYOUTS, '']}>
|
||||||
|
{(layoutKey) => (
|
||||||
|
<li class={clsx({ 'view-switcher__item--selected': props.layout === layoutKey })}>
|
||||||
|
<ConditionalWrapper
|
||||||
|
condition={props.layout !== layoutKey}
|
||||||
|
wrapper={(children) => <A href={`/expo/${layoutKey}`}>{children}</A>}
|
||||||
|
>
|
||||||
|
<span class="linkReplacement">
|
||||||
|
{layoutKey in EXPO_TITLES ? t(EXPO_TITLES[layoutKey as ExpoLayoutType]) : t('All')}
|
||||||
|
</span>
|
||||||
|
</ConditionalWrapper>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExpoNav
|
|
@ -33,6 +33,7 @@ export const LoadMoreWrapper = (props: LoadMoreProps) => {
|
||||||
)
|
)
|
||||||
|
|
||||||
const loadItems = async () => {
|
const loadItems = async () => {
|
||||||
|
// console.debug('LoadMoreWrapper.loadItems offset:', offset())
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
saveScrollPosition()
|
saveScrollPosition()
|
||||||
const newItems = await props.loadFunction(offset())
|
const newItems = await props.loadFunction(offset())
|
||||||
|
@ -47,6 +48,7 @@ export const LoadMoreWrapper = (props: LoadMoreProps) => {
|
||||||
)
|
)
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
restoreScrollPosition()
|
restoreScrollPosition()
|
||||||
|
// console.debug('LoadMoreWrapper.loadItems loaded:', newItems.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(loadItems)
|
onMount(loadItems)
|
||||||
|
@ -54,6 +56,7 @@ export const LoadMoreWrapper = (props: LoadMoreProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
<div>
|
||||||
<Show when={isLoadMoreButtonVisible() && !props.hidden}>
|
<Show when={isLoadMoreButtonVisible() && !props.hidden}>
|
||||||
<div class="load-more-container">
|
<div class="load-more-container">
|
||||||
<Button
|
<Button
|
||||||
|
@ -64,6 +67,7 @@ export const LoadMoreWrapper = (props: LoadMoreProps) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,20 @@ import {
|
||||||
Shout,
|
Shout,
|
||||||
Topic
|
Topic
|
||||||
} from '~/graphql/schema/core.gen'
|
} from '~/graphql/schema/core.gen'
|
||||||
import { LayoutType } from '~/types/common'
|
import { ExpoLayoutType } from '~/types/common'
|
||||||
import { byStat } from '../utils/sort'
|
import { byStat } from '../utils/sort'
|
||||||
import { useSession } from './session'
|
import { useSession } from './session'
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 5
|
export const PRERENDERED_ARTICLES_COUNT = 5
|
||||||
export const SHOUTS_PER_PAGE = 20
|
export const SHOUTS_PER_PAGE = 20
|
||||||
export const EXPO_LAYOUTS = ['audio', 'literature', 'video', 'image'] as LayoutType[]
|
export const EXPO_LAYOUTS = ['audio', 'literature', 'video', 'image'] as ExpoLayoutType[]
|
||||||
|
export const EXPO_TITLES: Record<ExpoLayoutType | '', string> = {
|
||||||
|
'audio': 'Audio',
|
||||||
|
'video': 'Video',
|
||||||
|
'image': 'Artworks',
|
||||||
|
'literature': 'Literature',
|
||||||
|
'': 'All'
|
||||||
|
}
|
||||||
|
|
||||||
type FeedContextType = {
|
type FeedContextType = {
|
||||||
sortedFeed: Accessor<Shout[]>
|
sortedFeed: Accessor<Shout[]>
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import { Params, RouteSectionProps, createAsync } from '@solidjs/router'
|
import { Params, RouteSectionProps, createAsync } from '@solidjs/router'
|
||||||
import { Show, onMount } from 'solid-js'
|
import { Show, createEffect, createSignal, on } 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 ExpoNav from '~/components/Views/Expo/ExpoNav'
|
||||||
|
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
||||||
import { PageLayout } from '~/components/_shared/PageLayout'
|
import { PageLayout } from '~/components/_shared/PageLayout'
|
||||||
import { EXPO_LAYOUTS, SHOUTS_PER_PAGE } from '~/context/feed'
|
import { EXPO_LAYOUTS, EXPO_TITLES, SHOUTS_PER_PAGE, useFeed } from '~/context/feed'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { loadShouts } from '~/graphql/api/public'
|
import { loadShouts } from '~/graphql/api/public'
|
||||||
import { LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
import { LoadShoutsFilters, LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
||||||
import { LayoutType } from '~/types/common'
|
import { ExpoLayoutType } from '~/types/common'
|
||||||
|
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
||||||
|
import { byCreated } from '~/utils/sort'
|
||||||
|
|
||||||
const fetchExpoShouts = async (layouts: string[]) => {
|
const fetchExpoShouts = async (layouts: string[]) => {
|
||||||
const result = await loadShouts({
|
const result = await loadShouts({
|
||||||
|
@ -28,35 +32,50 @@ export const route = {
|
||||||
|
|
||||||
export default (props: RouteSectionProps<Shout[]>) => {
|
export default (props: RouteSectionProps<Shout[]>) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
const { expoFeed, setExpoFeed, feedByLayout } = useFeed()
|
||||||
|
const [loadMoreVisible, setLoadMoreVisible] = createSignal(false)
|
||||||
|
const getTitle = (l?: string) => EXPO_TITLES[(l as ExpoLayoutType) || '']
|
||||||
|
|
||||||
const shouts = createAsync(
|
const shouts = createAsync(
|
||||||
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 getTitle = (l: string) => {
|
// Функция для загрузки дополнительных шотов
|
||||||
switch (l) {
|
const loadMore = async () => {
|
||||||
case 'audio': {
|
saveScrollPosition()
|
||||||
return t('Audio')
|
const limit = SHOUTS_PER_PAGE
|
||||||
|
const layouts = props.params.layout ? [props.params.layout] : EXPO_LAYOUTS
|
||||||
|
const offset = expoFeed()?.length || 0
|
||||||
|
const filters: LoadShoutsFilters = { layouts, featured: true }
|
||||||
|
const options: LoadShoutsOptions = { filters, limit, offset }
|
||||||
|
const shoutsFetcher = loadShouts(options)
|
||||||
|
const result = await shoutsFetcher()
|
||||||
|
setLoadMoreVisible(Boolean(result?.length))
|
||||||
|
if (result) {
|
||||||
|
setExpoFeed((prev) => Array.from(new Set([...(prev || []), ...result])).sort(byCreated))
|
||||||
}
|
}
|
||||||
case 'video': {
|
restoreScrollPosition()
|
||||||
return t('Video')
|
return result as LoadMoreItems
|
||||||
}
|
}
|
||||||
case 'image': {
|
// Эффект для загрузки данных при изменении layout
|
||||||
return t('Artworks')
|
createEffect(
|
||||||
|
on(
|
||||||
|
() => props.params.layout as ExpoLayoutType,
|
||||||
|
async (layout?: ExpoLayoutType) => {
|
||||||
|
const layouts = layout ? [layout] : EXPO_LAYOUTS
|
||||||
|
const offset = (layout ? feedByLayout()[layout]?.length : expoFeed()?.length) || 0
|
||||||
|
const options: LoadShoutsOptions = {
|
||||||
|
filters: { layouts, featured: true },
|
||||||
|
limit: SHOUTS_PER_PAGE,
|
||||||
|
offset
|
||||||
}
|
}
|
||||||
case 'literature': {
|
const shoutsFetcher = loadShouts(options)
|
||||||
return t('Literature')
|
const result = await shoutsFetcher()
|
||||||
|
setExpoFeed(result || [])
|
||||||
}
|
}
|
||||||
default: {
|
)
|
||||||
return t('Art')
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
document.title = getTitle(props.params.layout || '')
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
withPadding={true}
|
withPadding={true}
|
||||||
|
@ -64,9 +83,12 @@ export default (props: RouteSectionProps<Shout[]>) => {
|
||||||
title={`${t('Discours')} :: ${getTitle(props.params.layout || '')}`}
|
title={`${t('Discours')} :: ${getTitle(props.params.layout || '')}`}
|
||||||
>
|
>
|
||||||
<TopicsNav />
|
<TopicsNav />
|
||||||
|
<ExpoNav layout={(props.params.layout || '') as ExpoLayoutType | ''} />
|
||||||
|
<LoadMoreWrapper loadFunction={loadMore} pageSize={SHOUTS_PER_PAGE} hidden={!loadMoreVisible()}>
|
||||||
<Show when={shouts()} keyed>
|
<Show when={shouts()} keyed>
|
||||||
{(sss) => <Expo shouts={sss} layout={props.params.layout as LayoutType} />}
|
{(sss: Shout[]) => <Expo shouts={sss} layout={props.params.layout as ExpoLayoutType} />}
|
||||||
</Show>
|
</Show>
|
||||||
|
</LoadMoreWrapper>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
3
src/types/common.d.ts
vendored
3
src/types/common.d.ts
vendored
|
@ -4,7 +4,8 @@ export type RootSearchParams = {
|
||||||
token: string;
|
token: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LayoutType = 'article' | 'audio' | 'video' | 'image' | 'literature';
|
export type ExpoLayoutType = 'audio' | 'video' | 'image' | 'literature';
|
||||||
|
export type LayoutType = 'article' | ExpoLayoutType;
|
||||||
export type FollowsFilter = 'all' | 'authors' | 'topics' | 'communities';
|
export type FollowsFilter = 'all' | 'authors' | 'topics' | 'communities';
|
||||||
export type SortFunction<T> = (a: T, b: T) => number
|
export type SortFunction<T> = (a: T, b: T) => number
|
||||||
export type FilterFunction<T> = (a: T) => boolean
|
export type FilterFunction<T> = (a: T) => boolean
|
||||||
|
|
Loading…
Reference in New Issue
Block a user