Skip to content

feat(macos): menubar UI consistency overhaul — sections, hover, icons, toggles#23135

Closed
apethree wants to merge 4 commits intoopenclaw:mainfrom
apethree:codex/macos-settings-menubar-polish
Closed

feat(macos): menubar UI consistency overhaul — sections, hover, icons, toggles#23135
apethree wants to merge 4 commits intoopenclaw:mainfrom
apethree:codex/macos-settings-menubar-polish

Conversation

@apethree
Copy link

@apethree apethree commented Feb 22, 2026

Summary

Complete redesign of the macOS menubar menu for visual consistency and stability. Every row across every section now uses the same custom NSMenuItem.view rendering pipeline, eliminating the mix of native AppKit rendering and custom SwiftUI views that caused misaligned indents, inconsistent row heights, and blue selection highlights in some sections but not others.

What changed

Selection / hover colour

  • Before: mixed — some rows showed AppKit's bold blue selection highlight, others nothing
  • After: all selectable rows use a soft grey rounded rect (unemphasizedSelectedContentBackgroundColor), matching macOS system menus (Spotlight, Control Centre, etc.)
  • Toggle rows (OpenClaw on/off header, all Quick Settings toggles) show no selection background — clicking fires the action without any visual highlight

Sections & labels

  • Before: no section labels for Actions or App; sections had inconsistent leading indents
  • After: four clearly labelled sections — Status, Activity, Quick Settings, Actions, App — all with the same leading indent and 11 pt semibold grey headers
  • Separator between Context and Usage subsections removed (they belong to the same Activity section)

Row layout & padding

  • Before: Quick Settings rows were ~22 pt tall (3 pt vertical padding); node/session rows were ~28–30 pt; native Actions rows used AppKit's state-column indent (~38 px from left edge)
  • After: all single-line rows are uniform height (5 pt vertical padding); multi-line rows keep their own sizing; every row starts at the same 12 pt leading indent

Icons

  • Before: Quick Settings and Connected Devices icons were oversized (16 pt), creating visual inconsistency against the 13 pt icons in Actions; Connected Devices used laptopcomputer.and.iphone which rendered very large
  • After: all icons normalised to 13 pt inside 16×16 frames; Connected Devices uses network

Section headers (Context / Usage)

  • Before: plain greyed-out text labels with no icon
  • After: leading SF Symbol icon (list.bullet / bolt) + primary-colour label + secondary count subtitle; wrapped in HighlightedMenuItemHostView so they get the same grey hover as other rows

Exec Approvals dropdown

  • Before: native NSMenuItem items with AppKit checkmarks and blue selection
  • After: each option wrapped in HighlightedMenuItemHostView + MenuPickerRow (leading checkmark, grey hover, consistent indent)

Active header (OpenClaw toggle)

  • Before: native SwiftUI Toggle with AppKit checkmark rendering
  • After: custom MenuActiveHeaderView with a proper capsule toggle switch (macOS-style); ClickableMenuItemHostView intercepts mouseDown to fire the action since NSMenuItem.target/action is ignored for custom views

Cost usage submenu

  • Before: used NSHostingController + separate NSHostingView for the same view (two independent render trees causing blank/wrong chart)
  • After: single NSHostingView sized via fittingSize

New Swift files

  • MenuActiveHeaderView.swiftMenuActiveHeaderView (capsule toggle header) + ClickableMenuItemHostView subclass
  • MenuToggleViews.swiftCapsuleToggle, QuickSettingsRow, MenuSubMenuRow, MenuNativeItemRow, MenuPickerRow, MenuSectionLabelView

gitignore

  • Added .vscode/ and .claude/ to .gitignore

After

after

Before

before

AI-assisted:

  • AI-assisted change
  • Tested locally (targeted)

Greptile Summary

Confidence Score: 5/5
This PR is safe to merge with minimal risk only UI changes.
Replaces the mixed native-AppKit/SwiftUI rendering pipeline in the macOS menubar with a unified NSMenuItem.view-based system across all sections.

Core infrastructure (MenuHighlightedHostView.swift, MenuActiveHeaderView.swift):

  • HighlightedMenuItemHostView changed from final to open class; adds showsHighlight: Bool flag to gate hover/selection drawing
  • Selection color changed from selectedContentBackgroundColor (blue) to unemphasizedSelectedContentBackgroundColor (soft grey) with tighter inset
  • New ClickableMenuItemHostView subclass intercepts mouseDown to fire actions (required because NSMenuItem.target/action is ignored for custom views); sets
    showsHighlight = false for toggle rows

New views (MenuToggleViews.swift):

  • CapsuleToggle — animated macOS-style switch glyph
  • QuickSettingsRow / MenuSubMenuRow — toggle and picker rows with consistent 13 pt icons, 5 pt vertical padding, 12 pt leading indent
  • MenuNativeItemRow — wraps native SwiftUI Button/Menu items so Actions and App sections share the same indent and grey hover
  • MenuPickerRow — selection list row with leading checkmark for Exec Approvals submenu
  • MenuSectionLabelView — 11 pt semibold grey section headers

Injection pipeline (MenuSessionsInjector.swift):

  • Adds injectActiveHeader, injectQuickSettings, injectActionsLabel, injectAppLabel, injectNativeItemViews — each idempotent via numeric tags (9_415_559 through
    9_415_564)
  • injectNativeItemViews walks items after the Actions label, wraps submenu items with HighlightedMenuItemHostView and button items with ClickableMenuItemHostView +
    NSApp.sendAction forwarding
  • Voice Wake moved above Exec Approvals; separator between Context/Usage removed
  • buildExecApprovalsSubmenu replaced with HighlightedMenuItemHostView-wrapped MenuPickerRow items
  • buildCostUsageSubmenu simplified to single NSHostingView (was double-allocating via NSHostingController + NSHostingView)

View cleanup (MenuContentView.swift, session/usage label views):

  • Removed Toggle, settingToggleRow, and related bindings from MenuContent.body — all now owned by the injector
  • Removed @Environment(.menuItemHighlighted) color-inversion logic from SessionMenuLabelView, UsageMenuLabelView, SessionMenuPreviewView, NodesMenu views — all
    text now uses static .primary/.secondary

- Unified selection highlight: all custom rows now use soft grey
  (unemphasizedSelectedContentBackgroundColor) instead of blue
- Toggle rows (OpenClaw header, Quick Settings) show no hover/selection
  background via showsHighlight = false on ClickableMenuItemHostView
- Exec Approvals submenu items wrapped in HighlightedMenuItemHostView
  with MenuPickerRow (checkmark + grey hover, no blue)
- Moved active header, Quick Settings toggles, Status section (Gateway
  + Connected Devices), Activity section, and section labels out of
  SwiftUI MenuContent into MenuSessionsInjector custom NSMenuItem.views
  so they align and highlight consistently
- Native Actions/App section items wrapped via injectNativeItemViews()
  to receive the same grey hover and leading indent as injected rows
- Context/Usage section headers gain icons and primary text colour
- Added "Actions" and "App" section labels; Voice Wake moved above
  Exec Approvals in Quick Settings
- Separator between Context and Usage sections removed
- Cost usage submenu fixed (single NSHostingView, no double view tree)
- .gitignore: exclude .vscode/ and .claude/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@apethree apethree force-pushed the codex/macos-settings-menubar-polish branch from 266adc1 to 2bba12d Compare February 22, 2026 02:18
@apethree
Copy link
Author

@steipete MacOS app menu items fix. It needs a lot of fixing but this is a good start.

@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Feb 28, 2026
@openclaw-barnacle
Copy link

Closing due to inactivity.
If you believe this PR should be revived, post in #pr-thunderdome-dangerzone on Discord to talk to a maintainer.
That channel is the escape hatch for high-quality PRs that get auto-closed.

@openclaw-barnacle openclaw-barnacle bot closed this Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: macos App: macos size: XL stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant