xtablo-source/.planning/phases/20-tablo-detail-kanban-restyle/20-03-PLAN.md
Arthur Belleville 20e0a02edc
docs(20): create phase 20 plan — tablo detail page + kanban restyle
3 plans in 2 waves: handler+viewmodel (wave 1), templ components + CSS
restyle in parallel (wave 2). Covers DETAIL-01 and TASK-01.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-18 15:29:41 +02:00

15 KiB
Raw Blame History

phase plan type wave depends_on files_modified autonomous requirements must_haves
20-tablo-detail-kanban-restyle 03 execute 2
20-01
go-backend/internal/web/ui/app.css
true
DETAIL-01
TASK-01
truths artifacts key_links
app.css contains a .tablo-detail-header rule with flex-direction, padding, and border-bottom
app.css contains a .tablo-detail-title rule with font-size 1.75rem and font-weight 600
app.css contains a .tablo-metadata-row rule with display flex and gap 24px
app.css contains a .tablo-kanban-board rule with display flex, gap 16px, and overflow-x auto
app.css contains a .tablo-kanban-column rule with width 18rem, border-radius 0.75rem, and border
app.css contains a .task-card rule with flex-direction column, border-radius 8px, and gap 8px
app.css contains a .task-drag-handle rule with opacity 0 and a .task-card:hover .task-drag-handle rule with opacity 1
app.css contains a .task-card-delete rule with opacity 0 at rest and visible on .task-card:hover
app.css contains a .tablo-progress-bar rule with background var(--color-brand-primary) — NOT var(--project-color)
app.css contains a .tablo-files-table-wrapper rule with border-radius 12px
app.css .task-list rule is updated to include gap 8px and padding 8px
path provides contains
go-backend/internal/web/ui/app.css All tablo detail + kanban restyle CSS rules .tablo-detail-header
from to via pattern
go-backend/internal/web/views/tablo_detail.templ go-backend/internal/web/ui/app.css CSS class names applied to HTML elements .tablo-kanban-board
Apply all CSS changes from the UI-SPEC to app.css: new tablo detail header styles, kanban board layout, task card restyle (column-flex, hover shadow, opacity-based drag handle), progress bar fill fix, files table wrapper, and updated task-list gap. This plan runs in parallel with Plan 02 since CSS class names are already locked in the UI-SPEC.

Purpose: Without these CSS rules, the templ components from Plan 02 render unstyled. This plan is the visual half of the restyle.

Output: Updated app.css with all new and modified CSS blocks from UI-SPEC.

<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>

@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/20-tablo-detail-kanban-restyle/20-UI-SPEC.md @/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/20-tablo-detail-kanban-restyle/20-RESEARCH.md @/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/skills/sketch-findings-xtablo-source/SKILL.md Task 1: Tablo detail header and metadata CSS go-backend/internal/web/ui/app.css - go-backend/internal/web/ui/app.css (read lines 1040-1080 — existing .project-progress-track, .project-progress-bar, .project-progress-label rules to understand context before modifying) - go-backend/internal/web/ui/app.css (read lines 880-920 — existing .tab-nav, .tab-nav-item rules to confirm no tab changes needed) - go-backend/internal/web/ui/base.css (read first 60 lines — confirm --color-brand-primary, --color-border-default, --color-surface-muted, --color-text-primary token names) Edit go-backend/internal/web/ui/app.css. Append a new section at the end of the file titled "/* === Tablo Detail Page === */". Add the following CSS blocks in this order. Use exact property values from the UI-SPEC — do not approximate or simplify.
BLOCK 1: .tablo-detail-page — outer container
  padding: 24px 32px;

BLOCK 2: .tablo-detail-header — header element
  border-bottom: 1px solid var(--color-border-muted);
  display: flex;
  flex-direction: column;
  gap: 0;
  padding-bottom: 0;

BLOCK 3: .tablo-detail-title-row — flex row with avatar + h1
  align-items: center;
  display: flex;
  gap: 16px;
  margin-bottom: 0;
  padding-bottom: 16px;

BLOCK 4: .tablo-detail-avatar — 48×48 colored circle
  align-items: center;
  border-radius: 12px;
  color: #ffffff;
  display: flex;
  flex-shrink: 0;
  font-size: 1rem;
  font-weight: 700;
  height: 48px;
  justify-content: center;
  width: 48px;

BLOCK 5: .tablo-detail-title — h1 tablo name
  color: var(--color-text-primary);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.2;
  margin: 0;

BLOCK 6: .tablo-metadata-row — metadata flex row
  align-items: center;
  border-bottom: 1px solid var(--color-border-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  padding-block: 16px;

BLOCK 7: .tablo-meta-segment — each segment in metadata row
  align-items: center;
  color: var(--color-text-secondary);
  display: flex;
  font-size: 0.875rem;
  gap: 8px;

BLOCK 8: .tablo-meta-progress — progress segment override
  align-items: center;
  display: flex;
  gap: 8px;

BLOCK 9: .tablo-progress-bar — detail page progress bar fill (MUST use brand-primary, NOT project-color — Pitfall 5)
  background: var(--color-brand-primary);
  border-radius: 9999px;
  height: 5px;

BLOCK 10: .tablo-tab-bar — tab navigation below header
  border-bottom: 1px solid var(--color-border-muted);
  display: flex;
  gap: 24px;
  margin-top: 0;
  padding-top: 8px;

BLOCK 11: .tablo-tab-bar .tab-nav-item — override for tabs within tablo detail
  font-size: 0.875rem;
  padding-bottom: 12px;

Do NOT modify the existing .project-progress-bar rule (it is used by tablo cards on the list page which keep var(--project-color)). The tablo detail page uses .tablo-progress-bar (different class) to avoid the conflict.

Do NOT modify .tab-nav or .tab-nav-item globally — only scope changes to .tablo-tab-bar context if any override is needed.
grep -c "tablo-detail-header\|tablo-detail-title\|tablo-metadata-row\|tablo-progress-bar\|tablo-tab-bar" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/go-backend/internal/web/ui/app.css grep count returns 5 or more (one match per class block); .tablo-progress-bar uses var(--color-brand-primary) not var(--project-color); grep for "tablo-progress-bar" returns a rule with "background: var(--color-brand-primary)". Task 2: Kanban board, task card, files table, and task-list gap CSS go-backend/internal/web/ui/app.css - go-backend/internal/web/ui/app.css (read lines 1283-1350 — existing .task-list, .task-row, .task-body, .task-check rules; understand what to modify vs what to add) - go-backend/internal/web/ui/app.css (read lines 1254-1268 — existing .tasks-section rule with border-radius: 1rem — do NOT change this; kanban column gets its own rule) - go-backend/internal/web/ui/base.css (confirm --color-surface-default, --color-border-default, --color-border-strong, --color-surface-muted token names) Edit go-backend/internal/web/ui/app.css. Continue the "/* === Tablo Detail Page === */" section from Task 1 (or append after it). Add the following blocks:
BLOCK 12: .tablo-kanban-board — flex container for the kanban columns
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 16px;
  padding-top: 24px;

BLOCK 13: .tablo-kanban-column — each column card
  background: var(--color-surface-default);
  border: 1px solid var(--color-border-default);
  border-radius: 0.75rem;
  flex-shrink: 0;
  overflow: hidden;
  width: 18rem;

BLOCK 14: .tablo-kanban-column-header — column header area
  align-items: center;
  background: var(--color-surface-muted);
  display: flex;
  gap: 8px;
  justify-content: space-between;
  padding: 12px 16px;

BLOCK 15: .tablo-kanban-column-title — column h3 label
  color: var(--color-text-primary);
  font-size: 0.875rem;
  font-weight: 600;
  margin: 0;

BLOCK 16: .tablo-kanban-task-count — task count pill
  background: var(--color-surface-default);
  border: 1px solid var(--color-border-muted);
  border-radius: 9999px;
  color: var(--color-text-secondary);
  font-size: 0.75rem;
  padding: 0 8px;

BLOCK 17: .tablo-kanban-add-link — "+ Ajouter" link
  color: var(--color-text-brand);
  font-size: 0.875rem;
  font-weight: 400;
  margin-left: auto;
  text-decoration: none;

BLOCK 18: .tablo-kanban-empty — empty column state
  color: var(--color-text-faint);
  font-size: 0.875rem;
  padding: 24px 16px;
  text-align: center;

BLOCK 19: .task-card — new card layout (replaces/supplements .task-row for tablo detail)
  background: var(--color-surface-default);
  border: 1px solid var(--color-border-default);
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-block: 8px;
  padding-inline: 12px;
  transition: box-shadow 0.12s ease, border-color 0.12s ease;

BLOCK 20: .task-card:hover
  border-color: var(--color-border-strong);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);

BLOCK 21: .task-card-top-row — row with drag handle, title, delete icon
  align-items: flex-start;
  display: flex;
  gap: 6px;

BLOCK 22: .task-drag-handle — drag handle (Braille pattern)
  color: var(--color-text-faint);
  cursor: grab;
  flex-shrink: 0;
  font-size: 1rem;
  opacity: 0;
  transition: opacity 0.12s ease;

BLOCK 23: .task-card:hover .task-drag-handle — reveal on card hover
  opacity: 1;

BLOCK 24: .task-card-title — task title text
  color: var(--color-text-primary);
  flex: 1;
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;

BLOCK 25: .task-card-delete — delete icon wrapper (opacity hidden at rest)
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.12s ease;

BLOCK 26: .task-card:hover .task-card-delete — reveal on card hover
  opacity: 1;

Now modify the EXISTING .task-list rule (around line 1283 in app.css):
Find the current rule:
  .task-list {
    display: flex;
    flex-direction: column;
  }
Change it to add gap and padding:
  .task-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px;
  }
This change affects both the global tasks page and the tablo detail page equally — gap between cards is desired everywhere.

Add files table wrapper CSS:

BLOCK 27: .tablo-files-table-wrapper — wrapper for the files table
  border: 1px solid var(--color-border-default);
  border-radius: 12px;
  overflow: hidden;

BLOCK 28: .tablo-files-table-wrapper thead tr
  background: var(--color-surface-muted);

BLOCK 29: .tablo-files-table-wrapper thead th
  color: var(--color-text-muted);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;

BLOCK 30: .tablo-files-table-wrapper tbody tr
  border-bottom: 1px solid var(--color-border-default);

BLOCK 31: .tablo-files-table-wrapper tbody tr:hover
  background: var(--color-surface-subtle);

CRITICAL checks before saving:
- .tablo-progress-bar uses "background: var(--color-brand-primary)" — grep to verify
- .task-card and .task-row are SEPARATE rules — .task-row must NOT be removed (it is used by the global tasks page)
- .tasks-section border-radius (1rem) must NOT be changed — only .tablo-kanban-column gets 0.75rem
- All opacity transitions use "0.12s ease" consistent with design system
grep -v "^:space:*//" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/go-backend/internal/web/ui/app.css | grep -c "tablo-kanban-board\|tablo-kanban-column\|task-card\b\|task-drag-handle\|tablo-files-table-wrapper\|tablo-kanban-empty" grep count returns 6 or more; .task-card block exists with flex-direction: column; .task-drag-handle exists with opacity: 0; .task-card:hover .task-drag-handle exists with opacity: 1; .tablo-kanban-board exists with overflow-x: auto; .task-list updated to include gap: 8px; .task-row unchanged.

<threat_model>

Trust Boundaries

Boundary Description
CSS cascade New .task-card rules must not override or break .task-row rules used on global /tasks page

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-20-06 Tampering CSS cascade — .task-card vs .task-row collision mitigate .task-card is a new separate selector; .task-row selector is unchanged; they do not overlap since tablo-detail uses task-card and global tasks page uses task-row
T-20-SC Tampering npm/pip/cargo installs accept No package installs — CSS file edit only
</threat_model>
After Plan 03: - grep for "tablo-kanban-board" in app.css returns at least one match with "overflow-x: auto" - grep for "tablo-progress-bar" in app.css returns a match with "background: var(--color-brand-primary)" - grep for "tablo-progress-bar" does NOT return "var(--project-color)" - grep for ".task-card\b" in app.css returns the column-flex card rule - grep for ".task-drag-handle" returns opacity: 0 rule - grep for ".task-card:hover .task-drag-handle" returns opacity: 1 rule - grep for ".task-row" still returns the original horizontal rule (not removed) - grep for ".tasks-section" still has border-radius: 1rem (not changed to 0.75rem) - grep for ".task-list" returns updated rule with gap: 8px - go build ./... still exits 0 (CSS is static — no compilation risk, but verify Go still compiles cleanly)

<success_criteria>

  • Visual: tablo detail header shows tablo name in large font, metadata row, and progress bar with purple fill
  • Visual: kanban columns are 18rem wide with rounded corners, muted header background
  • Visual: task cards are white box with column layout, subtle border, hover shadow
  • Visual: drag handle appears on card hover (opacity transition, not display toggle)
  • Visual: delete icon appears on card hover
  • Visual: empty columns show "Aucune tâche" centered
  • CSS regression: global /tasks kanban page still renders correctly (task-row unchanged) </success_criteria>
Create `.planning/phases/20-tablo-detail-kanban-restyle/20-03-SUMMARY.md` when done.