fix(web): keep menu labels on one line and fold the admin section by default
ci / ts / ts (packages + web) (push) Successful in 1m27s
ci / ts / ts (packages + web) (push) Successful in 1m27s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
dfc72b1d69
commit
2b76060ea3
4 files changed
+34
-9
No files matched your search
@@ -79,25 +79,44 @@ function NavLink({
|
||||
}
|
||||
|
||||
const FOLDED_KEY = 'pipu.nav.folded';
|
||||
const TOUCHED_KEY = 'pipu.nav.touched';
|
||||
|
||||
function readFolded(): string[] {
|
||||
function readIds(key: string): string[] {
|
||||
try {
|
||||
const v: unknown = JSON.parse(localStorage.getItem(FOLDED_KEY) ?? '[]');
|
||||
const v: unknown = JSON.parse(localStorage.getItem(key) ?? '[]');
|
||||
return Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** Раздел меню: заголовок сворачивает пункты; состояние помнит браузер. Свёрнутый раздел показывает сумму бейджей. */
|
||||
function NavSection({ id, title, badge, children }: { id: string; title: string; badge?: number; children: ReactNode }) {
|
||||
const [folded, setFolded] = useState(() => readFolded().includes(id));
|
||||
/** Раздел меню: заголовок сворачивает пункты; явный выбор помнит браузер. Свёрнутый раздел показывает сумму бейджей. */
|
||||
function NavSection({
|
||||
id,
|
||||
title,
|
||||
badge,
|
||||
children,
|
||||
defaultFolded = false,
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
badge?: number;
|
||||
children: ReactNode;
|
||||
defaultFolded?: boolean;
|
||||
}) {
|
||||
const [folded, setFolded] = useState(() => {
|
||||
if (readIds(FOLDED_KEY).includes(id)) return true;
|
||||
if (readIds(TOUCHED_KEY).includes(id)) return false;
|
||||
return defaultFolded;
|
||||
});
|
||||
const toggle = () => {
|
||||
const next = !folded;
|
||||
setFolded(next);
|
||||
try {
|
||||
const rest = readFolded().filter((x) => x !== id);
|
||||
const rest = readIds(FOLDED_KEY).filter((x) => x !== id);
|
||||
localStorage.setItem(FOLDED_KEY, JSON.stringify(next ? [...rest, id] : rest));
|
||||
const touched = readIds(TOUCHED_KEY);
|
||||
if (!touched.includes(id)) localStorage.setItem(TOUCHED_KEY, JSON.stringify([...touched, id]));
|
||||
} catch {
|
||||
// Без хранилища раздел просто не запомнит состояние.
|
||||
}
|
||||
@@ -188,7 +207,7 @@ function Shell() {
|
||||
/>
|
||||
</NavSection>
|
||||
{staff && (
|
||||
<NavSection id="admin" title={t('nav.admin')} badge={pending}>
|
||||
<NavSection id="admin" title={t('nav.admin')} badge={pending} defaultFolded>
|
||||
<NavLink to="/admin/users" label={t('nav.users')} icon={groupIcon} activeIcon={groupFillIcon} />
|
||||
{user.role === 'admin' && (
|
||||
<NavLink to="/admin/sources" label={t('nav.sources')} icon={storageIcon} activeIcon={storageFillIcon} />
|
||||
|
||||
Reference in new issue
Block a user