203 lines
12 KiB
Markdown
203 lines
12 KiB
Markdown
|
|
---
|
|||
|
|
phase: 16-tablo-detail
|
|||
|
|
plan: 01
|
|||
|
|
type: execute
|
|||
|
|
wave: 1
|
|||
|
|
depends_on: []
|
|||
|
|
files_modified:
|
|||
|
|
- backend/internal/web/ui/icon_button.templ
|
|||
|
|
- backend/internal/web/ui/app.css
|
|||
|
|
autonomous: true
|
|||
|
|
requirements:
|
|||
|
|
- DETAIL-01
|
|||
|
|
- DETAIL-02
|
|||
|
|
- DETAIL-03
|
|||
|
|
- DETAIL-04
|
|||
|
|
|
|||
|
|
must_haves:
|
|||
|
|
truths:
|
|||
|
|
- "icon_button.templ UIIcon switch contains a case for 'download' that emits a download SVG arrow"
|
|||
|
|
- "icon_button.templ UIIcon switch contains a case for 'chat' that emits a speech-bubble SVG"
|
|||
|
|
- "app.css contains .tasks-section, .task-row, .task-check, .task-list, .task-body, .task-meta, .tasks-add-button CSS rules using var(--...) tokens"
|
|||
|
|
- "app.css contains .project-progress-track and .project-progress-bar CSS rules"
|
|||
|
|
- "app.css contains .tab-nav, .tab-nav-item, .tab-nav-item.is-active, .tab-nav-item:hover CSS rules"
|
|||
|
|
- "app.css contains .tablo-metadata-row and .tablo-metadata-date CSS rules"
|
|||
|
|
- "app.css contains .kanban-column and scoped .kanban-column .tasks-section-header h3 { font-size: 1rem } override"
|
|||
|
|
- "app.css contains .etape-group-header, .etape-group-color-dot, .etape-group-label CSS rules"
|
|||
|
|
- "app.css contains .task-list-empty CSS rule"
|
|||
|
|
- "templ generate && go build ./... exits 0 after changes"
|
|||
|
|
artifacts:
|
|||
|
|
- path: backend/internal/web/ui/icon_button.templ
|
|||
|
|
provides: Download and chat icon SVG cases in UIIcon switch
|
|||
|
|
contains: "case \"download\":"
|
|||
|
|
- path: backend/internal/web/ui/app.css
|
|||
|
|
provides: All new CSS sections for Phase 16 (19–25)
|
|||
|
|
contains: ".tasks-section {"
|
|||
|
|
key_links:
|
|||
|
|
- from: backend/internal/web/ui/icon_button.templ
|
|||
|
|
to: backend/internal/web/ui/icon_button_templ.go
|
|||
|
|
via: templ generate
|
|||
|
|
pattern: "case \"download\""
|
|||
|
|
- from: backend/internal/web/ui/app.css
|
|||
|
|
to: browser render
|
|||
|
|
via: static asset embed
|
|||
|
|
pattern: ".tab-nav-item.is-active"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase Goal
|
|||
|
|
|
|||
|
|
**As a** tablo owner, **I want to** see a fully restyled tablo detail page — header, kanban, etapes, and files — **so that** the detail view looks visually consistent with the design system established in Phases 13–15.
|
|||
|
|
|
|||
|
|
<objective>
|
|||
|
|
Add the two missing icon SVG cases (`download`, `chat`) to `UIIcon` in `icon_button.templ`, and append all Phase 16 CSS sections (19–25) to `app.css`. This is the shared substrate that plans 02–04 build on — without it, `@ui.IconButton` with `Icon: "download"` or `Icon: "chat"` renders the icon name as raw text.
|
|||
|
|
|
|||
|
|
Purpose: Unblock header restyling (Discussion/Download IconButtons), kanban restyling (task-row CSS), and files restyling (table + icons).
|
|||
|
|
Output: Updated `icon_button.templ` with `download` and `chat` cases; `app.css` with Sections 19–25 appended.
|
|||
|
|
</objective>
|
|||
|
|
|
|||
|
|
<execution_context>
|
|||
|
|
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/get-shit-done/workflows/execute-plan.md
|
|||
|
|
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/get-shit-done/templates/summary.md
|
|||
|
|
</execution_context>
|
|||
|
|
|
|||
|
|
<context>
|
|||
|
|
@.planning/ROADMAP.md
|
|||
|
|
@.planning/phases/16-tablo-detail/16-CONTEXT.md
|
|||
|
|
@.planning/phases/16-tablo-detail/16-RESEARCH.md
|
|||
|
|
@.planning/phases/16-tablo-detail/16-PATTERNS.md
|
|||
|
|
@.planning/phases/16-tablo-detail/16-UI-SPEC.md
|
|||
|
|
|
|||
|
|
<interfaces>
|
|||
|
|
<!-- Key patterns the executor needs. No exploration required. -->
|
|||
|
|
|
|||
|
|
From backend/internal/web/ui/icon_button.templ (current UIIcon switch structure):
|
|||
|
|
- Package: `package ui`
|
|||
|
|
- Switch starts at line ~18, cases: "plus", "grid3x3", "list", "filter", "search", "calendar", "pencil", "trash"
|
|||
|
|
- `default:` case emits `<span>{kind}</span>` (renders icon name as text — this is the bug)
|
|||
|
|
- Insert `case "download":` and `case "chat":` BEFORE the `default:` case
|
|||
|
|
|
|||
|
|
From backend/internal/web/ui/app.css (current state):
|
|||
|
|
- File is 450 lines; ends after Section 18 (project-card-top, project-avatar)
|
|||
|
|
- Line 355-361: `.overview-section-heading h3, .tasks-section-header h3` shared rule exists (do NOT add a second `.tasks-section-header h3` rule; add only the scoped `.kanban-column .tasks-section-header h3 { font-size: 1rem; }` override)
|
|||
|
|
- Sections to append: 19 (tasks-section block), 20 (progress bar), 21 (tab nav), 22 (metadata row), 23 (kanban-column wrapper), 24 (etape group), 25 (task-list-empty)
|
|||
|
|
- All token names: `var(--color-surface-default)`, `var(--color-border-subtle)`, `var(--color-border-muted)`, `var(--color-border-strong)`, `var(--color-text-secondary)`, `var(--color-text-muted)`, `var(--color-text-faint)`, `var(--color-text-primary)`, `var(--color-text-brand)`, `var(--color-text-brand-strong)`, `var(--color-text-inverse)`, `var(--color-surface-muted)`, `var(--color-surface-neutral-hover)`, `var(--color-brand-primary)`, `var(--color-project-fallback)`, `var(--project-color, var(--color-project-fallback))`
|
|||
|
|
</interfaces>
|
|||
|
|
</context>
|
|||
|
|
|
|||
|
|
<tasks>
|
|||
|
|
|
|||
|
|
<task type="auto">
|
|||
|
|
<name>Task 1: Add `download` and `chat` icon cases to UIIcon switch</name>
|
|||
|
|
<files>backend/internal/web/ui/icon_button.templ</files>
|
|||
|
|
<read_first>
|
|||
|
|
- backend/internal/web/ui/icon_button.templ (read entire file — ~80 lines — before editing; understand the full switch structure and the `default:` position)
|
|||
|
|
</read_first>
|
|||
|
|
<action>
|
|||
|
|
Read the full `icon_button.templ` file. Find the UIIcon switch's `default:` case. Insert two new cases immediately before `default:`:
|
|||
|
|
|
|||
|
|
Case "download": emit an SVG with `viewBox="0 0 24 24"`, `fill="none"`, `stroke="currentColor"`, `stroke-width="2"`, `stroke-linecap="round"`, `stroke-linejoin="round"`, `aria-hidden="true"`. Contents: `path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"`, `polyline points="7 10 12 15 17 10"`, `line x1="12" x2="12" y1="15" y2="3"`.
|
|||
|
|
|
|||
|
|
Case "chat": emit an SVG with same attributes. Contents: `path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"`.
|
|||
|
|
|
|||
|
|
Do NOT modify any other part of the file. Do NOT change the `default:` case or any existing cases.
|
|||
|
|
|
|||
|
|
After editing, run: `just generate` (or `templ generate ./backend/...`) to regenerate `icon_button_templ.go`.
|
|||
|
|
</action>
|
|||
|
|
<verify>
|
|||
|
|
<automated>grep -c 'case "download"' /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/icon_button.templ && grep -c 'case "chat"' /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/icon_button.templ && cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source && go build ./backend/...</automated>
|
|||
|
|
</verify>
|
|||
|
|
<acceptance_criteria>
|
|||
|
|
- `icon_button.templ` contains `case "download":` with a polyline + line SVG body
|
|||
|
|
- `icon_button.templ` contains `case "chat":` with a path SVG body
|
|||
|
|
- Both new cases appear before the `default:` case in the switch
|
|||
|
|
- `go build ./backend/...` exits 0 (templ-generated file updated, no compile errors)
|
|||
|
|
- The `default:` case and all 8 existing cases are unchanged
|
|||
|
|
</acceptance_criteria>
|
|||
|
|
<done>UIIcon switch contains "download" and "chat" cases; project compiles cleanly.</done>
|
|||
|
|
</task>
|
|||
|
|
|
|||
|
|
<task type="auto">
|
|||
|
|
<name>Task 2: Append CSS Sections 19–25 to app.css</name>
|
|||
|
|
<files>backend/internal/web/ui/app.css</files>
|
|||
|
|
<read_first>
|
|||
|
|
- backend/internal/web/ui/app.css (read lines 340–450 to confirm the end of the file and the existing shared `.tasks-section-header h3` rule at lines 355–361; verify no duplication before appending)
|
|||
|
|
- .planning/phases/16-tablo-detail/16-PATTERNS.md (Pattern Assignments section: "New CSS blocks to append — Blocks 1, 2, 3" — these are the verbatim CSS blocks to append)
|
|||
|
|
- .planning/phases/16-tablo-detail/16-UI-SPEC.md (New CSS Classes Required section — additional property values that refine the blocks)
|
|||
|
|
</read_first>
|
|||
|
|
<action>
|
|||
|
|
Append the following seven CSS sections to the END of `backend/internal/web/ui/app.css`. Do NOT modify any existing rules. The shared `.tasks-section-header h3` rule at lines ~355-361 already exists — do NOT add another one; only add the scoped `.kanban-column .tasks-section-header h3 { font-size: 1rem; }` override.
|
|||
|
|
|
|||
|
|
Append in order:
|
|||
|
|
|
|||
|
|
Section 19 — Tasks section (ported from go-backend): `.tasks-section`, `.tasks-section-header`, `.tasks-add-button`, `.task-list`, `.task-row`, `.task-row:hover`, `.task-check`, `.task-check.is-complete`, `.task-body`, `.task-body p`, `.task-row.is-complete .task-body p`, `.task-meta`. All values from PATTERNS.md Block 1 verbatim.
|
|||
|
|
|
|||
|
|
Section 20 — Progress bar: `.project-progress-track`, `.project-progress-bar`. All values from PATTERNS.md Block 2 verbatim.
|
|||
|
|
|
|||
|
|
Section 21 — Tab nav: `.tab-nav`, `.tab-nav-item`, `.tab-nav-item.is-active`, `.tab-nav-item:hover:not(.is-active)`. Values from PATTERNS.md Block 3 / UI-SPEC.
|
|||
|
|
|
|||
|
|
Section 22 — Tablo detail metadata row: `.tablo-metadata-row`, `.tablo-metadata-date`, `.tablo-metadata-date svg`. Values from PATTERNS.md Block 3 / UI-SPEC.
|
|||
|
|
|
|||
|
|
Section 23 — Kanban column wrapper: `.kanban-column { flex-shrink: 0; width: 18rem; }` and `.kanban-column .tasks-section-header h3 { font-size: 1rem; }`.
|
|||
|
|
|
|||
|
|
Section 24 — Etape group sub-headings: `.etape-group-header`, `.etape-group-color-dot`, `.etape-group-label`, `.etape-group-label.is-unassigned`. Values from PATTERNS.md Block 3 / UI-SPEC.
|
|||
|
|
|
|||
|
|
Section 25 — Empty task list: `.task-list-empty { color: var(--color-text-faint); font-size: 0.875rem; font-style: italic; padding: 0.75rem 1rem; }`.
|
|||
|
|
|
|||
|
|
Every CSS value must use `var(--...)` tokens. No hardcoded hex values. No Tailwind utility classes.
|
|||
|
|
</action>
|
|||
|
|
<verify>
|
|||
|
|
<automated>grep -c "\.tasks-section {" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.tab-nav-item\.is-active" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.kanban-column" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.etape-group-header" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.task-list-empty" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css</automated>
|
|||
|
|
</verify>
|
|||
|
|
<acceptance_criteria>
|
|||
|
|
- `app.css` contains exactly one `.tasks-section {` rule (no duplication)
|
|||
|
|
- `app.css` contains `.tab-nav-item.is-active` with `border-bottom-color: var(--color-brand-primary)` and `color: var(--color-text-brand)`
|
|||
|
|
- `app.css` contains `.kanban-column` with `width: 18rem`
|
|||
|
|
- `app.css` contains `.kanban-column .tasks-section-header h3` with `font-size: 1rem`
|
|||
|
|
- `app.css` contains `.etape-group-header` with `background: var(--color-surface-muted)`
|
|||
|
|
- `app.css` contains `.task-list-empty` with `font-style: italic`
|
|||
|
|
- `app.css` contains `.project-progress-track` and `.project-progress-bar`
|
|||
|
|
- `grep -c "#[0-9a-fA-F]\{3,6\}" app.css` returns 0 for newly appended lines (no hardcoded hex in new rules)
|
|||
|
|
- `go build ./backend/...` exits 0 (CSS is a static asset, build verifies no templ regressions)
|
|||
|
|
</acceptance_criteria>
|
|||
|
|
<done>app.css has all Phase 16 CSS sections appended; no hardcoded hex values; project compiles cleanly.</done>
|
|||
|
|
</task>
|
|||
|
|
|
|||
|
|
</tasks>
|
|||
|
|
|
|||
|
|
<threat_model>
|
|||
|
|
## Trust Boundaries
|
|||
|
|
|
|||
|
|
| Boundary | Description |
|
|||
|
|
|----------|-------------|
|
|||
|
|
| Static asset → browser | CSS and templ-generated HTML served as static embed; no user input processed |
|
|||
|
|
|
|||
|
|
## STRIDE Threat Register
|
|||
|
|
|
|||
|
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
|||
|
|
|-----------|----------|-----------|-------------|-----------------|
|
|||
|
|
| T-16-01-01 | Tampering | app.css static embed | accept | CSS is embedded at build time; no runtime user modification possible; existing CSP controls unchanged |
|
|||
|
|
| T-16-01-02 | Information Disclosure | SVG icon markup | accept | SVG icons are decorative, contain no user data; aria-hidden="true" on all decorative SVGs |
|
|||
|
|
|
|||
|
|
No new trust boundaries. No user input, no authentication changes, no handler changes.
|
|||
|
|
</threat_model>
|
|||
|
|
|
|||
|
|
<verification>
|
|||
|
|
After both tasks complete:
|
|||
|
|
```bash
|
|||
|
|
cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source
|
|||
|
|
go test ./backend/internal/web/... -count=1
|
|||
|
|
```
|
|||
|
|
All existing tests must pass. The CSS and icon changes do not affect test behavior (tests verify handler output, not CSS class names in most cases).
|
|||
|
|
</verification>
|
|||
|
|
|
|||
|
|
<success_criteria>
|
|||
|
|
- `icon_button.templ` has `case "download":` and `case "chat":` before `default:`
|
|||
|
|
- `app.css` has 7 new sections (19–25) appended with no hardcoded hex values
|
|||
|
|
- `go test ./backend/internal/web/... -count=1` passes with no new failures
|
|||
|
|
- `go build ./backend/...` exits 0
|
|||
|
|
</success_criteria>
|
|||
|
|
|
|||
|
|
<output>
|
|||
|
|
After completion, create `.planning/phases/16-tablo-detail/16-01-SUMMARY.md` using the summary template.
|
|||
|
|
</output>
|