Documents the in-progress CSS->MUI migration (spec/plans, page-migration pattern, kit, gates, dialog gotchas) and the convention to keep the agent-memory progress tracker (project_mui_migration.md) updated as phases merge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
After clicking the confirm button, it shows 'Zpracovávám…' (disabled) while the action is in flight — matching how the form modal shows 'Ukládám…'. The earlier freeze keeps it through the close fade (no flash back to the confirm label).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per request: the delete ConfirmDialog no longer shows the in-flight 'Pracuji…'/disabled state — button stays 'Smazat' and the dialog closes on success, consistent with the Vozidla delete. The kit ConfirmDialog still supports loading for callers that want it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On save/delete success the parent flips loading false a beat before the dialog finishes its fade-out, so the button flashed back to 'Uložit změny'/'Smazat'. Both dialogs now freeze the loading flag (and the label props) while open, so the closing dialog keeps showing 'Ukládám…'/'Pracuji…'. Same derive-state-from-props pattern as the title freeze.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scroll: MUI only locks <body>, but base.css 'html{overflow-x:hidden}' makes <html> the vertical scroller (overflow-x:hidden forces overflow-y:auto), so the page scrolled behind modals. Added a ref-counted useDialogScrollLock that locks <html> (with scrollbar-width padding) + disableScrollLock on the kit dialogs. Labels: Modal now freezes title/subtitle/submitText while closing (derive-state-from-props), so editing then saving no longer briefly flashes the 'create' title/button during the fade-out.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Select value/option restricted to string (MUI sets the literal child value; string|number + onChange:string was a type lie). DataTable sortDirection uses ?? 'asc' so aria-sort is never undefined on the active column. StatusChip sx-merge drops undefined; Pagination clamps page into range; DataTable dev-warns on sortKey without onSort; Alert onClose JSDoc.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DateField (committed in 58a3bca) renders MUI X DatePicker, which requires a LocalizationProvider ancestor — without it, it throws at render time (tsc/build don't catch it). Added to MuiProvider.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the useRef-during-render snapshot with React's blessed 'adjust state when a prop changes' pattern (useState + guarded setState during render). Render-pure, same self-contained behavior. Avoids writing to a ref during render.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The message was bound to the caller's selected row, which gets nulled on close at the same instant the Dialog begins its fade-out — so it faded out with empty text. Now the dialog caches the last shown title/message and renders that through the exit transition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires the MUI AppShell into the admin route and deletes the legacy chrome (AdminLayout, Sidebar, layout.css). Spinner CSS (.admin-spinner/.admin-loading) lives in base.css and is unaffected. tsc -b clean, build OK, 148 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add src/admin/ui/SidebarNav.tsx: drawer content component using MUI
List/ListItemButton with NavLink polymorphism. Active item uses the
`selected` prop for the white "pill" styling (not NavLink active class).
Renders logo header, permission-filtered nav sections, and user/logout
footer. Not yet wired — next task mounts it in a Drawer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move MenuItem/MenuSection interfaces and the full menuSections array (6 sections,
~30 items with inline SVG icons) verbatim from Sidebar.tsx into src/admin/ui/navData.tsx.
Add exported isItemActive/hasItemPermission pure helpers (folding in the matchAlso
branch that was previously inline in Sidebar's NavLink className callback).
Sidebar updated to import and use these; rendering and active-state behavior unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Define a minimal local interface for colorSchemes light/dark palettes and
assert the imported theme once via `as unknown as ThemeWithColorSchemes`,
replacing the 6 raw accesses that TypeScript rejected under tsc -b.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds src/admin/pages/UiKit.tsx and registers a DEV-only <Route path="ui-kit">
sibling to <Route path="login">, outside the AdminLayout shell. The lazy import
uses the ternary `import.meta.env.DEV ? lazy(...) : null` pattern so Vite/Rolldown
evaluates the condition at build time and the UiKit chunk is entirely absent from
production bundles (confirmed: no UiKit-*.js in dist-client/assets after build:client).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wraps AdminApp in MuiProvider (ThemeProvider v7, defaultMode=dark) and
adds MuiColorSchemeSync to mirror ThemeContext's data-theme attribute
into MUI's JS color-scheme state so useColorScheme().mode stays in sync.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds MuiButton, MuiCard, and MuiChip styleOverrides to the theme: pill-shaped
buttons (borderRadius 999) with a red-gradient containedPrimary, 16px soft-
shadow cards, and pill chips. Driven by a new failing test first (TDD).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Install @mui/material@^7, @emotion/react@^11, @emotion/styled@^11,
@mui/x-date-pickers@^8 as production dependencies. Downgrade
@types/react and @types/react-dom from ^19 to ^18.3 to match the
React 18.3.1 runtime. tsc --noEmit and vite build:client both pass
cleanly with no new errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Approved design for migrating the admin frontend off ~7,100 lines of hand-written CSS onto MUI, themed to the existing brand, dark/light preserved, modern 'soft-SaaS shell + dense tables' look, rolled out incrementally (foundation-first, always shippable). Verified via 4-way adversarial review (editorial, MUI-docs accuracy, codebase-fit, completeness) with fixes applied. Also gitignores .superpowers/ brainstorm mockups.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Combines the undeployed v1.9.7 (compact 2-up filter bars) with the date-field
unification (all date fields via AdminDatePicker + mode-aware placeholder).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- The project create-modal start/end dates used raw <input type="date">;
converted to <AdminDatePicker> so every date field in the app now goes
through the shared component (react-datepicker on desktop, native on touch).
- AdminDatePicker now defaults its placeholder by mode (date 'dd.mm.rrrr',
month 'mm.rrrr', time 'hh:mm') so empty date fields always show a format
hint; explicit placeholders (e.g. 'Od'/'Do' range filters) still override.
- Dropped WarehouseReceiptForm's ad-hoc 'dd.mm.yyyy' so it inherits the
unified Czech default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.admin-search-bar on phones (<=768px) was flex-direction:column with each
control forced full-width (min-width:100% at <=480), so multi-filter bars
(warehouse receipts/issues, sales lists) became a tall stack of huge controls.
Now: the search box spans the row; filter selects/date pickers sit two-per-row;
the reset button spans the row. 44px/16px touch sizing unchanged; applies
consistently to every page using .admin-search-bar.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>