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:
Claude Opus 5
2026-08-05 21:06:58 +06:00
committed by bdeshi
parent af2cae7fa9
commit cf7d9a4583
9 changed files with 391 additions and 95 deletions
+22 -5
View File
@@ -640,7 +640,6 @@ private final class SettingsViewController: NSViewController {
// MARK: - About tab
private let projectAuthor = "bdeshi"
private let projectHomepage = "https://github.com/bdeshi/shannoncoat"
private final class AboutViewController: NSViewController {
@@ -668,19 +667,36 @@ private final class AboutViewController: NSViewController {
icon.centerXAnchor.constraint(equalTo: iconContainer.centerXAnchor),
])
// Centred under the icon, same wrapper trick as the icon itself.
let tagline = NSTextField(labelWithString: "which coat will Claude wear today?")
tagline.font = .systemFont(ofSize: NSFont.systemFontSize)
tagline.textColor = .secondaryLabelColor
tagline.translatesAutoresizingMaskIntoConstraints = false
let taglineContainer = NSView()
taglineContainer.translatesAutoresizingMaskIntoConstraints = false
taglineContainer.addSubview(tagline)
NSLayoutConstraint.activate([
tagline.topAnchor.constraint(equalTo: taglineContainer.topAnchor),
tagline.bottomAnchor.constraint(equalTo: taglineContainer.bottomAnchor),
tagline.centerXAnchor.constraint(equalTo: taglineContainer.centerXAnchor),
])
// Names itself rather than opening with a bare verb — this panel is
// reachable without the window title in view.
let description = NSTextField(wrappingLabelWithString:
"Runs multiple Claude Desktop profiles side by side, each paired with its own isolated Claude Code config.")
"shannoncoat runs multiple Claude Desktop profiles side by side, each paired with its own "
+ "isolated Claude Code config.")
description.font = .systemFont(ofSize: NSFont.systemFontSize)
let authorField = NSTextField(labelWithString: "Author: \(projectAuthor)")
let sourceField = NSTextField(labelWithString: "Source: \(projectHomepage)")
let versionField = NSTextField(labelWithString: "Version: \(UpdateChecker.displayVersion)")
for field in [authorField, sourceField, versionField] {
for field in [sourceField, versionField] {
field.textColor = .secondaryLabelColor
field.font = .systemFont(ofSize: NSFont.smallSystemFontSize)
}
let stack = NSStackView(views: [iconContainer, description, authorField, sourceField, versionField])
let stack = NSStackView(views: [iconContainer, taglineContainer, description,
sourceField, versionField])
stack.orientation = .vertical
stack.alignment = .leading
stack.spacing = 10
@@ -694,6 +710,7 @@ private final class AboutViewController: NSViewController {
stack.bottomAnchor.constraint(equalTo: view.bottomAnchor),
description.widthAnchor.constraint(equalToConstant: Self.contentWidth),
iconContainer.widthAnchor.constraint(equalTo: description.widthAnchor),
taglineContainer.widthAnchor.constraint(equalTo: description.widthAnchor),
])
view.layoutSubtreeIfNeeded()