expo-opening-fix
This commit is contained in:
parent
424af47b38
commit
83c660235a
|
@ -1,7 +1,6 @@
|
||||||
import { A } from '@solidjs/router'
|
import { A } from '@solidjs/router'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { For, Show, createEffect, createSignal, on } from 'solid-js'
|
import { For, Show, createEffect, createSignal, on } from 'solid-js'
|
||||||
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
|
||||||
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 } from '~/context/feed'
|
import { EXPO_LAYOUTS, SHOUTS_PER_PAGE } from '~/context/feed'
|
||||||
|
@ -18,20 +17,24 @@ import styles from '~/styles/views/Expo.module.scss'
|
||||||
|
|
||||||
export const ExpoNav = (props: { layout: ExpoLayoutType | '' }) => {
|
export const ExpoNav = (props: { layout: ExpoLayoutType | '' }) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<ul class={clsx('view-switcher')}>
|
<ul class={clsx('view-switcher')}>
|
||||||
<For each={[...EXPO_LAYOUTS, '']}>
|
<For each={[...EXPO_LAYOUTS, '']}>
|
||||||
{(layoutKey) => (
|
{(layoutKey) => (
|
||||||
<li class={clsx({ 'view-switcher__item--selected': props.layout === layoutKey })}>
|
<li class={clsx({ 'view-switcher__item--selected': props.layout === layoutKey })}>
|
||||||
<ConditionalWrapper
|
{props.layout !== layoutKey ? (
|
||||||
condition={props.layout !== layoutKey}
|
<A href={`/expo/${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>
|
||||||
|
</A>
|
||||||
|
) : (
|
||||||
<span class="linkReplacement">
|
<span class="linkReplacement">
|
||||||
{layoutKey in EXPO_TITLES ? t(EXPO_TITLES[layoutKey as ExpoLayoutType]) : t('All')}
|
{layoutKey in EXPO_TITLES ? t(EXPO_TITLES[layoutKey as ExpoLayoutType]) : t('All')}
|
||||||
</span>
|
</span>
|
||||||
</ConditionalWrapper>
|
)}
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
@ -88,36 +91,41 @@ export const Expo = (props: Props) => {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
try {
|
||||||
<div class={styles.Expo}>
|
return (
|
||||||
<Show when={props.shouts} fallback={<Loading />} keyed>
|
<div class={styles.Expo}>
|
||||||
{(feed: Shout[]) => (
|
<Show when={props.shouts} fallback={<Loading />} keyed>
|
||||||
<div class="wide-container">
|
{(feed) => (
|
||||||
<div class="row">
|
<div class="wide-container">
|
||||||
<For each={feed.slice(0, SHOUTS_PER_PAGE) || []}>
|
<div class="row">
|
||||||
{(shout) => (
|
<For each={Array.from(feed || []).slice(0, SHOUTS_PER_PAGE)}>
|
||||||
<div id={`shout-${shout.id}`} class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
{(shout) => (
|
||||||
<ArticleCard
|
<div id={`shout-${shout.id}`} class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
||||||
article={shout}
|
<ArticleCard
|
||||||
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
|
article={shout}
|
||||||
desktopCoverSize="XS"
|
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
|
||||||
withAspectRatio={true}
|
desktopCoverSize="XS"
|
||||||
/>
|
withAspectRatio={true}
|
||||||
</div>
|
/>
|
||||||
)}
|
</div>
|
||||||
</For>
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={reactedTopMonthArticles()?.length > 0}>
|
||||||
|
<ArticleCardSwiper title={t('Top month')} slides={reactedTopMonthArticles()} />
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={favoriteTopArticles()?.length > 0}>
|
||||||
|
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<Show when={reactedTopMonthArticles()?.length > 0}>
|
</Show>
|
||||||
<ArticleCardSwiper title={t('Top month')} slides={reactedTopMonthArticles()} />
|
</div>
|
||||||
</Show>
|
)
|
||||||
|
} catch (error) {
|
||||||
<Show when={favoriteTopArticles()?.length > 0}>
|
console.error('Error in Expo component:', error)
|
||||||
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
return <div>An error occurred. Please try again later.</div>
|
||||||
</Show>
|
}
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,83 +32,85 @@ export const ArticleCardSwiper = (props: Props) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ShowOnlyOnClient>
|
<Show when={props.slides && props.slides.length > 0}>
|
||||||
<div
|
<ShowOnlyOnClient>
|
||||||
class={clsx({
|
<div
|
||||||
[styles.Swiper]: props.slides?.length > 1,
|
class={clsx({
|
||||||
[styles.articleMode]: true,
|
[styles.Swiper]: props.slides?.length > 1,
|
||||||
[styles.ArticleCardSwiper]: props.slides?.length > 1
|
[styles.articleMode]: true,
|
||||||
})}
|
[styles.ArticleCardSwiper]: props.slides?.length > 1
|
||||||
>
|
})}
|
||||||
<Show when={props.title}>
|
>
|
||||||
<div class="wide-container">
|
<Show when={props.title}>
|
||||||
<div class="row">
|
<div class="wide-container">
|
||||||
<div class="col-md-12">
|
<div class="row">
|
||||||
<h2 class={styles.sliderTitle}>{props.title}</h2>
|
<div class="col-md-12">
|
||||||
|
<h2 class={styles.sliderTitle}>{props.title}</h2>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Show>
|
||||||
</Show>
|
<div class={styles.container}>
|
||||||
<div class={styles.container}>
|
<Show when={props.slides?.length > 0}>
|
||||||
<Show when={props.slides?.length > 0}>
|
<Show when={props.slides.length !== 1} fallback={<Row1 article={props.slides[0]} />}>
|
||||||
<Show when={props.slides.length !== 1} fallback={<Row1 article={props.slides[0]} />}>
|
<Show when={props.slides.length !== 2} fallback={<Row2 articles={props.slides} />}>
|
||||||
<Show when={props.slides.length !== 2} fallback={<Row2 articles={props.slides} />}>
|
<div class={styles.holder}>
|
||||||
<div class={styles.holder}>
|
<swiper-container
|
||||||
<swiper-container
|
ref={(el) => (mainSwipeRef = el)}
|
||||||
ref={(el) => (mainSwipeRef = el)}
|
centered-slides={true}
|
||||||
centered-slides={true}
|
observer={true}
|
||||||
observer={true}
|
space-between={10}
|
||||||
space-between={10}
|
breakpoints={{
|
||||||
breakpoints={{
|
576: { spaceBetween: 20, slidesPerView: 1.5 },
|
||||||
576: { spaceBetween: 20, slidesPerView: 1.5 },
|
992: { spaceBetween: 52, slidesPerView: 1.5 }
|
||||||
992: { spaceBetween: 52, slidesPerView: 1.5 }
|
}}
|
||||||
}}
|
round-lengths={true}
|
||||||
round-lengths={true}
|
loop={true}
|
||||||
loop={true}
|
speed={800}
|
||||||
speed={800}
|
autoplay={{
|
||||||
autoplay={{
|
disableOnInteraction: false,
|
||||||
disableOnInteraction: false,
|
delay: 6000,
|
||||||
delay: 6000,
|
pauseOnMouseEnter: true
|
||||||
pauseOnMouseEnter: true
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<For each={props.slides}>
|
||||||
<For each={props.slides}>
|
{(slide, index) => (
|
||||||
{(slide, index) => (
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// @ts-ignore
|
||||||
// @ts-ignore
|
<swiper-slide virtual-index={index()}>
|
||||||
<swiper-slide virtual-index={index()}>
|
<ArticleCard
|
||||||
<ArticleCard
|
article={slide}
|
||||||
article={slide}
|
settings={{
|
||||||
settings={{
|
additionalClass: 'swiper-slide',
|
||||||
additionalClass: 'swiper-slide',
|
isFloorImportant: true,
|
||||||
isFloorImportant: true,
|
isWithCover: true,
|
||||||
isWithCover: true,
|
nodate: true
|
||||||
nodate: true
|
}}
|
||||||
}}
|
desktopCoverSize="L"
|
||||||
desktopCoverSize="L"
|
/>
|
||||||
/>
|
</swiper-slide>
|
||||||
</swiper-slide>
|
)}
|
||||||
)}
|
</For>
|
||||||
</For>
|
</swiper-container>
|
||||||
</swiper-container>
|
<div
|
||||||
<div
|
class={clsx(styles.navigation, styles.prev)}
|
||||||
class={clsx(styles.navigation, styles.prev)}
|
onClick={() => mainSwipeRef?.swiper.slidePrev()}
|
||||||
onClick={() => mainSwipeRef?.swiper.slidePrev()}
|
>
|
||||||
>
|
<Icon name="swiper-l-arr" class={styles.icon} />
|
||||||
<Icon name="swiper-l-arr" class={styles.icon} />
|
</div>
|
||||||
|
<div
|
||||||
|
class={clsx(styles.navigation, styles.next)}
|
||||||
|
onClick={() => mainSwipeRef?.swiper.slideNext()}
|
||||||
|
>
|
||||||
|
<Icon name="swiper-r-arr" class={styles.icon} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
</Show>
|
||||||
class={clsx(styles.navigation, styles.next)}
|
|
||||||
onClick={() => mainSwipeRef?.swiper.slideNext()}
|
|
||||||
>
|
|
||||||
<Icon name="swiper-r-arr" class={styles.icon} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ShowOnlyOnClient>
|
||||||
</ShowOnlyOnClient>
|
</Show>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { Params, RouteSectionProps, createAsync } from '@solidjs/router'
|
import { Params, RouteSectionProps, createAsync } from '@solidjs/router'
|
||||||
import { Show, createEffect, createSignal, on } from 'solid-js'
|
import { Show, createEffect, createMemo, createSignal, on } from 'solid-js'
|
||||||
|
import { isServer } from 'solid-js/web'
|
||||||
import { TopicsNav } from '~/components/HeaderNav/TopicsNav'
|
import { TopicsNav } from '~/components/HeaderNav/TopicsNav'
|
||||||
import { Expo, ExpoNav } from '~/components/Views/ExpoView'
|
import { Expo, ExpoNav } from '~/components/Views/ExpoView'
|
||||||
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
||||||
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
import { PageLayout } from '~/components/_shared/PageLayout'
|
import { PageLayout } from '~/components/_shared/PageLayout'
|
||||||
import { EXPO_LAYOUTS, EXPO_TITLES, SHOUTS_PER_PAGE, useFeed } 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'
|
||||||
|
@ -18,7 +20,7 @@ const fetchExpoShouts = async (layouts: string[]) => {
|
||||||
limit: SHOUTS_PER_PAGE,
|
limit: SHOUTS_PER_PAGE,
|
||||||
offset: 0
|
offset: 0
|
||||||
} as LoadShoutsOptions)
|
} as LoadShoutsOptions)
|
||||||
return result || []
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const route = {
|
export const route = {
|
||||||
|
@ -33,14 +35,14 @@ export default (props: RouteSectionProps<Shout[]>) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { expoFeed, setExpoFeed, feedByLayout } = useFeed()
|
const { expoFeed, setExpoFeed, feedByLayout } = useFeed()
|
||||||
const [loadMoreVisible, setLoadMoreVisible] = createSignal(false)
|
const [loadMoreVisible, setLoadMoreVisible] = createSignal(false)
|
||||||
const getTitle = (l?: string) => EXPO_TITLES[(l as ExpoLayoutType) || '']
|
const getTitle = createMemo(() => (l?: string) => EXPO_TITLES[(l as ExpoLayoutType) || ''])
|
||||||
|
|
||||||
const shouts = createAsync(
|
const shouts = createAsync(async () =>
|
||||||
async () =>
|
isServer
|
||||||
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 loadMore = async () => {
|
const loadMore = async () => {
|
||||||
saveScrollPosition()
|
saveScrollPosition()
|
||||||
const limit = SHOUTS_PER_PAGE
|
const limit = SHOUTS_PER_PAGE
|
||||||
|
@ -48,46 +50,52 @@ export default (props: RouteSectionProps<Shout[]>) => {
|
||||||
const offset = expoFeed()?.length || 0
|
const offset = expoFeed()?.length || 0
|
||||||
const filters: LoadShoutsFilters = { layouts, featured: true }
|
const filters: LoadShoutsFilters = { layouts, featured: true }
|
||||||
const options: LoadShoutsOptions = { filters, limit, offset }
|
const options: LoadShoutsOptions = { filters, limit, offset }
|
||||||
const shoutsFetcher = loadShouts(options)
|
const fetcher = await loadShouts(options)
|
||||||
const result = await shoutsFetcher()
|
const result = (await fetcher()) || []
|
||||||
setLoadMoreVisible(Boolean(result?.length))
|
setLoadMoreVisible(Boolean(result?.length))
|
||||||
if (result) {
|
if (result && Array.isArray(result)) {
|
||||||
setExpoFeed((prev) => Array.from(new Set([...(prev || []), ...result])).sort(byCreated))
|
setExpoFeed((prev) => Array.from(new Set([...(prev || []), ...result])).sort(byCreated))
|
||||||
}
|
}
|
||||||
restoreScrollPosition()
|
restoreScrollPosition()
|
||||||
return result as LoadMoreItems
|
return result as LoadMoreItems
|
||||||
}
|
}
|
||||||
// Эффект для загрузки данных при изменении layout
|
|
||||||
createEffect(
|
createEffect(
|
||||||
on(
|
on(
|
||||||
() => props.params.layout as ExpoLayoutType,
|
() => props.params.layout,
|
||||||
async (layout?: ExpoLayoutType) => {
|
async (currentLayout) => {
|
||||||
const layouts = layout ? [layout] : EXPO_LAYOUTS
|
const layouts = currentLayout ? [currentLayout] : EXPO_LAYOUTS
|
||||||
const offset = (layout ? feedByLayout()[layout]?.length : expoFeed()?.length) || 0
|
const offset = (currentLayout ? feedByLayout()[currentLayout]?.length : expoFeed()?.length) || 0
|
||||||
const options: LoadShoutsOptions = {
|
const options: LoadShoutsOptions = {
|
||||||
filters: { layouts, featured: true },
|
filters: { layouts, featured: true },
|
||||||
limit: SHOUTS_PER_PAGE,
|
limit: SHOUTS_PER_PAGE,
|
||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
const shoutsFetcher = loadShouts(options)
|
const result = await loadShouts(options)
|
||||||
const result = await shoutsFetcher()
|
if (result && Array.isArray(result)) {
|
||||||
setExpoFeed(result || [])
|
setExpoFeed(result)
|
||||||
|
} else {
|
||||||
|
setExpoFeed([])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
withPadding={true}
|
withPadding={true}
|
||||||
zeroBottomPadding={true}
|
zeroBottomPadding={true}
|
||||||
title={`${t('Discours')} :: ${getTitle(props.params.layout || '')}`}
|
title={`${t('Discours')} :: ${getTitle()((props.params.layout as ExpoLayoutType) || '')}`}
|
||||||
>
|
>
|
||||||
<TopicsNav />
|
<TopicsNav />
|
||||||
<ExpoNav layout={(props.params.layout || '') as ExpoLayoutType | ''} />
|
<ExpoNav layout={(props.params.layout as ExpoLayoutType) || ''} />
|
||||||
<LoadMoreWrapper loadFunction={loadMore} pageSize={SHOUTS_PER_PAGE} hidden={!loadMoreVisible()}>
|
<Show when={shouts()} fallback={<Loading />} keyed>
|
||||||
<Show when={shouts()} keyed>
|
{(sss) => (
|
||||||
{(sss: Shout[]) => <Expo shouts={sss} layout={props.params.layout as ExpoLayoutType} />}
|
<LoadMoreWrapper loadFunction={loadMore} pageSize={SHOUTS_PER_PAGE} hidden={!loadMoreVisible()}>
|
||||||
</Show>
|
<Expo shouts={sss as Shout[]} layout={(props.params.layout as ExpoLayoutType) || ''} />
|
||||||
</LoadMoreWrapper>
|
</LoadMoreWrapper>
|
||||||
|
)}
|
||||||
|
</Show>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user