import SwiftUI struct MainContentAudioRankingTopCard: View { let item: AudioRankingItemResponse let showRankChange: Bool let onTapContent: (Int) -> Void var body: some View { Button { onTapContent(item.contentId) } label: { GeometryReader { proxy in let width = proxy.size.width let imageSide = min(width * 0.42, proxy.size.height * 0.65) ZStack(alignment: .topLeading) { DownsampledKFImage( url: URL(string: item.coverImageUrl ?? ""), size: CGSize(width: width, height: proxy.size.height) ) .background(Color.gray800) .blur(radius: 10) Color.black.opacity(0.1) LinearGradient( colors: [Color.black.opacity(0), Color.black.opacity(0.72)], startPoint: .top, endPoint: .bottom ) rankColumn .padding(.leading, SodaSpacing.s20) .padding(.top, SodaSpacing.s4) VStack(spacing: SodaSpacing.s8) { DownsampledKFImage( url: URL(string: item.coverImageUrl ?? ""), size: CGSize(width: imageSide, height: imageSide) ) .background(Color.gray800) .aspectRatio(1, contentMode: .fill) .clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous)) .shadow(color: Color.black.opacity(0.2), radius: 15) VStack(spacing: 0) { Text(item.title) .appFont(size: 22, weight: .bold) .foregroundColor(.white) .lineLimit(1) .truncationMode(.tail) Text(item.creatorNickname) .appFont(.caption1) .foregroundColor(.white) .lineLimit(1) .truncationMode(.tail) } .frame(maxWidth: .infinity) } .padding(.horizontal, SodaSpacing.s20) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) } .clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous)) } .aspectRatio(1.57, contentMode: .fit) } .buttonStyle(.plain) } private var rankColumn: some View { VStack(alignment: .center, spacing: -20) { Text("\(item.rank)") .appFont(size: 96, family: .pattaya) .foregroundStyle( LinearGradient( colors: [.white, Color.gray200], startPoint: .top, endPoint: .bottom ) ) .shadow(color: Color.black.opacity(0.48), radius: 2) .lineLimit(1) MainContentRankChangeBadge( showRankChange: showRankChange, rankChange: item.rankChange, isNew: item.isNew ) } .frame(width: 86, alignment: .center) } }