Hi,
I'm working on an app that will mostly live in the menu bar.
I'm trying to make a menu item that looks similar to the Tailscale app's menu:
Note: I'm inspired by how Tailscale's menu is rendered:
I have made a View that shows my avatar, name, and optionally the company I work for:
import SwiftUI
struct MenuWhoAmI: View {
var username: String
var binding: String?
var body: some View {
HStack {
AsyncImage(url: URL(string: "https://avatars.githubusercontent.com/u/76716")!){ image in
image.resizable().scaledToFit()
} placeholder: {
ProgressView()
}
.clipShape(Circle())
VStack(alignment: .leading) {
Text(username)
if let binding = binding {
Text("\(binding)").foregroundStyle(.secondary)
}
}
}
}
}
#Preview {
VStack(alignment: .leading) {
MenuWhoAmI(username: "grahamc").padding()
Divider()
MenuWhoAmI(username: "grahamc", binding: "DeterminateSystems").padding()
}.padding()
}
I tried using it in my menu bar:
import SwiftUI
@main
struct DeterminateApp: App {
var body: some Scene {
MenuBarExtra("Determinate", image: "MenuIcon") {
MenuWhoAmI(username: "grahamc")
Button("Two") {}
Button("Three") {}
Divider()
Button("Quit") {
NSApplication.shared.terminate(nil)
}.keyboardShortcut("q")
}.menuBarExtraStyle(.menu)
}
}
and it renders differently:
After reading the forums and documentation, I understood the MenuBarExtra only renders certain elements. I then tried to use an NSStatusBar with an AppDelegate:
import AppKit
import SwiftUI
@main
struct DeterminateApp: App {
@NSApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
Window("Authentication", id: "login") {}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
private var statusItem: NSStatusItem!
func applicationDidFinishLaunching(_ notification: Notification) {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
if let button = statusItem.button {
button.image = NSImage(named: NSImage.Name("MenuIcon"))
}
statusItem.menu = NSHostingMenu(rootView: Group {
Button(action: { print("hi") }) {
MenuWhoAmI(username: "grahamc")
}
})
}
}
and still, the avatar/name doesn't render like I'd expect, missing the circle clipping:
...and I'm a bit mystified.
How can I make this menu render the way I'm trying for?
Thank you!