From 14b0f431aa516bfb5ebe524da5fb15a1892e1d28 Mon Sep 17 00:00:00 2001 From: Vellum Assistant Date: Mon, 18 May 2026 21:15:27 -0400 Subject: [PATCH] feat(macos): show persona avatar in HomeDetailPanel header for assistant-initiated rows Co-Authored-By: Vellum Assistant --- .../Home/DetailPanel/HomeDetailPanel.swift | 45 ++++++++++++++++++- .../Features/Home/HomeGallerySection.swift | 32 +++++++++---- .../MainWindow/PanelCoordinator.swift | 3 +- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/clients/macos/vellum-assistant/Features/Home/DetailPanel/HomeDetailPanel.swift b/clients/macos/vellum-assistant/Features/Home/DetailPanel/HomeDetailPanel.swift index 056f802fea..f2b215353d 100644 --- a/clients/macos/vellum-assistant/Features/Home/DetailPanel/HomeDetailPanel.swift +++ b/clients/macos/vellum-assistant/Features/Home/DetailPanel/HomeDetailPanel.swift @@ -43,6 +43,11 @@ struct HomeDetailPanel: View { /// attachments footer to the bottom and wants the body text field to /// expand into the empty space above it. var scrollable: Bool = true + /// When `true`, render the 32pt persona avatar in the header's leading + /// slot instead of the category icon chip. Used for assistant-initiated + /// feed rows (`FeedItem.fromAssistant == true`) so the detail header + /// matches its list-row counterpart. + var showsPersonaAvatar: Bool = false @ViewBuilder let content: () -> Content var body: some View { @@ -83,7 +88,11 @@ struct HomeDetailPanel: View { private var header: some View { HStack(spacing: VSpacing.sm) { HStack(spacing: VSpacing.sm) { - if let icon { + if showsPersonaAvatar { + personaAvatar + .frame(width: 32, height: 32) + .accessibilityHidden(true) + } else if let icon { RoundedRectangle(cornerRadius: VRadius.md) .fill(iconBackground ?? VColor.surfaceBase) .frame(width: 32, height: 32) @@ -133,4 +142,38 @@ struct HomeDetailPanel: View { trailing: VSpacing.lg )) } + + /// 32pt persona avatar rendered into the header's leading slot for + /// assistant-initiated rows. Mirrors `HomeRecapRow.personaAvatar` at a + /// larger size; a follow-up extraction can dedupe this with + /// `HomePageView.greetingAvatar` and `HomeRecapRow.personaAvatar`. + @ViewBuilder + private var personaAvatar: some View { + let appearance = AvatarAppearanceManager.shared + let size: CGFloat = 32 + if appearance.customAvatarImage != nil { + VAvatarImage( + image: appearance.fullAvatarImage, + size: size, + showBorder: false + ) + } else if let bodyShape = appearance.characterBodyShape, + let eyes = appearance.characterEyeStyle, + let color = appearance.characterColor { + AnimatedAvatarView( + bodyShape: bodyShape, + eyeStyle: eyes, + color: color, + size: size, + entryAnimationEnabled: false + ) + .frame(width: size, height: size) + } else { + VAvatarImage( + image: appearance.fullAvatarImage, + size: size, + showBorder: false + ) + } + } } diff --git a/clients/macos/vellum-assistant/Features/Home/HomeGallerySection.swift b/clients/macos/vellum-assistant/Features/Home/HomeGallerySection.swift index dc53101c11..0a77321a6e 100644 --- a/clients/macos/vellum-assistant/Features/Home/HomeGallerySection.swift +++ b/clients/macos/vellum-assistant/Features/Home/HomeGallerySection.swift @@ -149,16 +149,30 @@ struct HomeGallerySection: View { description: "Reusable white right-side panel container with a standardized header (icon + title + \"Go to Thread\" action + dismiss)." ) - HomeDetailPanel( - icon: .file, - title: "Panel title", - onGoToThread: {}, - onDismiss: {} - ) { - Text("Detail content goes here.") - .padding(VSpacing.lg) + VStack(spacing: VSpacing.lg) { + HomeDetailPanel( + icon: .file, + title: "Panel title", + onGoToThread: {}, + onDismiss: {} + ) { + Text("Detail content goes here.") + .padding(VSpacing.lg) + } + .frame(height: 260) + + HomeDetailPanel( + icon: .bell, + title: "Assistant-initiated", + onGoToThread: {}, + onDismiss: {}, + showsPersonaAvatar: true + ) { + Text("Persona avatar replaces the category chip when the row originated from the assistant.") + .padding(VSpacing.lg) + } + .frame(height: 260) } - .frame(height: 520) } // MARK: - HomeSuggestionPillBar diff --git a/clients/macos/vellum-assistant/Features/MainWindow/PanelCoordinator.swift b/clients/macos/vellum-assistant/Features/MainWindow/PanelCoordinator.swift index fba2fb96ae..3782809ac1 100644 --- a/clients/macos/vellum-assistant/Features/MainWindow/PanelCoordinator.swift +++ b/clients/macos/vellum-assistant/Features/MainWindow/PanelCoordinator.swift @@ -280,7 +280,8 @@ extension MainWindowView { iconForeground: iconForegroundForFeedItem(item), iconBackground: iconBackgroundForFeedItem(item), onGoToThread: goToThreadHandler(for: item), - onDismiss: { activeHomeDetailPanel = nil } + onDismiss: { activeHomeDetailPanel = nil }, + showsPersonaAvatar: item.fromAssistant == true ) { Text(item.summary).font(VFont.bodyMediumDefault).foregroundStyle(VColor.contentSecondary).padding(VSpacing.lg) }