diff --git a/date-wizard/Sources/DateWizard/MenuBarDays.swift b/date-wizard/Sources/DateWizard/MenuBarDays.swift index 1c56ae7cdc..dacdf7576a 100644 --- a/date-wizard/Sources/DateWizard/MenuBarDays.swift +++ b/date-wizard/Sources/DateWizard/MenuBarDays.swift @@ -45,7 +45,15 @@ final class MenuBarDays { // ── lifecycle ───────────────────────────────────────────────────── func install() { barThickness = NSStatusBar.system.thickness + // Pin the wand LEFT of Menu Band. NSStatusItem has no absolute-ordering + // API; its autosaveName + "Preferred Position" default is the lever macOS + // honors (higher = further left). Seed once; a user ⌘-drag persists over it. + let posKey = "NSStatusItem Preferred Position datewizard" + if UserDefaults.standard.object(forKey: posKey) == nil { + UserDefaults.standard.set(24, forKey: posKey) + } statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + statusItem.autosaveName = "datewizard" if let button = statusItem.button { self.button = button button.imagePosition = .imageOnly @@ -131,13 +139,13 @@ final class MenuBarDays { // ── menu-bar-fit negotiation ────────────────────────────────────── // The wand's ladder: bare → presence-dot → full countdown pill. With no // upcoming event the ladder collapses to just the bare wand so the broker's - // width model stays honest (nothing to shed). Low priority (20): the badge - // is glanceable-but-redundant with the calendar, so DateWizard sheds it - // before Menu Band gives up piano keys. + // width model stays honest (nothing to shed). High priority (40): the wand's + // countdown is the thing to defend, so Menu Band gives up piano keys before + // DateWizard sheds the badge. private func startFitNegotiation() { guard let statusItem, fit == nil else { return } let has = (nextEventDate != nil) - fit = MenuBarFit(slug: "datewizard", priority: 20, + fit = MenuBarFit(slug: "datewizard", priority: 40, rungs: fitRungs(hasNext: has), statusItem: statusItem, startAt: has ? 2 : 0) { [weak self] _, idx in self?.fitRung = idx diff --git a/slab/menuband/Sources/MenuBand/AppDelegate.swift b/slab/menuband/Sources/MenuBand/AppDelegate.swift index b63b98eee3..f7997d3bde 100644 --- a/slab/menuband/Sources/MenuBand/AppDelegate.swift +++ b/slab/menuband/Sources/MenuBand/AppDelegate.swift @@ -698,7 +698,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate { KeyboardIconRenderer.iconScale = max(1.0, min(1.6, (barThickness - 0.5) / baseIconH)) } + // Keep Menu Band to the RIGHT of the wand: lower preferred position than + // datewizard's (higher = further left). Seed once; a ⌘-drag persists over it. + let mbPosKey = "NSStatusItem Preferred Position menuband" + if UserDefaults.standard.object(forKey: mbPosKey) == nil { + UserDefaults.standard.set(8, forKey: mbPosKey) + } statusItem = NSStatusBar.system.statusItem(withLength: KeyboardIconRenderer.imageSize.width) + statusItem.autosaveName = "menuband" debugLog("statusItem created, button=\(statusItem.button != nil) length=\(statusItem.length)") if let button = statusItem.button { let cell = NoHighlightStatusBarCell() @@ -1995,7 +2002,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate { fitLayouts = layouts let startIdx = layouts.firstIndex(of: saved) ?? layouts.count - 1 - fit = MenuBarFit(slug: "menuband", priority: 40, rungs: rungs, + // priority 20 (below datewizard's 40): Menu Band yields piano keys before + // the wand sheds its countdown badge. + fit = MenuBarFit(slug: "menuband", priority: 20, rungs: rungs, statusItem: statusItem, startAt: startIdx) { [weak self] _, idx in guard let self, idx >= 0, idx < self.fitLayouts.count else { return } KeyboardIconRenderer.displayLayout = self.fitLayouts[idx]