73 lines
2.0 KiB
TypeScript
73 lines
2.0 KiB
TypeScript
import { h, type FunctionComponent } from 'preact'
|
|
import { useEffect, useReducer, useRef } from 'preact/hooks'
|
|
import cn from 'classnames'
|
|
|
|
import NavigationItem from './navigation_item.tsx'
|
|
import s from './navigation.module.scss'
|
|
|
|
import type { Route } from '../../../shared/types.ts'
|
|
|
|
type NavigationGroupProps = {
|
|
base: string
|
|
currentPath: string
|
|
path: string
|
|
routes: Route[]
|
|
title: string
|
|
}
|
|
|
|
const NavigationGroup: FunctionComponent<NavigationGroupProps> = ({ base, currentPath, path, routes, title }) => {
|
|
const itemsRef = useRef<HTMLUListElement | null>(null)
|
|
const [visible, toggle] = useReducer((visible, force) => (typeof force === 'boolean' ? force : !visible), false)
|
|
const current = currentPath === path || (path !== '/' && currentPath.startsWith(path))
|
|
|
|
useEffect(() => {
|
|
itemsRef.current!.style.height = itemsRef.current!.scrollHeight + 'px'
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
toggle(false)
|
|
}, [currentPath])
|
|
|
|
return (
|
|
<li
|
|
className={cn(s.groupBase, {
|
|
[s.visible]: current || visible,
|
|
[s.current]: current,
|
|
})}
|
|
>
|
|
<div className={s.groupTop} onClick={toggle}>
|
|
<span className={s.groupTitle}>{title}</span>
|
|
<div className={s.groupIcon} />
|
|
</div>
|
|
|
|
<ul ref={itemsRef} className={s.items}>
|
|
{routes
|
|
.filter(({ nav }) => nav !== false)
|
|
.map(({ path, title, routes }) =>
|
|
routes ? (
|
|
<NavigationGroup
|
|
key={path}
|
|
base={base}
|
|
currentPath={currentPath}
|
|
path={path}
|
|
title={title}
|
|
routes={routes}
|
|
/>
|
|
) : (
|
|
<NavigationItem
|
|
key={path}
|
|
base={base}
|
|
currentPath={currentPath}
|
|
path={path}
|
|
title={title}
|
|
name={title.toLowerCase()}
|
|
/>
|
|
),
|
|
)}
|
|
</ul>
|
|
</li>
|
|
)
|
|
}
|
|
|
|
export default NavigationGroup
|