Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2025-12-22 22:46:45 -06:00
parent edd9218738
commit 64199d5bb3
11 changed files with 61 additions and 191 deletions

View File

@ -29,72 +29,26 @@ enum Design {
typealias BaseFontSize = CasinoDesign.BaseFontSize
typealias IconSize = CasinoDesign.IconSize
// MARK: - Baccarat-Specific Component Sizes
// MARK: - Baccarat-Specific Sizes (use CasinoDesign.Size for shared values)
enum Size {
// MARK: - Hand Scaling
// Card display on table
static let cardWidthTable: CGFloat = 70 // iPhone
static let cardWidthTableiPad: CGFloat = 90 // iPad
static let cardOverlap: CGFloat = -35 // iPhone (negative = more overlap)
static let cardOverlapiPad: CGFloat = -45 // iPad
// Use shared scaling from CasinoKit
static var handScale: CGFloat { CasinoDesign.Size.handScale }
static var fontScale: CGFloat { CasinoDesign.Size.fontScale }
/// Additional scale multiplier for large screens (iPad).
static let largeScreenMultiplier: CGFloat = 1.2
// Cards - base values from CasinoDesign
static let cardWidthSmall: CGFloat = CasinoDesign.Size.cardWidthSmall
static let cardWidthMedium: CGFloat = CasinoDesign.Size.cardWidthMedium
static let cardWidthLarge: CGFloat = CasinoDesign.Size.cardWidthLarge
static let cardAspectRatio: CGFloat = CasinoDesign.Size.cardAspectRatio
/// Base card width before scaling
static let cardWidthTableBase: CGFloat = 45
/// Base card overlap before scaling.
/// More negative = more overlap (less card visible).
private static let cardOverlapBase: CGFloat = -25
/// Card width scaled for the current device.
static var cardWidthTable: CGFloat {
cardWidthTableBase * handScale
}
/// Card width scaled for iPad (with large screen multiplier).
static var cardWidthTableLarge: CGFloat {
cardWidthTableBase * handScale * largeScreenMultiplier
}
/// Card overlap scaled for the current device.
static var cardOverlap: CGFloat {
cardOverlapBase * handScale
}
/// Card overlap scaled for iPad (with large screen multiplier).
static var cardOverlapLarge: CGFloat {
cardOverlapBase * handScale * largeScreenMultiplier
}
// Chips - use CasinoDesign values
static let chipSmall: CGFloat = CasinoDesign.Size.chipSmall
static let chipMedium: CGFloat = CasinoDesign.Size.chipMedium
static let chipSelector: CGFloat = CasinoDesign.Size.chipMedium
static let chipBadge: CGFloat = CasinoDesign.Size.chipBadge
static let chipBadgeInner: CGFloat = CasinoDesign.Size.chipBadgeInner
// Shared values
static let valueBadge: CGFloat = CasinoDesign.Size.valueBadge
static let checkmark: CGFloat = CasinoDesign.Size.checkmark
static let maxContentWidthPortrait: CGFloat = CasinoDesign.Size.maxContentWidthPortrait
static let maxContentWidthLandscape: CGFloat = CasinoDesign.Size.maxContentWidthLandscape
static let maxModalWidth: CGFloat = CasinoDesign.Size.maxModalWidth
// Baccarat-specific table layout
// Table layout
static let tableAspectRatio: CGFloat = 1.6
static let roadMapCell: CGFloat = 16
static let diamondIcon: CGFloat = 24
static let topBetRowHeight: CGFloat = 52
static let mainBetRowHeight: CGFloat = 65
static let topBetRowHeight: CGFloat = 40
static let mainBetRowHeight: CGFloat = 50
static let bonusZoneWidth: CGFloat = 80
// Labels
static let labelFontSize: CGFloat = 14
static let labelRowHeight: CGFloat = 30
}
}
@ -107,11 +61,9 @@ extension Color {
/// Typealias for consistent table colors across all games.
typealias Table = CasinoTable
// MARK: - Border Colors
// MARK: - Border Colors (Baccarat-specific)
enum Border {
static let goldLight = CasinoTable.goldLight
static let goldDark = CasinoTable.goldDark
static let gold = Color(red: 0.7, green: 0.55, blue: 0.25)
static let silver = Color(red: 0.6, green: 0.6, blue: 0.65)
}
@ -140,77 +92,6 @@ extension Color {
static let dragonBonusDark = Color(red: 0.15, green: 0.2, blue: 0.35)
}
// MARK: - Button Colors
enum Button {
static let goldLight = Color(red: 1.0, green: 0.85, blue: 0.3)
static let goldDark = Color(red: 0.9, green: 0.7, blue: 0.2)
static let destructive = Color(red: 0.6, green: 0.2, blue: 0.2)
}
// MARK: - Chip Colors (for theming)
enum Chip {
static let gold = Color(red: 0.8, green: 0.65, blue: 0.2)
// Chip base colors by denomination
static let tenBase = Color(red: 0.2, green: 0.4, blue: 0.8)
static let tenHighlight = Color(red: 0.3, green: 0.5, blue: 0.9)
static let twentyFiveBase = Color(red: 0.1, green: 0.6, blue: 0.3)
static let twentyFiveHighlight = Color(red: 0.2, green: 0.7, blue: 0.4)
static let fiftyBase = Color(red: 0.8, green: 0.5, blue: 0.1)
static let fiftyHighlight = Color(red: 0.9, green: 0.6, blue: 0.2)
static let hundredBase = Color(red: 0.1, green: 0.1, blue: 0.1)
static let hundredHighlight = Color(red: 0.3, green: 0.3, blue: 0.3)
static let fiveHundredBase = Color(red: 0.6, green: 0.2, blue: 0.6)
static let fiveHundredHighlight = Color(red: 0.7, green: 0.3, blue: 0.7)
static let thousandBase = Color(red: 0.8, green: 0.65, blue: 0.2)
static let thousandHighlight = Color(red: 0.9, green: 0.75, blue: 0.3)
static let fiveThousandBase = Color(red: 0.7, green: 0.1, blue: 0.2)
static let fiveThousandHighlight = Color(red: 0.85, green: 0.2, blue: 0.3)
static let tenThousandBase = Color(red: 0.2, green: 0.5, blue: 0.5)
static let tenThousandHighlight = Color(red: 0.3, green: 0.6, blue: 0.6)
static let twentyFiveThousandBase = Color(red: 0.5, green: 0.3, blue: 0.1)
static let twentyFiveThousandHighlight = Color(red: 0.65, green: 0.45, blue: 0.2)
static let fiftyThousandBase = Color(red: 0.75, green: 0.75, blue: 0.8)
static let fiftyThousandHighlight = Color(red: 0.85, green: 0.85, blue: 0.9)
static let hundredThousandBase = Color(red: 0.9, green: 0.1, blue: 0.3)
static let hundredThousandHighlight = Color(red: 1.0, green: 0.2, blue: 0.4)
// Accent stripe colors
static let goldStripe = Color(red: 0.9, green: 0.75, blue: 0.3)
static let darkStripe = Color(red: 0.2, green: 0.2, blue: 0.3)
static let goldRubyStripe = Color(red: 0.9, green: 0.85, blue: 0.3)
}
// MARK: - Card Colors
enum Card {
// Card back
static let backDark = Color(red: 0.6, green: 0.1, blue: 0.15)
static let backLight = Color(red: 0.4, green: 0.05, blue: 0.1)
static let patternLight = Color(red: 0.9, green: 0.7, blue: 0.4)
static let patternDark = Color(red: 0.7, green: 0.5, blue: 0.2)
static let innerDark = Color(red: 0.5, green: 0.08, blue: 0.12)
static let innerLight = Color(red: 0.35, green: 0.04, blue: 0.08)
static let diamondPattern = Color(red: 0.9, green: 0.7, blue: 0.4)
static let logoText = Color(red: 0.4, green: 0.05, blue: 0.1)
}
// MARK: - Modal Colors
enum Modal {
static let backgroundLight = Color(red: 0.12, green: 0.12, blue: 0.14)
static let backgroundDark = Color(red: 0.08, green: 0.08, blue: 0.1)
}
// MARK: - Settings Colors
enum Settings {
static let background = Color(red: 0.08, green: 0.12, blue: 0.18)
static let cardBackground = Color.white.opacity(CasinoDesign.Opacity.verySubtle)
static let accent = Color(red: 0.9, green: 0.75, blue: 0.3)
}
}
// MARK: - Localized Strings Helper

View File

@ -99,7 +99,7 @@ struct ActionButtonsView: View {
.padding(Design.Spacing.medium + Design.Spacing.xxSmall)
.background(
Circle()
.fill(Color.Button.destructive)
.fill(Color.CasinoButton.destructive)
)
.opacity(gameState.currentBets.isEmpty ? Design.Opacity.disabled : 1.0)
.disabled(gameState.currentBets.isEmpty)
@ -112,7 +112,7 @@ struct ActionButtonsView: View {
.padding(.vertical, Design.Spacing.medium + Design.Spacing.xxSmall)
.background(
Capsule()
.fill(Color.Button.destructive)
.fill(Color.CasinoButton.destructive)
)
.opacity(gameState.currentBets.isEmpty ? Design.Opacity.disabled : 1.0)
.disabled(gameState.currentBets.isEmpty)
@ -122,7 +122,7 @@ struct ActionButtonsView: View {
@ViewBuilder
private var dealButton: some View {
let buttonBackground = LinearGradient(
colors: [Color.Button.goldLight, Color.Button.goldDark],
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
startPoint: .top,
endPoint: .bottom
)
@ -160,7 +160,7 @@ struct ActionButtonsView: View {
@ViewBuilder
private var newRoundButton: some View {
let buttonBackground = LinearGradient(
colors: [Color.Button.goldLight, Color.Button.goldDark],
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
startPoint: .top,
endPoint: .bottom
)

View File

@ -54,7 +54,7 @@ struct GameTableView: View {
/// Maximum width for game content on large screens
private var maxContentWidth: CGFloat {
isLandscape ? Design.Size.maxContentWidthLandscape : Design.Size.maxContentWidthPortrait
isLandscape ? CasinoDesign.Size.maxContentWidthLandscape : CasinoDesign.Size.maxContentWidthPortrait
}
private var state: GameState {

View File

@ -18,7 +18,7 @@ struct GameOverView: View {
/// Maximum width for the modal card on iPad
private var maxModalWidth: CGFloat {
horizontalSizeClass == .regular ? Design.Size.maxModalWidth : .infinity
horizontalSizeClass == .regular ? CasinoDesign.Size.maxModalWidth : .infinity
}
// MARK: - Scaled Font Sizes (Dynamic Type)
@ -134,7 +134,7 @@ struct GameOverView: View {
Capsule()
.fill(
LinearGradient(
colors: [Color.Button.goldLight, Color.Button.goldDark],
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
startPoint: .top,
endPoint: .bottom
)
@ -149,7 +149,7 @@ struct GameOverView: View {
RoundedRectangle(cornerRadius: modalCornerRadius)
.fill(
LinearGradient(
colors: [Color.Modal.backgroundLight, Color.Modal.backgroundDark],
colors: [Color.CasinoModal.backgroundLight, Color.CasinoModal.backgroundDark],
startPoint: .top,
endPoint: .bottom
)

View File

@ -35,7 +35,7 @@ struct ResultBannerView: View {
/// Maximum width for the banner card on iPad
private var maxBannerWidth: CGFloat {
horizontalSizeClass == .regular ? Design.Size.maxModalWidth : .infinity
horizontalSizeClass == .regular ? CasinoDesign.Size.maxModalWidth : .infinity
}
// MARK: - Scaled Font Sizes (Dynamic Type)
@ -151,7 +151,7 @@ struct ResultBannerView: View {
Capsule()
.fill(
LinearGradient(
colors: [Color.Button.goldLight, Color.Button.goldDark],
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
startPoint: .top,
endPoint: .bottom
)
@ -177,7 +177,7 @@ struct ResultBannerView: View {
Capsule()
.fill(
LinearGradient(
colors: [Color.Button.goldLight, Color.Button.goldDark],
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
startPoint: .top,
endPoint: .bottom
)

View File

@ -120,7 +120,7 @@ struct RulesHelpView: View {
var body: some View {
NavigationStack {
ZStack {
Color.Settings.background
Color.Sheet.background
.ignoresSafeArea()
VStack(spacing: 0) {
@ -137,7 +137,7 @@ struct RulesHelpView: View {
HStack(spacing: Design.Spacing.small) {
ForEach(pages.indices, id: \.self) { index in
Circle()
.fill(index == currentPage ? Color.Settings.accent : Color.white.opacity(Design.Opacity.light))
.fill(index == currentPage ? Color.Sheet.accent : Color.white.opacity(Design.Opacity.light))
.frame(width: 8, height: 8)
}
}
@ -151,10 +151,10 @@ struct RulesHelpView: View {
Button(String(localized: "Done")) {
dismiss()
}
.foregroundStyle(Color.Settings.accent)
.foregroundStyle(Color.Sheet.accent)
}
}
.toolbarBackground(Color.Settings.background, for: .navigationBar)
.toolbarBackground(Color.Sheet.background, for: .navigationBar)
.toolbarColorScheme(.dark, for: .navigationBar)
}
}
@ -184,7 +184,7 @@ struct RulePageView: View {
// Icon
Image(systemName: page.icon)
.font(.system(size: iconSize))
.foregroundStyle(Color.Settings.accent)
.foregroundStyle(Color.Sheet.accent)
.padding(.top, Design.Spacing.xxLarge)
// Title
@ -197,7 +197,7 @@ struct RulePageView: View {
ForEach(page.content.indices, id: \.self) { index in
HStack(alignment: .top, spacing: Design.Spacing.medium) {
Text("")
.foregroundStyle(Color.Settings.accent)
.foregroundStyle(Color.Sheet.accent)
Text(page.content[index])
.font(.system(size: bodySize))

View File

@ -27,7 +27,7 @@ struct SettingsView: View {
}
/// Accent color for settings components
private let accent = Color.Settings.accent
private let accent = Color.Sheet.accent
var body: some View {
SheetContainerView(
@ -334,7 +334,7 @@ struct DeckCountPicker: View {
title: count.displayName,
subtitle: count.description,
isSelected: selection == count,
accentColor: Color.Settings.accent,
accentColor: Color.Sheet.accent,
action: { selection = count }
)
}
@ -354,8 +354,8 @@ struct TableLimitsPicker: View {
title: limit.displayName,
subtitle: limit.detailedDescription,
isSelected: selection == limit,
accentColor: Color.Settings.accent,
badge: { BadgePill(text: limit.description, isSelected: selection == limit, accentColor: Color.Settings.accent) },
accentColor: Color.Sheet.accent,
badge: { BadgePill(text: limit.description, isSelected: selection == limit, accentColor: Color.Sheet.accent) },
action: { selection = limit }
)
}

View File

@ -28,12 +28,12 @@ struct BettingTableView: View {
/// Top bet row height - shorter in landscape
private var topRowHeight: CGFloat {
isLandscape ? 40 : Design.Size.topBetRowHeight
Design.Size.topBetRowHeight
}
/// Main bet row height - shorter in landscape
private var mainRowHeight: CGFloat {
isLandscape ? 50 : Design.Size.mainBetRowHeight
Design.Size.mainBetRowHeight
}
// MARK: - Computed Properties
@ -155,7 +155,7 @@ struct BettingTableView: View {
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
.strokeBorder(
LinearGradient(
colors: [Color.Border.goldLight, Color.Border.goldDark],
colors: [Color.CasinoTable.goldLight, Color.CasinoTable.goldDark],
startPoint: .top,
endPoint: .bottom
),
@ -404,7 +404,7 @@ private struct MainBetZone: View {
// Content - always centered
VStack(spacing: Design.Spacing.xxSmall + 1) {
Text(title)
.font(.system(size: Design.BaseFontSize.xxLarge, weight: .black, design: .rounded))
.font(.system(size: Design.BaseFontSize.xLarge, weight: .black, design: .rounded))
.tracking(2)
Text(payoutText)
@ -531,12 +531,12 @@ private struct ChipBadge: View {
// Outer ring
Circle()
.fill(isMax ? Color.gray : Color.yellow)
.frame(width: Design.Size.chipBadge, height: Design.Size.chipBadge)
.frame(width: CasinoDesign.Size.chipBadge, height: CasinoDesign.Size.chipBadge)
// Inner decoration
Circle()
.strokeBorder(Color.white.opacity(Design.Opacity.almostFull), lineWidth: Design.LineWidth.standard)
.frame(width: Design.Size.chipBadgeInner, height: Design.Size.chipBadgeInner)
.frame(width: CasinoDesign.Size.chipBadgeInner, height: CasinoDesign.Size.chipBadgeInner)
// Text
if isMax {

View File

@ -36,26 +36,14 @@ struct CardsDisplayArea: View {
// Use global debug flag from Design constants
private var showDebugBorders: Bool { Design.showDebugBorders }
/// Label font size - scales differently for small devices, standard iPhones, and iPads
/// Label font size - larger on iPad
private var labelFontSize: CGFloat {
if isLargeScreen {
return 14 * Design.Size.handScale * Design.Size.largeScreenMultiplier
} else if DeviceInfo.isSmallDevice {
return 12 // Smaller font for iPhone SE
} else {
return 14 // Standard iPhone
}
isLargeScreen ? 18 : Design.Size.labelFontSize
}
/// Minimum height for label row - scales differently for small devices, standard iPhones, and iPads
/// Minimum height for label row - larger on iPad
private var labelRowMinHeight: CGFloat {
if isLargeScreen {
return 30 * Design.Size.handScale * Design.Size.largeScreenMultiplier
} else if DeviceInfo.isSmallDevice {
return 24 // Smaller row for iPhone SE
} else {
return 30 // Standard iPhone
}
isLargeScreen ? 40 : Design.Size.labelRowHeight
}
/// Spacing between PLAYER and BANKER hands - reduced on smaller screens

View File

@ -27,25 +27,24 @@ struct CompactHandView: View {
horizontalSizeClass == .regular
}
/// WIN badge font size - only scales on iPad
/// WIN badge font size - larger on iPad
private var winBadgeFontSize: CGFloat {
let baseSize: CGFloat = 10
return isLargeScreen ? baseSize * Design.Size.handScale * Design.Size.largeScreenMultiplier : baseSize
isLargeScreen ? 14 : 10
}
/// Card width - responsive based on device type (uses DeviceKit)
/// Card width - larger on iPad
private var cardWidth: CGFloat {
isLargeScreen ? Design.Size.cardWidthTableLarge : Design.Size.cardWidthTable
isLargeScreen ? Design.Size.cardWidthTableiPad : Design.Size.cardWidthTable
}
/// Card height based on aspect ratio
private var cardHeight: CGFloat {
cardWidth * Design.Size.cardAspectRatio
cardWidth * CasinoDesign.Size.cardAspectRatio
}
/// Card overlap - scaled with card size (uses DeviceKit)
/// Card overlap - larger on iPad
private var cardOverlap: CGFloat {
isLargeScreen ? Design.Size.cardOverlapLarge : Design.Size.cardOverlap
isLargeScreen ? Design.Size.cardOverlapiPad : Design.Size.cardOverlap
}
private let placeholderSpacing: CGFloat = Design.Spacing.small

View File

@ -24,16 +24,18 @@ struct HandValueBadge: View {
horizontalSizeClass == .regular
}
/// Scale factor for badge sizing - only applies on iPad to avoid clipping on iPhone
private var scale: CGFloat {
isLargeScreen ? Design.Size.handScale * Design.Size.largeScreenMultiplier : 1.0
}
@ScaledMetric(relativeTo: .headline) private var baseValueFontSize: CGFloat = 15
@ScaledMetric(relativeTo: .headline) private var baseBadgeSize: CGFloat = 26
private var valueFontSize: CGFloat { baseValueFontSize * scale }
private var badgeSize: CGFloat { baseBadgeSize * scale }
/// Font size - larger on iPad
private var valueFontSize: CGFloat {
isLargeScreen ? baseValueFontSize * 1.5 : baseValueFontSize
}
/// Badge size - larger on iPad
private var badgeSize: CGFloat {
isLargeScreen ? baseBadgeSize * 1.5 : baseBadgeSize
}
// MARK: - Body