// // ChipView.swift // Baccarat // // A realistic casino-style betting chip. // import SwiftUI /// A realistic casino-style betting chip. struct ChipView: View { let denomination: ChipDenomination let size: CGFloat var isSelected: Bool = false init(denomination: ChipDenomination, size: CGFloat = 60, isSelected: Bool = false) { self.denomination = denomination self.size = size self.isSelected = isSelected } // MARK: - Layout Constants private let innerCircleRatio: CGFloat = 0.65 private let innerGradientRatio: CGFloat = 0.4 private let textSizeRatio: CGFloat = 0.25 private let selectionGlowPadding: CGFloat = 6 private let shadowOffset: CGFloat = 2 private let shadowOffsetY: CGFloat = 3 var body: some View { ZStack { // Base circle with gradient Circle() .fill( RadialGradient( colors: [ denomination.secondaryColor, denomination.primaryColor, denomination.primaryColor.opacity(Design.Opacity.heavy) ], center: .topLeading, startRadius: 0, endRadius: size ) ) // Edge stripes pattern ChipEdgePattern(stripeColor: denomination.stripeColor) .clipShape(.circle) // Inner circle Circle() .fill( RadialGradient( colors: [ denomination.secondaryColor, denomination.primaryColor ], center: .topLeading, startRadius: 0, endRadius: size * innerGradientRatio ) ) .frame(width: size * innerCircleRatio, height: size * innerCircleRatio) // Inner border Circle() .strokeBorder( denomination.stripeColor.opacity(Design.Opacity.heavy), lineWidth: Design.LineWidth.medium ) .frame(width: size * innerCircleRatio, height: size * innerCircleRatio) // Denomination text Text(denomination.displayText) .font(.system(size: size * textSizeRatio, weight: .heavy, design: .rounded)) .foregroundStyle(denomination.stripeColor) .shadow(color: .black.opacity(Design.Opacity.light), radius: Design.LineWidth.thin, x: 1, y: 1) // Outer border Circle() .strokeBorder( LinearGradient( colors: [ Color.white.opacity(Design.Opacity.overlay), Color.black.opacity(Design.Opacity.light) ], startPoint: .topLeading, endPoint: .bottomTrailing ), lineWidth: Design.LineWidth.medium ) // Selection glow if isSelected { Circle() .strokeBorder(Color.yellow, lineWidth: Design.LineWidth.thick) .frame(width: size + selectionGlowPadding, height: size + selectionGlowPadding) } } .frame(width: size, height: size) .shadow(color: .black.opacity(Design.Opacity.overlay), radius: isSelected ? Design.Shadow.radiusSmall * 2 : Design.Shadow.radiusSmall, x: shadowOffset, y: shadowOffsetY) .scaleEffect(isSelected ? Design.Scale.selected : Design.Scale.normal) .animation(.spring(duration: Design.Animation.selectionDuration), value: isSelected) } } #Preview { ZStack { Color.Table.preview .ignoresSafeArea() VStack(spacing: Design.Spacing.xxxLarge) { HStack(spacing: Design.Spacing.xLarge) { ForEach(ChipDenomination.allCases) { denom in ChipView(denomination: denom, size: Design.Size.chipSelector) } } ChipView(denomination: .hundred, size: 80, isSelected: true) } } }