subs-refactoring

This commit is contained in:
Untone 2024-05-21 02:15:52 +03:00
parent bec333f7c3
commit 79f94876f0
24 changed files with 253 additions and 336 deletions

View File

@ -423,14 +423,14 @@
"subscriber": "subscriber",
"subscriber_rp": "subscriber",
"subscribers": "subscribers",
"SubscriberWithCount": "{count, plural, =0 {no followers} one {{count} follower} other {{count} followers}}",
"FollowersWithCount": "{count, plural, =0 {no followers} one {{count} follower} other {{count} followers}}",
"subscribing...": "subscribing...",
"subscription": "subscription",
"Subscription": "Subscription",
"subscription_rp": "subscription",
"subscriptions": "subscriptions",
"Subscriptions": "Subscriptions",
"SubscriptionWithCount": "{count, plural, =0 {no subscriptions} one {{count} subscription} other {{count} subscriptions}}",
"FollowsWithCount": "{count, plural, =0 {no subscriptions} one {{count} subscription} other {{count} subscriptions}}",
"Substrate": "Substrate",
"Success": "Success",
"Successfully authorized": "Authorization successful",

View File

@ -451,11 +451,11 @@
"subscriber": "подписчик",
"subscriber_rp": "подписчика",
"subscribers": "подписчиков",
"SubscriberWithCount": "{count, plural, =0 {нет подписчиков} one {{count} подписчик} few {{count} подписчика} other {{count} подписчиков}}",
"FollowersWithCount": "{count, plural, =0 {нет подписчиков} one {{count} подписчик} few {{count} подписчика} other {{count} подписчиков}}",
"subscribing...": "Подписка...",
"Subscription": "Подписка",
"Subscriptions": "Подписки",
"SubscriptionWithCount": "{count, plural, =0 {нет подписок} one {{count} подписка} few {{count} подписки} other {{count} подписок}}",
"FollowsWithCount": "{count, plural, =0 {нет подписок} one {{count} подписка} few {{count} подписки} other {{count} подписок}}",
"Substrate": "Подложка",
"Success": "Успешно",
"Successfully authorized": "Авторизация успешна",

View File

@ -31,16 +31,7 @@ export const AudioPlayer = (props: Props) => {
const [isPlaying, setIsPlaying] = createSignal(false)
const currentTack = createMemo(() => props.media[currentTrackIndex()])
createEffect(
on(
() => currentTrackIndex(),
() => {
setCurrentTrackDuration(0)
},
{ defer: true },
),
)
createEffect(on(currentTrackIndex, () => setCurrentTrackDuration(0), { defer: true }))
const handlePlayMedia = async (trackIndex: number) => {
setIsPlaying(!isPlaying() || trackIndex !== currentTrackIndex())

View File

@ -1,6 +1,6 @@
import { openPage } from '@nanostores/router'
import { clsx } from 'clsx'
import { Match, Show, Switch, createEffect, createMemo, createSignal } from 'solid-js'
import { Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
import { useFollowing } from '../../../context/following'
import { useLocalize } from '../../../context/localize'
@ -34,17 +34,19 @@ export const AuthorBadge = (props: Props) => {
const { author, requireAuthentication } = useSession()
const { follow, unfollow, follows, following } = useFollowing()
const [isMobileView, setIsMobileView] = createSignal(false)
const [isFollowed, setIsFollowed] = createSignal<boolean>()
createEffect(() => {
if (!(follows && props.author)) return
const followed = follows?.authors?.some((authorEntity) => authorEntity.id === props.author?.id)
setIsFollowed(followed)
})
createEffect(() => {
setIsMobileView(!mediaMatches.sm)
})
const [isFollowed, setIsFollowed] = createSignal<boolean>(
follows?.authors?.some((authorEntity) => authorEntity.id === props.author?.id),
)
createEffect(() => setIsMobileView(!mediaMatches.sm))
createEffect(
on(
[() => follows?.authors, () => props.author, following],
([followingAuthors, currentAuthor, _]) => {
setIsFollowed(followingAuthors?.some((followedAuthor) => followedAuthor.id === currentAuthor?.id))
},
{ defer: true },
),
)
const { changeSearchParams } = useRouter()
const { t, formatDate, lang } = useLocalize()
@ -132,7 +134,7 @@ export const AuthorBadge = (props: Props) => {
<Show when={props.author.slug !== author()?.slug && !props.nameOnly}>
<div class={styles.actions}>
<FollowingButton
action={() => handleFollowClick()}
action={handleFollowClick}
isFollowed={isFollowed()}
actionMessageType={following()?.slug === props.author.slug ? following().type : undefined}
/>

View File

@ -429,7 +429,7 @@
}
}
.subscribersContainer {
.followersContainer {
display: flex;
flex-wrap: wrap;
font-size: 1.4rem;
@ -440,7 +440,7 @@
}
}
.subscribers {
.followers {
align-items: center;
cursor: pointer;
display: inline-flex;
@ -456,7 +456,7 @@
margin-right: 0;
}
.subscribersItem {
.followersItem {
position: relative;
&:nth-child(1) {
@ -473,7 +473,7 @@
}
}
.subscribersCounter {
.followsCounter {
font-weight: 500;
margin-left: 1rem;
}
@ -481,7 +481,7 @@
&:hover {
background: none !important;
.subscribersCounter {
.followsCounter {
background: var(--background-color-invert);
}
}

View File

@ -27,7 +27,7 @@ import styles from './AuthorCard.module.scss'
type Props = {
author: Author
followers?: Author[]
following?: Array<Author | Topic>
flatFollows?: Array<Author | Topic>
}
export const AuthorCard = (props: Props) => {
const { t, lang } = useLocalize()
@ -39,7 +39,7 @@ export const AuthorCard = (props: Props) => {
const { follow, unfollow, follows, following } = useFollowing()
onMount(() => {
setAuthorSubs(props.following)
setAuthorSubs(props.flatFollows)
})
createEffect(() => {
@ -71,15 +71,15 @@ export const AuthorCard = (props: Props) => {
}
createEffect(() => {
if (props.following) {
if (props.flatFollows) {
if (followsFilter() === 'authors') {
setAuthorSubs(props.following.filter((s) => 'name' in s))
setAuthorSubs(props.flatFollows.filter((s) => 'name' in s))
} else if (followsFilter() === 'topics') {
setAuthorSubs(props.following.filter((s) => 'title' in s))
setAuthorSubs(props.flatFollows.filter((s) => 'title' in s))
} else if (followsFilter() === 'communities') {
setAuthorSubs(props.following.filter((s) => 'title' in s))
setAuthorSubs(props.flatFollows.filter((s) => 'title' in s))
} else {
setAuthorSubs(props.following)
setAuthorSubs(props.flatFollows)
}
}
})
@ -108,6 +108,73 @@ export const AuthorCard = (props: Props) => {
return t('Follow')
})
const FollowersModalView = () => (
<>
<h2>{t('Followers')}</h2>
<div class={styles.listWrapper}>
<div class="row">
<div class="col-24">
<For each={props.followers}>{(follower: Author) => <AuthorBadge author={follower} />}</For>
</div>
</div>
</div>
</>
)
const FollowingModalView = () => (
<>
<h2>{t('Subscriptions')}</h2>
<ul class="view-switcher">
<li
class={clsx({
'view-switcher__item--selected': followsFilter() === 'all',
})}
>
<button type="button" onClick={() => setFollowsFilter('all')}>
{t('All')}
</button>
<span class="view-switcher__counter">{props.flatFollows.length}</span>
</li>
<li
class={clsx({
'view-switcher__item--selected': followsFilter() === 'authors',
})}
>
<button type="button" onClick={() => setFollowsFilter('authors')}>
{t('Authors')}
</button>
<span class="view-switcher__counter">{props.flatFollows.filter((s) => 'name' in s).length}</span>
</li>
<li
class={clsx({
'view-switcher__item--selected': followsFilter() === 'topics',
})}
>
<button type="button" onClick={() => setFollowsFilter('topics')}>
{t('Topics')}
</button>
<span class="view-switcher__counter">{props.flatFollows.filter((s) => 'title' in s).length}</span>
</li>
</ul>
<br />
<div class={styles.listWrapper}>
<div class="row">
<div class="col-24">
<For each={authorSubs()}>
{(subscription) =>
isAuthor(subscription) ? (
<AuthorBadge author={subscription} subscriptionsMode={true} />
) : (
<TopicBadge topic={subscription} subscriptionsMode={true} />
)
}
</For>
</div>
</div>
</div>
</>
)
return (
<div class={clsx(styles.author, 'row')}>
<div class="col-md-5">
@ -125,35 +192,30 @@ export const AuthorCard = (props: Props) => {
<Show when={props.author.bio}>
<div class={styles.authorAbout} innerHTML={props.author.bio} />
</Show>
<Show when={props.followers?.length > 0 || props.following?.length > 0}>
<div class={styles.subscribersContainer}>
<Show when={props.followers?.length > 0 || props.flatFollows?.length > 0}>
<div class={styles.followersContainer}>
<Show when={props.followers && props.followers.length > 0}>
<a href="?m=followers" class={styles.subscribers}>
<a href="?m=followers" class={styles.followers}>
<For each={props.followers.slice(0, 3)}>
{(f) => (
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.subscribersItem} />
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.followersItem} />
)}
</For>
<div class={styles.subscribersCounter}>
{t('SubscriberWithCount', {
<div class={styles.followsCounter}>
{t('FollowersWithCount', {
count: props.followers.length ?? 0,
})}
</div>
</a>
</Show>
<Show when={props.following && props.following.length > 0}>
<a href="?m=following" class={styles.subscribers}>
<For each={props.following.slice(0, 3)}>
<Show when={props.flatFollows?.length > 0}>
<a href="?m=following" class={styles.followers}>
<For each={props.flatFollows.slice(0, 3)}>
{(f) => {
if ('name' in f) {
return (
<Userpic
size={'XS'}
name={f.name}
userpic={f.pic}
class={styles.subscribersItem}
/>
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.followersItem} />
)
}
@ -163,7 +225,7 @@ export const AuthorCard = (props: Props) => {
size={'XS'}
name={f.title}
userpic={f.pic}
class={styles.subscribersItem}
class={styles.followersItem}
/>
)
}
@ -171,9 +233,9 @@ export const AuthorCard = (props: Props) => {
return null
}}
</For>
<div class={styles.subscribersCounter}>
{t('SubscriptionWithCount', {
count: props?.following.length ?? 0,
<div class={styles.followsCounter}>
{t('FollowsWithCount', {
count: props?.flatFollows.length ?? 0,
})}
</div>
</a>
@ -251,77 +313,12 @@ export const AuthorCard = (props: Props) => {
</ShowOnlyOnClient>
<Show when={props.followers}>
<Modal variant="medium" isResponsive={true} name="followers" maxHeight>
<>
<h2>{t('Followers')}</h2>
<div class={styles.listWrapper}>
<div class="row">
<div class="col-24">
<For each={props.followers}>
{(follower: Author) => <AuthorBadge author={follower} />}
</For>
</div>
</div>
</div>
</>
<FollowersModalView />
</Modal>
</Show>
<Show when={props.following}>
<Show when={props.flatFollows}>
<Modal variant="medium" isResponsive={true} name="following" maxHeight>
<>
<h2>{t('Subscriptions')}</h2>
<ul class="view-switcher">
<li
class={clsx({
'view-switcher__item--selected': followsFilter() === 'all',
})}
>
<button type="button" onClick={() => setFollowsFilter('all')}>
{t('All')}
</button>
<span class="view-switcher__counter">{props.following.length}</span>
</li>
<li
class={clsx({
'view-switcher__item--selected': followsFilter() === 'authors',
})}
>
<button type="button" onClick={() => setFollowsFilter('authors')}>
{t('Authors')}
</button>
<span class="view-switcher__counter">
{props.following.filter((s) => 'name' in s).length}
</span>
</li>
<li
class={clsx({
'view-switcher__item--selected': followsFilter() === 'topics',
})}
>
<button type="button" onClick={() => setFollowsFilter('topics')}>
{t('Topics')}
</button>
<span class="view-switcher__counter">
{props.following.filter((s) => 'title' in s).length}
</span>
</li>
</ul>
<br />
<div class={styles.listWrapper}>
<div class="row">
<div class="col-24">
<For each={authorSubs()}>
{(subscription) =>
isAuthor(subscription) ? (
<AuthorBadge author={subscription} subscriptionsMode={true} />
) : (
<TopicBadge topic={subscription} subscriptionsMode={true} />
)
}
</For>
</div>
</div>
</div>
</>
<FollowingModalView />
</Modal>
</Show>
</div>

View File

@ -63,18 +63,8 @@ export const PasswordField = (props: Props) => {
}
}
createEffect(
on(
() => error(),
() => {
props.errorMessage?.(error())
},
{ defer: true },
),
)
createEffect(() => {
setError(props.setError)
})
createEffect(on(error, (er) => er && props.errorMessage?.(er), { defer: true }))
createEffect(() => setError(props.setError))
return (
<div class={clsx(styles.PassportField, props.class)}>

View File

@ -62,7 +62,7 @@ export const TableOfContents = (props: Props) => {
createEffect(
on(
() => props.body,
() => debouncedUpdateHeadings(),
(_) => debouncedUpdateHeadings(),
),
)

View File

@ -40,65 +40,19 @@ const LOAD_MORE_PAGE_SIZE = 9
export const AuthorView = (props: Props) => {
const { t } = useLocalize()
const { followers: myFollowers, follows: myFollows } = useFollowing()
const { session, author: me } = useSession()
const { author: me } = useSession()
const { sortedArticles } = useArticlesStore({ shouts: props.shouts })
const { page: getPage, searchParams } = useRouter()
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const [isBioExpanded, setIsBioExpanded] = createSignal(false)
const [author, setAuthor] = createSignal<Author>()
const [author, setAuthor] = createSignal<Author>(props.author)
const [followers, setFollowers] = createSignal([])
const [following, changeFollowing] = createSignal<Array<Author | Topic>>([]) // flat AuthorFollowsResult
const [showExpandBioControl, setShowExpandBioControl] = createSignal(false)
const [commented, setCommented] = createSignal<Reaction[]>()
const modal = MODALS[searchParams().m]
const [sessionChecked, setSessionChecked] = createSignal(false)
createEffect(
on(
[() => sessionChecked(), () => props.authorSlug, () => session()?.user?.app_data?.profile?.slug],
([checked, slug, mySlug]) => {
if (!checked && slug && mySlug === slug) {
setSessionChecked(true)
const appdata = session()?.user.app_data
if (appdata) {
console.info('preloaded my own profile')
setFollowers(myFollowers())
setAuthor(me())
const { authors, topics } = myFollows
changeFollowing([...authors, ...topics])
}
}
},
{ defer: true },
),
)
const bioContainerRef: { current: HTMLDivElement } = { current: null }
const bioWrapperRef: { current: HTMLDivElement } = { current: null }
const fetchData = async (slug: string) => {
try {
const [followsResult, followersResult, authorResult] = await Promise.all([
apiClient.getAuthorFollows({ slug }),
apiClient.getAuthorFollowers({ slug }),
loadAuthor({ slug }),
])
console.info('[components.Author] data loaded')
setAuthor(authorResult)
setFollowers(followersResult || [])
const { authors, topics } = followsResult
changeFollowing([...(authors || []), ...(topics || [])])
} catch (error) {
console.error('[components.Author] fetch error', error)
}
}
const checkBioHeight = () => {
if (bioContainerRef.current) {
setShowExpandBioControl(bioContainerRef.current.offsetHeight > bioWrapperRef.current.offsetHeight)
}
}
// пагинация загрузки ленты постов
const loadMore = async () => {
saveScrollPosition()
const { hasMore } = await loadShouts({
@ -110,36 +64,72 @@ export const AuthorView = (props: Props) => {
restoreScrollPosition()
}
// загружает профиль и подписки
const [isFetching, setIsFetching] = createSignal(false)
const fetchData = async (slug) => {
setIsFetching(true)
const authorResult = await loadAuthor({ slug })
setAuthor(authorResult)
console.info(`[Author] profile for @${slug} fetched`)
const followsResult = await apiClient.getAuthorFollows({ slug })
const { authors, topics } = followsResult
changeFollowing([...(authors || []), ...(topics || [])])
console.info(`[Author] follows for @${slug} fetched`)
const followersResult = await apiClient.getAuthorFollowers({ slug })
setFollowers(followersResult || [])
console.info(`[Author] followers for @${slug} fetched`)
setIsFetching(false)
}
// проверяет не собственный ли это профиль, иначе - загружает
createEffect(
on([() => me(), () => props.authorSlug], ([myProfile, slug]) => {
const my = slug && myProfile?.slug === slug
if (my) {
console.debug('[Author] my profile precached')
myProfile && setAuthor(myProfile)
setFollowers(myFollowers() || [])
changeFollowing([...(myFollows?.authors || []), ...(myFollows?.topics || [])])
} else if (slug && !isFetching()) {
fetchData(slug)
}
}),
{ defer: true },
)
// догружает ленту и комментарии
createEffect(
on(author, async (profile) => {
if (!commented() && profile) {
await loadMore()
const ccc = await apiClient.getReactionsBy({
by: { comment: true, created_by: profile.id },
})
setCommented(ccc)
}
}),
)
const bioContainerRef: { current: HTMLDivElement } = { current: null }
const bioWrapperRef: { current: HTMLDivElement } = { current: null }
const checkBioHeight = () => {
if (bioContainerRef.current) {
setShowExpandBioControl(bioContainerRef.current.offsetHeight > bioWrapperRef.current.offsetHeight)
}
}
onMount(() => {
if (!modal) hideModal()
fetchData(props.authorSlug)
checkBioHeight()
loadMore()
})
const pages = createMemo<Shout[][]>(() =>
splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE),
)
const fetchComments = async (commenter: Author) => {
const data = await apiClient.getReactionsBy({
by: { comment: true, created_by: commenter.id },
})
setCommented(data)
}
const authorSlug = createMemo(() => author()?.slug)
createEffect(
on(
() => authorSlug(),
() => {
fetchData(authorSlug())
fetchComments(author())
},
{ defer: true },
),
)
const ogImage = createMemo(() =>
author()?.pic
? getImageUrl(author()?.pic, { width: 1200 })
@ -168,7 +158,7 @@ export const AuthorView = (props: Props) => {
<Show when={author()} fallback={<Loading />}>
<>
<div class={styles.authorHeader}>
<AuthorCard author={author()} followers={followers() || []} following={following() || []} />
<AuthorCard author={author()} followers={followers() || []} flatFollows={following() || []} />
</div>
<div class={clsx(styles.groupControls, 'row')}>
<div class="col-md-16">

View File

@ -143,16 +143,20 @@ export const FeedView = (props: Props) => {
Promise.all([loadTopComments()]).finally(() => setIsRightColumnLoaded(true))
})
createEffect(() => {
if (session()?.access_token && !unratedArticles()) {
loadUnratedArticles()
}
})
createEffect(
on(
[() => session(), unratedArticles],
([s, seen]) => {
if (s?.access_token && !(seen?.length > 0)) loadUnratedArticles()
},
{ defer: true },
),
)
createEffect(
on(
() => page().route + searchParams().by + searchParams().period + searchParams().visibility,
() => {
[page, searchParams],
(_, _p) => {
resetSortedArticles()
loadMore()
},

View File

@ -136,9 +136,7 @@ export const InboxView = (props: Props) => {
}
createEffect(
on(
() => messages(),
() => {
on(messages, () => {
if (!messagesContainerRef.current) {
return
}
@ -149,8 +147,7 @@ export const InboxView = (props: Props) => {
top: messagesContainerRef.current.scrollHeight,
behavior: 'smooth',
})
},
),
}),
{ defer: true },
)
const handleScrollMessageContainer = () => {

View File

@ -87,13 +87,7 @@ export const TopicView = (props: Props) => {
loadReactedTopMonthArticles(topic()?.slug)
}
createEffect(
on(
() => topic(),
() => loadRandom(),
{ defer: true },
),
)
createEffect(on(topic, loadRandom, { defer: true }))
const title = createMemo(
() =>

View File

@ -66,7 +66,7 @@ export const InviteMembers = (props: Props) => {
createEffect(
on(
() => sortedAuthors(),
sortedAuthors,
(currentAuthors) => {
setAuthorsToInvite(currentAuthors.map((author) => ({ ...author, selected: false })))
},

View File

@ -129,8 +129,8 @@ export const Lightbox = (props: Props) => {
createEffect(
on(
() => zoomLevel(),
() => {
zoomLevel,
(_) => {
clearTimeout(fadeTimer)
fadeTimer = setTimeout(() => {

View File

@ -61,7 +61,7 @@ export const EditorSwiper = (props: Props) => {
createEffect(
on(
() => props.images.length,
() => {
(_) => {
mainSwipeRef.current?.swiper.update()
thumbSwipeRef.current?.swiper.update()
},

View File

@ -45,7 +45,7 @@ export const ImageSwiper = (props: Props) => {
createEffect(
on(
() => props.images.length,
() => {
(_) => {
mainSwipeRef.current?.swiper.update()
thumbSwipeRef.current?.swiper.update()
},

View File

@ -94,21 +94,14 @@ export const FollowingProvider = (props: { children: JSX.Element }) => {
createEffect(
on(
() => author(),
(a) => {
if (a?.id) {
try {
const appdata = session()?.user.app_data
() => session()?.user.app_data,
(appdata) => {
if (appdata) {
const { authors, followers, topics } = appdata
setFollows({ authors, topics })
setFollowers(followers)
if (!authors) fetchData()
}
} catch (e) {
console.error(e)
}
}
},
),
)

View File

@ -96,15 +96,15 @@ export const SessionProvider = (props: {
// handle auth state callback
createEffect(
on(
() => searchParams()?.state,
(state) => {
if (state) {
setOauthState((_s) => state)
const scope = searchParams()?.scope
? searchParams()?.scope?.toString().split(' ')
searchParams,
(params) => {
if (params?.state) {
setOauthState((_s) => params?.state)
const scope = params?.scope
? params?.scope?.toString().split(' ')
: ['openid', 'profile', 'email']
if (scope) console.info(`[context.session] scope: ${scope}`)
const url = searchParams()?.redirect_uri || searchParams()?.redirectURL || window.location.href
const url = params?.redirect_uri || params?.redirectURL || window.location.href
setConfig((c: ConfigType) => ({ ...c, redirectURL: url.split('?')[0] }))
changeSearchParams({ mode: 'confirm-email', m: 'auth' }, true)
}

View File

@ -1,6 +1,6 @@
import type { PageProps } from './types'
import { Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
import { Show, createEffect, createMemo, createSignal, on, onCleanup } from 'solid-js'
import { AuthorView, PRERENDERED_ARTICLES_COUNT } from '../components/Views/Author'
import { Loading } from '../components/_shared/Loading'
@ -20,38 +20,19 @@ export const AuthorPage = (props: PageProps) => {
Boolean(props.authorShouts) && Boolean(props.author) && props.author.slug === slug(),
)
const preload = () => {
return Promise.all([
loadShouts({
filters: { author: slug(), featured: false },
limit: PRERENDERED_ARTICLES_COUNT,
}),
loadAuthor({ slug: slug() }),
])
}
onMount(async () => {
if (isLoaded()) {
return
}
resetSortedArticles()
await preload()
setIsLoaded(true)
})
createEffect(
on(
() => slug(),
async () => {
on(slug, async (s) => {
if (s) {
setIsLoaded(false)
resetSortedArticles()
await preload()
await loadShouts({
filters: { author: s, featured: false },
limit: PRERENDERED_ARTICLES_COUNT,
})
await loadAuthor({ slug: s })
setIsLoaded(true)
},
{ defer: true },
),
}
}),
)
onCleanup(() => resetSortedArticles())

View File

@ -12,10 +12,9 @@ import { LayoutType } from '../types'
export const ExpoPage = (props: PageProps) => {
const { t } = useLocalize()
const { page } = useRouter()
const getLayout = createMemo<LayoutType>(() => page().params['layout'] as LayoutType)
const getTitle = () => {
switch (getLayout()) {
const layout = createMemo(() => page().params['layout'] as LayoutType)
const title = createMemo(() => {
switch (layout()) {
case 'audio': {
return t('Audio')
}
@ -32,22 +31,14 @@ export const ExpoPage = (props: PageProps) => {
return t('Art')
}
}
}
})
createEffect(
on(
() => getLayout(),
() => {
document.title = getTitle()
},
{ defer: true },
),
)
createEffect(on(title, (t) => (document.title = t), { defer: true }))
return (
<PageLayout withPadding={true} zeroBottomPadding={true} title={getTitle()}>
<PageLayout withPadding={true} zeroBottomPadding={true} title={title()}>
<Topics />
<Expo shouts={props.expoShouts} layout={getLayout()} />
<Expo shouts={props.expoShouts} layout={layout()} />
</PageLayout>
)
}

View File

@ -25,20 +25,9 @@ const handleMyFeedLoadShouts = (options: LoadShoutsOptions) => {
export const FeedPage = () => {
const { t } = useLocalize()
onCleanup(() => resetSortedArticles())
const { page } = useRouter()
createEffect(
on(
() => page().route,
() => {
resetSortedArticles()
},
{ defer: true },
),
)
createEffect(on(page, (_) => resetSortedArticles(), { defer: true }))
onCleanup(() => resetSortedArticles())
return (
<PageLayout title={t('Feed')}>

View File

@ -44,10 +44,10 @@ export const ProfileSecurityPage = () => {
createEffect(
on(
() => session()?.user?.email,
() => {
(email) => {
setFormData((prevData) => ({
...prevData,
['email']: session()?.user?.email,
email,
}))
},
),

View File

@ -37,19 +37,17 @@ export const TopicPage = (props: PageProps) => {
})
createEffect(
on(
() => slug(),
async () => {
on(slug, async (s) => {
if (s) {
setIsLoaded(false)
resetSortedArticles()
await preload()
setIsLoaded(true)
},
{ defer: true },
),
}
}),
)
onCleanup(() => resetSortedArticles())
onCleanup(resetSortedArticles)
const usePrerenderedData = props.topic?.slug === slug()

View File

@ -16,7 +16,7 @@ const cssModuleHMR = () => {
modules.forEach((module) => {
if (module.id.includes('.scss') || module.id.includes('.css')) {
module.isSelfAccepting = true
module.accept()
// module.accept()
}
})
},