Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
da7dcc1633
commit
884bc988f6
@ -67,17 +67,20 @@ enum Design {
|
|||||||
enum Size {
|
enum Size {
|
||||||
static let chipSmall: CGFloat = 36
|
static let chipSmall: CGFloat = 36
|
||||||
static let chipMedium: CGFloat = 50
|
static let chipMedium: CGFloat = 50
|
||||||
|
static let chipSelector: CGFloat = 50
|
||||||
static let cardWidthSmall: CGFloat = 45
|
static let cardWidthSmall: CGFloat = 45
|
||||||
static let cardWidthMedium: CGFloat = 55
|
static let cardWidthMedium: CGFloat = 55
|
||||||
static let cardWidthLarge: CGFloat = 65
|
static let cardWidthLarge: CGFloat = 65
|
||||||
static let valueBadge: CGFloat = 26
|
static let valueBadge: CGFloat = 26
|
||||||
static let checkmark: CGFloat = 22
|
static let checkmark: CGFloat = 22
|
||||||
static let tableAspectRatio: CGFloat = 1.6
|
static let tableAspectRatio: CGFloat = 1.6
|
||||||
|
static let roadMapCell: CGFloat = 16
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Animation
|
// MARK: - Animation
|
||||||
|
|
||||||
enum Animation {
|
enum Animation {
|
||||||
|
static let quick: Double = 0.3
|
||||||
static let springDuration: Double = 0.4
|
static let springDuration: Double = 0.4
|
||||||
static let springBounce: Double = 0.3
|
static let springBounce: Double = 0.3
|
||||||
static let fadeInDuration: Double = 0.3
|
static let fadeInDuration: Double = 0.3
|
||||||
@ -90,7 +93,9 @@ enum Design {
|
|||||||
static let disabled: Double = 0.5
|
static let disabled: Double = 0.5
|
||||||
static let subtle: Double = 0.1
|
static let subtle: Double = 0.1
|
||||||
static let light: Double = 0.3
|
static let light: Double = 0.3
|
||||||
|
static let overlay: Double = 0.4
|
||||||
static let medium: Double = 0.5
|
static let medium: Double = 0.5
|
||||||
|
static let secondary: Double = 0.5
|
||||||
static let strong: Double = 0.7
|
static let strong: Double = 0.7
|
||||||
static let heavy: Double = 0.8
|
static let heavy: Double = 0.8
|
||||||
static let nearOpaque: Double = 0.85
|
static let nearOpaque: Double = 0.85
|
||||||
@ -100,6 +105,7 @@ enum Design {
|
|||||||
|
|
||||||
enum LineWidth {
|
enum LineWidth {
|
||||||
static let thin: CGFloat = 1
|
static let thin: CGFloat = 1
|
||||||
|
static let standard: CGFloat = 2
|
||||||
static let medium: CGFloat = 2
|
static let medium: CGFloat = 2
|
||||||
static let thick: CGFloat = 3
|
static let thick: CGFloat = 3
|
||||||
static let heavy: CGFloat = 4
|
static let heavy: CGFloat = 4
|
||||||
@ -128,6 +134,7 @@ extension Color {
|
|||||||
static let backgroundDark = Color(red: 0.01, green: 0.12, blue: 0.06)
|
static let backgroundDark = Color(red: 0.01, green: 0.12, blue: 0.06)
|
||||||
static let backgroundLight = Color(red: 0.03, green: 0.25, blue: 0.12)
|
static let backgroundLight = Color(red: 0.03, green: 0.25, blue: 0.12)
|
||||||
static let baseDark = Color(red: 0.02, green: 0.15, blue: 0.08)
|
static let baseDark = Color(red: 0.02, green: 0.15, blue: 0.08)
|
||||||
|
static let preview = Color(red: 0.0, green: 0.3, blue: 0.15)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Border Colors
|
// MARK: - Border Colors
|
||||||
@ -171,6 +178,49 @@ extension Color {
|
|||||||
|
|
||||||
enum Chip {
|
enum Chip {
|
||||||
static let gold = Color(red: 0.8, green: 0.65, blue: 0.2)
|
static let gold = Color(red: 0.8, green: 0.65, blue: 0.2)
|
||||||
|
|
||||||
|
// Chip base colors
|
||||||
|
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
|
// MARK: - Modal Colors
|
||||||
|
|||||||
@ -123,12 +123,12 @@ struct CardBackView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Base
|
// Base
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
||||||
.fill(
|
.fill(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Color(red: 0.6, green: 0.1, blue: 0.15),
|
Color.Card.backDark,
|
||||||
Color(red: 0.4, green: 0.05, blue: 0.1)
|
Color.Card.backLight
|
||||||
],
|
],
|
||||||
startPoint: .topLeading,
|
startPoint: .topLeading,
|
||||||
endPoint: .bottomTrailing
|
endPoint: .bottomTrailing
|
||||||
@ -136,26 +136,26 @@ struct CardBackView: View {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Border
|
// Border
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
||||||
.strokeBorder(
|
.strokeBorder(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Color(red: 0.9, green: 0.7, blue: 0.4),
|
Color.Card.patternLight,
|
||||||
Color(red: 0.7, green: 0.5, blue: 0.2)
|
Color.Card.patternDark
|
||||||
],
|
],
|
||||||
startPoint: .topLeading,
|
startPoint: .topLeading,
|
||||||
endPoint: .bottomTrailing
|
endPoint: .bottomTrailing
|
||||||
),
|
),
|
||||||
lineWidth: 2
|
lineWidth: Design.LineWidth.medium
|
||||||
)
|
)
|
||||||
|
|
||||||
// Inner pattern area
|
// Inner pattern area
|
||||||
RoundedRectangle(cornerRadius: 4)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small / 2)
|
||||||
.fill(
|
.fill(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Color(red: 0.5, green: 0.08, blue: 0.12),
|
Color.Card.innerDark,
|
||||||
Color(red: 0.35, green: 0.04, blue: 0.08)
|
Color.Card.innerLight
|
||||||
],
|
],
|
||||||
startPoint: .top,
|
startPoint: .top,
|
||||||
endPoint: .bottom
|
endPoint: .bottom
|
||||||
@ -166,18 +166,18 @@ struct CardBackView: View {
|
|||||||
// Diamond pattern overlay
|
// Diamond pattern overlay
|
||||||
DiamondPatternView()
|
DiamondPatternView()
|
||||||
.foregroundStyle(
|
.foregroundStyle(
|
||||||
Color(red: 0.9, green: 0.7, blue: 0.4).opacity(0.3)
|
Color.Card.diamondPattern.opacity(Design.Opacity.light)
|
||||||
)
|
)
|
||||||
.padding(width * 0.12)
|
.padding(width * 0.12)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
.clipShape(RoundedRectangle(cornerRadius: Design.CornerRadius.small / 2))
|
||||||
|
|
||||||
// Center emblem
|
// Center emblem
|
||||||
Circle()
|
Circle()
|
||||||
.fill(
|
.fill(
|
||||||
RadialGradient(
|
RadialGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Color(red: 0.9, green: 0.7, blue: 0.4),
|
Color.Card.patternLight,
|
||||||
Color(red: 0.7, green: 0.5, blue: 0.2)
|
Color.Card.patternDark
|
||||||
],
|
],
|
||||||
center: .center,
|
center: .center,
|
||||||
startRadius: 0,
|
startRadius: 0,
|
||||||
@ -189,10 +189,10 @@ struct CardBackView: View {
|
|||||||
// B for Baccarat
|
// B for Baccarat
|
||||||
Text("B")
|
Text("B")
|
||||||
.font(.system(size: width * 0.18, weight: .bold, design: .serif))
|
.font(.system(size: width * 0.18, weight: .bold, design: .serif))
|
||||||
.foregroundStyle(Color(red: 0.4, green: 0.05, blue: 0.1))
|
.foregroundStyle(Color.Card.logoText)
|
||||||
}
|
}
|
||||||
.frame(width: width, height: height)
|
.frame(width: width, height: height)
|
||||||
.shadow(color: .black.opacity(0.3), radius: 4, x: 2, y: 2)
|
.shadow(color: .black.opacity(Design.Opacity.light), radius: Design.Shadow.radiusSmall, x: 2, y: 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,10 +230,10 @@ struct CardPlaceholderView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
||||||
.strokeBorder(
|
.strokeBorder(
|
||||||
Color.white.opacity(0.3),
|
Color.white.opacity(Design.Opacity.light),
|
||||||
style: StrokeStyle(lineWidth: 2, dash: [8, 4])
|
style: StrokeStyle(lineWidth: Design.LineWidth.medium, dash: [8, 4])
|
||||||
)
|
)
|
||||||
.frame(width: width, height: height)
|
.frame(width: width, height: height)
|
||||||
}
|
}
|
||||||
@ -241,10 +241,10 @@ struct CardPlaceholderView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(red: 0.0, green: 0.3, blue: 0.15)
|
Color.Table.preview
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
HStack(spacing: 20) {
|
HStack(spacing: Design.Spacing.xLarge) {
|
||||||
CardView(card: Card(suit: .hearts, rank: .ace), isFaceUp: true)
|
CardView(card: Card(suit: .hearts, rank: .ace), isFaceUp: true)
|
||||||
CardView(card: Card(suit: .spades, rank: .king), isFaceUp: true)
|
CardView(card: Card(suit: .spades, rank: .king), isFaceUp: true)
|
||||||
CardView(card: Card(suit: .diamonds, rank: .seven), isFaceUp: false)
|
CardView(card: Card(suit: .diamonds, rank: .seven), isFaceUp: false)
|
||||||
|
|||||||
@ -28,24 +28,24 @@ struct ChipSelectorView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView(.horizontal) {
|
ScrollView(.horizontal) {
|
||||||
HStack(spacing: 10) {
|
HStack(spacing: Design.Spacing.small) {
|
||||||
ForEach(availableChips) { denomination in
|
ForEach(availableChips) { denomination in
|
||||||
Button {
|
Button {
|
||||||
selectedChip = denomination
|
selectedChip = denomination
|
||||||
} label: {
|
} label: {
|
||||||
ChipView(
|
ChipView(
|
||||||
denomination: denomination,
|
denomination: denomination,
|
||||||
size: 50,
|
size: Design.Size.chipSelector,
|
||||||
isSelected: selectedChip == denomination
|
isSelected: selectedChip == denomination
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.opacity(balance >= denomination.rawValue ? 1.0 : 0.4)
|
.opacity(balance >= denomination.rawValue ? 1.0 : Design.Opacity.overlay)
|
||||||
.disabled(balance < denomination.rawValue)
|
.disabled(balance < denomination.rawValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.vertical, 6) // Extra padding for selection scale effect
|
.padding(.vertical, Design.Spacing.xSmall) // Extra padding for selection scale effect
|
||||||
}
|
}
|
||||||
.scrollIndicators(.hidden)
|
.scrollIndicators(.hidden)
|
||||||
.onChange(of: balance) { _, newBalance in
|
.onChange(of: balance) { _, newBalance in
|
||||||
@ -61,10 +61,10 @@ struct ChipSelectorView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(red: 0.0, green: 0.3, blue: 0.15)
|
Color.Table.preview
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: Design.Spacing.xLarge) {
|
||||||
Text("Balance: $50,000")
|
Text("Balance: $50,000")
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
|
|
||||||
|
|||||||
@ -68,34 +68,34 @@ enum ChipDenomination: Int, CaseIterable, Identifiable {
|
|||||||
/// The primary color for this chip.
|
/// The primary color for this chip.
|
||||||
var primaryColor: Color {
|
var primaryColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
case .ten: return Color(red: 0.2, green: 0.4, blue: 0.8) // Blue
|
case .ten: return Color.Chip.tenBase
|
||||||
case .twentyFive: return Color(red: 0.1, green: 0.6, blue: 0.3) // Green
|
case .twentyFive: return Color.Chip.twentyFiveBase
|
||||||
case .fifty: return Color(red: 0.8, green: 0.5, blue: 0.1) // Orange
|
case .fifty: return Color.Chip.fiftyBase
|
||||||
case .hundred: return Color(red: 0.1, green: 0.1, blue: 0.1) // Black
|
case .hundred: return Color.Chip.hundredBase
|
||||||
case .fiveHundred: return Color(red: 0.6, green: 0.2, blue: 0.6) // Purple
|
case .fiveHundred: return Color.Chip.fiveHundredBase
|
||||||
case .thousand: return Color(red: 0.8, green: 0.65, blue: 0.2) // Gold
|
case .thousand: return Color.Chip.thousandBase
|
||||||
case .fiveThousand: return Color(red: 0.7, green: 0.1, blue: 0.2) // Crimson
|
case .fiveThousand: return Color.Chip.fiveThousandBase
|
||||||
case .tenThousand: return Color(red: 0.2, green: 0.5, blue: 0.5) // Teal
|
case .tenThousand: return Color.Chip.tenThousandBase
|
||||||
case .twentyFiveThousand: return Color(red: 0.5, green: 0.3, blue: 0.1) // Bronze
|
case .twentyFiveThousand: return Color.Chip.twentyFiveThousandBase
|
||||||
case .fiftyThousand: return Color(red: 0.75, green: 0.75, blue: 0.8) // Platinum
|
case .fiftyThousand: return Color.Chip.fiftyThousandBase
|
||||||
case .hundredThousand: return Color(red: 0.9, green: 0.1, blue: 0.3) // Ruby
|
case .hundredThousand: return Color.Chip.hundredThousandBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The secondary/accent color for this chip.
|
/// The secondary/accent color for this chip.
|
||||||
var secondaryColor: Color {
|
var secondaryColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
case .ten: return Color(red: 0.3, green: 0.5, blue: 0.9)
|
case .ten: return Color.Chip.tenHighlight
|
||||||
case .twentyFive: return Color(red: 0.2, green: 0.7, blue: 0.4)
|
case .twentyFive: return Color.Chip.twentyFiveHighlight
|
||||||
case .fifty: return Color(red: 0.9, green: 0.6, blue: 0.2)
|
case .fifty: return Color.Chip.fiftyHighlight
|
||||||
case .hundred: return Color(red: 0.3, green: 0.3, blue: 0.3)
|
case .hundred: return Color.Chip.hundredHighlight
|
||||||
case .fiveHundred: return Color(red: 0.7, green: 0.3, blue: 0.7)
|
case .fiveHundred: return Color.Chip.fiveHundredHighlight
|
||||||
case .thousand: return Color(red: 0.9, green: 0.75, blue: 0.3)
|
case .thousand: return Color.Chip.thousandHighlight
|
||||||
case .fiveThousand: return Color(red: 0.85, green: 0.2, blue: 0.3)
|
case .fiveThousand: return Color.Chip.fiveThousandHighlight
|
||||||
case .tenThousand: return Color(red: 0.3, green: 0.6, blue: 0.6)
|
case .tenThousand: return Color.Chip.tenThousandHighlight
|
||||||
case .twentyFiveThousand: return Color(red: 0.65, green: 0.45, blue: 0.2)
|
case .twentyFiveThousand: return Color.Chip.twentyFiveThousandHighlight
|
||||||
case .fiftyThousand: return Color(red: 0.85, green: 0.85, blue: 0.9)
|
case .fiftyThousand: return Color.Chip.fiftyThousandHighlight
|
||||||
case .hundredThousand: return Color(red: 1.0, green: 0.2, blue: 0.4)
|
case .hundredThousand: return Color.Chip.hundredThousandHighlight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,14 +103,14 @@ enum ChipDenomination: Int, CaseIterable, Identifiable {
|
|||||||
var stripeColor: Color {
|
var stripeColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
case .ten, .twentyFive, .fifty: return .white
|
case .ten, .twentyFive, .fifty: return .white
|
||||||
case .hundred: return Color(red: 0.9, green: 0.75, blue: 0.3)
|
case .hundred: return Color.Chip.goldStripe
|
||||||
case .fiveHundred: return .white
|
case .fiveHundred: return .white
|
||||||
case .thousand: return .black
|
case .thousand: return .black
|
||||||
case .fiveThousand: return Color(red: 0.9, green: 0.75, blue: 0.3) // Gold stripes
|
case .fiveThousand: return Color.Chip.goldStripe
|
||||||
case .tenThousand: return .white
|
case .tenThousand: return .white
|
||||||
case .twentyFiveThousand: return Color(red: 0.9, green: 0.75, blue: 0.3)
|
case .twentyFiveThousand: return Color.Chip.goldStripe
|
||||||
case .fiftyThousand: return Color(red: 0.2, green: 0.2, blue: 0.3) // Dark stripes
|
case .fiftyThousand: return Color.Chip.darkStripe
|
||||||
case .hundredThousand: return Color(red: 0.9, green: 0.85, blue: 0.3) // Gold stripes
|
case .hundredThousand: return Color.Chip.goldRubyStripe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,13 +274,13 @@ struct ChipStackView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(red: 0.0, green: 0.3, blue: 0.15)
|
Color.Table.preview
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: Design.Spacing.xxxLarge) {
|
||||||
HStack(spacing: 15) {
|
HStack(spacing: Design.Spacing.xLarge) {
|
||||||
ForEach(ChipDenomination.allCases) { denom in
|
ForEach(ChipDenomination.allCases) { denom in
|
||||||
ChipView(denomination: denom, size: 50)
|
ChipView(denomination: denom, size: Design.Size.chipSelector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ struct GameTableView: View {
|
|||||||
onSettings: { showSettings = true }
|
onSettings: { showSettings = true }
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(minLength: 4)
|
Spacer(minLength: Design.Spacing.xSmall)
|
||||||
|
|
||||||
// Cards display area
|
// Cards display area
|
||||||
CardsDisplayArea(
|
CardsDisplayArea(
|
||||||
@ -61,7 +61,7 @@ struct GameTableView: View {
|
|||||||
isTie: isTie
|
isTie: isTie
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(minLength: 4)
|
Spacer(minLength: Design.Spacing.xSmall)
|
||||||
|
|
||||||
// Road map history
|
// Road map history
|
||||||
if settings.showHistory && !state.roundHistory.isEmpty {
|
if settings.showHistory && !state.roundHistory.isEmpty {
|
||||||
@ -69,16 +69,16 @@ struct GameTableView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(minLength: 8)
|
Spacer(minLength: Design.Spacing.small)
|
||||||
|
|
||||||
// Mini Baccarat betting table
|
// Mini Baccarat betting table
|
||||||
MiniBaccaratTableView(
|
MiniBaccaratTableView(
|
||||||
gameState: state,
|
gameState: state,
|
||||||
selectedChip: selectedChip
|
selectedChip: selectedChip
|
||||||
)
|
)
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, Design.Spacing.medium)
|
||||||
|
|
||||||
Spacer(minLength: 8)
|
Spacer(minLength: Design.Spacing.small)
|
||||||
|
|
||||||
// Chip selector - shows higher chips as you win more!
|
// Chip selector - shows higher chips as you win more!
|
||||||
ChipSelectorView(
|
ChipSelectorView(
|
||||||
@ -86,7 +86,7 @@ struct GameTableView: View {
|
|||||||
balance: state.balance,
|
balance: state.balance,
|
||||||
maxBet: state.maxBet
|
maxBet: state.maxBet
|
||||||
)
|
)
|
||||||
.padding(.bottom, 12)
|
.padding(.bottom, Design.Spacing.medium)
|
||||||
|
|
||||||
// Action buttons
|
// Action buttons
|
||||||
ActionButtonsView(
|
ActionButtonsView(
|
||||||
@ -100,7 +100,7 @@ struct GameTableView: View {
|
|||||||
onNewRound: { state.newRound() }
|
onNewRound: { state.newRound() }
|
||||||
)
|
)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.bottom, 4)
|
.padding(.bottom, Design.Spacing.xSmall)
|
||||||
}
|
}
|
||||||
.safeAreaPadding(.bottom)
|
.safeAreaPadding(.bottom)
|
||||||
|
|
||||||
@ -295,11 +295,11 @@ struct CardsDisplayArea: View {
|
|||||||
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = 14
|
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = 14
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 32) {
|
HStack(spacing: Design.Spacing.xxxLarge) {
|
||||||
// Player side
|
// Player side
|
||||||
VStack(spacing: 10) {
|
VStack(spacing: Design.Spacing.small) {
|
||||||
// Label with value
|
// Label with value
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: Design.Spacing.small) {
|
||||||
Text("PLAYER")
|
Text("PLAYER")
|
||||||
.font(.system(size: labelFontSize, weight: .bold, design: .rounded))
|
.font(.system(size: labelFontSize, weight: .bold, design: .rounded))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
@ -319,9 +319,9 @@ struct CardsDisplayArea: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Banker side
|
// Banker side
|
||||||
VStack(spacing: 10) {
|
VStack(spacing: Design.Spacing.small) {
|
||||||
// Label with value
|
// Label with value
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: Design.Spacing.small) {
|
||||||
Text("BANKER")
|
Text("BANKER")
|
||||||
.font(.system(size: labelFontSize, weight: .bold, design: .rounded))
|
.font(.system(size: labelFontSize, weight: .bold, design: .rounded))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
@ -340,11 +340,11 @@ struct CardsDisplayArea: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 16)
|
.padding(.top, Design.Spacing.large)
|
||||||
.padding(.bottom, 14)
|
.padding(.bottom, Design.Spacing.xLarge)
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 14)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.xLarge)
|
||||||
.fill(Color.black.opacity(0.25))
|
.fill(Color.black.opacity(0.25))
|
||||||
)
|
)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
@ -385,12 +385,12 @@ struct CompactHandView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(6)
|
.padding(Design.Spacing.xSmall)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
||||||
.strokeBorder(
|
.strokeBorder(
|
||||||
isWinner ? Color.yellow : Color.clear,
|
isWinner ? Color.yellow : Color.clear,
|
||||||
lineWidth: 2
|
lineWidth: Design.LineWidth.standard
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.overlay(alignment: .bottom) {
|
.overlay(alignment: .bottom) {
|
||||||
@ -398,13 +398,13 @@ struct CompactHandView: View {
|
|||||||
Text("WIN")
|
Text("WIN")
|
||||||
.font(.system(size: winBadgeFontSize, weight: .black))
|
.font(.system(size: winBadgeFontSize, weight: .black))
|
||||||
.foregroundStyle(.black)
|
.foregroundStyle(.black)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, Design.Spacing.small)
|
||||||
.padding(.vertical, 2)
|
.padding(.vertical, Design.Spacing.xxSmall)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(Color.yellow)
|
.fill(Color.yellow)
|
||||||
)
|
)
|
||||||
.offset(y: 10)
|
.offset(y: Design.Spacing.small)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,13 +437,13 @@ struct TableBackgroundView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Base dark green
|
// Base dark green
|
||||||
Color(red: 0.02, green: 0.15, blue: 0.08)
|
Color.Table.baseDark
|
||||||
|
|
||||||
// Radial gradient for depth
|
// Radial gradient for depth
|
||||||
RadialGradient(
|
RadialGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Color(red: 0.03, green: 0.25, blue: 0.12),
|
Color.Table.backgroundLight,
|
||||||
Color(red: 0.01, green: 0.12, blue: 0.06)
|
Color.Table.backgroundDark
|
||||||
],
|
],
|
||||||
center: .center,
|
center: .center,
|
||||||
startRadius: 50,
|
startRadius: 50,
|
||||||
@ -452,7 +452,7 @@ struct TableBackgroundView: View {
|
|||||||
|
|
||||||
// Subtle felt texture
|
// Subtle felt texture
|
||||||
FeltPatternView()
|
FeltPatternView()
|
||||||
.opacity(0.03)
|
.opacity(Design.Opacity.subtle / 3)
|
||||||
}
|
}
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
}
|
}
|
||||||
@ -493,13 +493,13 @@ struct TopBarView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
// Balance display
|
// Balance display
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||||
Text("BALANCE")
|
Text("BALANCE")
|
||||||
.font(.system(size: labelFontSize, weight: .medium, design: .rounded))
|
.font(.system(size: labelFontSize, weight: .medium, design: .rounded))
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.white.opacity(0.6))
|
||||||
.tracking(1)
|
.tracking(1)
|
||||||
|
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
Text("$")
|
Text("$")
|
||||||
.font(.system(size: currencyFontSize, weight: .bold))
|
.font(.system(size: currencyFontSize, weight: .bold))
|
||||||
.foregroundStyle(.yellow.opacity(0.8))
|
.foregroundStyle(.yellow.opacity(0.8))
|
||||||
@ -508,27 +508,27 @@ struct TopBarView: View {
|
|||||||
.font(.system(size: balanceFontSize, weight: .black, design: .rounded))
|
.font(.system(size: balanceFontSize, weight: .black, design: .rounded))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.contentTransition(.numericText())
|
.contentTransition(.numericText())
|
||||||
.animation(.spring(duration: 0.3), value: balance)
|
.animation(.spring(duration: Design.Animation.quick), value: balance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 14)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.padding(.vertical, 6)
|
.padding(.vertical, Design.Spacing.xSmall)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(Color.black.opacity(0.4))
|
.fill(Color.black.opacity(Design.Opacity.overlay))
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
// Cards remaining indicator (if enabled)
|
// Cards remaining indicator (if enabled)
|
||||||
if showCardsRemaining {
|
if showCardsRemaining {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
Image(systemName: "rectangle.portrait.on.rectangle.portrait.fill")
|
Image(systemName: "rectangle.portrait.on.rectangle.portrait.fill")
|
||||||
.font(.system(size: smallFontSize))
|
.font(.system(size: smallFontSize))
|
||||||
Text("\(cardsRemaining)")
|
Text("\(cardsRemaining)")
|
||||||
.font(.system(size: smallFontSize, weight: .medium))
|
.font(.system(size: smallFontSize, weight: .medium))
|
||||||
}
|
}
|
||||||
.foregroundStyle(.white.opacity(0.5))
|
.foregroundStyle(.white.opacity(Design.Opacity.secondary))
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
@ -538,25 +538,25 @@ struct TopBarView: View {
|
|||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
.font(.system(size: buttonFontSize))
|
.font(.system(size: buttonFontSize))
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.white.opacity(0.6))
|
||||||
.padding(8)
|
.padding(Design.Spacing.small)
|
||||||
.background(
|
.background(
|
||||||
Circle()
|
Circle()
|
||||||
.fill(Color.black.opacity(0.4))
|
.fill(Color.black.opacity(Design.Opacity.overlay))
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reset button
|
// Reset button
|
||||||
Button("Reset", systemImage: "arrow.counterclockwise", action: onReset)
|
Button("Reset", systemImage: "arrow.counterclockwise", action: onReset)
|
||||||
.font(.system(size: smallFontSize, weight: .medium))
|
.font(.system(size: smallFontSize, weight: .medium))
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.white.opacity(0.6))
|
||||||
.padding(.horizontal, 10)
|
.padding(.horizontal, Design.Spacing.small)
|
||||||
.padding(.vertical, 6)
|
.padding(.vertical, Design.Spacing.xSmall)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(Color.black.opacity(0.4))
|
.fill(Color.black.opacity(Design.Opacity.overlay))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 4)
|
.padding(.top, Design.Spacing.xSmall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,14 +574,14 @@ struct ActionButtonsView: View {
|
|||||||
@ScaledMetric(relativeTo: .body) private var statusFontSize: CGFloat = 14
|
@ScaledMetric(relativeTo: .body) private var statusFontSize: CGFloat = 14
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: Design.Spacing.medium) {
|
||||||
if gameState.currentPhase == .betting {
|
if gameState.currentPhase == .betting {
|
||||||
// Clear bets button
|
// Clear bets button
|
||||||
Button("Clear", systemImage: "xmark.circle", action: onClear)
|
Button("Clear", systemImage: "xmark.circle", action: onClear)
|
||||||
.font(.system(size: clearButtonFontSize, weight: .semibold))
|
.font(.system(size: clearButtonFontSize, weight: .semibold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(Color.Button.destructive)
|
.fill(Color.Button.destructive)
|
||||||
@ -593,8 +593,8 @@ struct ActionButtonsView: View {
|
|||||||
Button("Deal", systemImage: "play.fill", action: onDeal)
|
Button("Deal", systemImage: "play.fill", action: onDeal)
|
||||||
.font(.system(size: primaryButtonFontSize, weight: .bold))
|
.font(.system(size: primaryButtonFontSize, weight: .bold))
|
||||||
.foregroundStyle(.black)
|
.foregroundStyle(.black)
|
||||||
.padding(.horizontal, 32)
|
.padding(.horizontal, Design.Spacing.xxxLarge)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(
|
.fill(
|
||||||
@ -613,8 +613,8 @@ struct ActionButtonsView: View {
|
|||||||
Button("New Round", systemImage: "arrow.right.circle", action: onNewRound)
|
Button("New Round", systemImage: "arrow.right.circle", action: onNewRound)
|
||||||
.font(.system(size: primaryButtonFontSize, weight: .bold))
|
.font(.system(size: primaryButtonFontSize, weight: .bold))
|
||||||
.foregroundStyle(.black)
|
.foregroundStyle(.black)
|
||||||
.padding(.horizontal, 32)
|
.padding(.horizontal, Design.Spacing.xxxLarge)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(
|
.fill(
|
||||||
@ -628,7 +628,7 @@ struct ActionButtonsView: View {
|
|||||||
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
.shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
|
||||||
} else {
|
} else {
|
||||||
// Playing indicator
|
// Playing indicator
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.tint(.white)
|
.tint(.white)
|
||||||
.scaleEffect(0.8)
|
.scaleEffect(0.8)
|
||||||
@ -636,8 +636,8 @@ struct ActionButtonsView: View {
|
|||||||
.font(.system(size: statusFontSize, weight: .medium))
|
.font(.system(size: statusFontSize, weight: .medium))
|
||||||
.foregroundStyle(.white.opacity(Design.Opacity.heavy))
|
.foregroundStyle(.white.opacity(Design.Opacity.heavy))
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,18 +16,23 @@ struct ResultBannerView: View {
|
|||||||
@State private var showText = false
|
@State private var showText = false
|
||||||
@State private var showWinnings = false
|
@State private var showWinnings = false
|
||||||
|
|
||||||
|
// MARK: - Scaled Font Sizes (Dynamic Type)
|
||||||
|
|
||||||
|
@ScaledMetric(relativeTo: .largeTitle) private var resultFontSize: CGFloat = Design.BaseFontSize.largeTitle
|
||||||
|
@ScaledMetric(relativeTo: .title2) private var winningsFontSize: CGFloat = 28
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Background overlay
|
// Background overlay
|
||||||
Color.black.opacity(showBanner ? 0.5 : 0)
|
Color.black.opacity(showBanner ? Design.Opacity.medium : 0)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
.animation(.easeIn(duration: 0.3), value: showBanner)
|
.animation(.easeIn(duration: Design.Animation.fadeInDuration), value: showBanner)
|
||||||
|
|
||||||
// Banner
|
// Banner
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: Design.Spacing.xLarge) {
|
||||||
// Result text
|
// Result text
|
||||||
Text(result.displayText)
|
Text(result.displayText)
|
||||||
.font(.system(size: 36, weight: .black, design: .rounded))
|
.font(.system(size: resultFontSize, weight: .black, design: .rounded))
|
||||||
.foregroundStyle(
|
.foregroundStyle(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [.white, result.color],
|
colors: [.white, result.color],
|
||||||
@ -35,13 +40,13 @@ struct ResultBannerView: View {
|
|||||||
endPoint: .bottom
|
endPoint: .bottom
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.shadow(color: result.color.opacity(0.8), radius: 10)
|
.shadow(color: result.color.opacity(Design.Opacity.heavy), radius: Design.Shadow.radiusLarge)
|
||||||
.scaleEffect(showText ? 1.0 : 0.5)
|
.scaleEffect(showText ? 1.0 : 0.5)
|
||||||
.opacity(showText ? 1.0 : 0)
|
.opacity(showText ? 1.0 : 0)
|
||||||
|
|
||||||
// Winnings display
|
// Winnings display
|
||||||
if winnings != 0 {
|
if winnings != 0 {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: Design.Spacing.small) {
|
||||||
if winnings > 0 {
|
if winnings > 0 {
|
||||||
Image(systemName: "plus.circle.fill")
|
Image(systemName: "plus.circle.fill")
|
||||||
.foregroundStyle(.green)
|
.foregroundStyle(.green)
|
||||||
@ -54,14 +59,14 @@ struct ResultBannerView: View {
|
|||||||
.foregroundStyle(.red)
|
.foregroundStyle(.red)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.font(.system(size: 28, weight: .bold, design: .rounded))
|
.font(.system(size: winningsFontSize, weight: .bold, design: .rounded))
|
||||||
.scaleEffect(showWinnings ? 1.0 : 0.5)
|
.scaleEffect(showWinnings ? 1.0 : 0.5)
|
||||||
.opacity(showWinnings ? 1.0 : 0)
|
.opacity(showWinnings ? 1.0 : 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(Design.Spacing.xxxLarge + Design.Spacing.small)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 24)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.xxLarge + Design.Spacing.xSmall)
|
||||||
.fill(
|
.fill(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
@ -73,34 +78,34 @@ struct ResultBannerView: View {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 24)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.xxLarge + Design.Spacing.xSmall)
|
||||||
.strokeBorder(
|
.strokeBorder(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
result.color.opacity(0.8),
|
result.color.opacity(Design.Opacity.heavy),
|
||||||
result.color.opacity(0.3)
|
result.color.opacity(Design.Opacity.light)
|
||||||
],
|
],
|
||||||
startPoint: .topLeading,
|
startPoint: .topLeading,
|
||||||
endPoint: .bottomTrailing
|
endPoint: .bottomTrailing
|
||||||
),
|
),
|
||||||
lineWidth: 3
|
lineWidth: Design.LineWidth.thick
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.shadow(color: result.color.opacity(0.3), radius: 30)
|
.shadow(color: result.color.opacity(Design.Opacity.light), radius: Design.Shadow.radiusXXLarge)
|
||||||
.scaleEffect(showBanner ? 1.0 : 0.8)
|
.scaleEffect(showBanner ? 1.0 : 0.8)
|
||||||
.opacity(showBanner ? 1.0 : 0)
|
.opacity(showBanner ? 1.0 : 0)
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
withAnimation(.spring(duration: 0.4, bounce: 0.3)) {
|
withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce)) {
|
||||||
showBanner = true
|
showBanner = true
|
||||||
}
|
}
|
||||||
|
|
||||||
withAnimation(.spring(duration: 0.4, bounce: 0.3).delay(0.2)) {
|
withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce).delay(0.2)) {
|
||||||
showText = true
|
showText = true
|
||||||
}
|
}
|
||||||
|
|
||||||
withAnimation(.spring(duration: 0.4, bounce: 0.3).delay(0.4)) {
|
withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce).delay(0.4)) {
|
||||||
showWinnings = true
|
showWinnings = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,10 +119,13 @@ struct ConfettiPiece: View {
|
|||||||
@State private var rotation: Double = 0
|
@State private var rotation: Double = 0
|
||||||
@State private var opacity: Double = 1
|
@State private var opacity: Double = 1
|
||||||
|
|
||||||
|
private let confettiWidth: CGFloat = 8
|
||||||
|
private let confettiHeight: CGFloat = 12
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(color)
|
.fill(color)
|
||||||
.frame(width: 8, height: 12)
|
.frame(width: confettiWidth, height: confettiHeight)
|
||||||
.rotationEffect(.degrees(rotation))
|
.rotationEffect(.degrees(rotation))
|
||||||
.position(position)
|
.position(position)
|
||||||
.opacity(opacity)
|
.opacity(opacity)
|
||||||
@ -154,7 +162,7 @@ struct ConfettiView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(red: 0.0, green: 0.3, blue: 0.15)
|
Color.Table.preview
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
ResultBannerView(result: .playerWins, winnings: 500)
|
ResultBannerView(result: .playerWins, winnings: 500)
|
||||||
|
|||||||
@ -11,28 +11,33 @@ import SwiftUI
|
|||||||
struct RoadMapView: View {
|
struct RoadMapView: View {
|
||||||
let results: [RoundResult]
|
let results: [RoundResult]
|
||||||
|
|
||||||
|
// MARK: - Scaled Fonts (Dynamic Type)
|
||||||
|
|
||||||
|
@ScaledMetric(relativeTo: .caption2) private var historyFontSize: CGFloat = Design.BaseFontSize.small
|
||||||
|
@ScaledMetric(relativeTo: .caption2) private var dotSize: CGFloat = 22
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: Design.Spacing.xSmall) {
|
||||||
Text("HISTORY")
|
Text("HISTORY")
|
||||||
.font(.system(size: 10, weight: .bold, design: .rounded))
|
.font(.system(size: historyFontSize, weight: .bold, design: .rounded))
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.white.opacity(0.6))
|
||||||
.tracking(1)
|
.tracking(1)
|
||||||
|
|
||||||
ScrollView(.horizontal) {
|
ScrollView(.horizontal) {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: Design.Spacing.xSmall) {
|
||||||
ForEach(results) { result in
|
ForEach(results) { result in
|
||||||
RoadDot(result: result.result)
|
RoadDot(result: result.result, dotSize: dotSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.vertical, 4)
|
.padding(.vertical, Design.Spacing.xSmall)
|
||||||
}
|
}
|
||||||
.scrollIndicators(.hidden)
|
.scrollIndicators(.hidden)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, Design.Spacing.medium)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, Design.Spacing.small)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
||||||
.fill(Color.black.opacity(0.3))
|
.fill(Color.black.opacity(Design.Opacity.light))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,6 +45,11 @@ struct RoadMapView: View {
|
|||||||
/// A single dot in the road display.
|
/// A single dot in the road display.
|
||||||
struct RoadDot: View {
|
struct RoadDot: View {
|
||||||
let result: GameResult
|
let result: GameResult
|
||||||
|
let dotSize: CGFloat
|
||||||
|
|
||||||
|
// MARK: - Scaled Fonts (Dynamic Type)
|
||||||
|
|
||||||
|
@ScaledMetric(relativeTo: .caption2) private var labelFontSize: CGFloat = Design.BaseFontSize.small
|
||||||
|
|
||||||
private var color: Color {
|
private var color: Color {
|
||||||
switch result {
|
switch result {
|
||||||
@ -61,14 +71,14 @@ struct RoadDot: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(color)
|
.fill(color)
|
||||||
.frame(width: 22, height: 22)
|
.frame(width: dotSize, height: dotSize)
|
||||||
|
|
||||||
Circle()
|
Circle()
|
||||||
.strokeBorder(Color.white.opacity(0.3), lineWidth: 1)
|
.strokeBorder(Color.white.opacity(Design.Opacity.light), lineWidth: Design.LineWidth.thin)
|
||||||
.frame(width: 22, height: 22)
|
.frame(width: dotSize, height: dotSize)
|
||||||
|
|
||||||
Text(label)
|
Text(label)
|
||||||
.font(.system(size: 10, weight: .bold))
|
.font(.system(size: labelFontSize, weight: .bold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,7 +86,7 @@ struct RoadDot: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(red: 0.0, green: 0.3, blue: 0.15)
|
Color.Table.preview
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
RoadMapView(results: [
|
RoadMapView(results: [
|
||||||
|
|||||||
@ -19,11 +19,11 @@ struct SettingsView: View {
|
|||||||
NavigationStack {
|
NavigationStack {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Background
|
// Background
|
||||||
Color(red: 0.08, green: 0.12, blue: 0.08)
|
Color.Settings.background
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 24) {
|
VStack(spacing: Design.Spacing.xxLarge) {
|
||||||
// Table Limits Section (First!)
|
// Table Limits Section (First!)
|
||||||
SettingsSection(title: "TABLE LIMITS", icon: "banknote") {
|
SettingsSection(title: "TABLE LIMITS", icon: "banknote") {
|
||||||
TableLimitsPicker(selection: $settings.tableLimits)
|
TableLimitsPicker(selection: $settings.tableLimits)
|
||||||
@ -57,7 +57,7 @@ struct SettingsView: View {
|
|||||||
)
|
)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
.background(Color.white.opacity(0.1))
|
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||||
|
|
||||||
SettingsToggle(
|
SettingsToggle(
|
||||||
title: "Show History",
|
title: "Show History",
|
||||||
@ -76,7 +76,7 @@ struct SettingsView: View {
|
|||||||
|
|
||||||
if settings.showAnimations {
|
if settings.showAnimations {
|
||||||
Divider()
|
Divider()
|
||||||
.background(Color.white.opacity(0.1))
|
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||||
|
|
||||||
SpeedPicker(speed: $settings.dealingSpeed)
|
SpeedPicker(speed: $settings.dealingSpeed)
|
||||||
}
|
}
|
||||||
@ -91,24 +91,24 @@ struct SettingsView: View {
|
|||||||
Image(systemName: "arrow.counterclockwise")
|
Image(systemName: "arrow.counterclockwise")
|
||||||
Text("Reset to Defaults")
|
Text("Reset to Defaults")
|
||||||
}
|
}
|
||||||
.font(.system(size: 14, weight: .medium))
|
.font(.system(size: Design.BaseFontSize.medium, weight: .medium))
|
||||||
.foregroundStyle(.red.opacity(0.8))
|
.foregroundStyle(.red.opacity(Design.Opacity.heavy))
|
||||||
.padding()
|
.padding()
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 12)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
|
||||||
.fill(Color.red.opacity(0.1))
|
.fill(Color.red.opacity(Design.Opacity.subtle))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 8)
|
.padding(.top, Design.Spacing.small)
|
||||||
}
|
}
|
||||||
.padding(.vertical)
|
.padding(.vertical)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Settings")
|
.navigationTitle("Settings")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbarBackground(Color(red: 0.08, green: 0.12, blue: 0.08), for: .navigationBar)
|
.toolbarBackground(Color.Settings.background, for: .navigationBar)
|
||||||
.toolbarBackground(.visible, for: .navigationBar)
|
.toolbarBackground(.visible, for: .navigationBar)
|
||||||
.toolbarColorScheme(.dark, for: .navigationBar)
|
.toolbarColorScheme(.dark, for: .navigationBar)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
@ -143,19 +143,19 @@ struct SettingsSection<Content: View>: View {
|
|||||||
@ViewBuilder let content: Content
|
@ViewBuilder let content: Content
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
||||||
// Header
|
// Header
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: Design.Spacing.small) {
|
||||||
Image(systemName: icon)
|
Image(systemName: icon)
|
||||||
.font(.system(size: 12, weight: .semibold))
|
.font(.system(size: Design.BaseFontSize.body, weight: .semibold))
|
||||||
.foregroundStyle(.yellow.opacity(0.8))
|
.foregroundStyle(.yellow.opacity(Design.Opacity.heavy))
|
||||||
|
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.system(size: 12, weight: .bold, design: .rounded))
|
.font(.system(size: Design.BaseFontSize.body, weight: .bold, design: .rounded))
|
||||||
.tracking(1)
|
.tracking(1)
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
.foregroundStyle(.white.opacity(0.6))
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 4)
|
.padding(.horizontal, Design.Spacing.xSmall)
|
||||||
|
|
||||||
// Content card
|
// Content card
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
@ -163,7 +163,7 @@ struct SettingsSection<Content: View>: View {
|
|||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 12)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
|
||||||
.fill(Color.white.opacity(0.05))
|
.fill(Color.white.opacity(0.05))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -176,44 +176,44 @@ struct DeckCountPicker: View {
|
|||||||
@Binding var selection: DeckCount
|
@Binding var selection: DeckCount
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: Design.Spacing.medium) {
|
||||||
ForEach(DeckCount.allCases) { count in
|
ForEach(DeckCount.allCases) { count in
|
||||||
Button {
|
Button {
|
||||||
selection = count
|
selection = count
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||||
Text(count.displayName)
|
Text(count.displayName)
|
||||||
.font(.system(size: 16, weight: .semibold))
|
.font(.system(size: Design.BaseFontSize.large, weight: .semibold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
|
|
||||||
Text(count.description)
|
Text(count.description)
|
||||||
.font(.system(size: 12))
|
.font(.system(size: Design.BaseFontSize.body))
|
||||||
.foregroundStyle(.white.opacity(0.5))
|
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if selection == count {
|
if selection == count {
|
||||||
Image(systemName: "checkmark.circle.fill")
|
Image(systemName: "checkmark.circle.fill")
|
||||||
.font(.system(size: 22))
|
.font(.system(size: Design.Size.checkmark))
|
||||||
.foregroundStyle(.yellow)
|
.foregroundStyle(.yellow)
|
||||||
} else {
|
} else {
|
||||||
Circle()
|
Circle()
|
||||||
.strokeBorder(Color.white.opacity(0.3), lineWidth: 2)
|
.strokeBorder(Color.white.opacity(Design.Opacity.light), lineWidth: Design.LineWidth.medium)
|
||||||
.frame(width: 22, height: 22)
|
.frame(width: Design.Size.checkmark, height: Design.Size.checkmark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
|
||||||
.fill(selection == count ? Color.yellow.opacity(0.1) : Color.clear)
|
.fill(selection == count ? Color.yellow.opacity(Design.Opacity.subtle) : Color.clear)
|
||||||
)
|
)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
|
||||||
.strokeBorder(
|
.strokeBorder(
|
||||||
selection == count ? Color.yellow.opacity(0.5) : Color.white.opacity(0.1),
|
selection == count ? Color.yellow.opacity(Design.Opacity.medium) : Color.white.opacity(Design.Opacity.subtle),
|
||||||
lineWidth: 1
|
lineWidth: Design.LineWidth.thin
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -234,19 +234,19 @@ struct BalancePicker: View {
|
|||||||
GridItem(.flexible()),
|
GridItem(.flexible()),
|
||||||
GridItem(.flexible()),
|
GridItem(.flexible()),
|
||||||
GridItem(.flexible())
|
GridItem(.flexible())
|
||||||
], spacing: 10) {
|
], spacing: Design.Spacing.small) {
|
||||||
ForEach(options, id: \.self) { amount in
|
ForEach(options, id: \.self) { amount in
|
||||||
Button {
|
Button {
|
||||||
balance = amount
|
balance = amount
|
||||||
} label: {
|
} label: {
|
||||||
Text("$\(amount / 1000)K")
|
Text("$\(amount / 1000)K")
|
||||||
.font(.system(size: 14, weight: .bold))
|
.font(.system(size: Design.BaseFontSize.medium, weight: .bold))
|
||||||
.foregroundStyle(balance == amount ? .black : .white)
|
.foregroundStyle(balance == amount ? .black : .white)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
||||||
.fill(balance == amount ? Color.yellow : Color.white.opacity(0.1))
|
.fill(balance == amount ? Color.yellow : Color.white.opacity(Design.Opacity.subtle))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
@ -263,14 +263,14 @@ struct SettingsToggle: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Toggle(isOn: $isOn) {
|
Toggle(isOn: $isOn) {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.system(size: 15, weight: .medium))
|
.font(.system(size: 15, weight: .medium))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
|
|
||||||
Text(subtitle)
|
Text(subtitle)
|
||||||
.font(.system(size: 12))
|
.font(.system(size: Design.BaseFontSize.body))
|
||||||
.foregroundStyle(.white.opacity(0.5))
|
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tint(.yellow)
|
.tint(.yellow)
|
||||||
@ -288,24 +288,24 @@ struct SpeedPicker: View {
|
|||||||
]
|
]
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: Design.Spacing.small) {
|
||||||
Text("Dealing Speed")
|
Text("Dealing Speed")
|
||||||
.font(.system(size: 15, weight: .medium))
|
.font(.system(size: 15, weight: .medium))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: Design.Spacing.small) {
|
||||||
ForEach(options, id: \.1) { option in
|
ForEach(options, id: \.1) { option in
|
||||||
Button {
|
Button {
|
||||||
speed = option.1
|
speed = option.1
|
||||||
} label: {
|
} label: {
|
||||||
Text(option.0)
|
Text(option.0)
|
||||||
.font(.system(size: 13, weight: .medium))
|
.font(.system(size: 13, weight: .medium))
|
||||||
.foregroundStyle(speed == option.1 ? .black : .white.opacity(0.7))
|
.foregroundStyle(speed == option.1 ? .black : .white.opacity(Design.Opacity.strong))
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, Design.Spacing.small)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(speed == option.1 ? Color.yellow : Color.white.opacity(0.1))
|
.fill(speed == option.1 ? Color.yellow : Color.white.opacity(Design.Opacity.subtle))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
@ -320,30 +320,30 @@ struct TableLimitsPicker: View {
|
|||||||
@Binding var selection: TableLimits
|
@Binding var selection: TableLimits
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 10) {
|
VStack(spacing: Design.Spacing.small) {
|
||||||
ForEach(TableLimits.allCases) { limit in
|
ForEach(TableLimits.allCases) { limit in
|
||||||
Button {
|
Button {
|
||||||
selection = limit
|
selection = limit
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||||
Text(limit.displayName)
|
Text(limit.displayName)
|
||||||
.font(.system(size: 16, weight: .semibold))
|
.font(.system(size: Design.BaseFontSize.large, weight: .semibold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
|
|
||||||
Text(limit.detailedDescription)
|
Text(limit.detailedDescription)
|
||||||
.font(.system(size: 12))
|
.font(.system(size: Design.BaseFontSize.body))
|
||||||
.foregroundStyle(.white.opacity(0.5))
|
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
// Limits badge
|
// Limits badge
|
||||||
Text(limit.description)
|
Text(limit.description)
|
||||||
.font(.system(size: 12, weight: .bold, design: .rounded))
|
.font(.system(size: Design.BaseFontSize.body, weight: .bold, design: .rounded))
|
||||||
.foregroundStyle(selection == limit ? .black : .yellow)
|
.foregroundStyle(selection == limit ? .black : .yellow)
|
||||||
.padding(.horizontal, 10)
|
.padding(.horizontal, Design.Spacing.small)
|
||||||
.padding(.vertical, 4)
|
.padding(.vertical, Design.Spacing.xSmall)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(selection == limit ? Color.yellow : Color.yellow.opacity(0.2))
|
.fill(selection == limit ? Color.yellow : Color.yellow.opacity(0.2))
|
||||||
@ -351,24 +351,24 @@ struct TableLimitsPicker: View {
|
|||||||
|
|
||||||
if selection == limit {
|
if selection == limit {
|
||||||
Image(systemName: "checkmark.circle.fill")
|
Image(systemName: "checkmark.circle.fill")
|
||||||
.font(.system(size: 20))
|
.font(.system(size: Design.Size.checkmark - 2))
|
||||||
.foregroundStyle(.yellow)
|
.foregroundStyle(.yellow)
|
||||||
} else {
|
} else {
|
||||||
Circle()
|
Circle()
|
||||||
.strokeBorder(Color.white.opacity(0.3), lineWidth: 2)
|
.strokeBorder(Color.white.opacity(Design.Opacity.light), lineWidth: Design.LineWidth.medium)
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: Design.Size.checkmark - 2, height: Design.Size.checkmark - 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
|
||||||
.fill(selection == limit ? Color.yellow.opacity(0.1) : Color.clear)
|
.fill(selection == limit ? Color.yellow.opacity(Design.Opacity.subtle) : Color.clear)
|
||||||
)
|
)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
|
||||||
.strokeBorder(
|
.strokeBorder(
|
||||||
selection == limit ? Color.yellow.opacity(0.5) : Color.white.opacity(0.1),
|
selection == limit ? Color.yellow.opacity(Design.Opacity.medium) : Color.white.opacity(Design.Opacity.subtle),
|
||||||
lineWidth: 1
|
lineWidth: Design.LineWidth.thin
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user