78 lines
3.0 KiB
TypeScript
78 lines
3.0 KiB
TypeScript
import { notFound } from "next/navigation";
|
|
import { AppMetaInfo, ChangelogTimeline, DownloadButtons, QRCodeSection, VersionHistory } from "@/components/app-detail";
|
|
import { AppGrid, UnlockSection } from "@/components/sections";
|
|
import { ScrollReveal } from "@/components/scroll-reveal";
|
|
import { DetailScrollShowcase } from "@/components/detail-scroll-showcase";
|
|
import { getAppBySlug, getApps } from "@/services/apps.service";
|
|
import { ScreenshotGallery } from "@/components/screenshot-gallery";
|
|
import { AccessGate } from "@/components/access-gate";
|
|
|
|
export default async function AppDetailPage({ params }: { params: Promise<{ slug: string }> }) {
|
|
const { slug } = await params;
|
|
const app = await getAppBySlug(slug);
|
|
if (!app) return notFound();
|
|
|
|
const appResources = await getApps();
|
|
const related = appResources.filter((i) => i.slug !== slug).slice(0, 3);
|
|
return (
|
|
<div className="space-y-6 py-8">
|
|
<ScrollReveal>
|
|
<section className="card-glass relative overflow-hidden">
|
|
<div className="pointer-events-none absolute -right-8 -top-8 h-36 w-36 rounded-full bg-cyan-300/20 blur-3xl" />
|
|
<div className="flex items-center gap-4">
|
|
<div className="text-4xl">{app.icon}</div>
|
|
<div>
|
|
<h1 className="text-3xl font-bold">{app.name}</h1>
|
|
<p className="text-slate-300">{app.subtitle}</p>
|
|
</div>
|
|
</div>
|
|
<div className="mt-3 flex flex-wrap gap-2">
|
|
{app.tags.map((t) => <span key={t} className="pill">{t}</span>)}
|
|
</div>
|
|
</section>
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.03}>
|
|
<AppMetaInfo app={app} />
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.06}>
|
|
<AccessGate slug={app.slug}>
|
|
<DownloadButtons app={app} />
|
|
</AccessGate>
|
|
</ScrollReveal>
|
|
<DetailScrollShowcase name={app.name} />
|
|
<ScrollReveal delay={0.08}>
|
|
<VersionHistory app={app} />
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.1}>
|
|
<ChangelogTimeline app={app} />
|
|
</ScrollReveal>
|
|
|
|
<ScrollReveal delay={0.12}>
|
|
<section className="card-glass">
|
|
<h3 className="text-lg font-semibold">软件介绍</h3>
|
|
<p className="mt-2 text-sm text-slate-300">{app.description}</p>
|
|
<h4 className="mt-4 font-medium">使用说明</h4>
|
|
<ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-slate-300">
|
|
{app.usage.map((u) => <li key={u}>{u}</li>)}
|
|
</ul>
|
|
</section>
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.14}>
|
|
<ScreenshotGallery slug={app.slug} shots={app.screenshots} />
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.16}>
|
|
<QRCodeSection />
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.18}>
|
|
<UnlockSection />
|
|
</ScrollReveal>
|
|
<ScrollReveal delay={0.2}>
|
|
<section className="space-y-3">
|
|
<h3 className="text-lg font-semibold">相关推荐</h3>
|
|
<AppGrid apps={related} />
|
|
</section>
|
|
</ScrollReveal>
|
|
</div>
|
|
);
|
|
}
|