diff --git a/.planning/phases/12-native-tablo-chat/12-UI-SPEC.md b/.planning/phases/12-native-tablo-chat/12-UI-SPEC.md new file mode 100644 index 0000000..d8e07e0 --- /dev/null +++ b/.planning/phases/12-native-tablo-chat/12-UI-SPEC.md @@ -0,0 +1,299 @@ +--- +phase: 12 +slug: native-tablo-chat +status: approved +shadcn_initialized: false +preset: none +created: 2026-05-16 +--- + +# Phase 12 - UI Design Contract + +> Visual and interaction contract for native per-tablo discussion in the Go+HTMX app. This phase must produce a functional, readable discussion surface, not a rich consumer chat product. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | none | +| Preset | not applicable | +| Component library | local Go templ components in `backend/internal/web/ui` | +| Icon library | none required for this phase | +| Font | inherited system sans-serif from existing `Layout` | + +Use the existing `Layout`, tablo detail tab shell, `ui.Button`, form field/error, border, slate, and blue focus conventions. Do not introduce shadcn, Radix, lucide, custom SVG icons, copied chat UI blocks, or a client-side framework. + +--- + +## Surface Contract + +### Page Role + +- Discussion is a normal tab inside the tablo detail page. +- Tab label: `Discussion`. +- Tab order: `Overview / Tasks / Files / Events / Discussion`. +- Direct route/fallback behavior must render the full tablo detail page with Discussion active, matching other tabs. +- The UI is a work discussion attached to a tablo, not a standalone inbox or global chat product. +- Do not add a hero, decorative illustration, marketing copy, split-pane messenger layout, presence strip, typing indicator, rich media panel, or nested cards. + +### Primary Regions + +1. **Tab heading row** + - Left: `Discussion` heading and simple participant count, e.g. `1 participant`. + - Right: no primary action beyond the composer. Do not add settings, invite, search, filter, or overflow menus in Phase 12. + - Must wrap cleanly on mobile. + +2. **Message history** + - One continuous vertical message list. + - Oldest messages at the top, newest at the bottom. + - Include simple day separators. + - Message rows show author, absolute timestamp, and escaped text. + - Rows are compact but readable, optimized for scanning ongoing work context. + +3. **Composer** + - Fixed to the bottom of the Discussion tab content flow, not browser-fixed. + - Plain textarea plus `Send message` button. + - Uses normal CSRF-protected POST and server validation. + - No Enter-to-send behavior in Phase 12. + +4. **Unread badge** + - Dashboard tablo cards show a small unread badge when count > 0. + - Badge is informational and should not dominate the card. + - If count is unavailable, omit the badge rather than showing stale placeholder copy. + +5. **Empty state** + - Shows inside the message history area, above the composer. + - Must not hide the composer; users should be able to start the discussion immediately. + +--- + +## Spacing Scale + +Declared values (must be multiples of 4): + +| Token | Value | Usage | +|-------|-------|-------| +| xs | 4px | Metadata separators, badge text padding, inline gaps | +| sm | 8px | Message row inner gaps, day separator gaps, composer control gaps | +| md | 16px | Default tab section spacing, message list padding, textarea padding | +| lg | 24px | Heading-to-history gap, composer top separation | +| xl | 32px | Empty-state vertical spacing | +| 2xl | 48px | Not used except sparse empty-state breathing room | +| 3xl | 64px | Not used in Phase 12 | + +Exceptions: none. + +### Layout Rules + +- Use the existing tablo detail content width and tab container. +- Discussion tab content uses one primary vertical stack, not a card inside a card. +- Message history can have a single border-y or border container if needed, but individual messages should not be decorative cards. +- Message rows use 8-12px vertical padding and 12-16px horizontal padding. +- Day separators use 16-24px vertical spacing and 14px text. +- Composer uses 16px top margin/padding and a clear border/top divider. +- Mobile layout must not require horizontal scrolling. Long message text, author names, and timestamps must wrap or truncate safely. + +--- + +## Typography + +| Role | Size | Weight | Line Height | +|------|------|--------|-------------| +| Body / message text | 16px | 400 | 1.5 | +| Label / author | 14px | 600 | 1.4 | +| Metadata / timestamp | 12px or 14px | 400 | 1.4 | +| Heading | 24px | 600 | 1.25 | +| Empty state heading | 20px | 600 | 1.3 | + +### Typography Rules + +- Use existing tab/detail heading proportions; do not use display-scale type inside the tab. +- Message text uses `text-base text-slate-900` or equivalent. +- Author uses `text-sm font-semibold text-slate-900`. +- Timestamp uses `text-xs` or `text-sm text-slate-500`. +- Participant count and day separators use subdued metadata styling. +- Do not use viewport-scaled font sizes, negative letter spacing, bubble-specific oversized typography, or markdown/rich-text rendering. + +--- + +## Color + +| Role | Value | Usage | +|------|-------|-------| +| Dominant (60%) | `#ffffff` | Page background, tab surface, composer surface | +| Secondary (30%) | `#f8fafc` / `#f1f5f9` | Empty state, day separator lines, subtle unread badge background | +| Accent (10%) | `#2563eb` | Send button, focus rings, unread badge text/border | +| Text primary | `#0f172a` | Heading, author, message text | +| Text secondary | `#475569` / `#64748b` | Participant count, timestamps, empty body | +| Border | `#e2e8f0` | Message dividers, composer divider, textarea border | +| Destructive | `#b91c1c` | Not used in Phase 12 UI | + +Accent reserved for: +- `Send message` button. +- Focus rings inherited from `ui.Button` and form fields. +- Unread badge when count > 0. +- SSE/error recovery messages only when they require user attention. + +Do not use chat-bubble palettes, heavy purple chat styling from the historical React UI, gradient backgrounds, decorative colored sidebars, or color-only status indicators. + +--- + +## Message List Contract + +Each message row must show: + +1. **Author** + - Prefer display name if available. + - Fall back to email. + - Do not render `You` as the only author label in Phase 12. + +2. **Timestamp** + - Absolute timestamp, not relative-only. + - Planner may choose exact format, but it must be understandable without live refresh. + +3. **Message text** + - Escaped server-rendered text. + - Preserve readable line breaks from textarea input if the implementation supports multiline messages. + - Long unbroken text must wrap safely. + +4. **Day separator** + - Use concise date text such as `May 16, 2026`. + - Separator is visual structure only; do not make it an interactive control. + +Do not show in Phase 12: + +- Edit/delete controls. +- Reactions. +- Replies or threads. +- Read receipts. +- Typing indicators. +- Presence. +- Attachments, files, images, voice messages, link previews, or rich media. +- Message search or filters. +- Pinned messages. + +### Ordering + +- Oldest message appears first. +- Newest message appears last. +- New POST response renders the sender's message immediately. +- SSE updates append new messages or refresh the relevant fragment for other open views. + +--- + +## Composer Contract + +| Element | Contract | +|---------|----------| +| Textarea label | Visible or accessible label: `Message` | +| Placeholder | `Write a message...` | +| Button | `Send message` | +| Empty validation | `Message is required.` | +| Length validation | `Message is too long.` or more specific max-length copy | +| Generic send error | `Message could not be sent. Please try again.` | + +Composer rules: + +- Use a `