Files
app/src/admin/components/TitleSync.tsx
BOHA 4d0ec53514 feat(shell): scrollable status tabs, per-page tab titles, skip-to-content, Czech MUI locale
- Shared Tabs: variant=scrollable + auto scroll buttons — the 5 status-filter
  tabs no longer clip unreachable at ~360px (desktop rendering unchanged).
- TitleSync: browser tab shows the active page ('Faktury · BOHA'; ambiguous
  labels qualified with their section, e.g. 'Záznam – Docházka · BOHA');
  index.html fallback now 'BOHA Admin'.
- Skip-to-content link (visually hidden, visible on focus) + id/tabIndex on
  <main> — keyboard users skip the 248px sidebar.
- MUI csCZ locale merged into the theme (kills built-in English strings like
  'No options'); Czech noOptionsText on Customer/Supplier pickers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 03:22:06 +02:00

43 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { menuSections, isItemActive } from "../ui/navData";
/**
* Null-rendering helper that keeps the browser tab title in sync with the
* active navigation item. Scans menuSections in order (first match wins) via
* the same isItemActive logic the sidebar uses, so detail routes covered by
* matchPrefix (e.g. /offers/123) inherit their section item's label.
* No cleanup on unmount — the last title simply persists.
*/
// Labels reused across sections ("Záznam", "Moje historie", "Správa",
// "Přehled") would produce identical tab titles — qualify those with their
// section label so /attendance and /trips tabs stay distinguishable.
const labelCounts = new Map<string, number>();
for (const section of menuSections) {
for (const item of section.items) {
labelCounts.set(item.label, (labelCounts.get(item.label) ?? 0) + 1);
}
}
export default function TitleSync() {
const { pathname } = useLocation();
useEffect(() => {
for (const section of menuSections) {
const item = section.items.find((candidate) =>
isItemActive(candidate, pathname),
);
if (item) {
const ambiguous = (labelCounts.get(item.label) ?? 0) > 1;
document.title = ambiguous
? `${item.label} ${section.label} · BOHA`
: `${item.label} · BOHA`;
return;
}
}
document.title = "BOHA Admin";
}, [pathname]);
return null;
}