A macOS utility to track home-manager JJ repo status

Simplify menu bar UI to text-only #2

merged opened by nolith.dev targeting main from ac/push-otompxxxtqyl

Remove the SF Symbol icon from the menu bar label, replacing it with compact text only. The icon was vertically misaligned with adjacent text and duplicated the directional information already conveyed by arrow characters (↑/↓).

The menu bar now shows:

  • ✓ when synced and clean
  • ● when synced with dirty working copy
  • ↑N / ↓N for ahead/behind counts (with optional ● for dirty)
  • ! for errors

This eliminates both the visual redundancy and the alignment issue.

Closes: https://tangled.org/nolith.tngl.sh/JJHomeManagerStatus.app/issues/1

AI-assisted: GitLab Duo Agentic Chat (Claude Sonnet 4)

Labels

None yet.

assignee

None yet.

Participants 1
Referenced by
AT URI
at://did:plc:nzep3slobztdph3kxswzbing/sh.tangled.repo.pull/3mgcui75nmg22
+9 -93
Diff #0
+2 -8
Sources/HomeManagerStatus/HomeManagerStatusApp.swift
··· 36 36 let status: RepoStatus 37 37 38 38 var body: some View { 39 - HStack(spacing: 2) { 40 - Image(systemName: status.menuBarIcon) 41 - .symbolRenderingMode(.palette) 42 - if !status.menuBarLabel.isEmpty { 43 - Text(status.menuBarLabel) 44 - .monospacedDigit() 45 - } 46 - } 39 + Text(status.menuBarLabel) 40 + .monospacedDigit() 47 41 } 48 42 } 49 43
+6 -29
Sources/HomeManagerStatus/RepoStatus.swift
··· 1 - import SwiftUI 1 + import Foundation 2 2 3 3 /// Represents the current status of the jj repository relative to trunk(). 4 4 struct RepoStatus: Equatable { ··· 32 32 var isDiverged: Bool { ahead > 0 && behind > 0 && error == nil } 33 33 var hasError: Bool { error != nil } 34 34 35 - /// The SF Symbol name to display in the menu bar. 36 - var menuBarIcon: String { 37 - if hasError { 38 - return "exclamationmark.triangle.fill" 39 - } 40 - if isDiverged { 41 - return "arrow.up.arrow.down.circle.fill" 42 - } 43 - if isAhead { 44 - return "arrow.up.circle.fill" 45 - } 46 - if isBehind { 47 - return "arrow.down.circle.fill" 48 - } 49 - return "checkmark.circle.fill" 50 - } 51 - 52 - /// The color for the menu bar icon. 53 - var menuBarColor: Color { 54 - if hasError { return .red } 55 - if isDiverged { return .yellow } 56 - if isAhead { return .blue } 57 - if isBehind { return .orange } 58 - return .green 59 - } 60 - 61 - /// Compact text shown next to the icon in the menu bar. 35 + /// Compact text shown in the menu bar. 62 36 var menuBarText: String { 63 37 if hasError { return "!" } 64 38 if isDiverged { return "\u{2191}\(ahead)\u{2193}\(behind)" } ··· 67 41 return "" 68 42 } 69 43 70 - /// Full text for the menu bar label (icon is handled separately via Image). 44 + /// Full text for the menu bar label. 71 45 var menuBarLabel: String { 72 46 var label = menuBarText 73 47 if dirty && !hasError { 74 48 label += "\u{25CF}" // ● dot 75 49 } 50 + if label.isEmpty { 51 + return "\u{2713}" // ✓ checkmark 52 + } 76 53 return label 77 54 } 78 55
+1 -56
Tests/HomeManagerStatusTests/RepoStatusTests.swift
··· 1 - import SwiftUI 2 1 import XCTest 3 2 4 3 @testable import HomeManagerStatus ··· 50 49 XCTAssertFalse(status.isDiverged) 51 50 } 52 51 53 - // MARK: - Menu bar icon 54 - 55 - func testMenuBarIconSynced() { 56 - let status = RepoStatus.synced(at: fixedDate) 57 - XCTAssertEqual(status.menuBarIcon, "checkmark.circle.fill") 58 - } 59 - 60 - func testMenuBarIconAhead() { 61 - let status = RepoStatus(ahead: 1, behind: 0, dirty: false, error: nil, checkedAt: fixedDate) 62 - XCTAssertEqual(status.menuBarIcon, "arrow.up.circle.fill") 63 - } 64 - 65 - func testMenuBarIconBehind() { 66 - let status = RepoStatus(ahead: 0, behind: 1, dirty: false, error: nil, checkedAt: fixedDate) 67 - XCTAssertEqual(status.menuBarIcon, "arrow.down.circle.fill") 68 - } 69 - 70 - func testMenuBarIconDiverged() { 71 - let status = RepoStatus(ahead: 2, behind: 3, dirty: false, error: nil, checkedAt: fixedDate) 72 - XCTAssertEqual(status.menuBarIcon, "arrow.up.arrow.down.circle.fill") 73 - } 74 - 75 - func testMenuBarIconError() { 76 - let status = RepoStatus.error("oops", at: fixedDate) 77 - XCTAssertEqual(status.menuBarIcon, "exclamationmark.triangle.fill") 78 - } 79 - 80 - // MARK: - Menu bar color 81 - 82 - func testMenuBarColorSynced() { 83 - let status = RepoStatus.synced(at: fixedDate) 84 - XCTAssertEqual(status.menuBarColor, .green) 85 - } 86 - 87 - func testMenuBarColorAhead() { 88 - let status = RepoStatus(ahead: 1, behind: 0, dirty: false, error: nil, checkedAt: fixedDate) 89 - XCTAssertEqual(status.menuBarColor, .blue) 90 - } 91 - 92 - func testMenuBarColorBehind() { 93 - let status = RepoStatus(ahead: 0, behind: 1, dirty: false, error: nil, checkedAt: fixedDate) 94 - XCTAssertEqual(status.menuBarColor, .orange) 95 - } 96 - 97 - func testMenuBarColorDiverged() { 98 - let status = RepoStatus(ahead: 1, behind: 1, dirty: false, error: nil, checkedAt: fixedDate) 99 - XCTAssertEqual(status.menuBarColor, .yellow) 100 - } 101 - 102 - func testMenuBarColorError() { 103 - let status = RepoStatus.error("oops", at: fixedDate) 104 - XCTAssertEqual(status.menuBarColor, .red) 105 - } 106 - 107 52 // MARK: - Menu bar text 108 53 109 54 func testMenuBarTextSynced() { ··· 141 86 142 87 func testMenuBarLabelSyncedClean() { 143 88 let status = RepoStatus.synced(dirty: false, at: fixedDate) 144 - XCTAssertEqual(status.menuBarLabel, "") 89 + XCTAssertEqual(status.menuBarLabel, "\u{2713}") 145 90 } 146 91 147 92 func testMenuBarLabelSyncedDirty() {

History

1 round 0 comments
sign up or login to add to the discussion
nolith.dev submitted #0
1 commit
expand
Simplify menu bar UI to text-only
1/1 success
expand
expand 0 comments
pull request successfully merged