Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ struct HomeDetailPanel<Content: View>: 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 {
Expand Down Expand Up @@ -83,7 +88,11 @@ struct HomeDetailPanel<Content: View>: 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)
Expand Down Expand Up @@ -133,4 +142,38 @@ struct HomeDetailPanel<Content: View>: 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
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down