aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/components/collapsed-navigation.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/collapsed-navigation.tsx
feat: initialize React Spectrum template with layouts and showcases
Diffstat (limited to 'src/components/collapsed-navigation.tsx')
-rw-r--r--src/components/collapsed-navigation.tsx54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/components/collapsed-navigation.tsx b/src/components/collapsed-navigation.tsx
new file mode 100644
index 0000000..1748317
--- /dev/null
+++ b/src/components/collapsed-navigation.tsx
@@ -0,0 +1,54 @@
+import { NavLink } from 'react-router'
+import { ActionButton } from '@react-spectrum/s2/ActionButton'
+import { Menu, MenuItem, MenuTrigger, SubmenuTrigger, Text } from '@react-spectrum/s2/Menu'
+import { Tooltip, TooltipTrigger } from '@react-spectrum/s2/Tooltip'
+import { menuItems, type NavigationItem } from '../route-config'
+import iconStyles from './menu-icon.module.css'
+import styles from './layout-basic.module.css'
+
+function containsPage(item: NavigationItem, pageId?: string): boolean {
+ return item.id === pageId || !!item.children?.some((child) => containsPage(child, pageId))
+}
+
+function renderMenuItem(item: NavigationItem) {
+ const Icon = item.Icon
+ const content = <>{Icon && <Icon />}<Text>{item.title}</Text></>
+
+ return item.children ? (
+ <SubmenuTrigger key={item.id}>
+ <MenuItem id={item.id} textValue={item.title}>{content}</MenuItem>
+ <Menu aria-label={item.title}>{item.children.map(renderMenuItem)}</Menu>
+ </SubmenuTrigger>
+ ) : (
+ <MenuItem key={item.id} id={item.id} href={item.path} textValue={item.title}>{content}</MenuItem>
+ )
+}
+
+function CollapsedNavigation({ activePageId }: { activePageId?: string }) {
+ return (
+ <div className={styles.iconNavigation}>
+ {menuItems.map((item) => {
+ const Icon = item.Icon
+ const icon = Icon ? <Icon UNSAFE_className={iconStyles.icon} /> : item.title.slice(0, 1)
+
+ return item.children ? (
+ <div key={item.id} className={`${styles.iconNavigationGroup}${containsPage(item, activePageId) ? ` ${styles.isActive}` : ''}`}>
+ <MenuTrigger direction="right" align="start">
+ <TooltipTrigger placement="right">
+ <ActionButton aria-label={item.title} isQuiet>{icon}</ActionButton>
+ <Tooltip>{item.title}</Tooltip>
+ </TooltipTrigger>
+ <Menu aria-label={item.title}>{item.children.map(renderMenuItem)}</Menu>
+ </MenuTrigger>
+ </div>
+ ) : (
+ <NavLink key={item.id} className={styles.iconNavigationLink} to={item.path} end aria-label={item.title} title={item.title}>
+ {icon}
+ </NavLink>
+ )
+ })}
+ </div>
+ )
+}
+
+export default CollapsedNavigation