# planning-ui.md ## UI Planning for workspace-chat-polish This document outlines the visual hierarchy, component boundaries, interaction affordances, keyboard parity, responsive behavior, and handoff decisions for the Chat sidebar polish, grounded in the existing specification. ### 1. Overview - The Chat sidebar is a **reusable, contextual component** mounted only on Chat routes, replacing the Spaces sidebar in that context. - It contains exactly three collapsible sections: **Favorites**, **Channels**, and **DMs**. - The sidebar must not own message history; conversation ownership remains with `ChatWorkspace`. ### 2. Visual Hierarchy | Level | Component | Responsibility | Evidence | |-------|-----------|----------------|----------| | Global Shell | `AppShell` | Determines if current route is a Chat route and selects `Sidebar` vs `ChatSidebar`. | Spec §182 | | Chat Context | `ChatSidebar` | Owns section state, search/filter, navigation, and mutations. | Spec §183 | | Section Header | `ChatSectionHeader` | Disclosure control, hover/focus actions, Add, More menu. | Spec §100‑104 | | List Rows | `ChatListRow` (shared) | Avatar, label, preview/count, selected state, unread treatment. | Spec §125‑126 | | Conversation | `ChatWorkspace` | Owns message history, thread state, composer, message mutations. | Spec §186 | | Composer | `ChatComposer` | Accepts explicit `send`/`edit` mode, controlled body, submit/cancel callbacks. | Spec §146‑147 | | Delete | Shared accessible dialog | Confirms destructive action, traps/restores focus, disables duplicate submission. | Spec §148‑149 | ### 3. Component Boundaries - **`ChatSidebar`**: Reusable, route‑aware, **must not** own message history. - **`ChatSectionHeader`**: Handles disclosure (`aria-expanded`), hover/focus visibility, Add and More actions. - **`ChatListRow`**: Shared row primitive for Favorites, Channels, DMs with variants for metadata, unread state, and participant avatars. - **`ChatWorkspace`**: After `ChatSidebar` mounts, removes its own channel‑navigation aside to avoid duplicate navigation. - **`ChatComposer`**: Controlled edit state; populates composer with original body, shows `Update`/`Cancel`, preserves conflict recovery. ### 4. Interaction Affordances - **Hover/Focus**: All actions (Add, More, disclosure) hidden at rest but exposed on `:hover` and `:focus-within`. Use `focus-visible` for keyboard exposure. - **Section Disclosure**: `aria-expanded` on the disclosure control; labelled region for section body. - **Add Actions**: Right‑aligned in section header; also accessible via keyboard focus. - **More Menu**: Right‑aligned in section header; provides section‑level actions. - **Message Identity**: Use avatar primitive; display name > email > fallback (e.g., `Unknown member`). Raw UUID never shown as primary label. Tooltip for abbreviated identity. - **Edit Flow**: Focus primary composer → load original body → show `Update`/`Save` and `Cancel` → preserve edited message in history with editing indicator. - **Delete Flow**: Open shared accessible dialog stating “deletion is destructive”, provide Cancel and Delete actions, prevent accidental submission, restore focus to originating message action on Cancel. ### 5. Keyboard Parity - All hover‑only controls must be reachable via keyboard (`focus-within`). - Section headers and row actions must have clear accessible names and maintain `aria-expanded` state. - Focus management: Delete dialog traps focus; on Cancel restores focus to the originating message action. ### 6. Responsive Behavior - **Desktop**: Secondary Chat surface 260–300 px wide, bordered from conversation; both are independently scrollable. - **Narrow Viewports**: Chat surface becomes an accessible sheet/drawer (single column) rather than forcing a three‑column layout. - Maintain global rail width and behavior across breakpoints. ### 7. Open Risks & Decisions | Risk | Description | Decision / Mitigation | |------|-------------|-----------------------| | **Flat Channels list length** | May become long; requires search/filter now but keep grouping opt‑in. | Implement search/filter affordance in `ChatSectionHeader` now; grouping remains user‑selected later (Spec §161). | | **System status visibility** | Save, send failures, reconnect, delete completion need visible status and non‑visual announcements. | Use existing status primitives (toast/aria-live) and ensure announcements on mutation completion (Spec §162). | | **Edit Cancel path clarity** | Must be obvious; edit state belongs to conversation scope. | Ensure `Update`/`Cancel` buttons are prominently styled and keyboard‑accessible; focus returns to message action after cancel (Spec §163). | | **Edit pending state** | Disable actions while mutations pending; show conflict recovery. | Disable `Update`/`Delete` during pending; surface conflict message rather than losing text (Spec §166). | | **Delete dialog focus handling** | Must trap focus and restore on Cancel. | Use shared dialog primitive with focus trap; verify focus restoration after cancel (Spec §149). | | **Profile fallback** | Should never render raw UUID as primary author label. | Fallback to initials or `Unknown member`; show tooltip for abbreviated identity (Spec §132). | | **Favorite cross‑workspace authorization** | Must reject targets outside active workspace. | Enforce via service authorization; unique indexes on discriminated target; do not weaken cross‑workspace checks (Spec §198). | | **Channel metadata & space links** | Optional nullable `spaceId` only if justified; must stay tenant‑scoped. | Add minimal reusable fields (nullable `spaceId` + bounded metadata) and enforce object‑type validation in service layer (Spec §199). | | **DM participant projection** | Must validate one or many participants and render identity safely. | Reuse existing `createDirect` input; ensure participant picker shows safe identity; group‑DM indicator for >1 participant (Spec §128‑129, §222). | | **Route detection helper** | Must avoid false positives; recognize only `/[workspaceSlug]/chat` and descendants. | Implement segment‑aware helper based on `usePathname` (Spec §191). | | **Message history ownership** | `ChatSidebar` must not own message history. | Ensure `ChatWorkspace` remains sole owner; `ChatSidebar` only provides navigation and section state (Spec §183‑186). | ### 8. Handoff Decisions - **Route‑aware shell** to render `ChatSidebar` only on Chat routes; preserve existing `Sidebar` elsewhere. - **Extract ChatSidebar contracts** from `ChatWorkspace` without altering data behavior (Spec §110‑111). - **Implement profile projection** for channel authors to display safe identity (Spec §197). - **Reuse existing composer** for edit mode; add explicit `edit` mode control. - **Adopt shared accessible dialog** for delete flow; no inline delete panel. - **Favorites persistence** to evolve from object‑only to discriminated target (`object`/`chatChannel`) with mutual‑exclusion and unique indexes (Spec §198). - **Channel metadata** to be added only if product use requires it; keep space grouping optional and non‑visual by default. --- **File:** `/workspace/submatter/.convoys/workspace-chat-polish/planning-ui.md` **Key Decisions:** - ChatSidebar is route‑aware, reusable, and owns only section state (no message history). - Component boundaries defined: `ChatSidebar`, `ChatSectionHeader`, `ChatListRow`, `ChatWorkspace`, `ChatComposer`, shared dialog. - Visual language reuses existing primitives; hover/focus actions exposed via `focus-within`. - Responsive: 260–300 px sidebar on desktop, sheet/drawer on narrow viewports. - Edit uses primary composer with `Update`/`Cancel`; delete uses shared accessible dialog with focus management. - Open risks addressed via search/filter, status announcements, edit pending state handling, delete focus trap, profile fallback, cross‑workspace favorite validation, channel metadata justification, DM participant safety, and segment‑aware route detection.