// // OriginalWorkDetailView.swift // SodaLive // // Created by klaus on 9/15/25. // import SwiftUI import Kingfisher struct OriginalWorkDetailView: View { @StateObject var viewModel = OriginalWorkDetailViewModel() let originalId: Int var body: some View { NavigationStack { BaseView(isLoading: $viewModel.isLoading) { ZStack(alignment: .top) { if let imageUrl = viewModel.response?.imageUrl { KFImage(URL(string: imageUrl)) .cancelOnDisappear(true) .resizable() .scaledToFill() .frame(width: screenSize().width, height: (168 * 288 / 306) + 56) .clipped() .blur(radius: 25) } Color.black.opacity(0.5).ignoresSafeArea() VStack(spacing: 0) { HStack(spacing: 0) { Image("ic_back") .resizable() .frame(width: 24, height: 24) .onTapGesture { AppState.shared.back() } Spacer() } .padding(.horizontal, 24) .frame(height: 56) if let response = viewModel.response { ScrollView(.vertical, showsIndicators: false) { VStack(spacing: 0) { OriginalWorkDetailHeaderView(item: response) .padding(.horizontal, 24) .padding(.bottom, 24) HStack(spacing: 0) { SeriesDetailTabView( title: "캐릭터", width: screenSize().width / 2, isSelected: viewModel.currentTab == .character ) { if viewModel.currentTab != .character { viewModel.currentTab = .character } } SeriesDetailTabView( title: "작품정보", width: screenSize().width / 2, isSelected: viewModel.currentTab == .info ) { if viewModel.currentTab != .info { viewModel.currentTab = .info } } } .background(Color.black) Rectangle() .foregroundColor(Color.gray90.opacity(0.5)) .frame(height: 1) .frame(maxWidth: .infinity) switch(viewModel.currentTab) { case .info: OriginalWorkInfoView(response: response) default: OriginalWorkCharacterView(characters: viewModel.characters) } } } } } } } .onAppear { if viewModel.response == nil { viewModel.originalId = originalId } } .navigationDestination(for: Int.self) { characterId in CharacterDetailView(characterId: characterId) } } } } struct OriginalWorkCharacterView: View { private let horizontalPadding: CGFloat = 12 private let gridSpacing: CGFloat = 12 let characters: [Character] var body: some View { ZStack { let width = (screenSize().width - (horizontalPadding * 2) - gridSpacing) / 2 LazyVGrid( columns: Array( repeating: GridItem( .flexible(), spacing: gridSpacing, alignment: .topLeading ), count: 2 ), alignment: .leading, spacing: gridSpacing ) { ForEach(characters.indices, id: \.self) { idx in let item = characters[idx] NavigationLink(value: item.characterId) { CharacterItemView( character: item, size: width, rank: 0, isShowRank: false ) } } } .padding(.horizontal, horizontalPadding) } .padding(.top, 24) .background(Color.black) } } struct OriginalWorkInfoView: View { let response: OriginalWorkDetailResponse @State private var isExpandDesc = false var body: some View { ZStack { VStack(spacing: 16) { VStack(alignment: .leading, spacing: 8) { Text("작품 소개") .font(.custom(Font.preBold.rawValue, size: 16)) .foregroundColor(.white) Text(response.description) .font(.custom(Font.preRegular.rawValue, size: 14)) .foregroundColor(Color(hex: "B0BEC5")) .lineLimit(isExpandDesc ? Int.max : 3) .truncationMode(.tail) .onTapGesture { isExpandDesc.toggle() } } .padding(16) .frame(maxWidth: .infinity, alignment: .leading) .background(Color(hex: "263238")) .cornerRadius(16) VStack(alignment: .leading, spacing: 8) { Text("원작 보러 가기") .font(.custom(Font.preBold.rawValue, size: 16)) .foregroundColor(Color(hex: "B0BEC5")) ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 8) { ForEach(0..