refactor: split monolithic state into context-based modules

Extract image, desktop, mobile, and config state into separate context
providers to improve modularity and reduce unnecessary re-renders.

Signed-off-by: Sped0n <hi@sped0n.com>
This commit is contained in:
Sped0n
2026-03-22 19:45:05 +08:00
parent 1c386386f3
commit f25b71a858
20 changed files with 1165 additions and 894 deletions

View File

@@ -1,17 +1,11 @@
import {
Match,
Show,
Switch,
createEffect,
createResource,
createSignal,
lazy,
type JSX
} from 'solid-js'
import { Match, Show, Switch, createResource, lazy, type JSX } from 'solid-js'
import { render } from 'solid-js/web'
import { ConfigStateProvider } from './configState'
import { DesktopStateProvider } from './desktop/state'
import { ImageStateProvider } from './imageState'
import { MobileStateProvider } from './mobile/state'
import { getImageJSON } from './resources'
import { StateProvider } from './state'
import '../scss/style.scss'
@@ -35,6 +29,34 @@ const container = document.getElementsByClassName('container')[0] as Container
const Desktop = lazy(async () => await import('./desktop/layout'))
const Mobile = lazy(async () => await import('./mobile/layout'))
function AppContent(props: {
isMobile: boolean
prevText: string
closeText: string
nextText: string
loadingText: string
}): JSX.Element {
return (
<Switch fallback={<div>Error</div>}>
<Match when={props.isMobile}>
<MobileStateProvider>
<Mobile closeText={props.closeText} loadingText={props.loadingText} />
</MobileStateProvider>
</Match>
<Match when={!props.isMobile}>
<DesktopStateProvider>
<Desktop
prevText={props.prevText}
closeText={props.closeText}
nextText={props.nextText}
loadingText={props.loadingText}
/>
</DesktopStateProvider>
</Match>
</Switch>
)
}
function Main(): JSX.Element {
// variables
const [ijs] = createResource(getImageJSON)
@@ -47,41 +69,20 @@ function Main(): JSX.Element {
const isWindowsDesktop = /windows nt/.test(ua)
const isMobile = isMobileUA || (hasTouchInput && hasTouchLayout && !isWindowsDesktop)
// states
const [scrollable, setScollable] = createSignal(true)
createEffect(() => {
if (scrollable()) {
container.classList.remove('disableScroll')
} else {
container.classList.add('disableScroll')
}
})
return (
<>
<Show when={ijs.state === 'ready'}>
<StateProvider length={ijs()?.length ?? 0}>
<Switch fallback={<div>Error</div>}>
<Match when={isMobile}>
<Mobile
ijs={ijs() ?? []}
closeText={container.dataset.close}
loadingText={container.dataset.loading}
setScrollable={setScollable}
/>
</Match>
<Match when={!isMobile}>
<Desktop
ijs={ijs() ?? []}
prevText={container.dataset.prev}
closeText={container.dataset.close}
nextText={container.dataset.next}
loadingText={container.dataset.loading}
/>
</Match>
</Switch>
</StateProvider>
<ImageStateProvider images={ijs() ?? []}>
<ConfigStateProvider>
<AppContent
isMobile={isMobile}
prevText={container.dataset.prev}
closeText={container.dataset.close}
nextText={container.dataset.next}
loadingText={container.dataset.loading}
/>
</ConfigStateProvider>
</ImageStateProvider>
</Show>
</>
)