From 4c263511c17d71da72e9d7144be453f0bdaa2c1a Mon Sep 17 00:00:00 2001 From: Jiun Bae Date: Mon, 26 Oct 2026 21:56:55 +0900 Subject: [PATCH] design: the hub wears the popup's marks Sidebar pages show their symbols on coloured tiles, as System Settings does, and Shelf board chips carry each widget's CardIconTile in its colour, so a widget looks the same in the popup and the hub. Board columns and chips use the Fill tokens and concentric corners. Form section footers are caption-size secondary text; the General page's menu bar icon note was rendering at body size. Settings and menu bar controls move their remaining literals onto tokens. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../Automation/AutomationSettingsView.swift | 2 +- Sources/MenubucketApp/Design/Components.swift | 4 ++- Sources/MenubucketApp/Hub/HubView.swift | 10 +++++-- .../Hub/HubWindowController.swift | 16 ++++++++++++ Sources/MenubucketApp/Hub/ShelfView.swift | 26 ++++++++++--------- .../MenubucketApp/MenuBarStyleControls.swift | 8 +++--- .../MenubucketApp/Settings/MenuBarPage.swift | 2 +- .../Settings/SettingsPages.swift | 2 +- .../Fixtures/design-literal-baseline.json | 7 +---- 9 files changed, 49 insertions(+), 28 deletions(-) diff --git a/Sources/MenubucketApp/Automation/AutomationSettingsView.swift b/Sources/MenubucketApp/Automation/AutomationSettingsView.swift index cebc9a5..4bbc51e 100644 --- a/Sources/MenubucketApp/Automation/AutomationSettingsView.swift +++ b/Sources/MenubucketApp/Automation/AutomationSettingsView.swift @@ -82,7 +82,7 @@ struct AutomationSettingsView: View { TextEditor(text: $draft) .font(.system(.body, design: .monospaced)) .frame(minHeight: 230) - .border(Color.secondary.opacity(0.25)) + .border(Fill.hairline) .accessibilityLabel("Automation JavaScript") HStack { Button(controller.isRunning ? String(localized: "Save & Reload") : String(localized: "Save Script")) { diff --git a/Sources/MenubucketApp/Design/Components.swift b/Sources/MenubucketApp/Design/Components.swift index a36e066..e906eec 100644 --- a/Sources/MenubucketApp/Design/Components.swift +++ b/Sources/MenubucketApp/Design/Components.swift @@ -111,7 +111,9 @@ extension View { /// in every language. A grouped form otherwise lays a wrapped footer out /// against the trailing edge. func formFooter() -> some View { - multilineTextAlignment(.leading) + font(.caption) + .foregroundStyle(.secondary) + .multilineTextAlignment(.leading) .frame(maxWidth: .infinity, alignment: .leading) } } diff --git a/Sources/MenubucketApp/Hub/HubView.swift b/Sources/MenubucketApp/Hub/HubView.swift index 1ddc737..fba5131 100644 --- a/Sources/MenubucketApp/Hub/HubView.swift +++ b/Sources/MenubucketApp/Hub/HubView.swift @@ -38,7 +38,13 @@ struct HubView: View { } private func sidebarRow(_ tab: HubTab) -> some View { - Label(tab.title, systemImage: tab.symbol) + // Symbols on coloured tiles, as in System Settings: the same mark + // a widget card carries in the popup. + Label { + Text(tab.title) + } icon: { + CardIconTile(symbol: tab.symbol, color: tab.tint, size: 20) + } .tag(tab) // A press as well as a selection, so accessibility clients that // press rather than select (automation, Switch Control) can @@ -52,7 +58,7 @@ struct HubView: View { Image(nsImage: BarShelfStatusIcon.logoImage(size: NSSize(width: 24, height: 18))) .renderingMode(.template) } - VStack(alignment: .leading, spacing: 1) { + VStack(alignment: .leading, spacing: 0) { Text("BarShelf") .font(.headline) Text("\(runtime.widgets.count) widgets installed") diff --git a/Sources/MenubucketApp/Hub/HubWindowController.swift b/Sources/MenubucketApp/Hub/HubWindowController.swift index 95d6a0d..4646ddc 100644 --- a/Sources/MenubucketApp/Hub/HubWindowController.swift +++ b/Sources/MenubucketApp/Hub/HubWindowController.swift @@ -37,6 +37,22 @@ enum HubTab: String, CaseIterable, Identifiable { } } + /// The tile colour behind the page's symbol in the sidebar. + var tint: Color { + switch self { + case .shelf: return .blue + case .menuBar: return .indigo + case .dock: return .teal + case .gallery: return .purple + case .create: return .pink + case .automation: return .orange + case .general, .advanced: return .gray + case .shortcuts: return .mint + case .updates: return .red + case .privacy: return .cyan + } + } + var symbol: String { switch self { case .shelf: return "square.grid.2x2" diff --git a/Sources/MenubucketApp/Hub/ShelfView.swift b/Sources/MenubucketApp/Hub/ShelfView.swift index 65f5834..c4e0368 100644 --- a/Sources/MenubucketApp/Hub/ShelfView.swift +++ b/Sources/MenubucketApp/Hub/ShelfView.swift @@ -174,7 +174,7 @@ struct ShelfView: View { // The end of the column, so a widget can be dropped last. RoundedRectangle(cornerRadius: Radius.control, style: .continuous) .strokeBorder(style: StrokeStyle(lineWidth: 1, dash: [4, 3])) - .foregroundStyle(dropHighlight == page.name ? Color.accentColor : Color.secondary.opacity(0.35)) + .foregroundStyle(dropHighlight == page.name ? AnyShapeStyle(Color.accentColor) : AnyShapeStyle(.tertiary)) .frame(height: 30) .overlay(Text("Drop here").font(.caption).foregroundStyle(.secondary)) .dropDestination(for: String.self) { ids, _ in @@ -190,7 +190,7 @@ struct ShelfView: View { .frame(width: columnWidth, alignment: .top) .background( RoundedRectangle(cornerRadius: Radius.card, style: .continuous) - .fill(Color.primary.opacity(0.035)) + .fill(Fill.card) ) } @@ -199,11 +199,13 @@ struct ShelfView: View { let disabled = runtime.prefs.isDisabled(widget.id) let status = chipStatus(widget, disabled: disabled) return HStack(spacing: Spacing.xs) { - Image(systemName: widget.manifest.icon ?? "square.dashed") - .foregroundStyle(isSelected ? Color.accentColor : .secondary) - .frame(width: 18) - .accessibilityHidden(true) - VStack(alignment: .leading, spacing: 1) { + // The same mark the widget's card carries in the popup. + CardIconTile( + symbol: widget.manifest.icon ?? "square.dashed", + color: runtime.prefs.effectiveAppearance(for: widget.manifest, widgetID: widget.id).accentColor ?? .accentColor, + size: 22 + ) + VStack(alignment: .leading, spacing: Spacing.hair / 2) { Text(widget.displayName) .lineLimit(1) // The widget's current reading says more about it than its @@ -229,15 +231,15 @@ struct ShelfView: View { } } .padding(.horizontal, Spacing.xs) - .padding(.vertical, 6) + .padding(.vertical, Spacing.stack) .opacity(disabled ? 0.55 : 1) .background( - RoundedRectangle(cornerRadius: Radius.control, style: .continuous) - .fill(isSelected ? Color.accentColor.opacity(0.16) : Color(nsColor: .controlBackgroundColor)) + RoundedRectangle(cornerRadius: Radius.nested(in: Radius.card, inset: Spacing.xxs), style: .continuous) + .fill(isSelected ? AnyShapeStyle(Color.accentColor.opacity(Fill.Wash.strong)) : AnyShapeStyle(Color(nsColor: .controlBackgroundColor))) ) .overlay( - RoundedRectangle(cornerRadius: Radius.control, style: .continuous) - .strokeBorder(isSelected ? Color.accentColor : Color.primary.opacity(0.08)) + RoundedRectangle(cornerRadius: Radius.nested(in: Radius.card, inset: Spacing.xxs), style: .continuous) + .strokeBorder(isSelected ? AnyShapeStyle(Color.accentColor) : AnyShapeStyle(Fill.hairline), lineWidth: 1) ) .contentShape(Rectangle()) .onTapGesture { selection = widget.id } diff --git a/Sources/MenubucketApp/MenuBarStyleControls.swift b/Sources/MenubucketApp/MenuBarStyleControls.swift index 0a21011..5807dfd 100644 --- a/Sources/MenubucketApp/MenuBarStyleControls.swift +++ b/Sources/MenubucketApp/MenuBarStyleControls.swift @@ -28,7 +28,7 @@ struct MenuBarStyleControls { @ViewBuilder var width: some View { let presentation = shown - VStack(alignment: .leading, spacing: 6) { + VStack(alignment: .leading, spacing: Spacing.stack) { Picker("Width", selection: Binding( get: { presentation.effectiveWidth }, set: { mode in change { $0.width = keep(mode, \.effectiveWidth) } } @@ -89,8 +89,8 @@ struct MenuBarStyleControls { @ViewBuilder var text: some View { let presentation = shown - VStack(alignment: .leading, spacing: 6) { - HStack(spacing: 10) { + VStack(alignment: .leading, spacing: Spacing.stack) { + HStack(spacing: Spacing.s) { Picker("Text alignment", selection: Binding( get: { presentation.effectiveAlignment }, set: { value in change { $0.alignment = keep(value, \.effectiveAlignment) } } @@ -152,7 +152,7 @@ struct MenuBarStyleControls { @ViewBuilder var color: some View { let presentation = shown - VStack(alignment: .leading, spacing: 4) { + VStack(alignment: .leading, spacing: Spacing.xxs) { Picker("Color", selection: Binding( get: { presentation.color ?? "automatic" }, // "automatic" is stored when it differs from what is diff --git a/Sources/MenubucketApp/Settings/MenuBarPage.swift b/Sources/MenubucketApp/Settings/MenuBarPage.swift index ef99531..8e7c675 100644 --- a/Sources/MenubucketApp/Settings/MenuBarPage.swift +++ b/Sources/MenubucketApp/Settings/MenuBarPage.swift @@ -208,7 +208,7 @@ private struct MenuBarItemRow: View { .controlSize(.small) } } - .padding(.vertical, 2) + .padding(.vertical, Spacing.hair) } /// What the item shows right now — or why a switched-on item shows diff --git a/Sources/MenubucketApp/Settings/SettingsPages.swift b/Sources/MenubucketApp/Settings/SettingsPages.swift index d5c64ee..43dd17b 100644 --- a/Sources/MenubucketApp/Settings/SettingsPages.swift +++ b/Sources/MenubucketApp/Settings/SettingsPages.swift @@ -516,7 +516,7 @@ private struct DiagnosticsRow: View { var body: some View { LabeledContent { - VStack(alignment: .trailing, spacing: 2) { + VStack(alignment: .trailing, spacing: Spacing.hair) { if hasRun { Label(outcome.text, systemImage: outcome.tone.symbol) .foregroundStyle(outcome.tone.color) diff --git a/Tests/MenubucketAppTests/Fixtures/design-literal-baseline.json b/Tests/MenubucketAppTests/Fixtures/design-literal-baseline.json index 96eb486..cd05e9b 100644 --- a/Tests/MenubucketAppTests/Fixtures/design-literal-baseline.json +++ b/Tests/MenubucketAppTests/Fixtures/design-literal-baseline.json @@ -1,5 +1,4 @@ { - "Sources\/MenubucketApp\/Automation\/AutomationSettingsView.swift" : 1, "Sources\/MenubucketApp\/Builder\/WidgetBuilderView.swift" : 107, "Sources\/MenubucketApp\/Dock\/DockFolderStack.swift" : 5, "Sources\/MenubucketApp\/Dock\/DockSettingsPage.swift" : 4, @@ -8,15 +7,11 @@ "Sources\/MenubucketApp\/Gallery\/GalleryCard.swift" : 17, "Sources\/MenubucketApp\/Gallery\/GalleryDetailView.swift" : 3, "Sources\/MenubucketApp\/Gallery\/GalleryView.swift" : 4, - "Sources\/MenubucketApp\/Hub\/HubView.swift" : 1, - "Sources\/MenubucketApp\/Hub\/ShelfView.swift" : 7, - "Sources\/MenubucketApp\/MenuBarStyleControls.swift" : 4, + "Sources\/MenubucketApp\/Hub\/ShelfView.swift" : 1, "Sources\/MenubucketApp\/Onboarding\/OnboardingView.swift" : 5, "Sources\/MenubucketApp\/Popover\/RootView.swift" : 2, "Sources\/MenubucketApp\/Renderer\/ViewTreeRenderer.swift" : 1, "Sources\/MenubucketApp\/ScreenshotMode.swift" : 169, - "Sources\/MenubucketApp\/Settings\/MenuBarPage.swift" : 1, - "Sources\/MenubucketApp\/Settings\/SettingsPages.swift" : 1, "Sources\/MenubucketApp\/WidgetSettingsView.swift" : 49, "WidgetExtension\/BarShelfWidgets\/ShelfTemplates.swift" : 20, "WidgetExtension\/BarShelfWidgets\/ShelfWidget.swift" : 6,