Update OKF docs bundle, README, and CLAUDE.md for today's features
Documents the shift planning and closure/payroll modules (new tables, routes, stores), the dark redesign, and the docker-compose-broken-host workaround. Adds CLAUDE.md pointing agents at docs/. Translates README to English and keeps host-specific infrastructure details out of the repo.
This commit is contained in:
@@ -1,45 +1,97 @@
|
||||
---
|
||||
type: Design Language
|
||||
title: TUI monochrome design system
|
||||
description: How the light-mono-tui design language is implemented in this app's CSS.
|
||||
resource: frontend/src/styles/tui.css
|
||||
title: Dark modern design system
|
||||
description: How EatMe's dark, sharp-edged, amber-accent design system is implemented in frontend/src/styles/theme.css.
|
||||
resource: frontend/src/styles/theme.css
|
||||
tags: [frontend, design, css]
|
||||
timestamp: 2026-08-12T00:00:00Z
|
||||
timestamp: 2026-08-16T00:00:00Z
|
||||
---
|
||||
|
||||
# TUI monochrome design system
|
||||
# Dark modern design system
|
||||
|
||||
The full design language spec lives outside this bundle at
|
||||
`~/doc/concepts/ui/light-mono-tui.md` (grey background, black type/borders,
|
||||
mono font, inverted active/hover states, no accent color, no radius, no
|
||||
shadow). This doc covers how EatMe implements it.
|
||||
Replaced the original light monochrome TUI style (mono font,
|
||||
`~/doc/concepts/ui/light-mono-tui.md`) on 2026-08-16, on explicit request
|
||||
— the TUI look read as dated to the app's actual end users. All tokens and
|
||||
component classes live in `frontend/src/styles/theme.css` (was
|
||||
`tui.css` — renamed since "TUI" stopped being an accurate description).
|
||||
|
||||
`frontend/src/styles/tui.css` defines the tokens (`--bg`, `--fg`, `--muted`,
|
||||
`--hover`, `--empty`, `--panel`, `--font`) and the component classes built on
|
||||
them: `.tabs`/`.tab`, `.btn`/`.btn-block`/`.btn-ghost`, `.panel`,
|
||||
`.field-row`, `.list`/`.row`, `.badge` (`-solid`, `-dashed`, `-double`),
|
||||
`.stat-grid`/`.stat-tile`, `.login-card`.
|
||||
# Rules this design follows
|
||||
|
||||
- **Dark background, sharp corners.** `--radius-lg`/`--radius`/`--radius-sm`
|
||||
are all `0` — deliberately, per explicit user preference against rounded
|
||||
corners even in an otherwise "modern SaaS" direction.
|
||||
- **One accent color, used sparingly.** `--accent` (warm amber, `#f2a93b`)
|
||||
marks state, not decoration: the active tab, "this shift is mine",
|
||||
today's calendar cell, focus rings. It is *not* used as a per-card or
|
||||
per-row accent border.
|
||||
- **No colored border-left/border-right accent stripes.** Explicitly
|
||||
rejected during design — a common AI-generated-UI tic. Emphasis instead
|
||||
comes from filled backgrounds (`.badge-solid`, `.tab.active`,
|
||||
`.calendar-slot.is-mine`) or a full inset ring around the whole element
|
||||
(`.month-calendar-cell.is-today`, `.month-calendar-day-btn.is-selected`),
|
||||
never a single colored edge.
|
||||
- **System sans-serif for body text**, `--font-mono` reserved for numbers/
|
||||
timestamps that benefit from tabular alignment (`.stat-value`,
|
||||
calendar time chips, the bar chart's axis labels) — a common dashboard
|
||||
convention (Linear, Vercel), not an all-monospace TUI throwback.
|
||||
- **Neutral hairline dividers**, not colored ones. `.list`/`.row`,
|
||||
`.stat-grid`, and the calendar grid all use a 1px `--border`-colored
|
||||
gap/border for internal separators.
|
||||
- **`color-scheme: dark`** is set globally so native form controls (date/
|
||||
time pickers, number spinners) render dark by default — otherwise bare
|
||||
`<input type="date">` etc. render as light-mode browser chrome floating
|
||||
in an otherwise-dark page, which is what a generic `input, select` base
|
||||
rule plus this fixes.
|
||||
|
||||
# Tokens
|
||||
|
||||
`--bg`, `--surface` (panels), `--surface-hover`, `--surface-2` (nested/
|
||||
input backgrounds), `--border`, `--border-strong`, `--fg`, `--muted`,
|
||||
`--muted-2`, `--accent`, `--accent-strong`, `--accent-fg` (text color for
|
||||
content sitting *on* the accent), `--radius-lg`/`--radius`/`--radius-sm`
|
||||
(all `0`), `--shadow-sm`/`--shadow-md`, `--font`, `--font-mono`.
|
||||
|
||||
# Component classes
|
||||
|
||||
Same class names as the previous TUI stylesheet — this was a pure CSS
|
||||
rewrite, no component file needed to change: `.tabs`/`.tab`,
|
||||
`.btn`/`.btn-block`/`.btn-ghost`, `.panel`, `.field-row`, `.list`/`.row`,
|
||||
`.badge` (`-solid`, `-dashed` — both restyled as pills, no more literal
|
||||
dashed border), `.stat-grid`/`.stat-tile`, `.login-card`,
|
||||
`.month-calendar-*`, `.calendar-slot`/`.calendar-chip`. `.badge-double`
|
||||
(from the old TUI system) was dropped — it had no remaining usages.
|
||||
|
||||
There's intentionally only one `.btn` visual style (no `.btn-primary`) —
|
||||
introducing a primary/secondary distinction would have meant touching
|
||||
every component that renders a button to classify its actions, which was
|
||||
out of scope for a CSS-only redesign pass.
|
||||
|
||||
# App-specific additions
|
||||
|
||||
Built for this app, following the same rules (square edges, monochrome,
|
||||
1px borders) rather than introducing new visual language:
|
||||
|
||||
- **`.bar-chart-*`** (`frontend/src/components/BarChart.tsx`) — the
|
||||
per-employee daily-hours chart. Y-axis labels + a repeating 1px
|
||||
`--empty`-colored gridline background at 25% steps computed from a
|
||||
"nice" rounded max (`Math.ceil` to the next whole hour); bars are solid
|
||||
`--fg`, `--muted` on hover; day-of-month labels render in a *separate*
|
||||
flex row below the fixed-height bar track (not nested inside each bar's
|
||||
percentage-height column) specifically to avoid the bars visually
|
||||
overlapping the labels.
|
||||
- **`.bar-chart-*`** (`frontend/src/components/BarChart.tsx`) — bars are
|
||||
`--accent`-filled with a rounded top edge only, y-axis and day labels in
|
||||
`--font-mono`; day-of-month labels render in a *separate* flex row below
|
||||
the fixed-height bar track (not nested inside each bar's percentage-
|
||||
height column) specifically to avoid the bars visually overlapping the
|
||||
labels.
|
||||
- **`.month-nav`** (`frontend/src/components/MonthNav.tsx`) — `[<] label [>]`
|
||||
bordered strip, styled like the design language's tab strip. Deliberately
|
||||
placed *inside* the employee-detail panel next to the chart it controls,
|
||||
not as a page-level control — an earlier version put it at the top of the
|
||||
whole admin stats page, which tested as confusing ("can't browse history
|
||||
on the chart") since it was visually disconnected from what it affected.
|
||||
segmented-control strip. Placed *inside* the panel it controls (employee
|
||||
detail chart, shift calendar, closure card), not as a page-level control
|
||||
— an earlier version put it at the top of the whole admin stats page,
|
||||
which tested as confusing since it was visually disconnected from what
|
||||
it affected.
|
||||
- **`.month-calendar-*`** (`frontend/src/components/MonthCalendar.tsx`) —
|
||||
shared 7-column Monday-first grid used by both
|
||||
[`ShiftPlanning`](/docs/frontend/index.md) (employee) and
|
||||
[`ShiftPlanManager`](/docs/frontend/index.md) (admin), via a
|
||||
`renderDay(dateStr, dayNumber)` render-prop rather than two separate
|
||||
calendar implementations. The employee view renders interactive slot
|
||||
buttons directly in each cell; the admin view renders compact read-only
|
||||
chips and a day-select button, since full slot editing (capacity, notes,
|
||||
assign dropdown) doesn't fit in a calendar cell — clicking a day opens a
|
||||
detail panel below the grid instead.
|
||||
|
||||
# Related
|
||||
|
||||
- [Zustand stores](./stores.md)
|
||||
- [System overview](/docs/architecture/overview.md)
|
||||
|
||||
@@ -2,5 +2,10 @@
|
||||
|
||||
Vite + React + TypeScript PWA, Google Identity Services for sign-in.
|
||||
|
||||
- [Zustand stores](./stores.md) - authStore, attendanceStore, adminStore — where all app logic lives
|
||||
- [TUI monochrome design system](./design-system.md) - the light-mono-tui design language and this app's chart/nav additions
|
||||
- [Zustand stores](./stores.md) - authStore, attendanceStore, adminStore, shiftPlanningStore, adminShiftStore, closureStore, adminPayrollStore — where all app logic lives
|
||||
- [Dark modern design system](./design-system.md) - theme.css tokens/components, and this app's chart/nav/calendar additions
|
||||
|
||||
Notable components beyond the design system doc's list: `MonthCalendar`
|
||||
(shared 7-column calendar grid), `ShiftPlanning` / `ShiftPlanManager`
|
||||
(employee / admin shift planning UI built on it), `ClosureCard` (employee
|
||||
month-end confirmation), `PayrollManager` (admin payroll workflow).
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
type: Frontend Module
|
||||
title: Zustand stores
|
||||
description: authStore, attendanceStore, and adminStore — where all app/fetch logic lives, keeping components thin.
|
||||
description: authStore, attendanceStore, adminStore, shiftPlanningStore, adminShiftStore, closureStore, adminPayrollStore — where all app/fetch logic lives, keeping components thin.
|
||||
resource: frontend/src/store
|
||||
tags: [frontend, zustand, state]
|
||||
timestamp: 2026-08-12T00:00:00Z
|
||||
timestamp: 2026-08-16T00:00:00Z
|
||||
---
|
||||
|
||||
# Zustand stores
|
||||
@@ -54,9 +54,31 @@ plus (if an employee is selected) `selectEmployee()` together, so the
|
||||
summary and the detail chart always show the same period. `removeEmployee`
|
||||
calls the soft-delete endpoint — see [employees](/docs/data-model/employees.md).
|
||||
|
||||
# `shiftPlanningStore.ts` / `adminShiftStore.ts`
|
||||
|
||||
Employee and admin sides of shift planning, kept as two separate stores
|
||||
(not one shared with a role flag) since the shapes barely overlap — the
|
||||
employee store tracks `available`/`mine` slot lists for a period, the
|
||||
admin store tracks the full per-period slot list plus create/update/assign
|
||||
actions. Both hold their own `period` ("YYYY-MM") and re-fetch on
|
||||
`prevPeriod`/`nextPeriod`, same pattern as `adminStore`'s `month`.
|
||||
|
||||
# `closureStore.ts` / `adminPayrollStore.ts`
|
||||
|
||||
Employee and admin sides of the month-end/payroll workflow. `closureStore`
|
||||
is small — `{ period, closure, summary }` plus `confirm()`.
|
||||
`adminPayrollStore` owns the per-period overview rows and the
|
||||
`saveAdjustments`/`lock`/`reopen`/`markPaid` actions, each just POSTing and
|
||||
then re-`load()`-ing rather than optimistically patching local state —
|
||||
deliberate, since the server recomputes `base_amount` from live attendance
|
||||
data on several of these calls and the UI should always reflect that, not
|
||||
a stale client guess.
|
||||
|
||||
# Related
|
||||
|
||||
- [attendance_events](/docs/data-model/attendance-events.md) — the state
|
||||
machine and `Session` shape these stores fetch
|
||||
- [shift_slots](/docs/data-model/shift-slots.md), [month_closures](/docs/data-model/month-closures.md), [payroll](/docs/data-model/payroll.md)
|
||||
- [Attendance API](/docs/api/attendance-routes.md)
|
||||
- [Admin API](/docs/api/admin-routes.md)
|
||||
- [Shift planning routes](/docs/api/shifts-routes.md), [Closure routes](/docs/api/closure-routes.md)
|
||||
|
||||
Reference in New Issue
Block a user