main
swift 111 lines 3.21 KB
Raw
1 import SwiftUI
2
3 enum WatchKleponTypography {
4 static let heroTitle = Font.system(size: 22, weight: .semibold, design: .serif)
5 static let sectionTitle = Font.system(size: 16, weight: .semibold, design: .serif)
6 static let cardTitle = Font.system(size: 17, weight: .semibold, design: .default)
7 static let body = Font.system(size: 14, weight: .regular, design: .default)
8 static let bodySecondary = Font.system(size: 12, weight: .regular, design: .default)
9 static let caption = Font.system(size: 11, weight: .semibold, design: .default)
10 }
11
12 struct WatchKleponCard<Content: View>: View {
13 let padding: CGFloat
14 @ViewBuilder var content: Content
15
16 init(padding: CGFloat = 14, @ViewBuilder content: () -> Content) {
17 self.padding = padding
18 self.content = content()
19 }
20
21 var body: some View {
22 content
23 .padding(padding)
24 .frame(maxWidth: .infinity, alignment: .leading)
25 .background(
26 RoundedRectangle(cornerRadius: 22, style: .continuous)
27 .fill(KleponColor.surface)
28 )
29 .overlay(
30 RoundedRectangle(cornerRadius: 22, style: .continuous)
31 .stroke(KleponColor.divider, lineWidth: 1)
32 )
33 }
34 }
35
36 struct WatchKleponSectionHeader: View {
37 let title: String
38 let subtitle: String?
39
40 init(_ title: String, subtitle: String? = nil) {
41 self.title = title
42 self.subtitle = subtitle
43 }
44
45 var body: some View {
46 VStack(alignment: .leading, spacing: 3) {
47 Text(title)
48 .font(WatchKleponTypography.sectionTitle)
49 .foregroundStyle(KleponColor.textPrimary)
50
51 if let subtitle {
52 Text(subtitle)
53 .font(WatchKleponTypography.bodySecondary)
54 .foregroundStyle(KleponColor.textSecondary)
55 }
56 }
57 .frame(maxWidth: .infinity, alignment: .leading)
58 }
59 }
60
61 struct WatchKleponChip: View {
62 let title: String
63 var icon: String? = nil
64
65 var body: some View {
66 HStack(spacing: 5) {
67 if let icon {
68 Image(systemName: icon)
69 .font(.system(size: 10, weight: .semibold))
70 }
71
72 Text(title)
73 .font(WatchKleponTypography.caption)
74 .lineLimit(1)
75 .minimumScaleFactor(0.8)
76 }
77 .foregroundStyle(KleponColor.textPrimary)
78 .padding(.horizontal, 10)
79 .padding(.vertical, 6)
80 .background(Capsule().fill(KleponColor.chipBackground))
81 }
82 }
83
84 struct WatchKleponChipGrid: View {
85 let items: [String]
86
87 var body: some View {
88 LazyVGrid(
89 columns: [GridItem(.adaptive(minimum: 72), spacing: 8)],
90 alignment: .leading,
91 spacing: 8
92 ) {
93 ForEach(items, id: \.self) { item in
94 WatchKleponChip(title: item)
95 }
96 }
97 }
98 }
99
100 struct WatchKleponFooterCard: View {
101 let message: String
102
103 var body: some View {
104 WatchKleponCard {
105 Text(message)
106 .font(WatchKleponTypography.bodySecondary)
107 .foregroundStyle(KleponColor.textSecondary)
108 .lineSpacing(2)
109 }
110 }
111 }