web-ui: browse + new-chat palettes and sidebar chrome polish - #558
Open
evebouf wants to merge 6 commits into
Open
web-ui: browse + new-chat palettes and sidebar chrome polish#558evebouf wants to merge 6 commits into
evebouf wants to merge 6 commits into
Conversation
added 6 commits
August 16, 2026 23:50
Adds the Browse and New chat command palettes with shared grid keyboard
navigation, and cleans up the sidebar chrome around them.
Palette titles ("Browse", "New chat") now use the same type as the tile
labels they sit above — 14px, normal weight, foreground colour — instead
of the 11px semibold muted treatment, so the header reads as part of the
same system rather than an eyebrow label.
Sidebar:
- Selected chats use the same tint as hover (foreground 4%). The 9% mix
read as too heavy against the light sidebar.
- The project chevron and the folder/channel/group glyph share one 14px
slot: the glyph shows at rest, the chevron cross-fades in on hover or
focus, and a collapsed group shows the chevron persistently. With the
indent rail tightened, chat titles start 10px further left and project
rows with a glyph gain 23px.
- Every sidebar icon button — project options, new chat, archive,
conversation options, sidebar collapse — now uses the app's floating
tooltip instead of the browser's native title bubble, and shares one
hover treatment (--secondary fill, foreground icon). The conversation
kebab and the sidebar toggle gained accurate aria-labels in the
process; the toggle's was previously hardcoded to "Hide sidebar" even
while collapsed.
- The new-chat tooltip drops the project name ("Start a new chat"); the
aria-label keeps it, since a screen reader has no row context.
Hovering anything with a `title` produced the OS bubble — a second, slower, unstyled tooltip sitting next to our own. Every one of the 88 sites across the web UI now either drops the attribute or routes through the floating tooltip. The plumbing is a `tip()` lit element directive in tooltip.ts, so a call site is one binding rather than four event handlers. It wraps attachTooltip/detachTooltip, which split.ts uses directly for the dockview tab element it does not render through lit. The four hand-written handler sets added earlier collapse into it. Three kinds of site, treated differently: - A title that merely repeated visible text is gone, not converted. The nav rows are the exception: their labels are display:none in the collapsed rail, so they keep a tooltip while collapsed and gain an aria-label, and toggling the sidebar now re-renders the nav so the tooltip tracks the state. - Icon-only controls get tip() plus an aria-label where the title had been carrying the accessible name on its own — attach files, send, view pasted text, remove attachment, refresh conversations. - Truncated or abbreviated text (queued message, row context, commit SHA, approval command, skill description) keeps its full text on hover through tip().
Brand mark is now an image: the ship painting fills the 22px tile via a sized background-image. The earlier `content: url()` approach rendered the JPEG at its natural size and let overflow clip it, so only the top-left corner (sky) showed. Orgs that set `branding.mark` still get their letter — `--brand-mark` defaults to `none`, and the pseudo-element covers the image with the accent when a mark is injected. Wordmark moves to an old-style serif so it reads as a brand rather than UI chrome. Aligned the brand row to the nav: mark centre and wordmark left edge now match the nav icons and labels exactly, and the gap under the header equals the row-to-row gap. Chrome: "Sessions" and "Browse" drop their uppercase transform, the Home row never renders as selected, a divider closes the quick-nav block, the search icon leaves the Sessions header, and the personal group drops its redundant person glyph. The project + gets the app's own tooltip instead of the browser's title bubble. Archived's count adopts the project count's size through one shared rule so the two can't drift. Selection is background-only: sidebar chat rows no longer bold their title and browse tiles no longer draw a border. Palettes get roomier padding. The top bar drops the "New chat" placeholder and the tooltip that echoed it; a real title still gets one, since it truncates.
The composer's Effort/Model/Harness popovers shouted their headers in 11px uppercase with letter-spacing while the Browse modal titles its palette in plain 14px foreground text. Two treatments for the same thing; keep the calmer one and drop .menu-title's weight, tracking, caps, and muted colour. The Skills and context-filter popovers share the class and follow suit. The sidebar group labels carried the same emphasis for no reason — Personal and Archived are destinations, not headings — so they lose their 600 weight and Archived its tracking. The row actions were three glyph sizes across two rows that sit under the same hover: the project + at 14, both option menus at 17, archive at 15. Settle on 15 everywhere; the 26px buttons and hit targets are untouched.
The pulsing blue dot that marked a working chat grew a box-shadow ring and
flashed its opacity on a 1.6s loop — two animated properties fighting for
attention in a 30px row. It becomes a scrolling swell wave: one path, one
transform, same blue. `syncWorkingPulse` had to change with it. It bailed on
`instanceof HTMLElement`, and an SVG is not one; the animation also lives on
an inner <g> rather than the element the ref lands on, so every wave would
have started at its own phase. It now takes any Element and pins
`getAnimations({ subtree: true })`, so the marks stay in step the way the
dots did.
The same wave replaces the chat-loading spinner. Its <style> block moves out
of the SVG into shell.css — inline styles would be re-parsed on every lit
render and duplicated per instance — and the viewBox is cropped to the band
the stroke actually occupies so a row-sized mark isn't mostly empty space.
Narrowing crops the viewBox rather than squeezing the width, which would
shorten the wavelength and read as a different wave.
Chats-page rows were double-padded: `.chat-row { padding: 0 }` is meant to
hand padding to the inner anchor, but `.list-row`'s 12px is declared 650
lines later at equal specificity and won, stacking 44px of vertical padding.
Scoping it to `.list-row.chat-row` lets the intended zero land — 66px rows
become 42px. Hover and selected painted solid `--secondary`, a light slab
that sits wrong in dark mode; both now use the sidebar's selected token, a
4% mix of --foreground that inverts per theme.
Sidebar: the footer avatar is an image rather than initials, the day
separators above the session list are hidden, the indent rail beside a
project's children is gone, and the right-edge inset drops from 29px to a
uniform 22px across the collapse toggle, project +, and Web-only switch.
knip has been failing the Lint job: the tooltip and settings refactors left behind exports with no consumers. Three are still used inside their own module and only lose the keyword — showTooltip and detachTooltip back the tip() directive and attachTooltip, placeMenuPopover backs toggleFormMenu. SEARCH_HOTKEY_LABEL has no caller at all now that the sidebar's search row carries no hotkey hint, so it goes; isMac stays for the ⌘K binding and the palette's footer hints.
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.
Adds the Browse and New chat command palettes with shared grid keyboard navigation, and cleans up the sidebar chrome around them.
Palettes
browse.ts,new-chat.ts,grid-nav.ts— the two palettes plus the arrow-key grid navigation they share.Their titles now use the same type as the tile labels beneath them (14px, normal weight,
--foreground) instead of an 11px semibold muted eyebrow, so the header reads as part of the same system.Sidebar
foreground 4%). The old 9% mix read as too heavy against the light sidebar. Trade-off worth a look: a selected row is now visually identical to a hovered one, so selection only reads when the pointer is elsewhere.titlebubble, and share a single hover treatment (--secondaryfill,--foregroundicon) via the base.session-menu-btnrule.title, so removing it would have left it unlabelled — it now hasaria-label="Options for <chat>". The sidebar toggle'stitlewas hardcoded to "Hide sidebar" in markup and only corrected later by an imperative updater; label derivation now lives in onesidebarToggleLabel()helper, so the tooltip says "Show sidebar" when collapsed.aria-labelkeeps it — a screen reader user has no visual row context to tell those buttons apart.Verification
npm run typecheckand the full web-ui suite (556 tests) pass;eslint plugins/web-uiis clean.Not yet done, and worth knowing before this lands:
/dev-instanceand attach before/afters.One specific thing to eyeball:
--secondaryisoklch(0.97 0 0), lighter than a hovered chat row (~0.945). In the project header that fill sits on an untinted background and reads as a subtle darker chip, but on a chat row — itself tinted while hovered — the icon button may read as a lighter patch instead of a darker one. If it looks inverted, the fix is a row-scopedcolor-mix(in srgb, var(--foreground) 9%, transparent), same size and shape, preserving the direction of contrast.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.