feat: comprehensive UI overhaul — theme, header, bubbles, sidebars, review page, launch screen - #54
Conversation
Replaces the minimal 4-item menu with a full macOS menu bar: - File: Open Folder (⌘O), Go to File (⌘P), Export Annotations - Edit: standard items + Find (⌘F), Find Next (⌘G), Find Prev (⌘⇧G) - Annotations: Add (⌘↩), Reload, Clear — with native icons - View: Command Palette (⌘K), Markdown Preview (⌘⇧M), Diff submenu - Review: Review Changes (⌘⇧R), Agent Feedback, Approve/Request Changes with status icons - Window: standard Minimize/Close All shortcuts align with existing in-app vim-style keybindings. Menu events route through Tauri emit → App.svelte listeners → runCommand/editorRef. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all gradient backgrounds with flat solid colors across panels, cards, popovers, and dialogs. Normalize panel sub-headers (FileTree, WorkspaceToolbar, AnnotationSidebar) to a shared min-height of 52px so the toolbar row aligns horizontally across all three columns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update surface, text, border, accent, shadow, and scrollbar tokens to use rgba-based opacity scales, establish accent tiers, and remove deprecated gradient tokens. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…w accent tokens to @theme - --view-active-border set to rgba(255,255,255,0.12) instead of transparent to preserve DiffModeToggle inset box-shadow active indicator - Forward --accent-active, --accent-badge-text, --accent-badge-border to @theme block for Tailwind utility access Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merge ReviewWorkspaceHeader (PR context + actions) and WorkspaceToolbar (view tabs + tools) into a single consolidated toolbar with three zones: left (review context), center (view switcher with amber tab indicator), right (mode-specific actions). Remove ReviewWorkspaceHeader from App.svelte. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ession file, remove dead code - Make PR repo link a clickable button that opens URL via shell - Local review verdict now uses reviewSession.files[0] instead of editor.currentFilePath, matching old ReviewWorkspaceHeader behavior - Remove duplicate Approve/Request Changes from Code view - Delete ReviewWorkspaceHeader, ReviewContextBanner, ReviewActionsGroup and associated test file — all dead code after header consolidation - Add context-link CSS class for clickable PR links Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace multi-expand Set<number> model with single-focus field so only one annotation bubble is expanded at a time. Add n/N shortcut keys to cycle through annotated lines with wrap-around, syncing sidebar selection and scroll position. Show position counter and key hints in the focused bubble footer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collapsed bubbles are now compact and subtle (no background fill, just a colored left border). Expanded bubbles get elevated treatment with kind- specific background, accent border, and box-shadow ring. Notch is hidden. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ard shortcuts Add toggle functions for both panels with saved width state, collapse arrows in FileTree and AnnotationSidebar headers, thin expand rails when collapsed, and Cmd+B / Cmd+Shift+B keyboard shortcuts. Resize handles hide when their adjacent panel is collapsed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace per-annotation ReviewCard rendering with proximity-grouped context blocks that share a single code snippet. Annotations within 5 lines merge into one block with status dots (amber/green) on annotated lines, L-tag hover-sync between threads and snippet, hidden-until-activated reply input, and surface-elevation styling replacing heavy bordered cards. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nd session cards Replace the dense GitHub Inbox landing page with a minimalist blank-slate launch screen: centered search input with amber focus glow, progressive disclosure (two-column layout only when history exists), ghost-styled session cards, and a collapsible review queue. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gles - [ and ] now cycle through Code → Review → PR tabs (wraps around, skips PR tab when no GitHub session active) - \ toggles both sidebars at once - Ctrl+h toggles left sidebar (file tree) - Ctrl+l toggles right sidebar (annotations) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…dges - Assign flatIndex AFTER sorting annotations by line number so j/k navigation follows the same top-to-bottom order as the visual layout - Remove COMMENT/kind and SUBMITTED/sync badges from thread headers — just show "author · time" for cleaner metadata - Same cleanup for reply headers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Small ↵ button next to the reply text box, disabled when empty, highlights amber on hover. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Tabs (Code/Review/PR) now use position:absolute + left:50% + translateX(-50%) so they stay centered regardless of which right-side actions are visible - Left zone and right zone use space-between flex layout - Submit review modal textarea gets autofocus when opened Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Tabs (Code/Review/PR) and mode actions (Submit, diff tools, etc.) are now in a single flex group on the right, separated by a thin divider. No more 800px gap between navigation and action. - Left zone: logo anchor + PR context, takes remaining space - Active tab underline changed from amber to white/grey — reserves solid amber exclusively for the Submit primary action - Removes absolute positioning hack for center tabs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…a file is selected Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace flex layout with CSS grid (1fr auto 1fr): - Left: PR context (truncatable) - Center: Tabs (justify-self: center — mathematically centered, never moves regardless of right-side content) - Right: Actions (justify-self: end — pinned to edge) Zero jitter. Tabs stay at the same X coordinate across all modes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Submit review (GitHub) and Approve/Request Changes (local) actions now show in every tab mode, not just the Review tab. Mode-specific tools (diff, inline, etc.) show first, then a divider, then the review actions. The terminal action is always visible and reachable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Toolbar renders above workspace-shell, spanning full width - EditorPane no longer owns the toolbar — exposes view-switching methods (selectCodeView, selectReviewView, selectPrView, enterDiff, cycleView, agentReviewVerdict) for App.svelte to wire - showPrView is now a bindable prop flowing between App and EditorPane - Include implementation plan docs for bubbles and review page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sidebars and their collapse rails are only rendered when a workspace has root folders. The launch screen gets the full width for the hero PR input and session cards. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Install tauri-plugin-log (Rust) and @tauri-apps/plugin-log (JS) - Register plugin in lib.rs with Info level - Add log:default permission to capabilities Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logs at key points: - cardEntries derivation start/end with file counts - Per-file: root count, annotation count, snippet count - mergeSnippets: input/valid counts - buildContextGroup: card count and line numbers - reviewPage store: openReviewPage lifecycle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…erate schemas Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…duplicate key error The each_key_duplicate Svelte error caused an infinite re-render loop freezing the review page. Root cause: annotation.id could appear multiple times when orphaned replies are promoted to roots. Using flatIndex (guaranteed unique sequential integer) as the key instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Major UI overhaul to modernize the app’s dark theme, consolidate header/navigation, improve annotation workflows (collapsed bubbles + keyboard navigation), add collapsible sidebars, revamp the Review page layout, and introduce a new launch screen.
Changes:
- Introduces a new GitHub-dark-inspired surface/token system and updates component styling to match (reduced gradients, new accents, shadows).
- Consolidates header UX into a single toolbar, adds sidebar collapse/expand rails + shortcuts, and adds
n/Nannotation navigation. - Overhauls Review page rendering (proximity grouping, merged snippets, inline threads, status dots, hover-sync) and redesigns the launch screen (hero PR input + recent sessions).
Reviewed changes
Copilot reviewed 39 out of 42 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/stores/reviewPage.svelte.ts | Adds logging around opening/loading review page data. |
| src/lib/controllers/appShell.svelte.ts | Adds annotation navigation + sidebar/view cycling shortcut plumbing. |
| src/lib/commands.ts | Extends command context; adds sidebar toggle commands. |
| src/lib/codemirror/theme.ts | Restyles inline annotation bubble UI + adds navigation footer styles. |
| src/lib/codemirror/bubbles.ts | Switches bubble expansion to single “focused line” model + exposes helpers. |
| src/components/review-header/ReviewSubmitControl.svelte | Focus handling for submit modal textarea. |
| src/components/review-header/ReviewContextBanner.svelte | Removes legacy review context banner component. |
| src/components/review-header/ReviewActionsGroup.svelte | Removes legacy review actions group component. |
| src/components/editor-pane/WorkspaceToolbar.svelte | New consolidated header/toolbar layout with persistent review actions + badges. |
| src/components/Toolbar.svelte | Simplifies toolbar background styling (drops gradient). |
| src/components/SettingsDialog.svelte | Updates dialog background to flat surface token. |
| src/components/ReviewWorkspaceHeader.test.ts | Removes tests for deleted header component. |
| src/components/ReviewWorkspaceHeader.svelte | Removes legacy header component (replaced by consolidated toolbar). |
| src/components/ReviewPage.svelte | Implements proximity grouping, inline threads, reply UX changes, hover sync, status dots, and logging. |
| src/components/ReviewCodeSnippet.svelte | Adds annotated-line status dots + line hover class support. |
| src/components/GitHubInbox.svelte | Replaces inbox with new “launch screen” UX (hero input, recent sessions, queue). |
| src/components/FileTree.svelte | Adds optional collapse button + style tweaks. |
| src/components/EditorPane.svelte | Exposes view cycling/select APIs; renames enterDiff import; binds PR view state outward. |
| src/components/CommandPalette.test.ts | Updates mocked command context to match new interface. |
| src/components/CommandPalette.svelte | Updates palette background styling to flat surface token. |
| src/components/AnnotationSidebar.svelte | Adds optional collapse control + restyled header tabs. |
| src/components/AnnotationPopover.svelte | Updates popover background styling to flat surface token. |
| src/components/AnnotationCard.svelte | Updates card background styling to flat surface token. |
| src/components/AnnotationBubble.svelte | Adds focused position footer (◀ x/y + n/N hints). |
| src/app.css | Updates global design tokens (surfaces, text opacity scale, accents, shadows, scrollbar). |
| src/App.svelte | Wires consolidated toolbar, collapsible side panels/rails, and PR view state. |
| src-tauri/src/lib.rs | Adds tauri log plugin and changes annotation shortcut accelerator string. |
| src-tauri/gen/schemas/macOS-schema.json | Adds log permission entries to generated schema. |
| src-tauri/gen/schemas/desktop-schema.json | Adds log permission entries to generated schema. |
| src-tauri/gen/schemas/capabilities.json | Adds log:default permission to default capability set. |
| src-tauri/capabilities/default.json | Adds log:default permission. |
| src-tauri/Cargo.toml | Adds Rust dependencies for logging (tauri-plugin-log, log). |
| package.json | Adds @tauri-apps/plugin-log. |
| package-lock.json | Locks @tauri-apps/plugin-log dependency. |
| docs/superpowers/specs/2026-03-29-ui-overhaul-design.md | Adds design spec for the UI overhaul. |
| docs/superpowers/plans/2026-03-30-05-review-page-overhaul.md | Adds implementation plan for review page overhaul. |
| docs/superpowers/plans/2026-03-30-03-collapsed-bubbles-navigation.md | Adds implementation plan for collapsed bubbles + navigation. |
| docs/superpowers/plans/2026-03-29-02-header-consolidation.md | Adds implementation plan for header consolidation. |
| docs/superpowers/plans/2026-03-29-01-theme-color-system.md | Adds implementation plan for theme/token changes. |
| Cargo.lock | Updates lockfile for new Rust dependencies. |
Comments suppressed due to low confidence (2)
src/components/editor-pane/WorkspaceToolbar.svelte:46
getReviewPageStateis imported and assigned toreviewStatebutreviewStateis never used. WithnoUnusedLocalsenabled, this will fail type-check/build; remove the import and the unusedreviewStatevariable (or use it).
src/components/editor-pane/WorkspaceToolbar.svelte:37onAgentReviewVerdictis destructured from props but never referenced. WithnoUnusedLocalsenabled, this will fail the build; remove it from$props()/type or wire it into the local review approve/request-changes buttons instead of callingsubmitReviewVerdictdirectly.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { submitReviewVerdict } from "$lib/review"; | ||
| import { clearReviewSession } from "$lib/stores/review.svelte"; | ||
| import { open as openUrl } from "@tauri-apps/plugin-shell"; | ||
| import type { SubmitGitHubReviewResult } from "$lib/types"; |
There was a problem hiding this comment.
SubmitGitHubReviewResult is imported but never used. With noUnusedLocals enabled this will cause a TypeScript error; remove the unused type import or use it for submitActiveGitHubReview typing.
| :global(.review-submit-thinking-arrow) { | ||
| display: inline-block; | ||
| animation: review-submit-thinking 0.9s ease-in-out infinite; | ||
| } | ||
| @keyframes -global-review-submit-thinking { | ||
| 0%, |
There was a problem hiding this comment.
The animation name used (review-submit-thinking) does not match the defined keyframes (-global-review-submit-thinking), so the “Submitting…” arrow animation won’t run. Rename the keyframes to match the animation name (or update the animation: property accordingly).
| @@ -14,7 +14,28 @@ | |||
| import { resolveAnnotation, updateChoices, addAnnotation, removeAnnotation } from "$lib/stores/annotations.svelte"; | |||
| import ReviewCard from "./ReviewCard.svelte"; | |||
There was a problem hiding this comment.
ReviewCard is imported but no longer used in this component. With noUnusedLocals enabled, this will fail type-check/build; remove the unused import.
| import ReviewCard from "./ReviewCard.svelte"; |
| const KIND_LABELS: Record<AnnotationKind, string> = { | ||
| comment: "comment", | ||
| lineNote: "note", | ||
| explanation: "explanation", | ||
| label: "label", | ||
| }; |
There was a problem hiding this comment.
KIND_LABELS is declared but never used. With noUnusedLocals enabled, this will fail type-check/build; remove it or render the kind label in the UI.
| function mergeSnippets(snippets: (FileSnippet | null)[]): FileSnippet | null { | ||
| const valid = snippets.filter((s): s is FileSnippet => s !== null); | ||
| info(`[ReviewPage] mergeSnippets: ${snippets.length} input, ${valid.length} valid`); |
There was a problem hiding this comment.
info() logging in derived computations (e.g., snippet merging) will run frequently and, combined with the app-wide log level set to Info, can create significant log spam and UI slowdown. Consider removing these logs or gating them behind a debug flag / using a more verbose log level.
| function mergeSnippets(snippets: (FileSnippet | null)[]): FileSnippet | null { | |
| const valid = snippets.filter((s): s is FileSnippet => s !== null); | |
| info(`[ReviewPage] mergeSnippets: ${snippets.length} input, ${valid.length} valid`); | |
| const DEBUG_SNIPPET_LOGS = false; | |
| function mergeSnippets(snippets: (FileSnippet | null)[]): FileSnippet | null { | |
| const valid = snippets.filter((s): s is FileSnippet => s !== null); | |
| if (DEBUG_SNIPPET_LOGS) { | |
| info(`[ReviewPage] mergeSnippets: ${snippets.length} input, ${valid.length} valid`); | |
| } |
| const focusedBubbleLineField = StateField.define<number | null>({ | ||
| create() { | ||
| return new Set(); | ||
| return null; // All collapsed by default | ||
| }, | ||
| update(value, tr) { | ||
| for (const effect of tr.effects) { | ||
| if (effect.is(toggleBubbleExpansionEffect)) { | ||
| const next = new Set(value); | ||
| if (next.has(effect.value)) { | ||
| next.delete(effect.value); | ||
| } else { | ||
| next.add(effect.value); | ||
| } | ||
| return next; | ||
| if (effect.is(setFocusedBubbleEffect)) { | ||
| return effect.value === value ? null : effect.value; | ||
| } |
There was a problem hiding this comment.
setFocusedBubbleEffect toggles focus off when the same line is set again. When there is only one annotated line, n/N navigation wraps to the same line and will collapse the bubble instead of keeping it focused. Consider making setFocusedBubbleEffect an idempotent “set” operation (no toggle) and handling click-to-collapse separately.
| .plugin(tauri_plugin_notification::init()) | ||
| .plugin( | ||
| tauri_plugin_log::Builder::new() | ||
| .level(log::LevelFilter::Info) |
There was a problem hiding this comment.
The app enables tauri_plugin_log at Info level globally. Since the UI code now emits many info() logs (e.g., ReviewPage derived recomputes), this can have performance and disk/log-size impact in production; consider lowering the default level or making it conditional on debug/dev builds.
| .level(log::LevelFilter::Info) | |
| .level(if cfg!(debug_assertions) { | |
| log::LevelFilter::Info | |
| } else { | |
| log::LevelFilter::Warn | |
| }) |
| @@ -56,14 +57,20 @@ export async function openReviewPage(mode: ReviewMode) { | |||
|
|
|||
| try { | |||
| if (mode === "changes") { | |||
| console.log("[ReviewPage store] loading changes..."); | |||
| await loadReviewChanges(); | |||
| console.log("[ReviewPage store] loadReviewChanges done, files:", state.files.length); | |||
| } else { | |||
| console.log("[ReviewPage store] loading feedback..."); | |||
| await loadAgentFeedback(); | |||
| console.log("[ReviewPage store] loadAgentFeedback done, files:", state.files.length); | |||
| } | |||
| } catch (e) { | |||
| console.error("[ReviewPage store] error:", e); | |||
| state.error = e instanceof Error ? e.message : String(e); | |||
| } finally { | |||
| state.loading = false; | |||
| console.log("[ReviewPage store] done. loading=false, error=", state.error); | |||
| } | |||
There was a problem hiding this comment.
openReviewPage adds multiple console.log/console.error calls. This will be noisy in production and can slow down repeated open/close cycles; prefer the Tauri log plugin (already added in this PR) and/or guard logs behind a debug setting.
| background: color-mix(in srgb, var(--danger) 10%, var(--surface-panel)); | ||
| color: var(--danger); |
There was a problem hiding this comment.
The error banner uses var(--danger), but the theme tokens define --color-danger (no --danger variable). This will render with invalid colors. Use the existing danger token (var(--color-danger) or a semantic token used elsewhere).
| background: color-mix(in srgb, var(--danger) 10%, var(--surface-panel)); | |
| color: var(--danger); | |
| background: color-mix(in srgb, var(--color-danger) 10%, var(--surface-panel)); | |
| color: var(--color-danger); |
… App.svelte The Code/Review/PR tab tests were looking for elements inside EditorPane, but the WorkspaceToolbar (which renders tabs) was moved to the global header in App.svelte. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sts, fix App panel count - EditorPane.test.ts: remove all toolbar-dependent tests (Source/Preview, Code/Review/PR tabs) since WorkspaceToolbar moved to App.svelte. Keep basic render test. - App.test.ts: expect 1 panel (center only) when no workspace is open since sidebars are now conditionally hidden. Add plugin-log mock. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Major UI overhaul across the entire application, driven by iterative design feedback:
n/Nkeyboard navigation auto-expands focused bubble with position counter (◀ 2/6)Cmd+B/Cmd+Shift+B,Ctrl+h/Ctrl+l,\for vim-style toggling[/]cycle through Code→Review→PR tabsTest plan
[/]— verify tabs stay centered, no layout jitterCmd+B,Cmd+Shift+B,Ctrl+h,Ctrl+l,\n/N— verify auto-expand, scroll, position counter🤖 Generated with Claude Code