Fix hero to match reference: white surface, image right, outlined CTA
Completely rebuilt FeaturedGameCard to match the Dribbble vtv reference. White/cream background surface instead of dark card. Stadium image sits on the right side and fades into white via left-to-right gradient. Dark text on light background. "Watch Now" as outlined orange pill (not filled). Plus icon for add-to-multiview. Title uses split weight: thin "Houston Astros vs" + bold orange "Seattle Mariners" — mimicking the "modern family" typography split. Cleaned up DashboardView header: removed bulky MLB/date/stat pills section. Replaced with compact inline date nav: chevron left, date text, chevron right, "Today" link, game count + live count on the right. One line instead of a full section. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -371,77 +371,71 @@ struct DashboardView: View {
|
||||
|
||||
@ViewBuilder
|
||||
private var headerSection: some View {
|
||||
VStack(spacing: 24) {
|
||||
HStack(alignment: .bottom) {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("MLB")
|
||||
.font(.headline.weight(.black))
|
||||
.foregroundStyle(DS.Colors.textTertiary)
|
||||
.kerning(4)
|
||||
Text(viewModel.displayDateString)
|
||||
.font(.system(size: 40, weight: .bold))
|
||||
.foregroundStyle(DS.Colors.textPrimary)
|
||||
.contentTransition(.numericText())
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 16) {
|
||||
statPill("\(viewModel.games.count)", label: "Games")
|
||||
if !viewModel.liveGames.isEmpty {
|
||||
statPill("\(viewModel.liveGames.count)", label: "Live", color: .red)
|
||||
}
|
||||
if !viewModel.activeStreams.isEmpty {
|
||||
statPill("\(viewModel.activeStreams.count)/4", label: "Streams", color: .green)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HStack(spacing: 16) {
|
||||
HStack(alignment: .center) {
|
||||
// Date navigation — compact inline
|
||||
HStack(spacing: 12) {
|
||||
Button {
|
||||
Task { await viewModel.goToPreviousDay() }
|
||||
} label: {
|
||||
Label("Previous Day", systemImage: "chevron.left")
|
||||
Image(systemName: "chevron.left")
|
||||
.font(.system(size: dateNavIconSize, weight: .semibold))
|
||||
.foregroundStyle(DS.Colors.textTertiary)
|
||||
}
|
||||
|
||||
Text(viewModel.displayDateString)
|
||||
.font(dateFont)
|
||||
.foregroundStyle(DS.Colors.textPrimary)
|
||||
.contentTransition(.numericText())
|
||||
|
||||
Button {
|
||||
Task { await viewModel.goToNextDay() }
|
||||
} label: {
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.system(size: dateNavIconSize, weight: .semibold))
|
||||
.foregroundStyle(DS.Colors.textTertiary)
|
||||
}
|
||||
|
||||
if !viewModel.isToday {
|
||||
Button {
|
||||
Task { await viewModel.goToToday() }
|
||||
} label: {
|
||||
Label("Today", systemImage: "calendar")
|
||||
}
|
||||
.tint(.blue)
|
||||
}
|
||||
|
||||
Button {
|
||||
Task { await viewModel.goToNextDay() }
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
Text("Next Day")
|
||||
Image(systemName: "chevron.right")
|
||||
Text("Today")
|
||||
.font(todayBtnFont)
|
||||
.foregroundStyle(DS.Colors.interactive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 12) {
|
||||
Text("\(viewModel.games.count) games")
|
||||
.font(metaCountFont)
|
||||
.foregroundStyle(DS.Colors.textTertiary)
|
||||
|
||||
if !viewModel.liveGames.isEmpty {
|
||||
HStack(spacing: 5) {
|
||||
Circle().fill(DS.Colors.live).frame(width: 7, height: 7)
|
||||
Text("\(viewModel.liveGames.count) live")
|
||||
.font(metaCountFont)
|
||||
.foregroundStyle(DS.Colors.live)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func statPill(_ value: String, label: String, color: Color = DS.Colors.interactive) -> some View {
|
||||
VStack(spacing: 2) {
|
||||
Text(value)
|
||||
.font(DS.Fonts.dataValue)
|
||||
.foregroundStyle(color)
|
||||
Text(label)
|
||||
.dataLabelStyle()
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 10)
|
||||
.background(DS.Colors.panelFill)
|
||||
.clipShape(RoundedRectangle(cornerRadius: DS.Radii.compact))
|
||||
.shadow(color: DS.Shadows.card, radius: DS.Shadows.cardRadius, y: DS.Shadows.cardY)
|
||||
}
|
||||
#if os(tvOS)
|
||||
private var dateFont: Font { .system(size: 32, weight: .bold) }
|
||||
private var dateNavIconSize: CGFloat { 22 }
|
||||
private var todayBtnFont: Font { .system(size: 22, weight: .bold, design: .rounded) }
|
||||
private var metaCountFont: Font { .system(size: 22, weight: .medium) }
|
||||
#else
|
||||
private var dateFont: Font { .system(size: 22, weight: .bold) }
|
||||
private var dateNavIconSize: CGFloat { 16 }
|
||||
private var todayBtnFont: Font { .system(size: 15, weight: .bold, design: .rounded) }
|
||||
private var metaCountFont: Font { .system(size: 14, weight: .medium) }
|
||||
#endif
|
||||
|
||||
// MARK: - Featured Channels
|
||||
|
||||
|
||||
Reference in New Issue
Block a user