's'
This commit is contained in:
126
app/day/[id]/page.tsx
Normal file
126
app/day/[id]/page.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { getDayData, daysData } from "../../data/days";
|
||||
import DayContent from "../../components/DayContent";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return daysData.map((d) => ({ id: String(d.day) }));
|
||||
}
|
||||
|
||||
export default async function DayPage({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
const dayId = parseInt(id, 10);
|
||||
const data = getDayData(dayId);
|
||||
|
||||
if (!data) return notFound();
|
||||
|
||||
const prevDay = getDayData(dayId - 1);
|
||||
const nextDay = getDayData(dayId + 1);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Top bar */}
|
||||
<header className="sticky top-0 z-50 border-b border-slate-100 bg-white/80 backdrop-blur-lg">
|
||||
<div className="mx-auto flex h-14 max-w-4xl items-center justify-between px-4 sm:px-6">
|
||||
<a
|
||||
href="/"
|
||||
className="flex items-center gap-1.5 text-sm font-medium text-slate-600 transition-colors hover:text-sky-600"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
返回首页
|
||||
</a>
|
||||
<span className="text-sm text-slate-400">
|
||||
Day {data.day} / 7
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Article header */}
|
||||
<div className="mx-auto max-w-4xl px-4 pt-10 pb-6 sm:px-6 sm:pt-16 sm:pb-10">
|
||||
<div className="mb-6 flex flex-wrap items-center gap-3 text-sm text-slate-500">
|
||||
<span className="rounded-full bg-slate-100 px-3 py-1 font-medium">
|
||||
阅读时间{data.readingTime}
|
||||
</span>
|
||||
<span className="rounded-full bg-sky-50 px-3 py-1 font-medium text-sky-600">
|
||||
第 {data.day} 天
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-sky-500 to-cyan-500 text-3xl text-white shadow-lg shadow-sky-500/20 sm:h-20 sm:w-20 sm:text-4xl">
|
||||
{data.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-extrabold tracking-tight text-slate-900 sm:text-4xl lg:text-5xl">
|
||||
{data.title}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto max-w-4xl px-4 sm:px-6">
|
||||
<hr className="border-slate-100" />
|
||||
</div>
|
||||
|
||||
{/* Markdown body */}
|
||||
<article className="mx-auto max-w-4xl px-4 py-10 sm:px-6 sm:py-14">
|
||||
<DayContent content={data.content} />
|
||||
</article>
|
||||
|
||||
{/* Prev / Next navigation */}
|
||||
<nav className="mx-auto max-w-4xl px-4 pb-20 sm:px-6">
|
||||
<div className="flex flex-col gap-4 border-t border-slate-100 pt-8 sm:flex-row sm:justify-between">
|
||||
{prevDay ? (
|
||||
<a
|
||||
href={`/day/${prevDay.day}`}
|
||||
className="group flex items-center gap-3 rounded-xl border border-slate-100 px-5 py-4 transition-all hover:border-sky-200 hover:bg-sky-50/50 sm:flex-1"
|
||||
>
|
||||
<svg className="h-5 w-5 shrink-0 text-slate-400 transition-colors group-hover:text-sky-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<div>
|
||||
<div className="text-xs text-slate-400">上一天</div>
|
||||
<div className="text-sm font-semibold text-slate-700 group-hover:text-sky-700">
|
||||
Day {prevDay.day}: {prevDay.title}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
) : (
|
||||
<div className="sm:flex-1" />
|
||||
)}
|
||||
{nextDay ? (
|
||||
<a
|
||||
href={`/day/${nextDay.day}`}
|
||||
className="group flex items-center justify-end gap-3 rounded-xl border border-slate-100 px-5 py-4 text-right transition-all hover:border-sky-200 hover:bg-sky-50/50 sm:flex-1"
|
||||
>
|
||||
<div>
|
||||
<div className="text-xs text-slate-400">下一天</div>
|
||||
<div className="text-sm font-semibold text-slate-700 group-hover:text-sky-700">
|
||||
Day {nextDay.day}: {nextDay.title}
|
||||
</div>
|
||||
</div>
|
||||
<svg className="h-5 w-5 shrink-0 text-slate-400 transition-colors group-hover:text-sky-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
) : (
|
||||
<div className="sm:flex-1" />
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t border-slate-100 bg-slate-50 py-8 text-center text-sm text-slate-400">
|
||||
<a href="/" className="font-medium text-slate-600 transition-colors hover:text-sky-600">
|
||||
🌍 数字游民指南
|
||||
</a>
|
||||
<span className="mx-2">·</span>
|
||||
开源免费 · 社区驱动
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user