73 lines
1.7 KiB
TypeScript
73 lines
1.7 KiB
TypeScript
import { h, type FunctionComponent } from 'preact'
|
|
import { useCallback, useEffect } from 'preact/hooks'
|
|
import { LocationProvider, Route, Router } from 'preact-iso'
|
|
import { get } from 'lowline'
|
|
import Head from './head.ts'
|
|
import Footer from './footer.tsx'
|
|
import Header from './header.tsx'
|
|
import ErrorPage from './error_page.tsx'
|
|
import routes from '../routes.ts'
|
|
import throttle from '../../shared/utils/throttle.ts'
|
|
|
|
import s from './app.module.scss'
|
|
|
|
type Props = {
|
|
error?: Error
|
|
title?: string
|
|
}
|
|
|
|
const remember = throttle(function remember() {
|
|
window.history.replaceState(
|
|
{
|
|
...window.history.state,
|
|
scrollTop: window.scrollY,
|
|
},
|
|
'',
|
|
null,
|
|
)
|
|
}, 100)
|
|
|
|
const App: FunctionComponent<Props> = ({ error, title }) => {
|
|
useEffect(() => {
|
|
addEventListener('scroll', remember)
|
|
|
|
return () => removeEventListener('scroll', remember)
|
|
})
|
|
|
|
const onRouteChange = useCallback(() => {
|
|
const offset = get(window.history, 'state.scrollTop')
|
|
|
|
setTimeout(() => {
|
|
window.scrollTo(0, offset || 0)
|
|
}, 100)
|
|
}, [])
|
|
|
|
return (
|
|
<LocationProvider>
|
|
<div id='app' className={s.base}>
|
|
<Head>
|
|
<title>{title || 'Untitled'}</title>
|
|
</Head>
|
|
|
|
<Header routes={routes} />
|
|
|
|
<main className={s.main}>
|
|
{error ? (
|
|
<ErrorPage error={error} />
|
|
) : (
|
|
<Router onRouteChange={onRouteChange}>
|
|
{routes.map((route) => (
|
|
<Route key={route.path} path={route.path} component={route.component} />
|
|
))}
|
|
</Router>
|
|
)}
|
|
</main>
|
|
|
|
<Footer />
|
|
</div>
|
|
</LocationProvider>
|
|
)
|
|
}
|
|
|
|
export default App
|