import { useEffect, useState } from 'react'
import {
AppShell,
ActionIcon,
Box,
Burger,
Drawer,
Group,
NavLink,
Stack,
Text,
Tooltip,
rem,
useMantineTheme,
} from '@mantine/core'
import { useDisclosure, useMediaQuery } from '@mantine/hooks'
import { CaretLeftIcon, CaretRightIcon } from '@phosphor-icons/react'
import { NavLink as RouterNavLink, Outlet, useLocation, useMatches } from 'react-router'
import { pageRoutes } from '../routes.ts'
import type { PageRoute } from '../routes.ts'
import classes from './BasicLayout.module.css'
const collapsedNavbarWidth = rem(64)
type NavigationProps = {
onNavigate?: () => void
collapsed?: boolean
routes?: PageRoute[]
parentPath?: string
}
function NavigationItem({
route,
parentPath,
collapsed,
onNavigate,
}: {
route: PageRoute
parentPath: string
collapsed: boolean
onNavigate?: () => void
}) {
const matches = useMatches()
const active = matches.some((match) => match.id === route.id)
const selected = matches.at(-1)?.id === route.id
const [opened, setOpened] = useState(active)
if (!route.handle) return null
const { title: label, icon: Icon } = route.handle
const to = !route.path
? parentPath
: route.path.startsWith('/')
? route.path
: `${parentPath.replace(/\/$/, '')}/${route.path}`
const hasChildren = route.children?.some((child) => child.handle)
const sharedProps = {
label,
noWrap: true,
p: 'xs',
'aria-label': label,
leftSection: ,
active,
'data-collapsed': collapsed || undefined,
classNames: {
root: classes.menuItem,
section: classes.icon,
body: classes.label,
},
}
return (
{hasChildren ? (
) : (
)}
)
}
function Navigation({
onNavigate,
collapsed = false,
routes = pageRoutes,
parentPath = '/',
}: NavigationProps) {
const { key } = useLocation()
return (
{routes.map((route) => (
))}
)
}
export function BasicLayout() {
const theme = useMantineTheme()
const desktop = useMediaQuery(`(min-width: ${theme.breakpoints.sm})`)
const [opened, { toggle, close }] = useDisclosure(false)
const [sidebarOpened, { toggle: toggleSidebar }] = useDisclosure(true)
const { key } = useLocation()
const matches = useMatches()
const title = matches
.map(({ handle }) => (
handle && typeof handle === 'object' && 'title' in handle && typeof handle.title === 'string'
? handle.title
: undefined
))
.findLast((value) => value !== undefined) ?? 'Template React'
useEffect(() => {
close()
}, [key, close])
useEffect(() => {
if (desktop) close()
}, [desktop, close])
return (
{sidebarOpened ? 'Template React' : 'TR'}
{sidebarOpened
?
: }
{title}
© {new Date().getFullYear()} Template React. 仅供示例使用。
)
}