0.3.16
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { matchPath, NavLink, Outlet, useLocation } from 'react-router-dom';
|
||||
import { NavLink, Outlet, useLocation } from 'react-router-dom';
|
||||
import { Icon } from './Icon';
|
||||
import { OmniSearch } from './OmniSearch';
|
||||
import { NotificationBell } from './NotificationBell';
|
||||
@@ -16,13 +16,12 @@ import { Confirm } from './ui';
|
||||
|
||||
function Rail({ open, onNavigate }: { open: boolean; onNavigate: () => void }) {
|
||||
const { unread } = useNotifications();
|
||||
const location = useLocation();
|
||||
|
||||
// A group holding the current page is open regardless of what was collapsed last time:
|
||||
// a rail that hides the page you are on is a rail that has lost its place.
|
||||
// Every category is visible. Children can be folded independently and the choice is
|
||||
// remembered between visits.
|
||||
const [collapsed, setCollapsed] = useState<Record<string, boolean>>(() => {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem('memby-admin-nav') ?? '{}') as Record<string, boolean>;
|
||||
return JSON.parse(localStorage.getItem('memby-admin-nav-v2') ?? '{}') as Record<string, boolean>;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
@@ -30,37 +29,18 @@ function Rail({ open, onNavigate }: { open: boolean; onNavigate: () => void }) {
|
||||
|
||||
const storeCollapsed = (next: Record<string, boolean>) => {
|
||||
try {
|
||||
localStorage.setItem('memby-admin-nav', JSON.stringify(next));
|
||||
localStorage.setItem('memby-admin-nav-v2', JSON.stringify(next));
|
||||
} catch {
|
||||
// Private-mode storage refusals cost the memory of which group is open, and
|
||||
// nothing else.
|
||||
}
|
||||
};
|
||||
|
||||
// The labelled groups are an accordion. Following a destination opens its group and
|
||||
// folds the one the operator has just left, including navigation from search or Back.
|
||||
useEffect(() => {
|
||||
const activeGroup = nav.find((group) =>
|
||||
group.items.some((item) => matchPath({ path: item.path, end: true }, location.pathname)),
|
||||
);
|
||||
if (!activeGroup) return;
|
||||
setCollapsed((current) => {
|
||||
const next = { ...current };
|
||||
nav.forEach((group) => {
|
||||
if (group.collapsible !== false) next[group.id] = group.id !== activeGroup.id;
|
||||
});
|
||||
storeCollapsed(next);
|
||||
return next;
|
||||
});
|
||||
}, [location.pathname]);
|
||||
|
||||
const toggle = (id: string, defaultCollapsed = false) => {
|
||||
setCollapsed((current) => {
|
||||
const next = { ...current };
|
||||
const collapseSelected = !(current[id] ?? defaultCollapsed);
|
||||
nav.forEach((group) => {
|
||||
if (group.collapsible !== false) next[group.id] = group.id === id ? collapseSelected : true;
|
||||
});
|
||||
next[id] = collapseSelected;
|
||||
storeCollapsed(next);
|
||||
return next;
|
||||
});
|
||||
@@ -71,11 +51,8 @@ function Rail({ open, onNavigate }: { open: boolean; onNavigate: () => void }) {
|
||||
{nav.map((group) => {
|
||||
const items = group.items.filter((item) => !item.hidden);
|
||||
if (items.length === 0) return null;
|
||||
const holdsCurrent = items.some((item) =>
|
||||
matchPath({ path: item.path, end: true }, location.pathname),
|
||||
);
|
||||
const collapsible = group.collapsible !== false;
|
||||
const expanded = holdsCurrent || !collapsible || !(collapsed[group.id] ?? group.defaultCollapsed ?? false);
|
||||
const expanded = !collapsible || !(collapsed[group.id] ?? group.defaultCollapsed ?? false);
|
||||
return (
|
||||
<div className="rail-group" key={group.id}>
|
||||
{group.label && collapsible ? (
|
||||
|
||||
Reference in New Issue
Block a user