// // AudioContentCard.swift // SodaLive // import SwiftUI enum AudioContentCardSize { case large case medium case small var width: CGFloat { switch self { case .large: return 185 case .medium: return 163 case .small: return 122 } } var labelWidth: CGFloat { width - (labelHorizontalPadding * 2) } var labelHorizontalPadding: CGFloat { switch self { case .large: return 0 case .medium: return SodaSpacing.s6 case .small: return SodaSpacing.s4 } } var titleTypography: SodaTypography { switch self { case .large, .medium: return .heading4 case .small: return .body1 } } var subtitleTypography: SodaTypography { switch self { case .large, .medium: return .body5 case .small: return .caption2 } } } struct AudioContentCard: View { let size: AudioContentCardSize let title: String let subtitle: String private let thumbnail: Thumbnail init( size: AudioContentCardSize, title: String, subtitle: String, @ViewBuilder thumbnail: () -> Thumbnail ) { self.size = size self.title = title self.subtitle = subtitle self.thumbnail = thumbnail() } var body: some View { VStack(alignment: .leading, spacing: SodaSpacing.s8) { thumbnailContent labelContent } .frame(width: size.width, alignment: .leading) } private var thumbnailContent: some View { thumbnail .frame(width: size.width, height: size.width) .clipped() .frame(width: size.width, height: size.width) .clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous)) } private var labelContent: some View { VStack(alignment: .leading, spacing: 2) { Text(title) .appFont(size.titleTypography) .foregroundColor(.white) .lineLimit(1) .truncationMode(.tail) Text(subtitle) .appFont(size.subtitleTypography) .foregroundColor(Color.gray500) .lineLimit(1) .truncationMode(.tail) } .frame(width: size.labelWidth, alignment: .leading) .padding(.horizontal, size.labelHorizontalPadding) .frame(width: size.width, alignment: .leading) } } struct AudioContentCard_Previews: PreviewProvider { static var previews: some View { HStack(alignment: .top, spacing: SodaSpacing.s20) { AudioContentCard( size: .large, title: "오디오 콘텐츠 제목입니다", subtitle: "크리에이터명" ) { previewThumbnail(Color.gray800) } AudioContentCard( size: .medium, title: "긴 제목은 한 줄로 말줄임 처리됩니다", subtitle: "긴 부제목도 한 줄로 말줄임 처리됩니다" ) { previewThumbnail(Color.gray700) } AudioContentCard( size: .small, title: "스몰 카드", subtitle: "오디오" ) { previewThumbnail(Color.gray900) } } .padding(SodaSpacing.s20) .background(Color.black) .previewLayout(.sizeThatFits) } private static func previewThumbnail(_ color: Color) -> some View { ZStack { color Image(systemName: "waveform") .font(.system(size: 32, weight: .bold)) .foregroundColor(Color.gray500) } } }