实现侧边栏分组展开折叠状态持久化记忆
This commit is contained in:
@@ -170,8 +170,29 @@ function getInitialOpenKeys(sections: SidebarSection[], selectedKey: string) {
|
|||||||
.map((section) => section.key)
|
.map((section) => section.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SIDEBAR_OPEN_KEYS_KEY = 'sidebar_open_keys'
|
||||||
|
const SIDEBAR_COLLAPSED_KEY = 'sidebar_collapsed'
|
||||||
|
|
||||||
|
function loadStoredOpenKeys(sections: SidebarSection[], selectedKey: string): string[] {
|
||||||
|
const initial = getInitialOpenKeys(sections, selectedKey)
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(SIDEBAR_OPEN_KEYS_KEY)
|
||||||
|
if (raw) {
|
||||||
|
const parsed = JSON.parse(raw)
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
return Array.from(new Set([...parsed, ...initial]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return initial
|
||||||
|
}
|
||||||
|
|
||||||
export default function MainLayout() {
|
export default function MainLayout() {
|
||||||
const [collapsed, setCollapsed] = useState(false)
|
const [collapsed, setCollapsed] = useState<boolean>(() => {
|
||||||
|
return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === 'true'
|
||||||
|
})
|
||||||
const { user, logout, isAdmin } = useAuth()
|
const { user, logout, isAdmin } = useAuth()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@@ -179,11 +200,15 @@ export default function MainLayout() {
|
|||||||
|
|
||||||
const sections = useMemo(() => (isAdmin ? adminSections : merchantSections), [isAdmin])
|
const sections = useMemo(() => (isAdmin ? adminSections : merchantSections), [isAdmin])
|
||||||
const selectedKey = getSelectedKey(location.pathname, location.search)
|
const selectedKey = getSelectedKey(location.pathname, location.search)
|
||||||
const [openKeys, setOpenKeys] = useState<string[]>(() => getInitialOpenKeys(sections, selectedKey))
|
const [openKeys, setOpenKeys] = useState<string[]>(() => loadStoredOpenKeys(sections, selectedKey))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const nextOpenKeys = getInitialOpenKeys(sections, selectedKey)
|
const nextOpenKeys = getInitialOpenKeys(sections, selectedKey)
|
||||||
setOpenKeys((current) => Array.from(new Set([...current, ...nextOpenKeys])))
|
setOpenKeys((current) => {
|
||||||
|
const merged = Array.from(new Set([...current, ...nextOpenKeys]))
|
||||||
|
localStorage.setItem(SIDEBAR_OPEN_KEYS_KEY, JSON.stringify(merged))
|
||||||
|
return merged
|
||||||
|
})
|
||||||
}, [sections, selectedKey])
|
}, [sections, selectedKey])
|
||||||
|
|
||||||
const toggleSection = (section: SidebarSection) => {
|
const toggleSection = (section: SidebarSection) => {
|
||||||
@@ -197,11 +222,18 @@ export default function MainLayout() {
|
|||||||
if (firstEnabledChild?.path) navigate(firstEnabledChild.path)
|
if (firstEnabledChild?.path) navigate(firstEnabledChild.path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setOpenKeys((current) =>
|
setOpenKeys((current) => {
|
||||||
current.includes(section.key)
|
const next = current.includes(section.key)
|
||||||
? current.filter((key) => key !== section.key)
|
? current.filter((key) => key !== section.key)
|
||||||
: [...current, section.key],
|
: [...current, section.key]
|
||||||
)
|
localStorage.setItem(SIDEBAR_OPEN_KEYS_KEY, JSON.stringify(next))
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleToggleCollapse = (next: boolean) => {
|
||||||
|
setCollapsed(next)
|
||||||
|
localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(next))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChildClick = (child: SidebarChild) => {
|
const handleChildClick = (child: SidebarChild) => {
|
||||||
@@ -300,7 +332,7 @@ export default function MainLayout() {
|
|||||||
<button
|
<button
|
||||||
className="app-header__collapse"
|
className="app-header__collapse"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setCollapsed(!collapsed)}
|
onClick={() => handleToggleCollapse(!collapsed)}
|
||||||
aria-label={collapsed ? '展开侧边栏' : '收起侧边栏'}
|
aria-label={collapsed ? '展开侧边栏' : '收起侧边栏'}
|
||||||
title={collapsed ? '展开侧边栏' : '收起侧边栏'}
|
title={collapsed ? '展开侧边栏' : '收起侧边栏'}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user