From 63e7d652902ad00964c40ef09bef403b60f901a2 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Mon, 18 May 2026 16:31:05 +0200 Subject: [PATCH] feat(phase-20): port tablo detail restyle to backend/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 20 work was executed against go-backend/ (prototype) instead of backend/ (production). This commit ports the Figma-aligned restyle to the correct codebase. Changes: - tablos.templ: replace project-card-top header with tablo-detail-header, tablo-detail-avatar, tablo-detail-title; update tab bar to tablo-tab-bar; localise tab labels to French (Vue d'ensemble, Tâches, Fichiers, Discussion, Événements) - tasks.templ: update KanbanBoard to tablo-kanban-board; KanbanColumn to tablo-kanban-column with new header/count/empty classes; TaskCard to card-style layout (task-card-top-row, task-card-title, task-card-delete) - app.css: add sections 25–27 — tablo detail page, kanban board/columns, and task card (card appearance, hover states) Co-Authored-By: Claude Sonnet 4.6 (1M context) --- backend/internal/web/ui/app.css | 192 ++++++++++++++++++++++++ backend/templates/tablos.templ | 256 ++++++++++++++------------------ backend/templates/tasks.templ | 86 +++++------ 3 files changed, 347 insertions(+), 187 deletions(-) diff --git a/backend/internal/web/ui/app.css b/backend/internal/web/ui/app.css index 80573c2..ec87dfc 100644 --- a/backend/internal/web/ui/app.css +++ b/backend/internal/web/ui/app.css @@ -1107,3 +1107,195 @@ border: 1px solid var(--color-border-default, #e2e8f0); color: var(--color-text-primary); } + +/* ============================================================ + Section 25 — Tablo detail page (Figma restyle) + ============================================================ */ + +.tablo-detail-page { + padding: 24px 32px; +} + +.tablo-detail-header { + border-bottom: 1px solid var(--color-border-muted); + display: flex; + flex-direction: column; + gap: 0; + padding-bottom: 0; +} + +.tablo-detail-title-row { + align-items: center; + display: flex; + gap: 16px; + padding-bottom: 16px; +} + +.tablo-detail-avatar { + align-items: center; + background: var(--color-surface-muted); + border-radius: 12px; + color: #ffffff; + display: flex; + flex-shrink: 0; + font-size: 1rem; + font-weight: 700; + height: 48px; + justify-content: center; + width: 48px; +} + +.tablo-detail-title { + color: var(--color-text-primary); + font-size: 1.75rem; + font-weight: 600; + line-height: 1.2; + margin: 0; +} + +/* Override the existing tablo-metadata-row for the detail page context */ +.tablo-detail-header .tablo-metadata-row { + border-bottom: 1px solid var(--color-border-muted); + gap: 24px; + margin-bottom: 0; + padding-block: 16px; +} + +.tablo-meta-segment { + align-items: center; + color: var(--color-text-secondary); + display: flex; + font-size: 0.875rem; + gap: 8px; +} + +.tablo-meta-progress { + align-items: center; + display: flex; + gap: 8px; +} + +.tablo-progress-bar { + background: var(--color-brand-primary); + border-radius: 9999px; + height: 5px; +} + +.tablo-tab-bar { + border-bottom: 1px solid var(--color-border-muted); + display: flex; + gap: 24px; + padding-top: 8px; +} + +.tablo-tab-bar .tab-nav-item { + font-size: 0.875rem; + padding-bottom: 12px; +} + +/* ============================================================ + Section 26 — Kanban board & columns (Figma restyle) + ============================================================ */ + +.tablo-kanban-board { + display: flex; + gap: 16px; + overflow-x: auto; + padding-bottom: 16px; + padding-top: 24px; +} + +.tablo-kanban-column { + background: var(--color-surface-default); + border: 1px solid var(--color-border-default); + border-radius: 0.75rem; + flex-shrink: 0; + overflow: hidden; + width: 18rem; +} + +.tablo-kanban-column-header { + align-items: center; + background: var(--color-surface-muted); + display: flex; + gap: 8px; + padding: 12px 16px; +} + +.tablo-kanban-column-title { + color: var(--color-text-primary); + font-size: 0.875rem; + font-weight: 600; + margin: 0; +} + +.tablo-kanban-task-count { + 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; +} + +.tablo-kanban-empty { + color: var(--color-text-faint); + font-size: 0.875rem; + padding: 24px 16px; + text-align: center; +} + +/* ============================================================ + Section 27 — Task card (kanban card style) + ============================================================ */ + +.task-card { + background: var(--color-surface-default); + border: 1px solid var(--color-border-default); + border-radius: 8px; + cursor: pointer; + display: flex; + flex-direction: column; + gap: 8px; + margin: 8px; + padding-block: 8px; + padding-inline: 12px; + transition: box-shadow 0.12s ease, border-color 0.12s ease; +} + +.task-card:hover { + border-color: var(--color-border-strong); + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08); +} + +.task-card-top-row { + align-items: flex-start; + display: flex; + gap: 6px; +} + +.task-card-title { + 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; +} + +.task-card-delete { + flex-shrink: 0; + opacity: 0; + transition: opacity 0.12s ease; +} + +.task-card:hover .task-card-delete { + opacity: 1; +} + +.task-card:hover .task-drag-handle { + opacity: 1; +} diff --git a/backend/templates/tablos.templ b/backend/templates/tablos.templ index 0ed5441..95a991d 100644 --- a/backend/templates/tablos.templ +++ b/backend/templates/tablos.templ @@ -406,58 +406,33 @@ templ TabloCardWithOOBFormClear(tablo sqlc.Tablo, csrfToken string) {
} -// TabloDetailPage renders the full detail page for a single tablo with a 3-tab layout. -// Tabs: Overview / Tasks / Files. activeTab selects the initially rendered tab content. +// TabloDetailPage renders the full detail page for a single tablo. +// Tabs: Overview / Tasks / Files / Discussion / Events. activeTab selects the initially rendered tab content. // files and tasks are pre-fetched slices for the active tab (may be nil for inactive tabs). // activePath and sidebarTablos drive the AppLayout sidebar. // UI-SPEC §3 Interaction Contract — GET /tablos/{id}. // D-07: signature includes activeTab string param; D-08: tab bar links carry hx-push-url. templ TabloDetailPage(user *auth.User, csrfToken string, activePath string, sidebarTablos []sqlc.Tablo, tablo sqlc.Tablo, tasks []sqlc.Task, etapes []sqlc.Etape, counts EtapeTaskCounts, filter EtapeFilter, files []sqlc.TabloFile, events EventsCalendar, discussion DiscussionTabData, activeTab string, pageTitle string, breadcrumb []BreadcrumbItem) { @AppLayout("Tablos — Xtablo", user, csrfToken, activePath, sidebarTablos, pageTitle, breadcrumb, nil) { - -
-
-
+
+
+
if tablo.Color.Valid && tablo.Color.String != "" { - +
if len(tablo.Title) > 0 { { string([]rune(tablo.Title)[0:1]) } } - +
} else { - +
if len(tablo.Title) > 0 { { string([]rune(tablo.Title)[0:1]) } } - +
}
@TabloTitleDisplay(tablo, csrfToken)
-
-
- - @ui.IconButton(ui.IconButtonProps{ - Label: "Discussion", - Icon: "chat", - Variant: ui.IconButtonVariantNeutral, - Tone: ui.IconButtonToneGhost, - Type: "button", - }) - - @ui.Button(ui.ButtonProps{ - Label: "Invite Member", - Variant: ui.ButtonVariantDefault, - Tone: ui.ButtonToneSoft, - Size: ui.SizeMD, - Type: "button", - })
@ui.IconButton(ui.IconButtonProps{ Label: "Delete tablo", @@ -473,116 +448,115 @@ templ TabloDetailPage(user *auth.User, csrfToken string, activePath string, side })
-
- -