docs(12): UI design contract
This commit is contained in:
parent
7ffa3600a0
commit
50a3f255fc
1 changed files with 299 additions and 0 deletions
299
.planning/phases/12-native-tablo-chat/12-UI-SPEC.md
Normal file
299
.planning/phases/12-native-tablo-chat/12-UI-SPEC.md
Normal file
|
|
@ -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 `<textarea>` for message input.
|
||||
- Use the existing CSRF hidden field pattern.
|
||||
- Submit with an explicit `Send message` button.
|
||||
- Disable or reject empty/whitespace-only messages through server validation.
|
||||
- Do not require JavaScript keyboard shortcuts.
|
||||
- The form should remain usable when HTMX is unavailable, even if realtime updates require SSE-capable browsers.
|
||||
|
||||
---
|
||||
|
||||
## Unread Badge Contract
|
||||
|
||||
- Dashboard tablo card badge appears only when unread count > 0.
|
||||
- Copy: numeric count only, e.g. `3`.
|
||||
- Accessible label should include context, e.g. `3 unread discussion messages`.
|
||||
- Badge shape may be a small rounded pill or circle, but must not resize the card layout unpredictably.
|
||||
- If counts exceed a practical display limit, planner may use `99+`.
|
||||
- Badge color uses accent sparingly; do not color the whole card.
|
||||
|
||||
---
|
||||
|
||||
## SSE And Realtime UX Contract
|
||||
|
||||
- SSE receive is silent during normal operation.
|
||||
- Browser/EventSource reconnect behavior should not show visible copy by default.
|
||||
- If history or send requests fail, show a normal error message in the Discussion tab or composer area.
|
||||
- Do not show `Reconnecting...`, connection status pills, online/offline presence, or typing status in Phase 12.
|
||||
- Real-time updates must not duplicate the sender's POST-rendered message.
|
||||
- If duplicate suppression requires a client/server message identifier, planner may define it.
|
||||
|
||||
---
|
||||
|
||||
## Copywriting Contract
|
||||
|
||||
| Element | Copy |
|
||||
|---------|------|
|
||||
| Tab label | `Discussion` |
|
||||
| Heading | `Discussion` |
|
||||
| Participant count | `1 participant` |
|
||||
| Primary CTA | `Send message` |
|
||||
| Textarea label | `Message` |
|
||||
| Textarea placeholder | `Write a message...` |
|
||||
| Empty state heading | `No messages yet` |
|
||||
| Empty state body | `Start the discussion for this tablo.` |
|
||||
| Empty validation | `Message is required.` |
|
||||
| Length validation | `Message is too long.` |
|
||||
| Generic load error | `Discussion could not be loaded. Please try again.` |
|
||||
| Generic send error | `Message could not be sent. Please try again.` |
|
||||
| Destructive confirmation | none |
|
||||
|
||||
Copy must stay functional and short. Do not add onboarding paragraphs, feature explanations, or promotional collaboration language.
|
||||
|
||||
---
|
||||
|
||||
## Responsive Behavior
|
||||
|
||||
- Desktop: heading row, history, and composer fit inside the existing tablo detail layout.
|
||||
- Mobile:
|
||||
- Heading and participant count stack if needed.
|
||||
- Message metadata can wrap above message text.
|
||||
- Composer textarea and send button may stack if horizontal space is tight.
|
||||
- Unread badge on dashboard cards must not overlap title, color dot, or delete controls.
|
||||
- Message history can scroll with the page. Do not introduce a fixed-height inner scroll panel unless the planner proves it is needed and mobile-safe.
|
||||
- Text must not overlap controls at any viewport.
|
||||
|
||||
---
|
||||
|
||||
## Accessibility Contract
|
||||
|
||||
- The tablo detail page still has one primary page heading; the Discussion tab section uses an appropriate heading level under the existing page structure.
|
||||
- Discussion tab link has visible text `Discussion`.
|
||||
- Message history uses semantic list markup where practical (`ol`/`li` preferred because order matters).
|
||||
- Composer textarea has an accessible label.
|
||||
- Send button has visible text.
|
||||
- Day separators are readable text, not visual-only lines.
|
||||
- Unread badge has an accessible label that includes the unread count and discussion context.
|
||||
- Error messages are text near the relevant form/history area.
|
||||
- Color is never the only indicator of unread or error state.
|
||||
|
||||
---
|
||||
|
||||
## Registry Safety
|
||||
|
||||
| Registry | Blocks Used | Safety Gate |
|
||||
|----------|-------------|-------------|
|
||||
| shadcn official | none | not required |
|
||||
| third-party registry | none | prohibited for this phase |
|
||||
|
||||
No registry components, copied chat UI blocks, or historical React chat component ports are allowed in Phase 12.
|
||||
|
||||
---
|
||||
|
||||
## 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-16
|
||||
Loading…
Reference in a new issue