refactor(mac): inject context card as NSMenuItem view
This commit is contained in:
47
apps/macos/Sources/Clawdis/MenuContextCardInjector.swift
Normal file
47
apps/macos/Sources/Clawdis/MenuContextCardInjector.swift
Normal file
@@ -0,0 +1,47 @@
|
||||
import AppKit
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
final class MenuContextCardInjector: NSObject, NSMenuDelegate {
|
||||
static let shared = MenuContextCardInjector()
|
||||
|
||||
private let tag = 9_415_227
|
||||
private let cardWidth: CGFloat = 320
|
||||
|
||||
func install(into statusItem: NSStatusItem) {
|
||||
// SwiftUI owns the menu, but we can inject a custom NSMenuItem.view right before display.
|
||||
statusItem.menu?.delegate = self
|
||||
}
|
||||
|
||||
func menuWillOpen(_ menu: NSMenu) {
|
||||
// Remove any previous injected card items.
|
||||
for item in menu.items where item.tag == self.tag {
|
||||
menu.removeItem(item)
|
||||
}
|
||||
|
||||
guard let insertIndex = self.findInsertIndex(in: menu) else { return }
|
||||
|
||||
let cardView = ContextMenuCardView(width: self.cardWidth)
|
||||
let hosting = NSHostingView(rootView: cardView)
|
||||
let size = hosting.fittingSize
|
||||
hosting.frame = NSRect(origin: .zero, size: NSSize(width: self.cardWidth, height: size.height))
|
||||
|
||||
let item = NSMenuItem()
|
||||
item.tag = self.tag
|
||||
item.view = hosting
|
||||
item.isEnabled = false
|
||||
|
||||
menu.insertItem(item, at: insertIndex)
|
||||
}
|
||||
|
||||
private func findInsertIndex(in menu: NSMenu) -> Int? {
|
||||
// Prefer inserting before the "Send Heartbeats" toggle item.
|
||||
if let idx = menu.items.firstIndex(where: { $0.title == "Send Heartbeats" }) {
|
||||
return idx
|
||||
}
|
||||
// Fallback: insert after the first two rows (active toggle + status).
|
||||
if menu.items.count >= 2 { return 2 }
|
||||
return menu.items.count
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user