2024-MacC-M14-Medio / SqoopDesignSystem / Sources / SQComponents / Explore / SQPlaylistCarouselCell.swift
SQPlaylistCarouselCell.swift
Raw
//
//  SQPlaylistCarouselCell.swift
//  SqoopDesignSystem
//
//  Created by  on 3/4/25.
//

import SwiftUI

public struct SQPlaylistCarouselCell: View {
    
    public enum Variant {
        case `default`(ranking: Int, title: String, thumbnailUrlString: String)
        case more
    }
    
    public let variant: Variant
    public let tapAction: () -> Void
    
    public init(
        variant: Variant,
        tapAction: @escaping () -> Void
    ) {
        self.variant = variant
        self.tapAction = tapAction
    }
    
    public var body: some View {
        Button {
            tapAction()
        } label: {
            switch variant {
            case let .default(ranking, title, urlString):
                Default(ranking: ranking, title: title, thumbnailUrlString: urlString)
                
            case .more:
                More()
            }
        }
        .clipShape(RoundedRectangle(cornerRadius: 8))
        .frame(width: 300, height: 180)
    }
}

// MARK: - Default

private struct Default: View {
    
    let ranking: Int
    let title: String
    let thumbnailUrlString: String
    
    var body: some View {
        ZStack {
            ThumbnailImage()
            Overlay()
            Content()
                .padding(16)
        }
    }
    
    private func ThumbnailImage() -> some View {
        Group {
            AsyncImage(url: URL(string: thumbnailUrlString)) { phase in
                if let image = phase.image {
                    image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                } else {
                    Image(.emptyThumbnail)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                }
            }
        }
        .frame(maxWidth: 300, maxHeight: 180)
    }
    
    private func Overlay() -> some View {
        Rectangle()
            .foregroundColor(.clear)
            .background(
                LinearGradient(
                    stops: [
                        Gradient.Stop(color: .black.opacity(0), location: 0.00),
                        Gradient.Stop(color: .black.opacity(0.7), location: 1.00),
                    ],
                    startPoint: UnitPoint(x: 0.5, y: 0),
                    endPoint: UnitPoint(x: 0.5, y: 1)
                )
            )
    }
    
    private func Content() -> some View {
        VStack(alignment: .leading) {
            Text("\(ranking)")
                .foregroundStyle(Color.textPrimary)
                .font(.system(size: 40, weight: .bold, design: .none))
                .italic()
            
            Spacer()
            
            HStack {
                Text(title)
                    .fontWithLineHeight(.body01(weight: .semiBold))
                    .lineLimit(2)
                    .multilineTextAlignment(.leading)
                    .foregroundStyle(Color.textPrimary)
                
                Spacer()
            }
        }
    }
}

// MARK: - More

private struct More: View {
    
    var body: some View {
        ZStack {
            Overlay()
            
            VStack(spacing: 6) {
                Image(symbol: .arrowRightCircle)
                    .font(.system(size: 36))
                
                Text("더 보러가기")
                    .fontWithLineHeight(.headline02)
                    
            }
            .foregroundStyle(Color.textBrand)
        }
    }
    
    private func Overlay() -> some View {
        Rectangle()
            .foregroundColor(.clear)
            .background(
                LinearGradient(
                    stops: [
                        Gradient.Stop(color: Color.bgGreyTransparent1, location: 0.00),
                        Gradient.Stop(color: Color(red: 0.05, green: 0.13, blue: 0.16), location: 1.00),
                    ],
                    startPoint: UnitPoint(x: -0.16, y: 0.75),
                    endPoint: UnitPoint(x: 1, y: 0.13)
                )
            )
    }
}

// MARK: - Preview

#Preview {
    ZStack {
        Color.bgBlack.ignoresSafeArea()
        VStack {
            SQPlaylistCarouselCell(
                variant: .default(
                    ranking: 1,
                    title: "플레이리스트의 제목입니다. 플레이리스트의 제목입니다. 플레이리스트의 제목입니다.",
                    thumbnailUrlString: "https://marketplace.canva.com/EAF2MPZnemI/1/0/1600w/canva-%EB%B3%B4%EB%9D%BC%EC%83%89%EC%9D%98-%EC%8B%AC%ED%94%8C%ED%95%9C-%EC%9D%8C%EC%95%85-%ED%94%8C%EB%A0%88%EC%9D%B4%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%9C%A0%ED%8A%9C%EB%B8%8C-%EC%8D%B8%EB%84%A4%EC%9D%BC-vRtE0XHyn6k.jpg"
                ),
                tapAction: {}
            )
            
            SQPlaylistCarouselCell(
                variant: .more,
                tapAction: {}
            )
        }
    }
    .loadSqoopFontSystem()
}