import SwiftUI /// Visual baseball diamond showing base runners, count, and outs struct DiamondView: View { var onFirst: Bool = false var onSecond: Bool = false var onThird: Bool = false var balls: Int = 0 var strikes: Int = 0 var outs: Int = 0 var body: some View { HStack(spacing: diamondCountGap) { // Diamond ZStack { // Diamond shape outline diamondPath .stroke(DS.Colors.textQuaternary, lineWidth: 1.5) // Base markers baseMarker(at: firstBasePos, occupied: onFirst) baseMarker(at: secondBasePos, occupied: onSecond) baseMarker(at: thirdBasePos, occupied: onThird) baseMarker(at: homePos, occupied: false, isHome: true) } .frame(width: diamondSize, height: diamondSize) // Count + Outs VStack(alignment: .leading, spacing: countSpacing) { HStack(spacing: 3) { Text("B").dataLabelStyle() ForEach(0..<4, id: \.self) { i in Circle() .fill(i < balls ? DS.Colors.positive : DS.Colors.textQuaternary) .frame(width: dotSize, height: dotSize) } } HStack(spacing: 3) { Text("S").dataLabelStyle() ForEach(0..<3, id: \.self) { i in Circle() .fill(i < strikes ? DS.Colors.live : DS.Colors.textQuaternary) .frame(width: dotSize, height: dotSize) } } HStack(spacing: 3) { Text("O").dataLabelStyle() ForEach(0..<3, id: \.self) { i in Circle() .fill(i < outs ? DS.Colors.warning : DS.Colors.textQuaternary) .frame(width: dotSize, height: dotSize) } } } } } // MARK: - Diamond geometry private var diamondPath: Path { let s = diamondSize let mid = s / 2 let inset: CGFloat = baseSize / 2 + 2 var path = Path() path.move(to: CGPoint(x: mid, y: inset)) // 2nd base (top) path.addLine(to: CGPoint(x: s - inset, y: mid)) // 1st base (right) path.addLine(to: CGPoint(x: mid, y: s - inset)) // Home (bottom) path.addLine(to: CGPoint(x: inset, y: mid)) // 3rd base (left) path.closeSubpath() return path } private var firstBasePos: CGPoint { CGPoint(x: diamondSize - baseSize / 2 - 2, y: diamondSize / 2) } private var secondBasePos: CGPoint { CGPoint(x: diamondSize / 2, y: baseSize / 2 + 2) } private var thirdBasePos: CGPoint { CGPoint(x: baseSize / 2 + 2, y: diamondSize / 2) } private var homePos: CGPoint { CGPoint(x: diamondSize / 2, y: diamondSize - baseSize / 2 - 2) } @ViewBuilder private func baseMarker(at position: CGPoint, occupied: Bool, isHome: Bool = false) -> some View { Group { if isHome { // Home plate: small pentagon-like shape Circle() .fill(DS.Colors.textQuaternary) .frame(width: baseSize * 0.7, height: baseSize * 0.7) } else { // Base: rotated square Rectangle() .fill(occupied ? DS.Colors.interactive : DS.Colors.textQuaternary) .frame(width: baseSize, height: baseSize) .rotationEffect(.degrees(45)) } } .position(position) } // MARK: - Platform sizing #if os(tvOS) private var diamondSize: CGFloat { 60 } private var baseSize: CGFloat { 12 } private var dotSize: CGFloat { 9 } private var countSpacing: CGFloat { 5 } private var diamondCountGap: CGFloat { 14 } #else private var diamondSize: CGFloat { 44 } private var baseSize: CGFloat { 9 } private var dotSize: CGFloat { 7 } private var countSpacing: CGFloat { 3 } private var diamondCountGap: CGFloat { 10 } #endif }