feat: scaffold headless frontend integration per design doc
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import type { ComponentType } from "react";
|
||||
import Hero from "./hero/Hero";
|
||||
import Stats from "./stats/Stats";
|
||||
import FeatureGrid from "./feature-grid/FeatureGrid";
|
||||
import FAQ from "./faq/FAQ";
|
||||
import CTA from "./cta/CTA";
|
||||
import LogoCloud from "./logo-cloud/LogoCloud";
|
||||
import type { StreamFieldBlock } from "@/types/wagtail";
|
||||
|
||||
/**
|
||||
* StreamField type → 组件映射表。
|
||||
* 必须与后端 apps/core/blocks.py 的 COMMON_BLOCKS 保持一致,
|
||||
* 否则新增/重命名 Block 时前后端会出现字段不对齐问题
|
||||
* (详见 documents/设计方案分析与完善版.md §2.6)。
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const components: Record<string, ComponentType<{ value: any }>> = {
|
||||
hero: Hero,
|
||||
stats: Stats,
|
||||
feature_grid: FeatureGrid,
|
||||
faq: FAQ,
|
||||
cta: CTA,
|
||||
logo_cloud: LogoCloud,
|
||||
};
|
||||
|
||||
export function BlockRenderer({ blocks }: { blocks: StreamFieldBlock[] }) {
|
||||
return (
|
||||
<>
|
||||
{blocks?.map((block) => {
|
||||
if (block.type === "richtext") {
|
||||
return (
|
||||
<div
|
||||
key={block.id}
|
||||
className="prose mx-auto max-w-3xl px-6 py-12"
|
||||
dangerouslySetInnerHTML={{ __html: block.value }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const Component = components[block.type];
|
||||
if (!Component) {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.warn(`未找到 Block 类型 "${block.type}" 对应的前端组件`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return <Component key={block.id} value={block.value} />;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user