feat(slark): channel header tabs + topic detail side panel#37
Open
feat(slark): channel header tabs + topic detail side panel#37
Conversation
added 30 commits
April 20, 2026 18:49
The slark app maps --slark-color-nav-active to --color-brand-primary, which means selected channels, active activity-bar icons, runtime tabs, agent rows, and more all render with a saturated teal background. This over-uses brand-primary — AGENTS.md reserves that color for links, focus rings, accented badges, and brand emphasis, not large surface fills. Switch to the brand-subtle wash pattern (same pair used by Plus tier badges: pale brand background + brand-primary text): --slark-color-nav-active → var(--color-brand-subtle) --slark-color-nav-active-fg → var(--color-brand-primary) --slark-color-nav-active-soft / -muted rebased on brand-primary All 11 call sites across ChatSidebar, ActivityBar, Sidebar, RuntimesSidebar, and AgentsSidebar pick this up automatically via the tokens. The ActivityBar's 3px selection indicator (bg-nav-active-fg) becomes brand-primary on a brand-subtle row — clear brand accent on a soft wash. Also refactor the one call site where the nav tokens were being abused as a primary-button style: the "Add" button for detected runtimes now uses <Button size="xs"> (the proper default filled variant) instead of hand-rolling bg-nav-active / text-nav-active-fg. No new tokens, no changes to ui-web. Made-with: Cursor
Based on review feedback: the brand-subtle wash still read as "blue selection" at a glance. Switch to the restrained Slack / Cursor pattern — neutral surface-3 fill + text-heading (near-black) + font-semibold — so selection is communicated by weight and text contrast instead of color. Zero brand tint in the selected row. --slark-color-nav-active → var(--color-surface-3) --slark-color-nav-active-fg → var(--color-text-heading) --slark-color-nav-active-soft → color-mix(text-heading 18%, transparent) --slark-color-nav-active-muted → color-mix(text-heading 78%, transparent) Also drop the 3px ActivityBarIndicator on active items: with a solid accent fill gone, the indicator was redundant decoration. Primary-action buttons (unread badges in ChatSidebar, brand-colored CTAs like the runtime Add button migrated in the previous commit) are unaffected — they keep using --color-brand-primary / default Button variant per AGENTS.md. Made-with: Cursor
Codifies the lessons from the slark nav color + density fixes into AGENTS.md so future work (AI agent or human) picks the right tokens on day one. Rules added under "Layout conventions": - Compact nav list density: px-2 container, 0 row gap, rounded-md, pl-2 pr-2 py-[3px] rows (~24px height), px-2 pt-3 pb-1 section headers — matches Slack / Cursor / Discord. - Selection row background: neutral surface-3 + text-heading + font-semibold; never fill persistent selection with brand/accent/ semantic tokens. Includes guidance for app-level CSS vars and an explicit exception clause for transient "spotlight" states. Slark fixes applying the new rules: - ChatSidebar: container px-2, rows rounded-md with no inter-row gap, unified "Add channels" affordance with list rows, section header aligned with list padding. - ChatView: use bg-surface-1 (pure white / --card) for the chat content panel instead of bg-background (surface-0 = page canvas, slight gray). Chat is a content panel, not the page shell. Made-with: Cursor
…dges Previous py-[3px] + 16px icons + 18px unread badge was too tight for a 13px label — rows felt cramped even with no inter-row gap. Back off to Slack's breathing room while keeping the 0-gap rhythm. ChatSidebar rows: - py-[3px] → py-[5px] (row height ~24px → ~28px) - icon h-4 w-4 (16px) → h-3.5 w-3.5 (14px) - unread badge h-[18px] min-w-[18px] px-1.5 → h-4 min-w-4 px-1 AGENTS.md "Compact nav list density" updated to match: - Row padding pl-2 pr-2 py-[5px], 14px icon, ~28px row height - New rule for unread/count badge sizing (h-4, compact 16px) - Keeps container px-2, 0 row gap, rounded-md, section header spec Made-with: Cursor
The section header already has a "+" icon button that opens the create-channel dialog. Having a second "+ Add channels" row at the bottom of the list is redundant affordance and adds visual noise in the compact nav density. - Remove the bottom "Add channels" Button row from ChatSidebar - Drop now-unused `chat.addChannels` i18n key (en-only, no zh parity) - Section header "+" button remains the single entry point for creating a channel, which is the Slack / Cursor convention Made-with: Cursor
py-[5px] still felt cramped per user feedback. Commit to Discord- density instead of trying to split the difference. - py-[5px] → py-2 (8px vertical) : row height ~28px → ~32px - gap-2 → gap-2.5 : 2px more icon-to-label breathing - AGENTS.md compact nav list spec updated to match (32px row height) Made-with: Cursor
The UI chrome (搜索 / 频道 / 设置) was already Chinese via i18n, but the mock channel names, descriptions, and workspace name were still hardcoded English, creating a jarring mix in the sidebar demo. Localizes the surfaces that show up in the nav list: - Workspace: Acme Engineering → 星云工程 - ch-welcome: welcome → 欢迎 (+ Chinese description) - ch-showcase: design-showcase → 设计展示 (+ Chinese description) - dm-agent-1: CodeBot → 代码助手 - dm-agent-2: DesignReviewer → 设计评审 Keeps user names (Alice Chen / Bob Kim / Charlie Park / Diana Wu) and agent/template/skill content + mock message bodies in English — those are out of scope for this pass and can be done in a follow-up if a fully localized demo is desired. Made-with: Cursor
Previous spec said 0 row gap on the assumption that rounded selected bg already separates rows. But when two adjacent rows are both filled at the same time (hover + hover, focus-ring + hover, unread-bg + hover), the fills physically touch and look like one smudged block — visually reported by user on welcome (focused) and design-showcase (hovered) row pair. New rule: space-y-0.5 (2px) is the minimum gap that prevents any two adjacent filled states from butting into each other, while staying tight enough to read as one coherent list (not a chain of disconnected pills). - ChatSidebar: wrap row lists in <div className="space-y-0.5"> - AGENTS.md "Compact nav list density": change row gap rule from 0 → space-y-0.5, with rationale about adjacent filled states. Made-with: Cursor
Two issues reported on the channel sidebar in zh-CN locale: 1. "频道" section header looked awkward because the styling (uppercase tracking-wider) is inherently English-first. CJK has no case, so text-transform: uppercase is a no-op, and the wide letter-spacing looks wrong on CJK glyphs. 2. Only pb-1 (4px) between the section label and the first row, which made the label feel like it was touching hover/selected backgrounds below it. Fixes: - Hardcode "Pinned" / "Channels" as English in ChatSidebar (matches Slack / Cursor / Linear convention in CJK locales — decorative category labels stay English regardless of app locale). - Bump section header padding: pb-1 → pb-2 (8px) so the label has clear separation from the first filled row below. AGENTS.md "Compact nav list density" updated with two new rules: - Section header language convention (decorative uppercase labels stay English across all locales, with rationale + escape hatch). - Section header spacing corrected to pb-2. Made-with: Cursor
… auto-translated Reverts commit 058b785. That commit localized channel names, the workspace name, and agent DM names to Chinese to align with the zh-CN UI chrome. On user review, this was the wrong call: These fields are user content (channel names, workspace names, and DM conversation titles are created by users and persist across locales), not UI chrome. An IM app should never mutate user-authored strings based on the viewer's locale — the name you saved is the name everyone sees. Reverted: - Workspace: 星云工程 → Acme Engineering - ch-welcome: 欢迎 + Chinese description → welcome + EN description - ch-showcase: 设计展示 + Chinese description → design-showcase + EN - dm-agent-1: 代码助手 → CodeBot - dm-agent-2: 设计评审 → DesignReviewer UI chrome / i18n keys already correctly show Chinese strings in zh-CN locale; that layer is unchanged. Made-with: Cursor
… 24px Section header at 10px was borderline unreadable at sidebar width, and the "+" button at h-4 w-4 (16px) had a hover fill too small to read as a real button (below accessible tap-target minimum too). - Section header: text-[10px] → text-[11px], Pin icon h-3 → h-3.5 - Create-channel "+" button: h-4 w-4 rounded → h-6 w-6 rounded-md, plus icon h-3 → h-3.5, giving a proper 24px hit area and a visible rounded hover fill matched to the list row radius. AGENTS.md "Compact nav list density" updated with: - Section header font size rule (11px, with rationale vs 10px) - New rule for section header affordance buttons (24px rounded-md with 14px icon, not 16px square) Made-with: Cursor
Two related fixes on the channel sidebar: 1. Search input was at px-3 (12px inset) while the list container below was at px-2 (8px inset). The 4px mismatch made the search look like a different component from the list it filters — the selection fill on "welcome" row visibly extended past the search's right edge. Align search wrapper to px-2. 2. Search input had border-transparent at rest, which made it read as a passive pill rather than an editable control. Per AGENTS.md border tokens, a sidebar search should show --color-border-subtle (rgba 0 0 0 / 0.06) — just enough to assert "this is an input" without shouting. Focus state unchanged (border-transparent + ring-1 ring-nav-ring). AGENTS.md "Compact nav list density" updated with a new rule for top-of-list search inputs: match px-2 with the list container, and always show border-border-subtle at rest, not border-transparent. Made-with: Cursor
The leftmost ActivityBar was a solid bg-nav-surface with no border, reading as a flat slab next to the white chat panel. Adopt the same frosted-glass recipe the rest of the codebase uses for floating chrome (nav bars, landing headers, floating toasts): translucent surface + backdrop-blur + subtle border. ActivityBar class change: border-r-0 bg-nav-surface → border-r border-border-subtle bg-nav-surface/75 backdrop-blur-md Keeps the nav-surface gray character (not switching to a new color), just makes it 75% alpha with medium blur and a hair-thin right border to separate from the white chat panel. AGENTS.md new section "Frosted glass (translucent surfaces)" under Design & styling > Elevation & shadow: - Canonical recipes for stacked nav vs sidebar/activity bar - Alpha range (70–92%) and rationale for both bounds - Always-pair-with-backdrop-blur-md rule + when to deviate - Always-add-subtle-border rule (prevents bleeding into neighbors) - Note on Electron vibrancy: classes work with or without, so apply them proactively — the effect lights up automatically if vibrancy is configured later. - Explicit anti-pattern: do not use on content panels (chat body, page cards) — those must stay fully opaque for readability. Made-with: Cursor
…ntent canvas
Wire up actual desktop-blur frosted glass on the macOS ActivityBar instead of
the previous CSS-only treatment that had nothing to blur through.
- main/index.ts: enable `vibrancy: "sidebar"` + `visualEffectState: "active"`
on macOS; drop the opaque `backgroundColor` so vibrancy can show through
(non-mac still sets `#fafafa` for a no-flash startup)
- renderer chain goes transparent so vibrancy reaches the chrome:
- index.html body: drop `bg-background`
- globals.css: `html / body / #root { background: transparent }`
- AppLayout root: drop `bg-background`
- AppLayout `<main>` gets `bg-surface-1` so every routed view has a solid
white content canvas (Team / Settings / Runtimes were missing bg and
silently showed vibrancy through as a "fake frosted" bug)
- ActivityBar: `bg-nav-surface/55` → `bg-nav/80` — the surface-2 token is
gray, which read as "dim" at low alpha; surface-1 (white) at 80% gives
the lightly-frosted-white look that matches Slack / Cursor / Finder
Made-with: Cursor
…titles Redesign the channel header into a single unified chrome block that replaces the old two-row title-plus-toolbar layout: - Unified header: title row (`h-9`) + tabs row share one `border-b` block with no divider between them, reading as one chrome surface instead of two stacked bars - Members as inline chip: Users icon + count sits immediately right of the channel name (not pushed to the far right), and opens AddMembersDialog on click. Replaces both the old right-aligned UserPlus button and the separate "Members" tab - Tabs: `Messages / Files / Artifacts` (Members removed since it's now the chip). Compact size — `h-6 px-2 text-[12px]` triggers with 12px icons — so they sit comfortably under the 15px title. Labels hardcoded English across locales, matching the CHANNELS / PINNED convention - Files + Artifacts tabs render EmptyState placeholders (hardcoded English strings — the previously-added chat.tab.* i18n keys were never wired after moving to hardcoded labels and are removed) - Drop channel description rendering entirely from the header — it was redundant with the title for most channels and stole horizontal space from the members chip - Hover fill on title + members buttons: `hover:bg-accent` → `hover:bg-surface-2`. Tailwind's `bg-accent` resolves to the raw brand teal, not our design-system `--color-accent` near-black — the old class flooded the whole row with teal on hover - Rename welcome channel: "welcome" → "Welcome to Nexu!", clear description Made-with: Cursor
Capture the new rules that came out of the Slark chrome + chat-header pass so the next contributor doesn't rediscover them: - Frosted glass: always start from surface-1 (white), never surface-2 (gray); tighter 75–85% alpha over native vibrancy; full Electron integration recipe (vibrancy config, transparent parent chain, opaque content panels as the inverse gotcha) - Row-level hover fill: ban `hover:bg-accent` (resolves to brand teal), prefer `hover:bg-surface-2`; grep new code for this before landing - Tab labels stay English across locales for page-level navigation tabs (chat header, settings, skills) — same convention as decorative uppercase category labels - Compact tab size inside a chat/channel header: `TabsList h-7 p-0.5`, `TabsTrigger h-6 px-2 text-[12px]`, `size-3` icons - Unified chat/channel header: title row + tabs row share one border-b container, no divider between them Made-with: Cursor
Product changes - Default /chat route now lands on ch-showcase so the demo conversation is visible at launch; mock data adds a "Yesterday" system join EventNotice, a kickoff message, and an @mention-me message so highlighted rows and consecutive-message grouping are exercised out of the box. - Unify every rich card's width to w-full max-w-[640px] (code, diff, tool-result, action, approval, progress, topic) so the feed has one card lane and cards are instantly distinguishable from chat bubbles. - ApprovalBlock, ActionCard, ProgressBlock retuned to design-system semantic tokens (info / success / warning / error + their subtle variants) and ui-web primitives (Button, Progress replaced with checklist) — no more hardcoded blue/green/red/amber. - Code and diff blocks collapse into a compact single-line pill (Cursor style) via a shared CollapsedContentRow; clicking expands via the existing ContentDetailOverlay. Keeps the chat feed scannable. - ProgressBlock rebuilt Cursor-style: drop the bar and the colored step dots, switch to Check / Loader2 / Circle icons in monochrome with 12px step spacing; "3 / 5" counter replaces the big percentage. Status color is carried purely by label styling (muted + strikethrough for done, heading for active, tertiary for pending). - TopicCard: brand-tinted border on white (not a brand wash) so the status pill owns the semantic color; hover deepens the border and adds shadow-sm for affordance. Prevents duplicate "brand flood" across four stacked topic cards and unblocks the highlighted-mention row styling from fighting the card surface. Topic → side-panel interaction (new) - Clicking a topic card now opens a persistent right-side detail panel instead of doing nothing. Four tabs: Artifacts / Members / Files / Pinned, matching the storybook chat-side-panel prototype (ca6c295). - Layout is push (not overlay): ChatView wraps the Messages tab in a flex row and animates the panel column width 0 → 380px over 200ms (ease-standard). No backdrop / scrim — the message list reflows. - State lives in ChatView and resets on channel switch. A dedicated onTopicOpen callback threads through MessageList → ContentBlocks → TopicBlock; it is intentionally separate from onExpand (which drives the fullscreen ContentDetailOverlay for code / diff / image) because topics are tracked threads, not transient previews. - TopicDetailPanel composes existing ui-web primitives (DetailPanel, Tabs, EmptyState) — no new primitives added. Dev DX - apps/slark/electron.vite.config.ts aliases @nexu-design/ui-web to packages/ui-web/src/index.ts (matching storybook's main.ts) so edits to ui-web primitives reflect instantly via HMR. Without this the renderer consumed the stale dist bundle from package.json's "main": "./dist/index.js", which silently blocked newly-added Tailwind utility classes in primitives from reaching the DOM even though Tailwind generated CSS for them. Made-with: Cursor
The right-side TopicDetailPanel's primary tab was a placeholder
"Artifacts" surface with a single summary card. What people expect on
a topic panel is the reply conversation itself — with inline images,
link previews, agent messages, and the originating opening context at
the top. This patch makes that happen.
Data
- Extend the topic content-block type with an optional `thread`
(`TopicThreadMessage[]`) so a topic can carry canned replies. Each
reply is { id, author, initials, createdAtLabel, text?, image?,
link?, isAgent?, accent? } — pre-baked display strings for mock
data; no timestamps, no driver logic.
- Add canned threads to three topics in ch-showcase:
* topic-1 (Billing retry storms — NEEDS REVIEW): 4 replies, includes
a Datadog dashboard link and a GitHub PR link; the fourth reply
is from the "Coder" agent.
* topic-2 (Landing redesign — ACTIVE): 3 replies, includes an
inline hero-exploration image and a Linear issue link.
* topic-3 (Auth rotation — DONE): 3 replies, includes a Notion
report link.
Panel UI
- Replace the "Artifacts" tab with a **Thread** tab (new default).
Renders the reply list with a small local component instead of the
full ChatMessage primitive — at 380px wide the panel needs tighter
padding, smaller avatars, and a custom link-card style, and
overriding ChatMessage for all of that would be more brittle than
a purpose-built reply row.
- If `topic.preview` exists, render it as an "Opening context" card
pinned above the replies, mirroring how Slack / Linear surface the
originating message at the top of a thread view.
- Agents in the thread get a Bot glyph avatar on `bg-brand-subtle`,
a green "Agent" badge, and the assignee accent color applied to
their author name — same visual language as the main chat feed.
- Inline images use the shared `ImageAttachment` primitive; links
render as a compact preview card (icon + title + description +
host) that opens in a new tab.
- Files tab now aggregates images and links across the thread
instead of showing EmptyState — images render as a 2-col grid,
links as a vertical list of the same preview card used inline.
Falls back to EmptyState when the thread carries nothing.
- Tab order reset to Thread / Files / Members / Pinned; Artifacts
was dropped because it duplicated Files once threads carry the
real payload.
Made-with: Cursor
File / image / voice / video attachments now share a single 360px frame so stacked attachments in a chat feed line up cleanly instead of wobbling between 320 / 340 / 360. ImageGallery keeps its 480px grid. Adds a chat-feed width-tier rule to AGENTS.md (card tier 640px, attachment tier 360px) so future primitives do not drift. Made-with: Cursor
Voice notes used to always expand their transcript below the waveform, which made a channel of voice recaps feel heavy. Now the transcript is hidden by default and a small captions icon fades in on hover (top-right of the waveform row). Clicking toggles the transcript inline; the button stays visible + active-styled while expanded, and ARIA aria-expanded / aria-label describe the state. Callers that want the old behaviour can pass defaultTranscriptOpen. Made-with: Cursor
…eight
Three follow-ups from the IM showcase review:
1. Play button hover no longer flips to the brand accent fill (which
read as a jarring teal disc on a light card). It now matches the
video attachment's language — stable background, subtle scale-110
on hover, same transition timing.
2. The hover-only captions icon was ambiguous. Replace it with a
plain-text toggle rendered BELOW the card ("Show transcript" /
"Hide transcript" with a rotating chevron). Always visible when a
transcript is present, so the affordance is obvious without
hunting.
3. Waveform bars were too tall for a compact feed. Shrink the bar
container from h-7 (28px) to h-5 (20px), halve the default
waveform heights, and drop the bar offset from +6 to +3. The
CustomWaveform story values are rescaled to match the new range.
Made-with: Cursor
The waveform is purely ornamental — it signals "this is audio" and nothing more. The previous h-5 bar row still read as content. Drop the bar container to h-4 (16px), narrow each bar from 3px → 2px, halve the default waveform heights, and reduce the render offset from +3 to +2 so the tallest bar sits at ~9px. Rescale the CustomWaveform story values to match the new range. Made-with: Cursor
Continuing the "waveform is decoration, not data" direction. Shrink the bar container from h-4 (16px) to h-3 (12px), cap default waveform values at 4 so the tallest bar renders at ~6px, and rescale the CustomWaveform story to match. Made-with: Cursor
Consolidate the Coder agent's five sequential artifacts (retry.ts code, client.ts diff, pnpm-test action, tool result, staging-rollout progress) into a single `agent-run` content block so the chat stays quiet. The renderer shows only the current (last) step expanded; earlier completed steps live behind a "Show N earlier steps" toggle. The approval card that follows stays in its own message on purpose — `AgentRunStep["block"]` narrows the union to code/diff/action/tool-result/ progress, so approval and topic blocks cannot be smuggled inside a run. Folding an ask into a "quiet" module would hide the thing that actually needs human attention. - types: add `agent-run` variant + `AgentRunStep` interface - mock: merge sc-8..sc-12 into one `sc-agent-run-1` message with 5 steps - ContentBlocks: add `AgentRunBlock` + `AgentRunStepRenderer`, wire the `agent-run` case into the switch Made-with: Cursor
The outer agent-run container was on surface-1 with a border, and its nested work cards (code, diff, action, tool-result, progress) were ALSO surface-1 with borders — so the two concentric rectangles read as a redundant double frame. Tinting the shell with surface-2 and dropping its border lets the white inner cards visibly 'sit inside' the run without competing strokes. Bumped the 'Show earlier steps' toggle hover to surface-3 so it still pops against the new surface-2 shell. Made-with: Cursor
A solid outlined circle for pending/not-yet-started steps can read as 'selectable' or 'actionable'. A dashed ring (as Cursor uses) more clearly communicates 'placeholder for a future step' and visually pairs with the strikethrough + muted label already applied to unreached items. stroke-dasharray is set inline because lucide forwards style to the root <svg>, and SVG stroke-dasharray inherits down to the child <circle>. Made-with: Cursor
The two-step flow (details → add members) always defaulted to "select
everyone" and the member picker screen was redundant with the separate
AddMembersDialog reachable from a channel. Collapsing to one step
removes a click, a progress bar, and a whole screen of UI the user
mostly clicked through.
On create we now seed membership with all workspace users + all agents
(same default as before); owners can prune from the channel members
panel afterwards.
Copy is hardcoded English — this product surface is English-only, and
the tokenised subtitle ("Step 1 of 2 — channel details") was the
noisiest side of the old dialog.
Made-with: Cursor
DialogDescription was rendering at text-base (13px per our token scale) which reads chunky for a secondary supporting line, especially with CJK. The spec puts dialog descriptions (and general hint / supporting text) at text-sm (12px), which also matches shadcn's upstream default. Applying it at the primitive so every dialog benefits instead of each caller overriding className. Made-with: Cursor
Two related fixes surfaced by the delete-channel confirm screenshot: 1. ui-web DialogTitle used leading-none, which on CJK glyphs cropped against the description underneath (no natural descender space). leading-tight (1.25) gives the title a few px of breathing room so the title/description gap reads correctly under all scripts while still feeling compact enough for Latin. 2. Slark ChatSidebar's channel-delete ConfirmDialog was still pulling copy through i18n. Matches the CreateChannelDialog treatment — this product surface is English-only, so hardcode the strings here too instead of having English copy bounce through the zh locale. Made-with: Cursor
…added) Previous commit 0e7cf0a slipped in four unrelated files that should have stayed untracked — a .claude skill submodule, two local .cursor hook artefacts, and a personal analysis markdown. None of them belong to the slark/ui-web surface. Removing from the index while keeping the working-tree copies. Made-with: Cursor
added 12 commits
April 21, 2026 12:02
Per the design spec, primary/confirm actions trail right and secondary actions sit to their left. The approval card had Approve on the left and Reject on the right — mirrored from the convention. Both keep flex-1 so the row still reads as 'pick one of two equal paths' rather than a weighted CTA. Made-with: Cursor
Four polish fixes to the message composer:
1. Send button promoted from a ghost Send icon to a circular accent-
filled ArrowUp — matches the Cursor composer. Three explicit states:
disabled (surface-3 fill + muted arrow, no text / nothing to abort),
ready (accent fill + white arrow, has text), and streaming
(accent fill + white stop square). One button, one footprint, three
meanings.
2. Stop works: clicking the stop square flips every in-flight reply
in the channel to isStreaming=false. simulateAgentReply's token
loop now re-reads the store each tick and bails out when the flag
is flipped, so further tokens stop being appended (cooperative
cancellation, no timer bookkeeping).
3. Placeholder copy is English and hardcoded: 'Message #channel' for
channels, 'Message {name}' for DMs — drops the useT lookup that
was routing through the zh locale.
4. Placeholder vertically centered by switching textarea padding from
py-1.5 (12px) to py-2 (16px) so the 20px line-box fills the 36px
collapsed height. Composer internal gap bumped from 0.5 (2px) to
2 (8px) so Attach and Send stop bumping shoulders.
Made-with: Cursor
The 'reacted' state was using brand-subtle + brand-primary text, which over-weighted emoji reactions in the feed — they read louder than the actual messages. Switching to surface-2 + text-primary keeps the reacted pill quiet while still clearly distinct from unreacted pills, and aligns the hover state with the reacted state so hovering foreshadows what clicking will do. Made-with: Cursor
… panel polish - New `lib/user-presence.ts` centralises presence→dot-class / label mapping so every call site agrees on green = online, yellow = away, gray = offline. Replaces ad-hoc lookups across the app. - `globals.css`: add `--slark-color-nexu-away` (warm yellow) and lift `--slark-color-nexu-offline` to 0.65 lightness so the gray dot reads clearly on the sidebar background. - `AgentsSidebar`: drop the `useT` indirection and hardcode English copy (teammate list is a product surface, not content). Rename the section from "People" to "Members"; widen the spacing below the search input; add a bottom-right presence dot overlay on each avatar; hold the Owner badge in `text-brand-primary bg-brand-subtle` regardless of row-selection state; shade member email / agent description with `text-text-tertiary` so the name keeps the emphasis. - `UserDetail`: remove the in-corner avatar status dot and move the status affordance below the name (dot + textual label) so the profile read order is Name → Status → Email → Runtime. Adopt the canonical workspace content-panel wrapper (`max-w-[800px] mx-auto px-4 pt-2 pb-6 sm:px-6 sm:pb-8`) so this panel shares left/right margins with Settings and Agent Detail. Drop Chinese copy in favour of English. Made-with: Cursor
- `SettingsView` > Workspace tab: remove the card-level "Workspace
details" title + description. The surrounding `PageHeader` already
reads "Workspace settings", so repeating a second heading in the
very next card just pushed the actual inputs down with no added
information.
- `Sidebar`: suppress the generic uppercase section label on the
Runtimes route. `RuntimesSidebar` owns its own header row ("Runtimes"
+ "N/M online" on a single line, indented to match the content) and
rendering both produced two differently-indented headers stacked on
top of each other.
Made-with: Cursor
… copy RuntimesSidebar: - Custom header with "Runtimes" + "N/M online" on a single line, left-aligned to content (px-3). - Add button swapped from filled black to outline (size="xs" variant="outline") — it was sitting at the same visual weight as primary page CTAs. - Installed / detected list rows render `RuntimeLogo` instead of generic Lucide glyphs, so Claude Code / Codex / Gemini / Pi show their actual brand marks. - "Detected on this device" always renders a single `RefreshCw` icon button on the right, so refreshing no longer swaps text ↔ button and causes horizontal layout shift. - Hardcoded English copy (drop `useT`). RuntimesView: - Hardcoded English copy (drop `useT`, `TranslationKey`, `statusLabelKeys` in favour of a simple inline map) — status pill reads Online / Offline / Error. - Runtime logo now sits inside the canonical logo tile — fixed-size `rounded-xl/2xl` surface chip with `border-border-subtle` and `bg-surface-1`, matching the `provider-settings` pattern. No more blue / teal logo backgrounds. - Optical-size helper (`logoOpticalScale` + `getLogoSize`) bumps the glyphs for Codex / Gemini CLI / Pi that ship with intrinsic padding, so every brand mark reads at the same perceived weight. - Install-guide cards refactored so the entire card navigates to docs (absolute-positioned `<a>` overlay) while the install command line is independently click-to-copy — new `InstallCommand` component with Copy / Check feedback. Jump icon switched to `ArrowUpRight` and aligned with the first line of the name. - Every `hover:bg-accent` / `bg-accent` in this view replaced with neutral `hover:bg-surface-2` or surface-2 + ring — `--color-accent` is near-black in light mode and turning it on as a hover state made the whole row look like the active/primary affordance. Made-with: Cursor
- Hardcode "Add workspace" and "Sign out of Nexu" (drop the `useT` keys for this menu — it's a product surface, not i18n content). - Remove the `DropdownMenuSeparator` between the existing workspaces and the "Add workspace" row. They're sibling affordances (same row shape, same tile leading slot), so splitting them with a divider implied a semantic break that doesn't exist. The separator before "Sign out" stays — that one does fence off a destructive action. - "Sign out" now follows the destructive-intent hover rule in AGENTS.md: neutral `text-text-primary` at rest (so the menu doesn't shout red every time it opens) and only swaps to `destructive/10` + `text-destructive` on hover / keyboard focus. Made-with: Cursor
…cent The circular send affordance was painted with `bg-accent` — that's the brand teal and it made the composer look like it had two competing brand moments (teal reaction pills had just been retired for the same reason). Swap to `bg-primary` / `text-primary-foreground` so the send button matches Button's canonical `default` variant (near-black fill) and reserve `--color-accent` for links and focus rings. Made-with: Cursor
`size="icon"` / `"icon-sm"` inherited the base class's `rounded-lg` (12px). For `icon-sm` (24px square) that's exactly half the width, so the hover fill rendered as a perfect circle. Pin both icon sizes to `rounded-md` (8px) per the design spec — controls live at `--radius-md`, only cards and panels use the larger `rounded-lg`. Made-with: Cursor
`--color-accent` is near-black in light mode. Using it as a *hover* background on outline buttons, ghost buttons, list rows, menu items, or cards produces a heavy filled affordance that reads as the primary action — directly conflicting with the "at most one accent-weighted action per group" rule. Sweep every slark call site to the neutral gray hover fill: - `ChatSidebar` pin/unpin context menu row → `hover:bg-surface-2`. - `MentionPicker` dropdown row → `hover:bg-surface-2`. - `AgentsView` agent card hover → `hover:bg-surface-2`. - `DevPanel` 5× state / user / runtime / workspace rows → `hover:bg-surface-2` (and dropped the `/50` opacity variant). - `ConnectRuntimeStep` runtime picker card hover → `hover:bg-surface-2`. Also expand the Color usage section in AGENTS.md with an explicit prohibition on `bg-accent` / `hover:bg-accent` / `/30` / `/40` / `/50` variants for hover states, pointing at `hover:bg-surface-2` (neutral), `rounded-lg hover:bg-surface-2` (dropdown / menu), and `hover:bg-destructive/10 hover:text-destructive` (destructive intent) as the sanctioned alternatives. Made-with: Cursor
…er release Phase 1 of PR #34 does not ship either of these two features; both continue to live on the dedicated feature branch `feature/chat-tabs-and-topic-panel` and will return in a follow-up release once the surrounding product scope is agreed. Surgically removed from this branch: - Channel header tabs (Messages / Files / Artifacts) — the chat header reverts to a single flat bar. The visual improvements that landed alongside the tabs work (Globe icon for channels, neutral `hover:bg-surface-2` title affordance, inline members chip with Users icon + count, no-drag on interactive elements, description suppressed from chrome) are *kept* — they were orthogonal wins and belong in phase 1. - Topic → right-side detail panel (Thread / Files / Members / Pinned) — `TopicDetailPanel.tsx` deleted; the `onTopicOpen` callback prop is unwound from `ChatView` → `MessageList` → `ContentBlockRenderer`; `TopicBlock` now renders as a read-only display card (still brand-tinted, still composable) with no click target. All topic card chrome, status pills, participant rows, preview text, etc. stay exactly as before — only the panel-opening interaction is deferred. Kept on purpose (orthogonal improvements that came with the same commits but are not part of the deferred features): - `MessageList` still highlights rows where the current user is `@mentioned` via `ChatMessage`'s `highlighted` prop. - `ContentBlocks` card-width unification, Cursor-style code / diff collapsing, monochrome progress steps, approval tone tokens — all untouched. - `TopicThreadMessage` type + `thread?` field on the topic block are intentionally preserved on the type side so mock data stays valid and the feature branch merges back cleanly later. Docstring updated to call out that it's dormant for now. Made-with: Cursor
Reintroduces the two chat-product features that were removed from the phase-1 PR #34 in 80ffbf4 so they can ship on their own review cycle. Channel header tabs (Messages / Files / Artifacts) - `ChatView` wraps the channel layout in `<Tabs>` with three surfaces: Messages (the live feed + composer), Files (EmptyState placeholder for now), Artifacts (EmptyState placeholder, reserved for future agent-output browsing). Tab labels are hardcoded English per the "tabs are orientation, not user content" convention that also governs the sidebar section headers. - Header chrome is a single unified border-b block — title row and tab row share one surface, no divider between them, so it reads as one piece of chrome instead of two stacked bars. - DMs intentionally keep the flat single-pane layout; tabs only render for `channel`-type channels. Topic → right-side detail panel (Thread / Files / Members / Pinned) - Clicking a topic card opens a persistent right-side panel instead of doing nothing. Primary tab is Thread (reply conversation with inline images + link previews); Files / Members / Pinned are secondary. - Layout is *push*, not overlay: the Messages tab's flex row animates a right column from width 0 → 380px over 200ms (ease-standard). No backdrop / scrim — the message list reflows. Closing keeps `activeTopic` until the width transition ends so the inner content doesn't flash empty mid-animation. - State lives in `ChatView` and resets on channel switch. The click path threads a dedicated `onTopicOpen` callback through `MessageList` → `ContentBlockRenderer` → `TopicBlock`; it is kept intentionally separate from `onExpand` (which drives the fullscreen modal overlay for code / diff / image) because topics are tracked threads, not transient previews. - `TopicDetailPanel` composes existing ui-web primitives (`DetailPanel`, `Tabs`, `EmptyState`) + reuses the `TopicThreadMessage` mock shape already on `types/index.ts`. No other changes vs the PR #34 tip: this branch is exactly `fix/slark-nav-active-brand-wash` HEAD + this one commit, so once PR #34 merges, the diff of this PR against `main` collapses to these two features alone. Made-with: Cursor
Deploying nexu-design with
|
| Latest commit: |
d55e078
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://cf2b6e44.nexu-design.pages.dev |
| Branch Preview URL: | https://feature-chat-tabs-and-topic.nexu-design.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces the two chat-product features that were intentionally deferred from the phase-1 PR #34:
Status / merge sequencing
main, the diff againstmainwill include all of fix(slark): neutral selection, compact nav density, white chat panel + codify rules #34's work; once fix(slark): neutral selection, compact nav density, white chat panel + codify rules #34 merges, the diff collapses to exactly one commit containing only these two features.Channel header tabs (Messages / Files / Artifacts)
Topic → right-side detail panel
Test plan
Made with Cursor