//
// 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()
}