From 1e0821915f9980c9170576b8a337737d99a0cd0c Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Fri, 15 May 2026 22:25:43 +0200 Subject: [PATCH] docs(09): UI design contract --- .planning/phases/09-etapes/09-UI-SPEC.md | 287 +++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 .planning/phases/09-etapes/09-UI-SPEC.md diff --git a/.planning/phases/09-etapes/09-UI-SPEC.md b/.planning/phases/09-etapes/09-UI-SPEC.md new file mode 100644 index 0000000..44ab1fb --- /dev/null +++ b/.planning/phases/09-etapes/09-UI-SPEC.md @@ -0,0 +1,287 @@ +--- +phase: 09 +slug: etapes +status: approved +shadcn_initialized: false +preset: none +created: 2026-05-15 +--- + +# Phase 09 - UI Design Contract + +> Visual and interaction contract for Phase 9. This phase adds etape controls to the existing Go/HTMX Tasks tab without redesigning the kanban. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | none | +| Preset | not applicable | +| Component library | local `backend/internal/web/ui` helpers plus Tailwind utility classes | +| Icon library | none currently used in this backend UI; do not introduce an icon package for this phase | +| Font | inherited app/system sans-serif | + +--- + +## Product Intent + +Phase 9 should feel like an extension of the current working kanban, not a new task product. The user asked for a first functional UI now and a beautiful UI later. Keep the surface quiet, compact, and explicit. + +Locked decisions from `09-CONTEXT.md`: + +- Etapes live in a compact top strip above the existing kanban. +- Etapes render as chips with task counts. +- Include an `Unassigned` chip. +- Selecting an etape filters the existing kanban. +- Status columns and task drag/drop behavior remain the primary task interaction. +- Task assignment happens in task create/edit forms. + +--- + +## Layout Contract + +### Tasks Tab Structure + +`TasksTabFragment` must render in this order: + +1. Etape strip zone. +2. Existing kanban board. + +Use a whole-fragment swap for etape filtering so active chip state, chip counts, add-task forms, and kanban contents stay in sync. + +Required outer ids/classes: + +- `#tab-content` remains the tab switch target. +- `#tasks-tab` should wrap the full Tasks tab fragment after Phase 9. +- `#etape-strip` should wrap the chip strip and etape management controls. +- `#kanban-board` remains the kanban board id. +- Existing `.sortable-column`, `.task-card-zone`, and `.task-card` semantics must remain stable. + +### Etape Strip + +The etape strip sits directly above `#kanban-board`. + +Visual contract: + +- Horizontal flex row with wrapping: `flex flex-wrap items-center gap-2`. +- Bottom spacing before kanban: `mb-4`. +- No surrounding card, no nested card, no panel border around the whole strip. +- Chips are compact inline buttons or links, not large cards. +- Chips should not resize the kanban columns. +- Long etape titles must truncate inside the chip with `max-w-*`, `truncate`, and visible count. + +Minimum chip set: + +- `All` chip: shows all tasks. +- `Unassigned` chip: filters tasks with no etape. +- One chip per etape. + +The `All` chip is allowed even though the user only explicitly requested `Unassigned`; it is the necessary return path from a filtered view. + +### Kanban Board + +Keep the existing four horizontal columns and fixed column width. + +Do not: + +- split columns into etape groups, +- turn etapes into lanes, +- move status labels under etapes, +- change `TaskColumns`, +- place the kanban inside a decorative card. + +When a filter has no tasks in a status, keep the existing empty copy style: `No tasks yet`. + +--- + +## Interaction Contract + +### Filtering + +Chip behavior: + +- `All` chip requests `/tablos/{id}/tasks` with no etape filter. +- `Unassigned` chip requests `/tablos/{id}/tasks?etape=unassigned`. +- Etape chips request `/tablos/{id}/tasks?etape={etape_id}`. +- HTMX target should be `#tab-content` or `#tasks-tab`, not only `#kanban-board`, because active chip state and counts must update with the board. +- `hx-push-url` should keep the current filter URL shareable and refresh-safe when practical. + +Active chip state: + +- Active chip uses a stronger border/text/background than inactive chips. +- Active chip must be visible without relying on color alone: use both border weight/color and text weight. + +### Etape Create/Edit/Delete + +Management controls should remain close to the strip. + +Recommended first shape: + +- A compact `New etape` button at the end of the strip. +- Inline create form swaps into a small strip-adjacent zone, not into the kanban columns. +- Edit/delete controls may be exposed from the active etape chip or an inline edit state; the plan may choose the simplest HTMX pattern that stays compact. +- Delete confirmation copy must make clear that tasks are kept and unassigned. + +Etape reorder: + +- Reordering can be implemented with explicit up/down controls or Sortable.js over the chip strip. +- If using Sortable.js, do not interfere with `.sortable-column` task drag/drop. +- Reorder controls must preserve chip dimensions and avoid layout shift. + +### Task Assignment + +Task create/edit forms must include an etape selector. + +Selector contract: + +- Label: `Etape`. +- Options include `No etape`. +- Existing etapes are listed by title. +- If the current board filter is a specific etape, new task forms may preselect that etape. +- If the current filter is `Unassigned`, forms should default to `No etape`. +- If the current filter is `All`, forms should default to `No etape` unless editing an assigned task. + +Selector styling should match existing inputs: + +- text size `text-sm`, +- border `border-slate-300`, +- rounded border, +- `px-2 py-1` inside compact task cards or `px-3 py-2` in larger forms. + +### Deletion + +Etape delete confirmation copy: + +- Heading: `Delete etape?` +- Body: `Tasks in this etape will stay in the tablo and move to Unassigned.` +- Primary destructive action: `Delete etape` +- Secondary action: `Keep etape` + +Deleting an etape must not visually remove task cards permanently from the tablo. After deletion, affected tasks should appear under `Unassigned` or `All` depending on the active filter. + +--- + +## Spacing Scale + +Declared values are multiples of 4 and align with existing Tailwind usage. + +| Token | Value | Usage | +|-------|-------|-------| +| xs | 4px | Icon-free inline gaps, chip inner count spacing | +| sm | 8px | Chip gaps, compact form field gaps | +| md | 16px | Strip-to-board spacing, card padding, column gaps | +| lg | 24px | Existing tab content rhythm | +| xl | 32px | Not required for this compact feature | +| 2xl | 48px | Not required | +| 3xl | 64px | Not required | + +Exceptions: none. + +--- + +## Typography + +Use current app typography; do not introduce viewport-scaled text. + +| Role | Size | Weight | Line Height | +|------|------|--------|-------------| +| Body | 14px (`text-sm`) | 400 | default Tailwind normal | +| Label | 14px (`text-sm`) | 500 | default Tailwind normal | +| Compact meta/count | 12px (`text-xs`) | 500 | default Tailwind normal | +| Section heading | 16px (`text-base`) | 600 | default Tailwind normal | +| Page heading | unchanged existing page heading | unchanged | unchanged | + +Chip titles should use `text-sm`. Counts should use `text-xs` or local badge styling. + +--- + +## Color + +Use the existing slate-forward palette. Do not add a new brand accent for etapes. + +| Role | Value | Usage | +|------|-------|-------| +| Dominant (60%) | `#ffffff` / `bg-white` | Task cards, form surfaces | +| Secondary (30%) | `#f1f5f9` / `bg-slate-100`; `#e2e8f0` / `border-slate-200` | Column headers, chip backgrounds, borders | +| Accent (10%) | `#1e293b` / `text-slate-800`, `border-slate-800` | Active chip, active tab-like state | +| Destructive | existing danger button styles | Etape delete confirmation only | + +Accent reserved for: + +- active etape chip, +- selected tab/filter state, +- primary create/save actions through existing `ui.Button` default styling. + +Do not use gradients, decorative colored strips, or a one-off etape color palette. + +--- + +## Copywriting Contract + +| Element | Copy | +|---------|------| +| Primary CTA | `New etape` | +| Etape title label | `Title` | +| Etape description label | `Description (optional)` | +| Empty etape strip body | `No etapes yet` | +| Empty etape strip action | `New etape` | +| Filter chip for all tasks | `All` | +| Filter chip for tasks without etape | `Unassigned` | +| Task assignment label | `Etape` | +| Task assignment empty option | `No etape` | +| Etape title validation | `Title is required` | +| Etape delete heading | `Delete etape?` | +| Etape delete body | `Tasks in this etape will stay in the tablo and move to Unassigned.` | +| Etape delete action | `Delete etape` | +| Etape delete cancel | `Keep etape` | +| Generic server error | `Something went wrong. Please try again.` | + +Avoid explanatory UI text about keyboard shortcuts, implementation, or how filtering works. The chip labels and active state should carry the interaction. + +--- + +## Accessibility Contract + +- Chips must be real links or buttons. +- Active chip must include `aria-current="true"` when rendered as a link. +- Delete/edit controls must have task- or etape-specific `aria-label` values when the visible label is short. +- Form labels must be associated with inputs via `for`/`id` or an equivalent explicit label pattern. +- Count badges must remain readable as text, not only visual badges. +- Focus styles must remain visible through existing browser/Tailwind focus treatment. + +--- + +## HTMX Swap Contract + +Preferred fragment boundaries: + +- Filtering: swap `#tasks-tab` or `#tab-content`. +- Etape create/edit/delete: swap a dedicated etape strip/form zone and include out-of-band updates if counts or board contents change. +- Task create/update: preserve current `.task-card-zone` and add-task slot behavior. +- Reorder: preserve `#kanban-board` as the task reorder response target. + +Any response that changes etape assignment or etape deletion should update chip counts. Whole Tasks-tab swap is acceptable for the first version. + +--- + +## Registry Safety + +| Registry | Blocks Used | Safety Gate | +|----------|-------------|-------------| +| shadcn official | none | not required | +| third-party registry | none | do not use | + +--- + +## Checker Sign-Off + +- [x] Dimension 1 Copywriting: PASS +- [x] Dimension 2 Visuals: PASS +- [x] Dimension 3 Color: PASS +- [x] Dimension 4 Typography: PASS +- [x] Dimension 5 Spacing: PASS +- [x] Dimension 6 Registry Safety: PASS + +**Approval:** approved 2026-05-15