native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(repo-appearance): tint shelf spine and add icon to spine header

- ShelfSpineView reads `@Shared(.repositoryAppearances)` for the book's
repo, derives `effectiveTintColor = repoColor ?? .accentColor`, and
feeds that color into `spineBackgroundColor`. The proximity-distance
ladder (selected=1.0, neighbor=0.5, …, far=0.05) is unchanged — only
the hue swaps. Hover-bumped intensity for unselected spines and the
neutral fallback when no book is open both still work.
- ShelfSpineHeader gains a 14pt icon at the top of the VStack, drawn
via the shared RepositoryIconImage so tinting matches the sidebar
exactly. Notification-dot top padding shifts when the icon is
present so the spacing reads consistently with or without an icon.

onevcat 4fa01da1 434d9202

+36 -3
+36 -3
supacode/Features/Shelf/Views/ShelfSpineView.swift
··· 1 + import Sharing 1 2 import SwiftUI 2 3 3 4 /// Vertical spine rendering for a single book on the Shelf. ··· 33 34 let onCloseBook: (() -> Void)? 34 35 35 36 @State private var isHovering = false 37 + @Shared(.repositoryAppearances) private var repositoryAppearances 36 38 37 39 var body: some View { 38 40 VStack(spacing: 0) { ··· 98 100 /// bumps its tint to 80% of the selected book's intensity — a clear 99 101 /// "this is interactable" affordance that sits just below the open 100 102 /// book and animates in/out smoothly. 103 + /// 104 + /// When the book's repository has a user-pinned color, that color 105 + /// replaces `Color.accentColor` as the proximity-tint base so the 106 + /// shelf reads as "books on shelves" instead of one continuous 107 + /// accent ribbon. The proximity ladder is unchanged — we only swap 108 + /// the hue. 101 109 private var spineBackgroundColor: Color { 102 110 guard distanceFromOpen != nil else { 103 111 return Color.primary.opacity(0.06) 104 112 } 105 113 let multiplier = isHovering && !isOpen ? 0.8 : accentProximityMultiplier 106 - return Color.accentColor.opacity(0.20 * multiplier) 114 + return effectiveTintColor.opacity(0.20 * multiplier) 115 + } 116 + 117 + /// Repo's pinned color, or `.accentColor` when none — used as the 118 + /// proximity-tint base and as the icon tint in the header. 119 + private var effectiveTintColor: Color { 120 + appearance.color?.color ?? .accentColor 121 + } 122 + 123 + private var appearance: RepositoryAppearance { 124 + repositoryAppearances[book.repositoryID] ?? .empty 107 125 } 108 126 109 127 /// Active-tab highlight fades more gently than the spine background — ··· 173 191 Button(action: onOpenBook) { 174 192 ShelfSpineHeader( 175 193 book: book, 176 - hasAggregatedNotification: terminalState?.hasUnseenNotification == true 194 + hasAggregatedNotification: terminalState?.hasUnseenNotification == true, 195 + icon: appearance.icon, 196 + iconTint: effectiveTintColor, 197 + repositoryRootURL: URL(fileURLWithPath: book.repositoryID) 177 198 ) 178 199 .frame(maxWidth: .infinity) 179 200 .contentShape(.rect) ··· 244 265 private struct ShelfSpineHeader: View { 245 266 let book: ShelfBook 246 267 let hasAggregatedNotification: Bool 268 + let icon: RepositoryIconSource? 269 + let iconTint: Color 270 + let repositoryRootURL: URL 247 271 248 272 var body: some View { 249 273 VStack(spacing: 6) { 274 + if let icon { 275 + RepositoryIconImage( 276 + icon: icon, 277 + repositoryRootURL: repositoryRootURL, 278 + tintColor: iconTint, 279 + size: 14 280 + ) 281 + .padding(.top, 6) 282 + } 250 283 Circle() 251 284 .fill(.orange) 252 285 .frame(width: ShelfMetrics.aggregatedDotSize, height: ShelfMetrics.aggregatedDotSize) 253 286 .opacity(hasAggregatedNotification ? 1 : 0) 254 287 .accessibilityLabel("Unread notifications") 255 288 .accessibilityHidden(!hasAggregatedNotification) 256 - .padding(.top, 6) 289 + .padding(.top, icon == nil ? 6 : 0) 257 290 rotatedTitle 258 291 } 259 292 }