Files
wagtailcms-frontend/app/demo/[industry]/[[...path]]/page.tsx
T

64 lines
4.0 KiB
TypeScript

import Link from "next/link";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { ApiError } from "@/services/api-client";
import { getDemoPage, getIndustryDemos } from "@/services/demo.service";
import { BlockRenderer } from "@/blocks/BlockRenderer";
type Props = { params: Promise<{ industry: string; path?: string[] }> };
async function load(params: Props["params"]) {
const { industry, path } = await params;
try {
return await getDemoPage(industry, path);
} catch (error) {
if (error instanceof ApiError && error.status === 404) notFound();
throw error;
}
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const page = await load(params);
return { title: { absolute: `${page.title} | ${page.label}演示` }, robots: { index: false, follow: false } };
}
export default async function IndustryDemoPage({ params }: Props) {
const [page, demos, route] = await Promise.all([load(params), getIndustryDemos(), params]);
const base = `/demo/${page.industry}`;
const colors: Record<string, string> = {
software: "border-sky-500", manufacturing: "border-orange-500", consulting: "border-emerald-500",
education: "border-violet-500", healthcare: "border-teal-500", dining: "border-rose-500",
construction: "border-amber-500", "real-estate": "border-indigo-500", "home-renovation": "border-lime-500",
"agri-food": "border-green-500", "energy-environment": "border-cyan-500", "auto-services": "border-red-500",
"culture-media": "border-fuchsia-500", "sports-fitness": "border-blue-500", "pet-services": "border-yellow-500",
"legal-services": "border-slate-700", "finance-tax": "border-purple-500", "human-resources": "border-pink-500",
};
return (
<div className={`border-t-4 ${colors[page.industry] ?? "border-slate-500"}`}>
<aside className="border-b bg-amber-50 px-6 py-3 text-center text-sm text-amber-950">
虚构行业演示 · 不代表真实客户、资质或业绩 · 请勿提交真实个人或商业敏感信息
</aside>
<header className="border-b bg-white px-6 py-5">
<div className="mx-auto flex max-w-7xl flex-wrap items-center justify-between gap-4">
<Link href={base} className="text-xl font-bold">{page.company}</Link>
<nav aria-label="切换行业" className="flex flex-wrap gap-3 text-sm">
{demos.items.map((item) => <Link key={item.slug} href={item.url} aria-current={item.slug === page.industry ? "page" : undefined} className={item.slug === page.industry ? "font-bold underline" : "text-slate-600"}>{item.label}</Link>)}
<Link href="/demo" className="text-slate-500">全部模板</Link>
</nav>
</div>
<nav aria-label="行业导航" className="mx-auto mt-5 flex max-w-7xl flex-wrap gap-5 text-sm">
{page.navigation.map((item) => <Link key={item.url} href={item.url} className="text-slate-700 hover:underline">{item.title}</Link>)}
</nav>
</header>
{route.path?.length ? <div className="mx-auto max-w-7xl px-6 pt-10"><h1 className="text-3xl font-bold">{page.title}</h1>{page.intro && <p className="mt-4 text-slate-600">{page.intro}</p>}</div> : null}
{page.html && <div className="prose mx-auto max-w-3xl px-6 py-12" dangerouslySetInnerHTML={{ __html: page.html }} />}
<BlockRenderer blocks={page.blocks} />
{!!page.children.length && <div className="mx-auto grid max-w-7xl gap-5 px-6 py-12 md:grid-cols-2">{page.children.map((child) => <Link key={child.url} href={child.url} className="rounded-xl border border-slate-200 bg-white p-6 font-semibold hover:shadow-md">{child.title} →</Link>)}</div>}
<footer className="border-t bg-slate-50 px-6 py-8 text-center text-sm text-slate-600">
<p>{page.company} · 模板内容仅供演示</p>
<div className="mt-3 flex justify-center gap-6"><Link href={`${base}/privacy-policy`}>演示隐私说明</Link><Link href="/demo">切换模板</Link><Link href="/">返回当前官网</Link></div>
</footer>
</div>
);
}