Restore Live shelf on Today, flatten Feed to time-ordered highlights

Today tab: Removed LiveSituationBar, restored the full Live game shelf
below the featured Astros card where it belongs.

Feed tab: Changed from two grouped shelves (condensed / highlights) to a
single horizontal scroll with ALL highlights ordered by timestamp (most
recent first). Added condensed game badge overlay on thumbnails. Added
date field to Highlight model for time-based ordering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-04-12 13:39:41 -05:00
parent cd605d889d
commit 39092e5f3d
4 changed files with 53 additions and 65 deletions

View File

@@ -121,25 +121,6 @@ struct DashboardView: View {
}
.padding(.top, 80)
} else {
// Live situation bar compact strip of all live games
if !viewModel.liveGames.isEmpty {
VStack(alignment: .leading, spacing: 12) {
HStack(spacing: 8) {
LiveIndicator()
Text("LIVE NOW")
.font(DS.Fonts.caption)
.foregroundStyle(DS.Colors.live)
.kerning(1.5)
}
.padding(.horizontal, 4)
LiveSituationBar(games: viewModel.liveGames) { game in
selectedGame = game
}
.padding(.horizontal, -horizontalPadding)
}
}
// Hero featured game
if let featured = viewModel.featuredGame {
FeaturedGameCard(game: featured) {
@@ -147,6 +128,9 @@ struct DashboardView: View {
}
}
if !viewModel.liveGames.isEmpty {
gameShelf(title: "Live", icon: "antenna.radiowaves.left.and.right", games: viewModel.liveGames, excludeId: viewModel.featuredGame?.id)
}
if !viewModel.scheduledGames.isEmpty {
gameShelf(title: "Upcoming", icon: "calendar", games: viewModel.scheduledGames, excludeId: viewModel.featuredGame?.id)
}

View File

@@ -35,23 +35,18 @@ struct FeedView: View {
if viewModel.highlights.isEmpty && !viewModel.isLoading {
emptyState
} else {
// Condensed Games
if !viewModel.condensedGames.isEmpty {
highlightShelf(
title: "Condensed Games",
icon: "film.stack",
items: viewModel.condensedGames
)
}
// Latest Highlights
if !viewModel.latestHighlights.isEmpty {
highlightShelf(
title: "Latest Highlights",
icon: "play.circle.fill",
items: viewModel.latestHighlights
)
// All highlights in one horizontal scroll, ordered by time
ScrollView(.horizontal) {
LazyHStack(spacing: DS.Spacing.cardGap) {
ForEach(viewModel.highlights) { item in
highlightCard(item)
.frame(width: cardWidth)
}
}
.padding(.vertical, 8)
}
.platformFocusSection()
.scrollClipDisabled()
}
}
.padding(.horizontal, edgeInset)
@@ -79,31 +74,6 @@ struct FeedView: View {
}
}
@ViewBuilder
private func highlightShelf(title: String, icon: String, items: [HighlightItem]) -> some View {
VStack(alignment: .leading, spacing: 14) {
Label(title, systemImage: icon)
#if os(tvOS)
.font(.system(size: 24, weight: .bold, design: .rounded))
#else
.font(.system(size: 18, weight: .bold, design: .rounded))
#endif
.foregroundStyle(DS.Colors.textSecondary)
ScrollView(.horizontal) {
LazyHStack(spacing: DS.Spacing.cardGap) {
ForEach(items) { item in
highlightCard(item)
.frame(width: cardWidth)
}
}
.padding(.vertical, 8)
}
.platformFocusSection()
.scrollClipDisabled()
}
}
@ViewBuilder
private func highlightCard(_ item: HighlightItem) -> some View {
Button {
@@ -136,6 +106,25 @@ struct FeedView: View {
.font(.system(size: playIconSize))
.foregroundStyle(.white.opacity(0.8))
.shadow(radius: 4)
// Condensed/Recap badge
if item.isCondensedGame {
VStack {
HStack {
Spacer()
Text("CONDENSED")
.font(DS.Fonts.caption)
.foregroundStyle(.white)
.kerning(0.8)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(DS.Colors.media)
.clipShape(Capsule())
}
Spacer()
}
.padding(8)
}
}
.frame(height: thumbnailHeight)
.clipShape(RoundedRectangle(cornerRadius: DS.Radii.compact))