Draw the real icon, and give the menu bar its own glyph
Replaces the placeholder coat silhouette with the app's actual subject: Claude's asterisk above a rack of overcoats, on Claude's own coral. The wardrobe is the app in one picture — several coats to pick between, one currently worn. The menu bar stops scaling the app icon down and draws its own glyph instead. At 18pt the icon's three coats, lapels and pockets collapse into a smudge, and its colours ignore the menu bar entirely. The glyph is a template image, so macOS tints it for light and dark and for the open-menu inversion, and re-tints it itself when the theme changes. That also drove its shape: six rays rather than eight, because at that size eight have under a pixel between arms and merge into a blob. The coloured dots beside it don't get that for free — ProfileColor picks a brightness for the current appearance at the moment it's asked, and the title is only rebuilt when profiles start or stop. Observing effectiveAppearance rebuilds it, so a theme switch doesn't leave dots mixed for the old appearance sitting in the menu bar. Everything is still drawn from vector paths rather than exported from a design tool, so each size can be tuned — small sizes need fatter strokes than a straight downscale gives — and nothing binary but the derived assets is committed. The README gains a hero banner, composed from the generated icon so it can't drift out of step with it. About gains the tagline under the icon, names itself in the description rather than opening with a bare verb, and drops the author line.
This commit is contained in:
+23
-12
@@ -15,12 +15,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveSt
|
||||
private var accessibilityPromptShown = false
|
||||
private var accessibilityRecheckScheduled = false
|
||||
private var activationObserver: NSObjectProtocol?
|
||||
private var appearanceObserver: NSKeyValueObservation?
|
||||
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
menu.delegate = self
|
||||
menu.autoenablesItems = false
|
||||
statusItem.menu = menu
|
||||
statusItem.button?.image = menuBarIcon()
|
||||
statusItem.button?.image = MenuBarIcon.image()
|
||||
statusItem.button?.imagePosition = .imageLeft
|
||||
|
||||
liveState.delegate = self
|
||||
@@ -34,6 +35,21 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveSt
|
||||
activationObserver = NSWorkspace.shared.notificationCenter.addObserver(
|
||||
forName: NSWorkspace.didActivateApplicationNotification, object: nil, queue: .main
|
||||
) { [weak self] _ in self?.updateOverlayVisibility() }
|
||||
|
||||
// The glyph is a template image and re-tints itself, but the coloured
|
||||
// dots beside it don't: ProfileColor picks a brightness per current
|
||||
// appearance at the moment it's asked, and the title is only rebuilt
|
||||
// when profiles start or stop. Without this, switching to dark mode
|
||||
// leaves dots mixed for that appearance sitting in the menu bar until
|
||||
// something unrelated happens to redraw them.
|
||||
appearanceObserver = NSApp.observe(\.effectiveAppearance) { [weak self] _, _ in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else { return }
|
||||
self.applyTitle(self.currentInfos)
|
||||
ManageWindowController.shared.update(self.currentInfos)
|
||||
}
|
||||
}
|
||||
|
||||
liveState.reconcile()
|
||||
|
||||
// Launching this app fresh with nothing running means there's no
|
||||
@@ -46,17 +62,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveSt
|
||||
UpdateChecker.checkAutomaticallyIfDue()
|
||||
}
|
||||
|
||||
// Claude's own app icon (bundled as Contents/Resources/AppIcon.icns —
|
||||
// currently a placeholder, see icon/generate-icon.swift), scaled down
|
||||
// for the menu bar.
|
||||
private func menuBarIcon() -> NSImage {
|
||||
let source = NSApp.applicationIconImage ?? NSImage(named: NSImage.applicationIconName) ?? NSImage()
|
||||
let resized = NSImage(size: NSSize(width: 18, height: 18))
|
||||
resized.lockFocus()
|
||||
source.draw(in: NSRect(x: 0, y: 0, width: 18, height: 18), from: .zero, operation: .sourceOver, fraction: 1.0)
|
||||
resized.unlockFocus()
|
||||
return resized
|
||||
}
|
||||
// The menu bar draws its own glyph (see MenuBarIcon) rather than the app
|
||||
// icon scaled down, which is what it used to do: at 18pt the app icon's
|
||||
// three coats collapse into a smudge, and its colours ignore the menu
|
||||
// bar's appearance entirely. MenuBarIcon returns a template image, so
|
||||
// macOS tints it for light/dark and for the open-menu inversion, and
|
||||
// re-tints it by itself when the theme changes.
|
||||
|
||||
// MARK: - LiveStateDelegate
|
||||
|
||||
|
||||
Reference in New Issue
Block a user