From e7c07fda4e43d8399c2096986db754e4eaf5f150 Mon Sep 17 00:00:00 2001 From: shuaiplus <2327005759@qq.com> Date: Wed, 6 May 2026 00:47:18 +0800 Subject: [PATCH] feat: enhance navigation with collapsible groups and improve styles --- NodeWarden-compat | 1 + .../src/components/AppAuthenticatedShell.tsx | 143 +++++++++++++----- webapp/src/lib/i18n/locales/en.ts | 3 + webapp/src/lib/i18n/locales/es.ts | 3 + webapp/src/lib/i18n/locales/ru.ts | 3 + webapp/src/lib/i18n/locales/zh-CN.ts | 3 + webapp/src/lib/i18n/locales/zh-TW.ts | 3 + webapp/src/styles/shell.css | 69 +++++++++ 8 files changed, 193 insertions(+), 35 deletions(-) create mode 160000 NodeWarden-compat diff --git a/NodeWarden-compat b/NodeWarden-compat new file mode 160000 index 0000000..408a89b --- /dev/null +++ b/NodeWarden-compat @@ -0,0 +1 @@ +Subproject commit 408a89b07d43d82be0841bee19baa11582ffdeb4 diff --git a/webapp/src/components/AppAuthenticatedShell.tsx b/webapp/src/components/AppAuthenticatedShell.tsx index 7afd533..58eea71 100644 --- a/webapp/src/components/AppAuthenticatedShell.tsx +++ b/webapp/src/components/AppAuthenticatedShell.tsx @@ -1,4 +1,6 @@ -import { ArrowUpDown, Cloud, Clock3, Folder as FolderIcon, Globe2, KeyRound, Lock, LogOut, Send as SendIcon, Settings as SettingsIcon, Shield, ShieldUser } from 'lucide-preact'; +import { ChevronDown, Clock3, Cloud, Folder as FolderIcon, KeyRound, Lock, LogOut, Send as SendIcon, Settings as SettingsIcon, ShieldUser } from 'lucide-preact'; +import type { ComponentChildren } from 'preact'; +import { useState } from 'preact/hooks'; import { Link } from 'wouter'; import AppMainRoutes from '@/components/AppMainRoutes'; import ThemeSwitch from '@/components/ThemeSwitch'; @@ -32,6 +34,53 @@ function isAdminProfile(profile: Profile | null): boolean { export default function AppAuthenticatedShell(props: AppAuthenticatedShellProps) { const routeAnimationKey = props.isImportRoute ? props.importRoute : props.location; const isAdmin = isAdminProfile(props.profile); + const vaultActive = props.location === '/vault' || props.location === '/vault/totp'; + const settingsActive = props.location === props.settingsAccountRoute || props.location === '/settings/domain-rules'; + const dataActive = props.location === '/backup' || props.isImportRoute; + const managementActive = props.location === '/admin' || props.location === '/security/devices'; + const [expandedGroups, setExpandedGroups] = useState({ + vault: true, + settings: false, + data: false, + management: false, + }); + + function toggleGroup(group: keyof typeof expandedGroups): void { + setExpandedGroups((current) => ({ ...current, [group]: !current[group] })); + } + + function groupOpen(group: keyof typeof expandedGroups, active: boolean): boolean { + return expandedGroups[group] || active; + } + + function renderNavGroup( + group: keyof typeof expandedGroups, + title: string, + icon: ComponentChildren, + active: boolean, + children: ComponentChildren + ) { + const open = groupOpen(group, active); + return ( +