feat(cms): add Cinematic Story Scroll and Apple Showcase blocks to Page Builder

This commit is contained in:
Your Name committed 2026-10-17 09:06:44 +07:00
1 parent 25cbe3549e
commit 8d9f2fc587
10 files changed
+971 -8

No files matched your search

@@ -16,6 +16,8 @@ import { Swiper, SwiperSlide } from 'swiper/react'
import { Autoplay, Pagination, Navigation } from 'swiper/modules'
import ScrollReveal from '../ScrollReveal'
import PageDivider from '../PageDivider'
import CinematicStoryScroll from '../CinematicStoryScroll'
import AppleWatchShowcase from '../AppleWatchShowcase'
import 'swiper/css'
import 'swiper/css/pagination'
import 'swiper/css/navigation'
@@ -2600,6 +2602,11 @@ export default function DynamicPageRenderer({ sections, categories, lang: langPr
'HERO_SPLIT_MINIMAL',
'HERO_VIDEO_MINIMAL',
'HERO_CAROUSEL',
'CINEMATIC_STORY_SCROLL',
'STORY_SCROLL',
'APPLE_SHOWCASE',
'APPLE_KEYNOTE_SHOWCASE',
'APPLE_WATCH_TOUR',
]), [])
const firstActiveSection = sections.find(s => s.isActive && s.type.toUpperCase() !== 'ANNOUNCEMENT_BAR' && s.type.toUpperCase() !== 'ANNOUNCEMENT_BAR_MINIMAL')
@@ -2831,6 +2838,96 @@ export default function DynamicPageRenderer({ sections, categories, lang: langPr
</ScrollReveal>
)
}
case 'CINEMATIC_STORY_SCROLL':
case 'STORY_SCROLL': {
const rawTheme = payload.storyTheme as string | undefined
const storyTheme = rawTheme === 'dark' ? 'dark' : 'light'
const storyHeroImage = (payload.storyHeroImage as string) || (payload.heroImage as string) || undefined
const storyScenes = Array.isArray(payload.storyScenes) ? (payload.storyScenes as any[]) : undefined
const endCtaTitle = (payload.endCtaTitle as string) || undefined
const endCtaButtonText = (payload.endCtaButtonText as string) || undefined
const endCtaLink = (payload.endCtaLink as string) || undefined
const targetProductId = Number(payload.productId) || 0
const foundProduct = targetProductId
? (categories.flatMap(c => (c as any).products || []) as Product[]).find(p => p.id === targetProductId)
: undefined
const mockProduct: Product = foundProduct || {
id: targetProductId || 1,
name: { en: 'Product Story', th: 'การนำเสนอผลิตภัณฑ์' },
description: { en: 'High Performance Story', th: 'การขับขี่สมรรถนะสูง' },
details: null,
price: 0,
brandId: 1,
categoryId: 1,
images: storyHeroImage ? [{ id: 1, url: storyHeroImage, order: 0 }] : [],
variants: [],
options: [
{
id: 1,
name: { en: 'Model', th: 'รุ่น' },
values: ['NVX155', 'LC135', 'Vario125', 'Vario150', 'PCX150', 'Beat110', 'Wave110-I', 'R15'] as any
}
] as any,
category: { id: 1, name: 'Braking' } as any,
brand: { id: 1, name: 'Brand Story' } as any,
}
return (
<div key={section.id} className="w-full">
<CinematicStoryScroll
product={mockProduct}
heroImage={storyHeroImage}
scenes={storyScenes}
lang={lang}
endCtaTitle={endCtaTitle}
endCtaButtonText={endCtaButtonText}
endCtaLink={endCtaLink}
storyTheme={storyTheme}
/>
</div>
)
}
case 'APPLE_SHOWCASE':
case 'APPLE_KEYNOTE_SHOWCASE':
case 'APPLE_WATCH_TOUR': {
const storyHeroImage = (payload.heroImage as string) || (payload.storyHeroImage as string) || undefined
const targetProductId = Number(payload.productId) || 0
const foundProduct = targetProductId
? (categories.flatMap(c => (c as any).products || []) as Product[]).find(p => p.id === targetProductId)
: undefined
const mockProduct: Product = foundProduct || {
id: targetProductId || 1,
name: { en: 'Keynote Showcase', th: 'การนำเสนอผลิตภัณฑ์' },
description: { en: 'Next-Gen Performance', th: 'นวัตกรรมมาตรฐานระดับโลก' },
details: null,
price: 0,
brandId: 1,
categoryId: 1,
images: storyHeroImage ? [{ id: 1, url: storyHeroImage, order: 0 }] : [],
variants: [],
category: { id: 1, name: 'Technology' } as any,
brand: { id: 1, name: 'Keynote' } as any,
}
return (
<div key={section.id} className="w-full">
<AppleWatchShowcase
product={mockProduct}
heroImage={storyHeroImage}
lang={lang}
endCtaTitle={payload.endCtaTitle as string | undefined}
endCtaButtonText={payload.endCtaButtonText as string | undefined}
endCtaLink={payload.endCtaLink as string | undefined}
/>
</div>
)
}
default:
if (process.env.NODE_ENV !== 'production') {
console.warn(`[DynamicPageRenderer] Unsupported section type: ${section.type}`)