feat(creator): 소개, 활동, SNS 섹션을 연결한다
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CreatorChannelActivitySection: View {
|
||||
let activity: CreatorChannelActivityResponse
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||
SectionTitle(title: I18n.CreatorChannelHome.activity)
|
||||
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s8) {
|
||||
activityRow(title: I18n.CreatorChannelHome.debut, value: activity.debutText)
|
||||
activityRow(title: I18n.CreatorChannelHome.liveCount, value: I18n.CreatorChannelHome.liveCountValue(activity.liveCount.comma()))
|
||||
activityRow(title: I18n.CreatorChannelHome.liveDurationHours, value: I18n.CreatorChannelHome.liveDurationHoursValue(activity.liveDurationHours.comma()))
|
||||
activityRow(title: I18n.CreatorChannelHome.liveContributorCount, value: I18n.CreatorChannelHome.liveContributorCountValue(activity.liveContributorCount.comma()))
|
||||
activityRow(title: I18n.CreatorChannelHome.audioContentCount, value: I18n.CreatorChannelHome.audioContentCountValue(activity.audioContentCount.comma()))
|
||||
activityRow(title: I18n.CreatorChannelHome.seriesCount, value: I18n.CreatorChannelHome.seriesCountValue(activity.seriesCount.comma()))
|
||||
}
|
||||
.padding(.horizontal, SodaSpacing.s20)
|
||||
}
|
||||
.padding(.top, SodaSpacing.s20)
|
||||
}
|
||||
|
||||
private func activityRow(title: String, value: String) -> some View {
|
||||
HStack(alignment: .top, spacing: SodaSpacing.s8) {
|
||||
Text(title)
|
||||
.appFont(size: 16, weight: .medium)
|
||||
.foregroundColor(Color.gray500)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Text(value)
|
||||
.appFont(size: 16, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension CreatorChannelActivityResponse {
|
||||
var debutText: String {
|
||||
let dDayText = dday.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
guard let debutDateUtc,
|
||||
let debutDate = DateParser.parse(debutDateUtc),
|
||||
!dDayText.isEmpty else {
|
||||
return dDayText
|
||||
}
|
||||
|
||||
return "\(debutDate.convertDateFormat(dateFormat: "yyyy.MM.dd"))(\(dDayText))"
|
||||
}
|
||||
}
|
||||
|
||||
struct CreatorChannelActivitySection_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CreatorChannelActivitySection(
|
||||
activity: CreatorChannelActivityResponse(
|
||||
debutDateUtc: "2026-06-11T00:00:00Z",
|
||||
dday: "D+1",
|
||||
liveCount: 719,
|
||||
liveDurationHours: 1839,
|
||||
liveContributorCount: 2189,
|
||||
audioContentCount: 281,
|
||||
seriesCount: 8
|
||||
)
|
||||
)
|
||||
.background(Color.black)
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CreatorChannelIntroduceSection: View {
|
||||
let introduce: String
|
||||
|
||||
private var trimmedIntroduce: String {
|
||||
introduce.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if !trimmedIntroduce.isEmpty {
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||
SectionTitle(title: I18n.CreatorChannelHome.introduce)
|
||||
|
||||
Text(trimmedIntroduce)
|
||||
.appFont(size: 16, weight: .regular)
|
||||
.foregroundColor(.white)
|
||||
.lineSpacing(4)
|
||||
.lineLimit(nil)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, SodaSpacing.s20)
|
||||
}
|
||||
.padding(.top, SodaSpacing.s20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CreatorChannelIntroduceSection_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CreatorChannelIntroduceSection(
|
||||
introduce: "크리에이터가 커뮤니티에 올린 글이 보이는 부분 크리에이터가 커뮤니티에 올린 글이 보이는 부분 크리에이터가 커뮤니티에 올린 글이 보이는 부분"
|
||||
)
|
||||
.background(Color.black)
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CreatorChannelSnsSection: View {
|
||||
let sns: CreatorChannelSnsResponse
|
||||
|
||||
@Environment(\.openURL) private var openURL
|
||||
|
||||
private var snsItems: [CreatorChannelSnsItem] {
|
||||
[
|
||||
CreatorChannelSnsItem(iconName: "ic_sns_instagram", url: sns.instagramUrl),
|
||||
CreatorChannelSnsItem(iconName: "ic_sns_youtube", url: sns.youtubeUrl),
|
||||
CreatorChannelSnsItem(iconName: "ic_sns_x", url: sns.xurl),
|
||||
CreatorChannelSnsItem(iconName: "ic_sns_kakao", url: sns.kakaoOpenChatUrl),
|
||||
CreatorChannelSnsItem(iconName: "ic_sns_fancimm", url: sns.fancimmUrl)
|
||||
]
|
||||
.compactMap { item in
|
||||
guard normalizedUrl(item.url) != nil else { return nil }
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if !snsItems.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
SectionTitle(title: I18n.CreatorChannelHome.sns)
|
||||
|
||||
HStack(alignment: .center, spacing: SodaSpacing.s16) {
|
||||
ForEach(snsItems) { item in
|
||||
Button {
|
||||
if let url = normalizedUrl(item.url) {
|
||||
openURL(url)
|
||||
}
|
||||
} label: {
|
||||
Image(item.iconName)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 52, height: 52)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, SodaSpacing.s20)
|
||||
}
|
||||
.padding(.top, SodaSpacing.s20)
|
||||
}
|
||||
}
|
||||
|
||||
private func normalizedUrl(_ urlString: String) -> URL? {
|
||||
let trimmed = urlString.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
guard !trimmed.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if trimmed.hasPrefix("http://") || trimmed.hasPrefix("https://") {
|
||||
return URL(string: trimmed)
|
||||
}
|
||||
|
||||
return URL(string: "https://\(trimmed)")
|
||||
}
|
||||
}
|
||||
|
||||
private struct CreatorChannelSnsItem: Identifiable {
|
||||
let iconName: String
|
||||
let url: String
|
||||
|
||||
var id: String { iconName }
|
||||
}
|
||||
|
||||
struct CreatorChannelSnsSection_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CreatorChannelSnsSection(
|
||||
sns: CreatorChannelSnsResponse(
|
||||
instagramUrl: "https://instagram.com/voiceon",
|
||||
fancimmUrl: "https://fancimm.com",
|
||||
xurl: "https://x.com/voiceon",
|
||||
youtubeUrl: "https://youtube.com",
|
||||
kakaoOpenChatUrl: "https://open.kakao.com"
|
||||
)
|
||||
)
|
||||
.background(Color.black)
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user