import SwiftUI struct CreatorChannelAudioSection: View { let audioContents: [CreatorChannelAudioContentResponse] let onSelectTab: (CreatorChannelTab) -> Void let onTapContent: (Int) -> Void private let homeVisibleCount = 9 private let itemsPerColumn = 3 private var rowWidth: CGFloat { AudioContentListRowStyle.compactWidth() } init( audioContents: [CreatorChannelAudioContentResponse], onSelectTab: @escaping (CreatorChannelTab) -> Void, onTapContent: @escaping (Int) -> Void = { _ in } ) { self.audioContents = audioContents self.onSelectTab = onSelectTab self.onTapContent = onTapContent } var body: some View { if audioContents.isEmpty == false { VStack(alignment: .leading, spacing: SodaSpacing.s14) { SectionTitle(title: I18n.CreatorChannelHome.audio) { onSelectTab(.audio) } ScrollView(.horizontal, showsIndicators: false) { HStack(alignment: .top, spacing: SodaSpacing.s8) { ForEach(audioContentColumns.indices, id: \.self) { index in VStack(alignment: .leading, spacing: SodaSpacing.s8) { ForEach(audioContentColumns[index]) { audioContent in AudioContentListRow( item: AudioContentListRowItem( audioContent: audioContent, subtitle: subtitle(for: audioContent) ), style: .compact(width: rowWidth) ) { onTapContent(audioContent.audioContentId) } } } } } .padding(.leading, SodaSpacing.s14) .padding(.trailing, SodaSpacing.s20) } } .padding(.top, SodaSpacing.s20) } } private var visibleAudioContents: [CreatorChannelAudioContentResponse] { Array(audioContents.prefix(homeVisibleCount)) } private var audioContentColumns: [[CreatorChannelAudioContentResponse]] { stride(from: 0, to: visibleAudioContents.count, by: itemsPerColumn).map { index in Array(visibleAudioContents[index.. String? { let subtitle = [audioContent.duration, audioContent.seriesName] .compactMap { value in guard let value, !value.isEmpty else { return nil } return value } .joined(separator: " • ") return subtitle.isEmpty ? nil : subtitle } } struct CreatorChannelAudioSection_Previews: PreviewProvider { static var previews: some View { CreatorChannelAudioSection( audioContents: (1...9).map { index in CreatorChannelAudioContentResponse( audioContentId: index, title: "콘텐츠 이름이 한 줄 콘텐츠 이름이 한 줄 콘텐츠 이름이 한 줄", duration: "3:00", imageUrl: "https://picsum.photos/300/300?\(index)", price: index.isMultiple(of: 2) ? 0 : 10, isAdult: false, isPointAvailable: index.isMultiple(of: 3), isFirstContent: index.isMultiple(of: 2), seriesName: index == 3 ? "시리즈 이름" : nil, isOriginalSeries: index == 3, isOwned: false, isRented: false ) }, onSelectTab: { _ in } ) .background(Color.black) .previewLayout(.sizeThatFits) } }