585 Commits

Author SHA1 Message Date
BOHA
fa90bcc93b fix(plan): drop the redundant 'Zrušit' button in the category-management modal
The Správa kategorií modal footer had two buttons that both just close it (Zrušit + Zavřít). Added an opt-in hideCancel prop to the kit Modal (default false → every other modal unchanged) and set it on PlanCategoriesModal, leaving only 'Zavřít'. Verified: footer shows only Zavřít; close/Escape/backdrop intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:09:59 +02:00
BOHA
3117e80027 feat(plan): migrate the planner grid to MUI (theme-driven, off plan.css)
PlanGrid's bespoke plan.css surface is replaced by a styled(Box) wrapper that scopes all the grid + chip rules and pulls every color from the theme palette via theme.vars (auto light/dark — no more [data-theme] CSS-var blocks). Sticky header + date column, marker-tape cells, category color via the per-cell --cat-color var, weekend/today treatment, hover affordances, the '+' empty hint, and the one-shot mutation pulse are all preserved; the paper-grain/ruled-paper texture was dropped for a clean MUI surface. plan.css trimmed from ~1150 lines to just the category-manager modal rows (the grid is MUI now; the toolbar/banner/day-choice modal had already moved to MUI components). Verified on /plan-work in both light and dark.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:05:27 +02:00
BOHA
2f7ca0f5a8 fix(theme): uniform contained-button text — white in light, black in dark
success/info/warning/error palettes had no explicit contrastText, so MUI auto-picked per color: in dark mode the brighter green/amber got black text while red/blue got white (inconsistent). Set contrastText explicitly per scheme (#fff in light, #1a1a1a in dark) so all contained color buttons (and filled chips) read uniformly — white on light, dark on dark.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:54:06 +02:00
BOHA
2367e8a0ff feat(ui): mobile card layout for the remaining item tables
OrderConfirmationModal (the order→confirmation editable items dialog) and InvoiceDetail's read-only paid-invoice items table now render stacked label:value cards on phones (< sm) instead of a wide horizontally-scrolling table; desktop keeps the table. Same pattern as the Offer/Invoice editors. Gates: tsc=0, build=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:48:47 +02:00
BOHA
b168c68264 feat(invoice-detail): mobile card layout for the editable line-items grid
Same treatment as OfferDetail: on phones SortableInvoiceRow renders a stacked card (labeled Popis/Množství/Jednotka/Jedn.cena inputs + DPH select when apply_vat, Celkem footer, drag+remove header) and the wrapper renders a card stack instead of the table (DndContext/SortableContext kept). Verified at 430px on invoices/new: no inner table, no page horizontal scroll.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:40:47 +02:00
BOHA
aeec0b703c fix(ui): wrap detail-page header action buttons on mobile
OfferDetail/OrderDetail/InvoiceDetail/ProjectDetail headers each have a custom action-button row that was flexShrink:0, so (like the alert/PageHeader cases) it stayed at content width and its buttons overflowed/clipped on phones. Dropped flexShrink:0 (and added flexWrap on ProjectDetail which lacked it) so the action row conforms to the available width and the buttons wrap onto multiple lines. Verified on OfferDetail at 430px: buttons span two rows, no container overflow, no page scroll.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:36:24 +02:00
BOHA
2ff26241d7 feat(offer-detail): mobile card layout for the line-items editor
On phones (< sm) the editable items grid was a wide horizontally-scrolling table of inputs — unusable. SortableItemRow now renders each item as a stacked card (labeled Popis / Množství / Jednotka / Cena/ks inputs, V ceně checkbox + Celkem, drag handle + remove in the header), and the wrapper renders a card stack instead of TableContainer/Table on mobile (DndContext/SortableContext preserved so drag still works via TouchSensor). Desktop keeps the table. Verified: no inner table on mobile, no page horizontal scroll.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:32:08 +02:00
BOHA
f0b5fb8a21 feat(ui): DataTable renders a card layout on phones instead of a scrolling table
On screens below the sm breakpoint, a wide multi-column table forced horizontal scrolling and truncated every cell (e.g. 'NA-202…'). DataTable now renders each row as a stacked label:value card on phones: every column becomes a 'HEADER: value' line with full, wrapping content; the actions column (key 'actions') drops to a right-aligned button row at the bottom; rowDanger/rowInactive/rowSx/onRowClick are all honored (action buttons stopPropagation so they don't trigger the row click). Tablets/desktop (>= sm) keep the normal table. Applies to every list table app-wide. Verified on Offers (actions) and Warehouse items (onRowClick): no truncation, no page horizontal scroll.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:20:08 +02:00
BOHA
1e155f6ffb fix(ui): wrap action-button groups so they don't clip on mobile
Since kit buttons now keep their natural width (flexShrink:0 + nowrap), a row of them can't shrink — so button groups that were flexShrink:0 with no wrap got clipped on phones (the page has overflow-x:hidden). The draft-concept Alert actions (Offers + Invoices) and the shared PageHeader actions now use flexWrap:wrap and drop flexShrink:0, so the group conforms to the available width and its buttons wrap onto stacked lines. Verified at 430px: the Offers draft alert no longer overflows (buttons stack), page has no horizontal scroll.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:05:32 +02:00
BOHA
8cee828212 fix(attendance): stop the page + leave modal overflowing (grid minmax + minWidth:0)
Two overflow fixes on Attendance.tsx: (1) the leave-request modal's Od/Do date row used a bare gridTemplateColumns '1fr 1fr', whose minmax(auto,1fr) tracks couldn't shrink below the two DatePickers' min-content, overflowing the narrow modal (horizontal scroll, 'Do' clipped) — now minmax(0,1fr). (2) On phones the whole page overflowed: the main two-column grid used { xs: '1fr' }, and the left column's 5-col 'Dnešní dokončené směny' table forced a 477px min-content (the TableContainer's overflow-x:auto never engaged because the grid item had min-width:auto). Now the grid uses minmax(0,1fr) and both columns get minWidth:0, so the table scrolls inside its container and the page fits the viewport. Verified at 390px width via DOM measurement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 15:48:39 +02:00
BOHA
b23d15453d fix(audit-log): stop replaying the page entrance animation on every filter
AuditLog uses a raw useQuery with the filters in the queryKey and a page-level early return (if isPending && no rows → <LoadingState/>), which sits ABOVE <PageEnter>. On any filter change the new queryKey had no cached data, so isPending flipped true with empty rows, the early return unmounted the whole PageEnter subtree, and it remounted (replaying the staggered entrance) when data arrived. Add placeholderData: keepPreviousData so rows persist through the refetch (isPending stays false, subtree never unmounts), and dim the table via isFetching instead of isPending. Verified by DOM node-identity: the PageEnter root survives a filter (no remount). The paginated list pages were already immune (usePaginatedQuery bakes in keepPreviousData).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 15:34:06 +02:00
BOHA
c4e71475ce fix(ui): unify checkbox size — drop size="small" on raw checkboxes
The kit CheckboxField (used on most pages) renders MUI's default medium checkbox, but four raw <Checkbox> usages forced size="small": OfferDetail's 'V ceně' table cell and 'Účtovat DPH' form checkbox, and the Settings permission-matrix module + per-permission checkboxes. They looked undersized next to the rest of the page. Removing size="small" makes every checkbox the same standard size app-wide.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 15:26:41 +02:00
BOHA
bf5d38df14 fix(ui): stop kit buttons from shrinking below their label (flexShrink: 0)
Follow-up to the nowrap fix: MUI's default flexShrink:1 was still squeezing buttons in flex rows below their content width, so with nowrap the label overflowed its padding and touched the button edges (measured: '+ Přidat položku' was 96px wide for 98px of content). Adding flexShrink:0 keeps each button at its natural width (now 131px, full padding restored). Verified via DOM measurement + visual on the offer detail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:10:31 +02:00
BOHA
9278d48a6d fix(ui): keep Button labels on one line (whiteSpace: nowrap)
In flex rows (e.g. the add-item/add-section buttons next to a 'Ze šablony…' select on OfferDetail/OrderConfirmationModal/InvoiceDetail), flexbox shrank a button below its text width and wrapped the label onto two lines, making the button tall. The kit Button now defaults to whiteSpace: nowrap (merged with any caller sx, still overridable), so labels stay single-line app-wide.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 13:08:36 +02:00
BOHA
4062029939 fix(projects): red links in the projects table (number + order columns)
The project-number column was plain text and the Objednávka link was colored text.secondary (grey/black). Make the number a RouterLink to /projects/:id and recolor the order link to primary.main, so both match the red table-link convention used on Offers/Orders/Invoices.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:54:13 +02:00
BOHA
f017867d5f fix(ui): unify list filters across all pages (bare controls, standard sizes)
Every list-page FilterBar now follows one spec: bare controls (no Field label rows — which broke flex-end alignment), standardized widths (search 1 1 320px grows; small selects 0 0 160px; entity selects 0 0 220px; MonthField 0 0 180px; dates 0 0 150px), consistent 'Všechny/Všichni/Všechna <entity>' defaults, and a placeholder on every search. TripsAdmin's separate month-Select + year-Select collapse into one MonthField (yyyy-MM, split at the query boundary) — matching Attendance/TripsHistory. The 4 labeled attendance/trips pages move off the Field wrapper; Projects & ReceivedInvoices move their inline search into a FilterBar. Chrome-verified all ~18 filter pages in light + the existing theme.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:49:28 +02:00
BOHA
f1c533488a fix(offers): align customer filter with the search field
The customer Select was wrapped in <Field label> while the search was bare, so in the flex-end FilterBar the Field's label + mb:2 pushed the select ~16px above the search input. Drop the Field wrapper (matching the bare list-page filter pattern used on AuditLog/Warehouse/Orders) and make the default option self-describing ("Všichni zákazníci"). Both controls now sit on the same line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:34:19 +02:00
BOHA
f9bb655f6a fix(attendance): restore two-column grid on the Docházka landing page
The PageEnter sweep had replaced the left grid column's wrapper with a React Fragment, so its two cards (clock + completed shifts) leaked out as separate grid items and the layout broke (shifts table jumped to the right cell, stat box wrapped to row 2). Wrap the left column back in a <Box> so the 2-col grid has exactly two column children again.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:34:19 +02:00
BOHA
c1bfabb033 fix(ui): Select dropdown caps menu height + shows empty-value option label
The kit Select now passes displayEmpty:true (so a selected value="" option like an "All" filter renders its label instead of a blank control) and MenuProps.PaperProps maxHeight:320 (so long option lists scroll inside the popover instead of listing every record). Both apply via slotProps.select and are overridable per call site. Verified app-wide: no call site regresses (audit of all 74 usages).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:34:19 +02:00
BOHA
ff3df907f4 feat(mui): make PageEnter entrance clearly perceptible (16px rise, 0.45s, 0.06s stagger)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 10:17:41 +02:00
BOHA
39fe84ce99 feat(mui): consistent staggered page entrance across all 43 route pages
Adopt the PageEnter wrapper as every page's outermost render element and remove the ad-hoc per-page entrance motion.div wrappers. Every page now enters the same way — all top-level sections rise+fade in, staggered — so nothing appears instantly and the motion is identical app-wide. Presentation-only: no data/logic/hooks/invalidate/permissions touched. Embedded sub-tabs (CompanySettings, ReceivedInvoices), Login (auth shell) and the dev UiKit are intentionally excluded. Gates: tsc -b --noEmit=0, build=0, vitest 152/152.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 10:13:06 +02:00
BOHA
b273614128 feat(mui): PageEnter kit primitive (consistent staggered page entrance) + adopt in WarehouseSuppliers
Each top-level child rises+fades in, staggered (0.4s, ease-out), so every page enters the same way and nothing appears instantly; honors prefers-reduced-motion. Replaces ad-hoc per-page motion.div entrance wrappers. One component → the look is tunable in one place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 09:53:41 +02:00
BOHA
1a0f57a247 fix(numbering): preview the next FREE offer number, not a stale one
previewOfferNumber returned applyPattern(previewNextSequence) directly; when the number_sequences 'offer' counter lags behind real quotations, that raw next number is already taken, so the offer editor showed an already-used number (e.g. NA-2026-0001 when 0001/0002 exist). Mirror generateOfferNumber's collision loop in the preview (without consuming the sequence). +2 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 09:22:44 +02:00
BOHA
c67dff4725 chore(mui): delete dead admin-*.css stylesheets (forms, buttons, components, tables, datepicker, filemanager, pagination, responsive, dashboard, settings, invoices, warehouse)
The page+component MUI migration has dropped all usages of these
stylesheets' classes. Verified by grep over src/**/*.{ts,tsx}: none of
their selectors are referenced as a className token anywhere.

Removed files + their imports from AdminApp.tsx:
forms.css, buttons.css, components.css, tables.css, datepicker.css,
filemanager.css, pagination.css, responsive.css, dashboard.css,
settings.css, invoices.css, warehouse.css

Kept: variables.css, base.css, plan.css (foundation), attendance.css
(live .attendance-location-map Leaflet container) and offers.css (live
.admin-rich-editor / .admin-rich-text-view + .ql-* Quill snow overrides).
The standalone <div className="admin-spinner"> in App.tsx remains styled
by base.css (buttons.css only held .admin-btn-scoped spinner modifiers).

Gates: tsc -b --noEmit (0), npm run build (ok), vitest (150 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:51:32 +02:00
BOHA
58da09cdc0 chore(mui): swap remaining admin-spinner loaders for kit LoadingState
Replace the three remaining hand-written admin-loading/admin-spinner
markup blocks with the kit <LoadingState /> component:
- AdminApp.tsx Suspense fallback
- AppShell.tsx loading branch
- PlanGrid.tsx no-data branch (plan-* classes untouched)

After this the only remaining admin-* classes in TSX are
admin-rich-editor (RichEditor/Quill) and admin-rich-text-view
(sanitized HTML in Order/Invoice detail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:50:39 +02:00
BOHA
ccdf0b68ea refactor(mui): remove dead legacy FormModal and ConfirmModal
Both components have zero importers after the phase-25 migrations
(verified: no `./FormModal` or `./ConfirmModal` imports remain; build
passes). Their MUI kit replacements are ui/Modal and ui/ConfirmDialog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:25 +02:00
BOHA
3b072ceefa refactor(mui): migrate ReservationPicker to kit Select
Replace the raw admin-form-select with the MUI kit Select (string-based
value, converted at the boundary). Same query (warehouseReservationList,
ACTIVE, perPage 100), same option labels, same onChange contract
(reservationId|null, remainingQty).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:20 +02:00
BOHA
68a8dae0dc refactor(mui): migrate ProjectFileManager to MUI kit
Replace legacy ConfirmModal with the kit ConfirmDialog (delete-confirm).
Re-skin onto Card + DataTable (file/folder rows), Box toolbar/breadcrumb,
EmptyState, LoadingState, kit Button/TextField/IconButton. The hidden
multipart file input is kept (per-file NAS upload). All queries,
mutations, invalidate keys (["projects", id, "files"]), NAS upload/
download/rename/create-folder/drag-drop logic, permissions, and Czech
text preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:16 +02:00
BOHA
e13f977c4d refactor(mui): migrate OrderConfirmationModal to kit Modal
Replace legacy FormModal with the MUI kit Modal. Map the two-step
flow (choose/edit) onto the kit footer: submitText + onSubmit switch
per step, submitDisabled gates "Vygenerovat PDF" when there are no
items. Re-skin lang/VAT toggles (kit Button variants), item editor
(kit TextField + IconButton inside a Box table). All generate/preview
logic, props, and Czech text preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:10 +02:00
BOHA
6f428b2297 feat(mui): migrate AlertContainer off admin-* CSS
Replaces framer-motion animation + custom SVG icons + admin-toast markup
with MUI Snackbar + MUI Alert (filled variant). useAlertState() consumption
(alerts array, removeAlert) is preserved verbatim — alert lifecycle
(timing, types, auto-dismiss) is owned by AlertContext and unchanged.
Alerts stack bottom-right with 72px vertical offset per slot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:37:32 +02:00
BOHA
67f98c1f66 feat(mui): migrate ErrorBoundary off admin-* CSS
Class component lifecycle (getDerivedStateFromError, componentDidCatch,
console.error, state shape) preserved verbatim. Only the fallback render
is re-skinned: Box+Typography for layout/text, kit Button for the reload
action. Czech strings unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:37:19 +02:00
BOHA
85d7ffaa14 feat(mui): migrate Forbidden off admin-* CSS
Re-skins the 403 fallback with MUI Box + kit EmptyState + kit Button
(component=Link). Czech text and routing preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:37:09 +02:00
BOHA
088fe39bab chore(mui): delete 8 dead legacy components replaced by the kit
Removed (zero importers, build-verified): FormField, Pagination, AdminDatePicker, SortIcon, warehouse Supplier/Location/Batch selects, WarehouseMovementTable. FormModal + ConfirmModal kept (still used by OrderConfirmationModal + ProjectFileManager — to be migrated before full removal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:34:58 +02:00
BOHA
9b43d4e827 feat(mui): migrate Attendance Location chrome onto MUI kit (Leaflet map kept)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:29:46 +02:00
BOHA
5630beee7c feat(mui): migrate Invoice Detail editor onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:27:07 +02:00
BOHA
90a27b893e feat(mui): migrate Offer Detail editor onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:21:31 +02:00
BOHA
2878041687 feat(mui): migrate OrderDetail onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:15:21 +02:00
BOHA
262f4c6ca5 feat(mui): migrate ProjectDetail onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:15:18 +02:00
BOHA
063ffd15ef feat(mui): migrate NotFound (404) onto MUI kit
Replace legacy admin-empty-state/admin-empty-icon/admin-btn markup and motion
wrapper with a centered MUI Box + Typography (h1 variant for 404 heading,
body1 for message) and a kit Button component={RouterLink}. All text and link
target ('/') preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:09:27 +02:00
BOHA
fa11d3e7e0 feat(mui): migrate Warehouse Inventory Form onto MUI kit
Replace legacy admin-* markup (motion.div header, admin-card, admin-table,
WarehouseMovementTable, LocationSelect, admin-form-input) with Box/Typography/
IconButton from @mui/material and Button/Card/TextField/Select/Field from the
kit. Item rows are inlined (grid) matching the receipt/issue form siblings.
All data logic (useQuery, useApiMutation, validate, handleSubmit, navigate,
hasPermission guard, Czech alerts) preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:09:21 +02:00
BOHA
d46827dfdf feat(mui): migrate WarehouseIssueForm onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:06:28 +02:00
BOHA
601db41a09 feat(mui): migrate WarehouseReceiptForm onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:04:57 +02:00
BOHA
8259c48f9e feat(mui): migrate WarehouseIssueDetail onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:01:20 +02:00
BOHA
1163407440 feat(mui): migrate WarehouseReceiptDetail onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:01:17 +02:00
BOHA
1cefcab697 feat(mui): migrate WarehouseInventoryDetail onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:56:39 +02:00
BOHA
c228d7a8ca feat(mui): migrate WarehouseItemDetail onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:56:36 +02:00
BOHA
c997a22a3c perf(mui): smooth theme cross-fade via View Transitions API (was per-element repaint jank)
The per-element color/box-shadow transition repainted the whole tree every frame (~5fps). Replaced with document.startViewTransition: the browser cross-fades one GPU-composited snapshot of the page — smooth regardless of element count. flushSync + useLayoutEffect ensure the data-theme flip is captured in the transition; instant fallback where unsupported / reduced-motion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:49:08 +02:00
BOHA
4d016cdab5 feat(mui): premium coordinated dark/light cross-fade (theme-transition class, toggle-only)
ThemeContext adds a .theme-transition class to <html> for ~300ms during a real toggle (skipped on initial mount); a scoped base.css rule applies a uniform 0.3s color/bg/border/fill/stroke/shadow transition to the whole tree only while that class is present — so the entire UI fades together on switch, while normal interactions keep their own transitions. Respects prefers-reduced-motion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:45:20 +02:00
BOHA
177d3f1902 fix(mui): stop dark/light oscillation (single data-theme owner) + animated ThemeToggle + white avatars
Removed MuiColorSchemeSync: it called MUI setMode which ALSO wrote data-theme, fighting ThemeContext (the other writer) → theme flip-flop loop. ThemeContext is now the sole owner; MUI's cssVariables CSS (scoped by [data-theme]) applies from the attribute, no JS bridge needed. New animated ThemeToggle kit button (sun/moon crossfade+rotate) replaces the static AppShell toggle. DashAttendanceToday avatars now solid-fill + white initials (matches StatCard/activity badges).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:39:14 +02:00
BOHA
ef0bb9f27e fix(mui): Dashboard icon badges (activity feed + 2FA status) — solid tile + white glyph
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:29:52 +02:00