aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/components/layout-basic.tsx
diff options
context:
space:
mode:
authorshu <nvcsadjkojf@outlook.com>2026-09-07 15:48:36 +0800
committershu <nvcsadjkojf@outlook.com>2026-09-07 15:48:36 +0800
commit481402e09fe760634b826b09e302e2e1bfec88b1 (patch)
tree9b55025bfcd6acd2c5d795f057de27028b422603 /src/components/layout-basic.tsx
feat: initialize React Spectrum template with layouts and showcases
Diffstat (limited to 'src/components/layout-basic.tsx')
-rw-r--r--src/components/layout-basic.tsx67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/components/layout-basic.tsx b/src/components/layout-basic.tsx
new file mode 100644
index 0000000..05f3eef
--- /dev/null
+++ b/src/components/layout-basic.tsx
@@ -0,0 +1,67 @@
+import { useState, type ReactNode } from 'react'
+import { useMatches } from 'react-router'
+import type { PageMetadata } from '../route-config'
+import CollapsedNavigation from './collapsed-navigation'
+import { ActionButton } from '@react-spectrum/s2/ActionButton'
+import { Tooltip, TooltipTrigger } from '@react-spectrum/s2/Tooltip'
+import SidebarMenu from './sidebar-menu'
+import MobileNavigation from './mobile-navigation'
+import GlobalSettings from './global-settings'
+import HomeIcon from '@react-spectrum/s2/icons/Home'
+import ChevronLeftIcon from '@react-spectrum/s2/icons/ChevronLeft'
+import ChevronRightIcon from '@react-spectrum/s2/icons/ChevronRight'
+import styles from './layout-basic.module.css'
+
+interface BasicLayoutProps {
+ children: ReactNode
+}
+
+function BasicLayout({ children }: BasicLayoutProps) {
+ const [isCollapsed, setIsCollapsed] = useState(false)
+ const currentPage = useMatches().at(-1)?.handle as PageMetadata | undefined
+
+ return (
+ <div className={`${styles.appLayout}${isCollapsed ? ` ${styles.isCollapsed}` : ''}`}>
+ <a className={styles.skipLink} href="#main-content">Skip to content</a>
+ <aside id="sidebar" className={styles.sidebar} aria-label="Sidebar">
+ <div className={styles.sidebarBrand} aria-label="React Spectrum">
+ {isCollapsed ? <HomeIcon /> : 'React Spectrum'}
+ </div>
+ <nav className={styles.sidebarNavigation} aria-label="Main navigation">
+ {isCollapsed && <CollapsedNavigation activePageId={currentPage?.id} />}
+ <div className={styles.expandedNavigation} hidden={isCollapsed}>
+ <SidebarMenu />
+ </div>
+ </nav>
+ </aside>
+ <div className={styles.contentLayout}>
+ <header className={styles.topbar}>
+ <MobileNavigation />
+ <div className={styles.desktopMenuToggle}>
+ <TooltipTrigger>
+ <ActionButton
+ aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
+ aria-expanded={!isCollapsed}
+ aria-controls="sidebar"
+ isQuiet
+ onPress={() => setIsCollapsed((collapsed) => !collapsed)}
+ >
+ {isCollapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}
+ </ActionButton>
+ <Tooltip>{isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}</Tooltip>
+ </TooltipTrigger>
+ </div>
+ <span>{currentPage?.title}</span>
+ <div className={styles.topbarActions}>
+ <GlobalSettings />
+ </div>
+ </header>
+ <main id="main-content" className={styles.pageContent} tabIndex={-1}>
+ {children}
+ </main>
+ </div>
+ </div>
+ )
+}
+
+export default BasicLayout