import React from 'react' function formatDate(value) { if (!value) return null try { return new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', year: 'numeric', }).format(new Date(value)) } catch { return null } } function formatYear(value) { if (!value) return null try { return new Intl.DateTimeFormat('en', { year: 'numeric' }).format(new Date(value)) } catch { return null } } function iconForType(type) { switch (type) { case 'first_upload': return 'fa-solid fa-seedling' case 'first_featured_artwork': return 'fa-solid fa-star' case 'first_group_release': return 'fa-solid fa-people-group' case 'biggest_download_spike': return 'fa-solid fa-bolt' case 'best_performing_work': return 'fa-solid fa-trophy' case 'most_productive_year': return 'fa-solid fa-calendar-check' case 'yearly_recap': return 'fa-solid fa-chart-column' case 'comeback_minor': return 'fa-solid fa-rotate-right' case 'comeback_major': return 'fa-solid fa-person-walking-arrow-right' case 'comeback_legendary': return 'fa-solid fa-fire-flame-curved' case 'upload_streak_3': case 'upload_streak_6': case 'upload_streak_12': return 'fa-solid fa-fire' case 'active_year_streak_3': case 'active_year_streak_5': return 'fa-solid fa-calendar-days' case 'before_now': return 'fa-solid fa-arrows-rotate' case 'era_started': return 'fa-solid fa-flag' default: return 'fa-solid fa-sparkles' } } function colorForType(type) { switch (type) { case 'first_featured_artwork': return { icon: 'text-amber-200', bg: 'bg-amber-400/12', border: 'border-amber-300/20', accent: 'from-amber-400/60' } case 'best_performing_work': return { icon: 'text-amber-200', bg: 'bg-amber-400/12', border: 'border-amber-300/20', accent: 'from-amber-400/60' } case 'biggest_download_spike': return { icon: 'text-sky-200', bg: 'bg-sky-400/12', border: 'border-sky-300/20', accent: 'from-sky-400/60' } case 'first_upload': return { icon: 'text-emerald-200', bg: 'bg-emerald-400/12', border: 'border-emerald-300/20', accent: 'from-emerald-400/60' } case 'first_group_release': return { icon: 'text-violet-200', bg: 'bg-violet-400/12', border: 'border-violet-300/20', accent: 'from-violet-400/60' } case 'comeback_minor': case 'comeback_major': case 'comeback_legendary': return { icon: 'text-orange-200', bg: 'bg-orange-400/12', border: 'border-orange-300/20', accent: 'from-orange-400/60' } case 'most_productive_year': return { icon: 'text-teal-200', bg: 'bg-teal-400/12', border: 'border-teal-300/20', accent: 'from-teal-400/60' } default: return { icon: 'text-sky-200', bg: 'bg-sky-400/12', border: 'border-sky-300/20', accent: 'from-sky-400/60' } } } function milestoneHref(item) { return item?.artwork?.url || item?.release?.url || null } function StatPill({ label, value }) { if (value === null || value === undefined || value === '') return null return (
{label}
{value}
) } function EmptyJourneyState({ username, memberSinceYear, yearsOnSkinbase }) { return (
Creator Journey is just getting started
Public milestones will appear here as @{username} builds more history on Skinbase.
) } // ── v2: Era strip ───────────────────────────────────────────────────────────── const ERA_COLORS = { early_years: { bg: 'bg-slate-800/60', border: 'border-slate-600/40', text: 'text-slate-300', icon: 'fa-solid fa-seedling', dot: 'bg-slate-400' }, breakthrough: { bg: 'bg-amber-900/30', border: 'border-amber-600/30', text: 'text-amber-200', icon: 'fa-solid fa-star', dot: 'bg-amber-400' }, experimental: { bg: 'bg-violet-900/30', border: 'border-violet-600/30', text: 'text-violet-200', icon: 'fa-solid fa-flask', dot: 'bg-violet-400' }, comeback: { bg: 'bg-emerald-900/30', border: 'border-emerald-600/30', text: 'text-emerald-200', icon: 'fa-solid fa-rotate-right', dot: 'bg-emerald-400' }, current: { bg: 'bg-sky-900/30', border: 'border-sky-600/30', text: 'text-sky-200', icon: 'fa-solid fa-bolt', dot: 'bg-sky-400' }, } function EraStrip({ eras }) { if (!eras?.length) return null return (
Creator Eras
{eras.map((era, i) => { const style = ERA_COLORS[era.type] ?? ERA_COLORS.current return (
{era.title} {era.is_current && ( Now )}
{formatYear(era.starts_at)} {era.ends_at ? ` – ${formatYear(era.ends_at)}` : era.is_current ? ' – present' : ''}
{era.description && (

{era.description}

)} {(era.stats?.uploads_count ?? 0) > 0 && (
{era.stats.uploads_count} upload{era.stats.uploads_count !== 1 ? 's' : ''}
)}
) })}
) } // ── v2: Streaks ────────────────────────────────────────────────────────────── function StreakBadge({ label, value, active = false }) { if (!value) return null return (
{value}
{label}
) } function StreaksSection({ streaks }) { if (!streaks) return null const { current_monthly_upload_streak, best_monthly_upload_streak, current_active_year_streak, best_active_year_streak } = streaks const hasAny = current_monthly_upload_streak > 0 || best_monthly_upload_streak > 0 || best_active_year_streak > 0 if (!hasAny) return null return (
Creative Streaks
{current_monthly_upload_streak > 0 && ( )} {best_monthly_upload_streak > 0 && ( )} {current_active_year_streak > 0 && ( = 3} /> )} {best_active_year_streak > 0 && ( )}
) } // ── Yearly Productivity Chart ──────────────────────────────────────────────── const STATUS_BAR_COLOR = { breakout: { bar: 'bg-emerald-400', label: 'bg-emerald-400/12 text-emerald-200 border-emerald-400/20' }, steady: { bar: 'bg-sky-400', label: 'bg-sky-400/12 text-sky-200 border-sky-400/20' }, experimental: { bar: 'bg-violet-400', label: 'bg-violet-400/12 text-violet-200 border-violet-400/20' }, comeback: { bar: 'bg-amber-400', label: 'bg-amber-400/12 text-amber-200 border-amber-400/20' }, quiet: { bar: 'bg-slate-500', label: 'bg-slate-700/60 text-slate-400 border-slate-600/30' }, } function YearlyProductivityChart({ recaps }) { if (!recaps?.length) return null // Sort oldest → newest for the chart const sorted = [...recaps] .filter((r) => r.metrics?.year && r.metrics?.uploads_count != null) .sort((a, b) => (a.metrics.year ?? 0) - (b.metrics.year ?? 0)) if (!sorted.length) return null const maxUploads = Math.max(...sorted.map((r) => r.metrics.uploads_count), 1) return (
Productivity
Year-by-year upload activity
{Object.entries(STATUS_BAR_COLOR) .filter(([key]) => sorted.some((r) => (r.metrics?.year_status ?? 'steady') === key)) .map(([key, val]) => ( {key} ))}
{sorted.map((item) => { const uploads = item.metrics.uploads_count const pct = Math.max(uploads / maxUploads, uploads > 0 ? 0.018 : 0) const status = item.metrics?.year_status ?? 'steady' const colors = STATUS_BAR_COLOR[status] ?? STATUS_BAR_COLOR.steady const isBest = uploads === maxUploads return (
{/* Year label */}
{item.metrics.year}
{/* Bar */}
{/* Tooltip on hover */}
{uploads} upload{uploads !== 1 ? 's' : ''} {(item.metrics?.views ?? 0) > 0 ? ` · ${Number(item.metrics.views).toLocaleString()} views` : ''} {(item.metrics?.downloads ?? 0) > 0 ? ` · ${Number(item.metrics.downloads).toLocaleString()} dl` : ''}
{/* Upload count + badge */}
{uploads} {isBest && best} {(item.metrics?.featured_count ?? 0) > 0 && !isBest && ( {item.metrics.featured_count} )}
) })}
{/* Summary footer */}
{sorted.length} active years {sorted.reduce((s, r) => s + r.metrics.uploads_count, 0).toLocaleString()} total uploads {Number(sorted.reduce((s, r) => s + (r.metrics.views ?? 0), 0)).toLocaleString()} total views
) } // ── v2: Growth & Evolution ─────────────────────────────────────────────────── const RELATION_LABELS = { remake_of: 'Remake', remaster_of: 'Remaster', revision_of: 'Revision', inspired_by: 'Inspired by own work', variation_of: 'Variation', } function EvolutionSection({ evolution }) { if (!evolution?.length) return null return (
Growth & Evolution
Then & Now
{evolution.map((item) => (
{/* Original */}
Original
{item.target_artwork?.title}
{formatYear(item.target_artwork?.published_at)}
{/* Arrow + relation type */}
{RELATION_LABELS[item.relation_type] ?? item.relation_type} {item.years_between > 0 && ( {item.years_between}yr later )}
{/* New version */}
New version
{item.source_artwork?.title}
{formatYear(item.source_artwork?.published_at)}
))}
) } export default function CreatorJourneySection({ journey, username }) { const summary = journey?.summary ?? {} const highlights = Array.isArray(journey?.highlights) ? journey.highlights : [] const timeline = Array.isArray(journey?.timeline) ? journey.timeline.slice(0, 6) : [] const recaps = Array.isArray(journey?.yearly_recaps) ? journey.yearly_recaps.slice(0, 3) : [] const allRecaps = Array.isArray(journey?.yearly_recaps) ? journey.yearly_recaps : [] const eras = Array.isArray(journey?.eras) ? journey.eras : [] const evolution = Array.isArray(journey?.evolution) ? journey.evolution : [] const streaks = journey?.streaks ?? null const latestMilestone = summary.latest_milestone ?? null const available = !!summary.available if (!available) { return (
Creator Journey

A profile built as a story, not only a feed

) } return (
Creator Journey

A profile shaped by milestones, turning points, and yearly chapters.

{latestMilestone && (

Latest moment: {latestMilestone.title} {latestMilestone.headline ? ` - ${latestMilestone.headline}` : ''}

)}
{/* ── v2: Era strip ── */} {highlights.length > 0 && (
{highlights.map((item) => { const href = milestoneHref(item) return (
{(() => { const c = colorForType(item.type); return
})() }
{item.title}
{item.headline || item.value}
{item.value && (
{item.value}
)}
{item.summary && (

{item.summary}

)} {href && ( Open source moment )}
) })}
)}
Timeline
Important creator milestones
{timeline.map((item, index) => { const href = milestoneHref(item) return (
{index < timeline.length - 1 &&
}
{item.title}
{formatDate(item.occurred_at) && (
{formatDate(item.occurred_at)}
)}
{item.headline &&
{item.headline}
} {item.summary &&
{item.summary}
} {href && ( View linked work )}
) })}
Yearly recap
Recent chapters
{recaps.map((item) => { const status = item.metrics?.year_status const statusColors = { breakout: 'bg-emerald-400/12 text-emerald-200', steady: 'bg-sky-400/12 text-sky-200', experimental: 'bg-violet-400/12 text-violet-200', comeback: 'bg-amber-400/12 text-amber-200', quiet: 'bg-slate-700 text-slate-400', } return (
{item.value}
{status && ( {status} )}
{item.headline}

{item.summary}

{(item.metrics?.featured_count ?? 0) > 0 && ( )} {item.metrics?.top_category && ( )}
) })}
{/* ── v2: Streaks ── */} {/* ── Yearly productivity chart ── */} {/* ── v2: Growth & Evolution ── */}
) }