From e7cd1d79328e077b0515d9fea891cf23cdea20e7 Mon Sep 17 00:00:00 2001 From: xNet Test Date: Wed, 17 Jun 2026 16:29:34 -0700 Subject: [PATCH 1/4] docs(exploration): explore polished chat & channels UI Co-Authored-By: Claude Opus 4.8 --- .../0198_[_]_POLISHED_CHAT_AND_CHANNELS_UI.md | 552 ++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 docs/explorations/0198_[_]_POLISHED_CHAT_AND_CHANNELS_UI.md diff --git a/docs/explorations/0198_[_]_POLISHED_CHAT_AND_CHANNELS_UI.md b/docs/explorations/0198_[_]_POLISHED_CHAT_AND_CHANNELS_UI.md new file mode 100644 index 000000000..4594a1eb2 --- /dev/null +++ b/docs/explorations/0198_[_]_POLISHED_CHAT_AND_CHANNELS_UI.md @@ -0,0 +1,552 @@ +# Polished Chat & Channels UI — A Cleaner, Fancier, More Robust Comms Surface + +## Problem Statement + +The ask, verbatim: + +> Let's make the chat and channels UI way better. So, way cleaner, way fancier, way more robust. We can look at Slack, we can look at Microsoft Teams, we can look at Zulip, we can look at Discord, see how they do things, and then take some screenshots and make the screenshots just look way, way better. So more features, cleaner UI, cleaner UX, cleaner interactions, animations, all that sort of stuff. + +xNet already has a real, working comms surface: a `Chats` rail icon, a left-panel channel/DM/voice list (`ChatsPanel`), and a channel tab (`ChannelView` → `ChannelChat`) with a genuinely sophisticated structured composer (`@` mentions, `#` tags, `[[` wiki-links, all keyboard-navigable). It is wired into the workbench and synced through the same `Change` node protocol as everything else. + +But visually and interactionally it reads as a developer-grade prototype, not a product people reach for over Slack. Messages are tiny `text-xs` rows with no avatars, no grouping, no hover affordances, no reactions, no threads, and no read/unread structure. The data model is far richer than what the UI shows — reactions, threads, attachments, edit/delete, and presence status are all *modeled* but never *rendered*. The core tension: this is not a greenfield build and it is not a data problem. It is a **presentation and interaction-design gap on top of a solid spine**. The naive "just add features" approach would bolt reactions and threads onto a layout that was never designed to carry them; the work is to rebuild the rendering layer to the standard set by Slack/Discord/Zulip while keeping the schema, service, and hooks intact. + +## Executive Summary + +**The headline finding: xNet already modeled a modern chat app and then rendered ~30% of it.** Reading the code, the data and service layers are in excellent shape and the missing pieces are almost entirely in the React presentation layer: + +- `ChatMessageSchema` already has `inReplyTo` (threads), `attachments` (files), `edited`/`editedAt`, `redacted` (soft delete), structured `mentions`, `tags`, and `links` (`packages/data/src/schema/schemas/chat-message.ts`). +- `ReactionSchema` already supports `emoji` reactions with a reactor, and `useReactionCounters` already loads and toggles them (`packages/react/src/hooks/useReactionCounters.ts`) — but **no message in `ChannelChat` renders a single reaction**. +- Presence already carries `status: 'active' | 'idle' | 'dnd'`, an `avatar`, and typing indicators (`packages/comms/src/presence/types.ts`) — but the roster renders names as plain text and the status dot is never shown. +- `@tanstack/react-virtual` is **already a dependency of `apps/web`** (`apps/web/package.json`) and unused by chat, which today scrolls a plain `
    ` and will choke on long histories. +- `packages/ui/src/theme/motion.css` already ships the exact keyframes a premium chat needs — `slide-in-bottom`, `scale-in`, `fade-in`, `shimmer`, `pulse-subtle` — so the "fancier animations" ask needs **zero new dependencies**; framer-motion is not in the tree and is not required. + +So the recommendation is **Option C: rebuild the presentation layer, keep the spine.** Extract a small set of reusable comms-UI primitives (`MessageList`, `MessageGroup`, `HoverToolbar`, `ReactionBar`, `Composer`, `PresenceDot`, `ThreadPane`), drive them from the existing hooks and service, and bring the surface up to the cross-app grammar that Slack, Discord, Teams, and Zulip all share: grouped avatar rows, hover toolbars, reaction pills, unread dividers, date separators, jump-to-bottom, threads in a right pane, and polished CSS micro-interactions. Keep the structured-pill composer (it is *better* than parsed text for a knowledge graph) and evolve it. Adopt Slack-style flat-with-threads now because it matches `inReplyTo` exactly, and design the header to admit an optional **Zulip-style topic lane** later as the long-term differentiator for async, knowledge-graph-native conversation. + +## Current State In The Repository + +### The surface as it exists today + +```mermaid +flowchart LR + Rail["Rail
    Chats icon"] --> Sidebar + subgraph Sidebar["ChatsPanel (left panel)"] + S1["3 fixed sections:
    Channels / Voice / DMs"] + S2["mention + occupancy badges"] + S3["inline create forms"] + end + Sidebar --> Main + subgraph Main["ChannelView → ChannelChat"] + M1["h-9 header:
    icon + name + topic + roster + call"] + M2["plain ul message list
    text-xs rows, no avatars"] + M3["typing line"] + M4["textarea composer
    @ # [[ pickers"] + end + Main -.->|"missing"| Right["(no right pane:
    no threads, members, pins, search)"] +``` + +**Sidebar** — [`apps/web/src/comms/ChatsPanel.tsx`](apps/web/src/comms/ChatsPanel.tsx) renders three hard-coded sections (`Channels`, `Voice rooms`, `Direct messages`). Rows are 12px text buttons with a Lucide kind-icon, a `◉ N` occupancy badge, and a mention-count pill. There is no workspace switcher, no custom/collapsible sections, no favorites/starred, no search, no presence dot on DMs, no unread bolding, and no last-message preview. Channel creation is an inline `name` input only — no topic, no privacy, no member picker. + +**Header** — [`apps/web/src/comms/ChannelView.tsx`](apps/web/src/comms/ChannelView.tsx) is a 36px-tall (`h-9`) bar: kind icon, name, topic, and `here: alice, bob` roster as plain text, plus `CallControls`. No avatar stack, no member count, no pin/search/info actions, no topic editing. + +**Message list + composer** — [`apps/web/src/comms/ChannelChat.tsx`](apps/web/src/comms/ChannelChat.tsx) is the heart of the surface and is doing a lot already: + +- `MessageRow` (lines 157–200) renders `
  • ` with author name, a monospace `formatTime` timestamp, an `(edited)` tag, and the body via `LinkifiedText`. Mentions/tags/links render as chip rows. Per-message `MessageActions` (report/sensitive) sits in the row, revealed by the `group` hover. +- `MessageList` (lines 204–261) is a plain `
      ` — **no virtualization**, **no grouping of consecutive messages**, **no date separators**, **no "new messages" divider**. +- Scroll-to-bottom is a blunt `useEffect` on `messages.length` that always jams to the bottom (lines 524–526) — it will yank the viewport away from a user reading history. +- The composer (lines 667–719) is a 2-row `