fix(web): keep menu labels on one line and fold the admin section by default
ci / ts / ts (packages + web) (push) Successful in 1m27s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mrleo1nidandCursor committed 2026-10-21 09:06:33 +03:00
1 parent dfc72b1d69
commit 2b76060ea3
4 files changed
+34 -9

No files matched your search

+26 -7
View File
@@ -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} />