SectionRenderer.tsx93 lines · main
1import { cn } from 'ui'
2
3import type { GoSection } from '../schemas'
4import CodeBlockSection from './CodeBlockSection'
5import FaqSection from './FaqSection'
6import FeatureGridSection from './FeatureGridSection'
7import FormSection from './FormSection'
8import HubSpotMeetingSection from './HubSpotMeetingSection'
9import MetricsSection from './MetricsSection'
10import QuoteSection from './QuoteSection'
11import SingleColumnSection from './SingleColumnSection'
12import StepsSection from './StepsSection'
13import ThreeColumnSection from './ThreeColumnSection'
14import TwoColumnSection from './TwoColumnSection'
15
16export type CustomSectionRenderers = {
17 [K in GoSection['type']]?: React.ComponentType<{
18 section: Extract<GoSection, { type: K }>
19 }>
20}
21
22interface SectionRendererProps {
23 section: GoSection
24 customRenderers?: CustomSectionRenderers
25}
26
27export default function SectionRenderer({ section, customRenderers }: SectionRendererProps) {
28 // Check for a custom renderer first
29 const CustomRenderer = customRenderers?.[section.type] as
30 | React.ComponentType<{ section: typeof section }>
31 | undefined
32
33 let content: React.ReactNode = null
34
35 if (CustomRenderer) {
36 content = <CustomRenderer section={section} />
37 } else {
38 switch (section.type) {
39 case 'single-column':
40 content = <SingleColumnSection section={section} />
41 break
42 case 'two-column':
43 content = <TwoColumnSection section={section} />
44 break
45 case 'three-column':
46 content = <ThreeColumnSection section={section} />
47 break
48 case 'form':
49 content = <FormSection section={section} />
50 break
51 case 'feature-grid':
52 content = <FeatureGridSection section={section} />
53 break
54 case 'metrics':
55 content = <MetricsSection section={section} />
56 break
57 case 'tweets':
58 // Tweets requires app-specific dependencies — must be provided via customRenderers
59 break
60 case 'faq':
61 content = <FaqSection section={section} />
62 break
63 case 'code-block':
64 content = <CodeBlockSection section={section} />
65 break
66 case 'steps':
67 content = <StepsSection section={section} />
68 break
69 case 'quote':
70 content = <QuoteSection section={section} />
71 break
72 case 'hubspot-meeting':
73 content = <HubSpotMeetingSection section={section} />
74 break
75 default: {
76 const _exhaustive: never = section
77 break
78 }
79 }
80 }
81
82 if (!content) return null
83
84 if (section.id || section.className) {
85 return (
86 <div id={section.id} className={cn(section.className)}>
87 {content}
88 </div>
89 )
90 }
91
92 return content
93}