feat: Normal App mode, Settings UI tabs, Dev Hub sub-title#112
feat: Normal App mode, Settings UI tabs, Dev Hub sub-title#112
Conversation
- App Mode setting: Normal App (default) / Menu Bar - Normal mode: shows in Dock, no auto-hide on blur, window stays in place (draggable via title bar), minimize on hide - Menu Bar mode: current behavior (hidden dock, auto-hide, center on show) - Instant switching via IPC (no restart needed) - Title bar uses -webkit-app-region: drag for frameless window Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Normal mode: show window immediately on app start - Cmd+Ctrl+R in normal mode: only show+focus (no hide/minimize) - Drag region only active in normal mode (fixes menu bar mode being draggable then snapping back) - Send app-mode-changed IPC to renderer for dynamic drag toggle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Switching to menu bar mode immediately re-centers window - Normal mode shortcut uses hide() not minimize() (no animation) - Shortcut toggles hide/show in both modes (restored from focus-only to full toggle) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a persisted App Mode (normal | menubar) with IPC get/set and notifications, moves Dock/show/hide logic into init and mode switch handlers, redesigns Settings into General/Sessions/Shortcuts tabs (adds App Mode control), and surfaces mode banners and shortcut display in the switcher UI. Changes
Sequence DiagramsequenceDiagram
actor User
participant Renderer as Renderer (popup.tsx / switcher-ui.tsx)
participant Preload as Preload (electronAPI)
participant Main as Main Process (main.ts)
participant Store as Settings Store
User->>Renderer: Open Settings / Toggle Mode
Renderer->>Preload: invoke getAppMode()
Preload->>Main: invoke('get-app-mode')
Main->>Store: read app-mode
Main-->>Preload: return appMode
Preload-->>Renderer: appMode
Renderer->>Renderer: update local state
User->>Renderer: setAppMode('menubar')
Renderer->>Preload: send setAppMode('menubar')
Preload->>Main: send('set-app-mode','menubar')
Main->>Store: write app-mode
Main->>Main: update appMode, adjust Dock, window behavior
Main->>Preload: emit 'app-mode-changed'
Preload-->>Renderer: onAppModeChanged callback
Renderer->>Renderer: show mode banner / update header
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
- Title bar shows 'Normal' or 'Menu Bar' in grey text - Banner on first launch (Normal mode) and on mode switch - Banner auto-dismisses after 5-6s, dismissable via x - Clicking Dock icon shows hidden window in Normal mode Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show actual quickSwitcher shortcut (from settings) on right side of title bar, before tab buttons - Fix banner flashing on every show (removed app-mode-changed IPC from showSwitcherWindow — only fires on actual mode change) - Mode indicator stays on left side next to CodeV Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shortcut text in title bar now updates in real-time when user saves or resets shortcuts in Settings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 'Dev Hub' in #888 (11px) next to CodeV - 'normal mode' / 'menu bar mode' in #555 (9px) below Dev Hub - Two-line layout using inline-flex column Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace single scrollable settings panel with 3 tabs: - General: Default Tab, App Mode, Left-Click, Launch at Login, Launch Terminal, Launch Mode, IDE, Working Dir - Sessions: Session Preview, Session Status (hooks) - Shortcuts: Global shortcuts (editable), Claude Session Launch, Tab Switching reference No more conditional content based on active main tab. No more scrolling needed — each tab fits without scroll. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Order: Launch at Login > App Mode > Left-Click > Default Tab > Working Dir > Launch Terminal > Launch Mode > IDE - Hints: Working Dir (projects/term), Launch Terminal (sessions), Launch Mode (tab/window), IDE (projects), Left-Click (tray) - Terminal renamed to Terminal.app in dropdown - Claude Session Launch moved below Tab Switching, noted (in Projects) - Working Dir always visible (removed switcherMode conditional) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/switcher-ui.tsx">
<violation number="1" location="src/switcher-ui.tsx:710">
P2: Banner dismiss timeouts are never cleared. If the mode changes while a previous banner's timeout is still pending, the stale timeout will prematurely dismiss the new banner. Store the timeout ID in a ref and call `clearTimeout` before scheduling a new one.</violation>
</file>
<file name="src/main.ts">
<violation number="1" location="src/main.ts:1976">
P2: `app.dock.show()` returns a `Promise<void>` in Electron but is not awaited. The renderer gets notified via `app-mode-changed` before the dock icon is guaranteed to be visible, and any rejection would be unhandled.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/electron-api.d.ts (1)
31-35: Tighten the new IPC contract before it spreadsstringeverywhere.Lines 32-35 model a closed set of values, but the declarations widen them to plain
stringand generic callback payloads. That drops exhaustiveness checks immediately in the new renderer code. Prefer a sharedAppMode = 'normal' | 'menubar'union and a typed shortcut payload on this surface.As per coding guidelines,
src/**/*.{ts,tsx}: Use TypeScript for all components with strict typing.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/electron-api.d.ts` around lines 31 - 35, The IPC type surface currently uses plain string and untyped callbacks for app mode and shortcuts (getAppMode, setAppMode, onAppModeChanged, onShortcutsUpdated), which loses exhaustiveness checks; define a shared union type AppMode = 'normal' | 'menubar' and replace any string usages with AppMode, and tighten IpcCallback payloads so onAppModeChanged receives AppMode and onShortcutsUpdated receives a properly typed ShortcutPayload interface (e.g., keys, enabled flags) to ensure strict typing across renderer and main code; update all references to these symbols to use the new types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main.ts`:
- Around line 1083-1087: The switcher window is shown (showSwitcherWindow)
before the backend is ready (bootstrap), causing the renderer's initial fetch
for working-folder to hit an unavailable local server; to fix, defer the initial
call to showSwitcherWindow until after await bootstrap() completes (or expose
and await an explicit readiness signal from bootstrap) so the renderer only
mounts when the server is ready; update the startup sequence around
createSwitcherWindow/showSwitcherWindow and bootstrap to ensure
showSwitcherWindow runs after bootstrap (or after the readiness event) and add a
comment referencing the renderer's working-folder fetch to document the
dependency.
In `@src/popup.tsx`:
- Around line 325-347: The tab switch handler currently calls
setSettingsTab(tab) even when a shortcut capture is in progress
(editingShortcut), which leaves the global shortcut paused and its UI hidden;
update the onClick for the tab buttons to first detect if editingShortcut is
active and gracefully stop/cancel that capture before changing tabs — e.g., call
the existing cancel/cleanup function (or
setEditingShortcut(null)/setEditingShortcut(false) and invoke the
resumeGlobalShortcutCapture or cancelShortcutEdit helper) and only then call
setSettingsTab(tab) so the capture is resumed or cleaned up whenever the user
navigates away from the "shortcuts" tab.
In `@src/switcher-ui.tsx`:
- Around line 686-710: The startup banner shown in the getAppMode() block should
only appear once per user, not every Normal-mode startup: persist a
“modeBannerSeen” flag (e.g., via localStorage or your app settings) and check it
before calling setModeBanner in the window.electronAPI.getAppMode() handler,
setting the flag after showing the banner; also remove the hardcoded
'Cmd+Ctrl+R' in the onAppModeChanged handler and instead construct the Menu Bar
mode message using the current quickSwitcherShortcut state
(quickSwitcherShortcut / setQuickSwitcherShortcut) so the copy always reflects
the user’s configured shortcut.
---
Nitpick comments:
In `@src/electron-api.d.ts`:
- Around line 31-35: The IPC type surface currently uses plain string and
untyped callbacks for app mode and shortcuts (getAppMode, setAppMode,
onAppModeChanged, onShortcutsUpdated), which loses exhaustiveness checks; define
a shared union type AppMode = 'normal' | 'menubar' and replace any string usages
with AppMode, and tighten IpcCallback payloads so onAppModeChanged receives
AppMode and onShortcutsUpdated receives a properly typed ShortcutPayload
interface (e.g., keys, enabled flags) to ensure strict typing across renderer
and main code; update all references to these symbols to use the new types.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6db25675-0447-4f41-98bd-93b6189c103f
📒 Files selected for processing (7)
CHANGELOG.mdpackage.jsonsrc/electron-api.d.tssrc/main.tssrc/popup.tsxsrc/preload.tssrc/switcher-ui.tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rtcut resume - Clear banner timeout before scheduling new one (cubic P2) - Await app.dock.show() (cubic P2) - Delay showSwitcherWindow to after bootstrap (CodeRabbit) - Resume paused shortcut when switching settings tabs (CodeRabbit) - Use actual shortcut key in mode switch banner (CodeRabbit) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 4 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/popup.tsx">
<violation number="1" location="src/popup.tsx:332">
P2: The shortcut-editing cleanup fires on every tab click, including re-clicking the "shortcuts" tab itself. This cancels an in-progress shortcut edit if the user clicks the active tab. Guard with `tab !== 'shortcuts'` to match the stated intent.</violation>
</file>
<file name="src/main.ts">
<violation number="1" location="src/main.ts:1087">
P2: The 100ms `setTimeout` does not guarantee `bootstrap()` has completed — `bootstrap()` is called ~190 lines later at line 1278, not earlier as the comment states. On slower machines or if the NestJS server takes >0ms to start, the window may show before the API server is ready, causing failed API calls from the renderer.
Consider moving `showSwitcherWindow()` to after the `await bootstrap()` call, or using an event/promise to signal server readiness.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
- Skip shortcut resume when re-clicking active Shortcuts tab - Move showSwitcherWindow() to after bootstrap() + loadUserSettings() (was using setTimeout(100) which didn't guarantee readiness) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@README.md`:
- Around line 57-58: Update the README text that currently reads "Settings → App
Mode" to the new tabbed-UI path "Settings → General → App Mode" so the
documentation matches the redesigned navigation; locate the string "Settings →
App Mode" in README.md and replace it with "Settings → General → App Mode".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0e7d61b1-7cac-49d1-a1e8-1f06d1410e92
📒 Files selected for processing (4)
README.mdsrc/main.tssrc/popup.tsxsrc/switcher-ui.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- src/popup.tsx
- src/switcher-ui.tsx
- src/main.ts
Settings → App Mode → Settings → General → App Mode Settings → Working Directory → Settings → General → Working Dir Settings → IDE Preference → Settings → General → IDE Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Add Normal App mode as an alternative to the current Menu Bar mode. New users default to Normal App mode for better discoverability.
Normal App mode
Cmd+Ctrl+Rtoggles show/hide (no minimize animation)Menu Bar mode (existing behavior)
Cmd+Ctrl+Rtoggles show/hideSettings
UI hints
Settings UI redesign
Test plan
Cmd+Ctrl+Rtoggles hide/show (no animation)Normal mode: what updates when unfocused (visible but not active)
Known limitation: New sessions won't appear until the window is re-focused. This is a trade-off — continuous full refresh would cause visual noise (sessions jumping around). Could be improved by detecting new sessions via fs.watch without full refresh (follow-up).
🤖 On behalf of @grimmerk — generated with Claude Code
Summary by CodeRabbit
New Features
Documentation