playreel/frontend/app/(ado2)/archive/[slug]/page.tsx
2026-09-08 15:00:42 +09:00

97 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import DisabledNotice from "@/components/disabled-notice";
import { FEATURES } from "@/lib/features";
import { use, useEffect, useState } from "react";
import Link from "next/link";
import MetadataCard from "@/components/metadata-card";
import { InternalOnlyWarning, LicenseBadge } from "@/components/license-badge";
import { apiFetch, archiveKind, type ArchiveEntry } from "@/lib/api";
function ArchiveDetailPageInner({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = use(params);
const [entry, setEntry] = useState<ArchiveEntry | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
apiFetch<ArchiveEntry>(`/api/archive/${slug}`).then(setEntry).catch((e) => setError(e.message));
}, [slug]);
if (error) return <p style={{ color: "rgb(255,122,122)" }}>{error}</p>;
if (!entry) return <p style={{ color: "var(--text-teal-1)" }}>불러오는 중…</p>;
return (
<div>
<div style={{ display: "flex", alignItems: "flex-start", marginBottom: "1rem" }}>
<Link href="/archive" className="btn-back">‹ 아카이브</Link>
</div>
<span className="tag" style={{ height: 20, padding: "0 8px", fontSize: "var(--text-xs)" }}>{archiveKind(entry)}</span>
<h1 className="page-title" style={{ textAlign: "left", margin: "0.5rem 0 1.5rem" }}>
{entry.metadata?.event_name ?? entry.name}
</h1>
<div className="archive-detail">
<div className="card" style={{ padding: "var(--s-4)" }}>
{entry.video_url ? (
<video src={entry.video_url} controls style={{ width: "100%", borderRadius: "var(--r-sm)", display: "block" }} />
) : (
// eslint-disable-next-line @next/next/no-img-element
<img src={entry.poster_url} alt={entry.name} style={{ width: "100%", borderRadius: "var(--r-sm)" }} />
)}
{entry.video_url && (
<div style={{ display: "flex", justifyContent: "center", marginTop: "var(--s-3)" }}>
<a href={entry.video_url} download className="btn-tonal-mint">MP4 다운로드</a>
</div>
)}
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "var(--s-5)" }}>
{entry.metadata && <MetadataCard meta={entry.metadata} />}
{entry.narration && (
<div className="card" style={{ padding: "var(--s-5)" }}>
<p className="eyebrow" style={{ margin: "0 0 var(--s-3)" }}>
나레이션
</p>
<ol style={{ margin: 0, paddingLeft: 18, fontSize: 15, lineHeight: 2 }}>
{entry.narration.map((s, i) => <li key={i}>{s}</li>)}
</ol>
</div>
)}
{entry.f2_variants.length > 0 && (
<div>
<p className="eyebrow" style={{ margin: "0 0 var(--s-3)" }}>
스타일 변형
</p>
{entry.f2_variants.some((v) => v.license === "internal-only") && (
<InternalOnlyWarning />
)}
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(140px, 1fr))", gap: "var(--s-3)", marginTop: "var(--s-3)" }}>
{entry.f2_variants.map((v) => (
<div key={v.template_id} className="card" style={{ overflow: "hidden" }}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={v.image_url} alt={v.name_ko ?? v.template_id} style={{ width: "100%", display: "block" }} />
<div style={{ padding: "var(--s-2)", display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
<p style={{ margin: 0, fontSize: 12, fontWeight: 600, color: "var(--text-teal-1)", textAlign: "center" }}>
{v.name_ko ?? v.template_id}
</p>
<LicenseBadge license={v.license ?? "internal-only"} />
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
);
}
export default function ArchiveDetailPage(props: Parameters<typeof ArchiveDetailPageInner>[0]) {
if (!FEATURES.archive) return <DisabledNotice title="아카이브" backHref="/" />;
return <ArchiveDetailPageInner {...props} />;
}