101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import Hero from "@/components/Hero";
|
|
import MatchupHUD from "@/components/MatchupHUD";
|
|
import Arena from "@/components/Arena";
|
|
import Footer from "@/components/Footer";
|
|
import { GROUP_A } from "@/lib/schedule";
|
|
import { getPredictions, getCrowd, matchUrl } from "@/lib/mockData";
|
|
import { parseLang, dict, teamShort } from "@/lib/i18n";
|
|
|
|
// L2. 경기 상세(대결) 페이지 — 6경기 정적 생성
|
|
export function generateStaticParams() {
|
|
return GROUP_A.map((m) => ({ matchId: m.matchId }));
|
|
}
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ matchId: string }>;
|
|
}): Promise<Metadata> {
|
|
const { matchId } = await params;
|
|
const match = GROUP_A.find((m) => m.matchId === matchId);
|
|
if (!match) return { title: "TriplePick 2026" };
|
|
const title = `${match.teamA.shortName} vs ${match.teamB.shortName} AI 승부예측 | TriplePick`;
|
|
const desc = `GPT·Claude·Gemini가 ${match.teamA.name} vs ${match.teamB.name}를 서로 다르게 예측했습니다. 당신의 픽을 찍고 AI와 겨뤄보세요.`;
|
|
return {
|
|
title,
|
|
description: desc,
|
|
openGraph: { title, description: desc, siteName: "TriplePick", type: "website", locale: "ko_KR" },
|
|
twitter: { card: "summary_large_image", title, description: desc },
|
|
};
|
|
}
|
|
|
|
export default async function MatchPage({
|
|
params,
|
|
searchParams,
|
|
}: {
|
|
params: Promise<{ matchId: string }>;
|
|
searchParams: Promise<{ lang?: string }>;
|
|
}) {
|
|
const { matchId } = await params;
|
|
const { lang: langParam } = await searchParams;
|
|
const lang = parseLang(langParam);
|
|
const t = dict(lang);
|
|
|
|
const match = GROUP_A.find((m) => m.matchId === matchId);
|
|
if (!match) notFound();
|
|
|
|
const predictions = getPredictions(match, lang);
|
|
const crowd = getCrowd(match);
|
|
const aShort = teamShort(match.teamA, lang);
|
|
const bShort = teamShort(match.teamB, lang);
|
|
const hook = lang === "en" ? t.hook(aShort, bShort) : match.hookText;
|
|
|
|
return (
|
|
<main className="shell">
|
|
<Hero
|
|
back
|
|
lang={lang}
|
|
share={{
|
|
url: matchUrl(match.matchId),
|
|
title: `${aShort} vs ${bShort} — TriplePick`,
|
|
text:
|
|
lang === "en"
|
|
? `${hook} — see all 3 AI picks and make yours!`
|
|
: `${hook} — AI 셋의 예측을 보고 당신의 픽을 찍어보세요!`,
|
|
}}
|
|
/>
|
|
|
|
{/* 경기별 후킹 카피 (한 줄) */}
|
|
<h1 className="mt-6 flex items-center justify-center gap-2 whitespace-nowrap text-[19px] font-extrabold leading-snug">
|
|
<span className="text-[var(--green)]">⫽</span>
|
|
{hook}
|
|
<span className="text-[var(--green)]">⫽</span>
|
|
</h1>
|
|
|
|
<MatchupHUD match={match} lang={lang} />
|
|
<Arena
|
|
match={match}
|
|
predictions={predictions}
|
|
crowd={crowd}
|
|
shareUrl={matchUrl(match.matchId)}
|
|
lang={lang}
|
|
/>
|
|
|
|
{/* 하단 CTA — 전체 일정으로(다른 경기 투표). ADO2 사용해보기 버튼과 동일 사양(퍼플 #A65EFF) */}
|
|
<Link
|
|
href={lang === "en" ? "/?lang=en" : "/"}
|
|
className="mt-7 flex items-center justify-center gap-1.5 rounded-full bg-[#A65EFF] px-6 py-3 text-[15px] font-extrabold text-white transition active:scale-[0.99]"
|
|
style={{ boxShadow: "0 10px 28px rgba(166,94,255,0.40)" }}
|
|
>
|
|
{t.moreMatches}
|
|
<span aria-hidden>→</span>
|
|
</Link>
|
|
|
|
<Footer lang={lang} />
|
|
</main>
|
|
);
|
|
}
|