feat(gift): 선물함 목록 컴포넌트를 추가한다
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import SwiftUI
|
||||
|
||||
struct GiftBoxCardView: View {
|
||||
let model: GiftListCardDisplayModel
|
||||
let onTap: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: onTap) {
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||
HStack(alignment: .top, spacing: SodaSpacing.s8) {
|
||||
DownsampledKFImage(
|
||||
url: profileURL,
|
||||
size: CGSize(width: SodaSpacing.s20, height: SodaSpacing.s20)
|
||||
)
|
||||
.background(Color.gray800)
|
||||
.clipShape(Circle())
|
||||
.accessibilityHidden(true)
|
||||
|
||||
Text(model.counterpartNickname)
|
||||
.appFont(.caption3)
|
||||
.foregroundColor(.white)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
if let dateText {
|
||||
Text(dateText)
|
||||
.appFont(.caption3)
|
||||
.foregroundColor(.gray500)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: SodaSpacing.s20)
|
||||
|
||||
HStack(spacing: SodaSpacing.s12) {
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s4) {
|
||||
Text(model.statusDisplay.title)
|
||||
.appFont(.body4)
|
||||
.foregroundColor(.white)
|
||||
|
||||
if let subtitle {
|
||||
Text(subtitle)
|
||||
.appFont(.caption3)
|
||||
.foregroundColor(.gray400)
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Image("ic_chevron_right")
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.scaledToFit()
|
||||
.foregroundColor(.white)
|
||||
.frame(width: SodaSpacing.s20, height: SodaSpacing.s20)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
.frame(minHeight: 39)
|
||||
}
|
||||
.multilineTextAlignment(.leading)
|
||||
.padding(SodaSpacing.s14)
|
||||
.frame(maxWidth: .infinity, minHeight: 101, alignment: .topLeading)
|
||||
.background(Color.gray900)
|
||||
.clipShape(RoundedRectangle(cornerRadius: SodaRadius.r14))
|
||||
.contentShape(RoundedRectangle(cornerRadius: SodaRadius.r14))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityElement(children: .ignore)
|
||||
.accessibilityLabel(accessibilityText)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.padding(.horizontal, SodaSpacing.s14)
|
||||
}
|
||||
|
||||
private var profileURL: URL? {
|
||||
guard let text = model.counterpartProfileImageUrl,
|
||||
!text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
|
||||
let url = URL(string: text),
|
||||
let scheme = url.scheme?.lowercased(),
|
||||
["https", "http"].contains(scheme),
|
||||
let host = url.host, !host.isEmpty else { return nil }
|
||||
return url
|
||||
}
|
||||
|
||||
private var dateText: String? {
|
||||
model.createdDateText.map { "\($0) 신청" }
|
||||
}
|
||||
|
||||
private var subtitle: String? {
|
||||
model.direction == .sent
|
||||
? "\(model.sizeName) · \(model.categoryName)"
|
||||
: model.statusDisplay.subtitle
|
||||
}
|
||||
|
||||
private var accessibilityText: String {
|
||||
[model.counterpartNickname, dateText, model.statusDisplay.title, subtitle,
|
||||
model.direction == .received ? "\(model.sizeName) · \(model.categoryName)" : nil]
|
||||
.compactMap { $0 }
|
||||
.joined(separator: ", ")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user