-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataBottomSheet.swift
More file actions
145 lines (123 loc) · 4.08 KB
/
DataBottomSheet.swift
File metadata and controls
145 lines (123 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// DataBottomSheet.swift
// Codive
//
// Created by 한태빈 on 2025/12/23.
//
import SwiftUI
// 바텀시트에서 사용할 아이템 모델 (나중에 API 생기면 붙일 예정)
struct DataBottomSheetClothItem: Identifiable, Hashable {
let id: UUID = .init()
let imageName: String
let brand: String
let title: String
}
struct DataBottomSheet: View {
// MARK: - Inputs
let dataBottomSheetTitle: String
let totalCount: Int
let items: [DataBottomSheetClothItem]
var onTapItem: (DataBottomSheetClothItem) -> Void = { _ in }
// MARK: - Layout constants
private let cornerRadius: CGFloat = 24
private let handleSize = CGSize(width: 52, height: 4)
private let gridHorizontalPadding: CGFloat = 0
private let headerHorizontalPadding: CGFloat = 20
private let headerTopPadding: CGFloat = 16
private let headerBottomPadding: CGFloat = 14
private let columnCount: Int = 3
private let gridSpacing: CGFloat = 0
private var columns: [GridItem] {
Array(repeating: GridItem(.flexible(), spacing: gridSpacing), count: columnCount)
}
var body: some View {
VStack(spacing: 0) {
handle
header
Divider()
grid
}
.background(Color.white)
.clipShape(RoundedCorner(radius: cornerRadius, corners: [.topLeft, .topRight]))
}
private var handle: some View {
Capsule()
.fill(Color.Codive.grayscale5)
.frame(width: handleSize.width, height: handleSize.height)
.padding(.top, 10)
.padding(.bottom, 10)
}
private var header: some View {
HStack(alignment: .firstTextBaseline, spacing: 8) {
Text(dataBottomSheetTitle)
.font(.codive_title2)
.foregroundStyle(Color.Codive.grayscale1)
Text("총 \(max(0, totalCount))벌")
.font(.codive_body2_medium)
.foregroundStyle(Color.Codive.grayscale4)
Spacer(minLength: 0)
}
.padding(.horizontal, headerHorizontalPadding)
.padding(.top, headerTopPadding)
.padding(.bottom, headerBottomPadding)
}
private var grid: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: gridSpacing) {
ForEach(items) { item in
CustomClothCard(
imageName: item.imageName,
brand: item.brand,
title: item.title
) {
onTapItem(item)
}
}
}
.padding(.horizontal, gridHorizontalPadding)
.padding(.bottom, 24)
}
}
}
extension View {
func dataBottomSheet(
isPresented: Binding<Bool>,
dataBottomSheetTitle: String,
totalCount: Int,
items: [DataBottomSheetClothItem],
onTapItem: @escaping (DataBottomSheetClothItem) -> Void = { _ in }
) -> some View {
self.sheet(isPresented: isPresented) {
DataBottomSheet(
dataBottomSheetTitle: dataBottomSheetTitle,
totalCount: totalCount,
items: items,
onTapItem: onTapItem
)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.hidden)
.background(Color.clear)
}
}
}
#Preview {
struct PreviewHost: View {
@State private var show = true
private let sampleItems: [DataBottomSheetClothItem] = Array(repeating: DataBottomSheetClothItem(
imageName: "samplecloth",
brand: "나이키",
title: "Cable knit cardigan navy..."
), count: 11)
var body: some View {
Color.gray.opacity(0.15)
.ignoresSafeArea()
.dataBottomSheet(
isPresented: $show,
dataBottomSheetTitle: "맨투맨",
totalCount: sampleItems.count,
items: sampleItems
)
}
}
return PreviewHost()
}