refactor(nextjs): Default layout field validation before rendering

This commit is contained in:
shiva raj badu 2025-07-23 22:46:22 +05:45
parent 5584b880b1
commit 817abf9b2e
No known key found for this signature in database
16 changed files with 186 additions and 198 deletions

View file

@ -36,6 +36,7 @@ export const useGroupLayouts = () => {
// Render slide content with group validation, automatic Tiptap text editing, and editable images/icons
const renderSlideContent = useMemo(() => {
return (slide: any, isEditMode: boolean) => {
console.time("renderSlideContent");
const Layout = getGroupLayout(slide.layout, slide.layout_group);
if (!Layout) {
return (
@ -75,8 +76,10 @@ export const useGroupLayouts = () => {
</EditableLayoutWrapper>
);
}
console.timeEnd("renderSlideContent");
return <Layout data={slide.content} />;
};
}, [getGroupLayout, dispatch]);
return {

View file

@ -162,15 +162,15 @@ const Header = ({
{/* Desktop Export Button with Popover */}
<div className="hidden lg:block">
<Popover open={open} onOpenChange={setOpen}>
<div className="hidden lg:block relative z-10">
<Popover open={open} onOpenChange={setOpen} >
<PopoverTrigger asChild>
<Button className={`border py-5 text-[#5146E5] font-bold rounded-[32px] transition-all duration-500 hover:border hover:bg-[#5146E5] hover:text-white w-full ${mobile ? "" : "bg-white"}`}>
<SquareArrowOutUpRight className="w-4 h-4 mr-1" />
Export
</Button>
</PopoverTrigger>
<PopoverContent align="end" className="w-[250px] space-y-2 py-3 px-2">
<PopoverContent align="end" className="w-[250px] space-y-2 py-3 px-2 z-50">
<ExportOptions mobile={false} />
</PopoverContent>
</Popover>
@ -186,7 +186,7 @@ const Header = ({
return (
<div style={{
zIndex: 1000,
}} className="bg-[#5146E5] w-full shadow-lg sticky top-0 z-50">
}} className="bg-[#5146E5] w-full shadow-lg sticky top-0">
<OverlayLoader
show={false}
text="Exporting presentation..."

View file

@ -66,8 +66,6 @@ const PresentationPage: React.FC<PresentationPageProps> = ({ presentation_id })
);
const onSlideChange = (newSlide: number) => {
handleSlideChange(newSlide, presentationData);
};

View file

@ -108,17 +108,12 @@ export const Schema = type10SlideSchema
export type Type10SlideData = z.infer<typeof type10SlideSchema>
interface Type10SlideLayoutProps {
data?: Partial<Type10SlideData>
data: Partial<Type10SlideData>
}
const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }) => {
const chartData = slideData?.data || [];
const chartType = slideData?.chartType || 'line';
const color = slideData?.color || '#3b82f6';
const dataKey = slideData?.dataKey || 'value';
const categoryKey = slideData?.categoryKey || 'name';
const showLegend = slideData?.showLegend || false;
const showTooltip = slideData?.showTooltip || true;
const { title, items, chartData, chartType = 'line', color = '#3b82f6', dataKey = 'value', categoryKey = 'name', showLegend = false, showTooltip = true } = slideData;
const renderChart = () => {
const commonProps = {
data: chartData,
@ -188,7 +183,7 @@ const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }
dataKey={dataKey}
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
>
{chartData.map((entry, index) => (
{chartData.map((entry: any, index: number) => (
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
))}
</Pie>
@ -219,9 +214,9 @@ const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }
>
<div className='w-full flex flex-col items-start justify-start'>
<h1 className="text-2xl text-start sm:text-3xl lg:text-4xl xl:text-5xl font-bold text-gray-900 leading-tight mb-4 lg:mb-8">
{slideData?.title || 'Chart Analysis'}
</h1>
{title && <h1 className="text-2xl text-start sm:text-3xl lg:text-4xl xl:text-5xl font-bold text-gray-900 leading-tight mb-4 lg:mb-8">
{title || 'Chart Analysis'}
</h1>}
</div>
<div className={`flex gap-6 w-full items-center `}>
@ -234,7 +229,7 @@ const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }
</div>
<div className="lg:w-1/2 relative">
<div className="space-y-3 lg:space-y-6">
{slideData?.items?.map((item, index) => (
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -245,20 +240,20 @@ const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }
<div className="flex gap-6">
<div className="w-[48px] h-[48px]">
<div className="w-full h-full bg-blue-600 rounded-lg flex items-center justify-center overflow-hidden">
<img
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
className="w-full h-full object-cover"
/>
/>}
</div>
</div>
<div className="w-[calc(100%-55px)] space-y-1">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
</div>

View file

@ -26,10 +26,11 @@ export const Schema = type1SlideSchema
export type Type1SlideData = z.infer<typeof type1SlideSchema>
interface Type1SlideLayoutProps {
data?: Partial<Type1SlideData>
data: Partial<Type1SlideData>
}
const Type1SlideLayout: React.FC<Type1SlideLayoutProps> = ({ data: slideData }) => {
const { title, description, image } = slideData;
return (
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] max-h-[720px] flex items-center aspect-video bg-white relative z-20 mx-auto"
@ -38,23 +39,23 @@ const Type1SlideLayout: React.FC<Type1SlideLayoutProps> = ({ data: slideData })
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3 sm:gap-8 md:gap-12 lg:gap-16 w-full">
<div className="flex flex-col w-full items-start justify-center space-y-1 md:space-y-2 lg:space-y-6">
{/* Title */}
<h1 className=" text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || ' This is the title of slide'}
</h1>
{title && <h1 className=" text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
{/* Description */}
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{slideData?.description || 'This is a test of the hot reload system! If you can see this text, hot reload is working perfectly. Changes should appear instantly without page refresh.'}
</p>
{description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{description}
</p>}
</div>
{/* Image */}
<div className="w-full max-h-[600px]">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
{image && <img
src={image?.__image_url__ || ''}
alt={image?.__image_prompt__ || title || ''}
className="w-full max-h-full object-cover rounded-lg shadow-md"
/>
/>}
</div>
</div>
</div>

View file

@ -39,18 +39,18 @@ export const Schema = type2NumberedSlideSchema
export type Type2NumberedSlideData = z.infer<typeof type2NumberedSlideSchema>
interface Type2NumberedSlideLayoutProps {
data?: Partial<Type2NumberedSlideData>
data: Partial<Type2NumberedSlideData>
}
const Type2NumberedSlideLayout: React.FC<Type2NumberedSlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const isGridLayout = items.length >= 4
const { title, items } = slideData;
const isGridLayout = items?.length && items?.length >= 4
const numberTranslations: string[] = ['01', '02', '03', '04', '05', '06']
const renderGridContent = () => {
return (
<div className="grid grid-cols-1 bg-white lg:grid-cols-2 relative gap-4 lg:gap-8 mt-4 lg:mt-12">
{items.map((item, index) => (
{items?.map((item, index) => (
<div
key={index}
style={{
@ -63,12 +63,12 @@ const Type2NumberedSlideLayout: React.FC<Type2NumberedSlideLayoutProps> = ({ dat
{numberTranslations[index] || `0${index + 1}`}
</div>
<div className="space-y-2">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
</div>
@ -80,7 +80,7 @@ const Type2NumberedSlideLayout: React.FC<Type2NumberedSlideLayoutProps> = ({ dat
const renderHorizontalContent = () => {
return (
<div className="flex flex-col lg:flex-row bg-white mt-4 lg:mt-12 w-full relative gap-4 lg:gap-8">
{items.map((item, index) => (
{items?.map((item, index) => (
<div
key={index}
style={{
@ -92,12 +92,12 @@ const Type2NumberedSlideLayout: React.FC<Type2NumberedSlideLayoutProps> = ({ dat
{numberTranslations[index] || `0${index + 1}`}
</div>
<div className="space-y-2 lg:space-y-4">
<h3 className=" text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className=" text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className=" text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className=" text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -111,9 +111,9 @@ const Type2NumberedSlideLayout: React.FC<Type2NumberedSlideLayoutProps> = ({ dat
>
<div className="text-center lg:pb-8 w-full">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Main Title'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
</div>
{isGridLayout ? renderGridContent() : renderHorizontalContent()}

View file

@ -39,29 +39,29 @@ export const Schema = type2SlideSchema
export type Type2SlideData = z.infer<typeof type2SlideSchema>
interface Type2SlideLayoutProps {
data?: Partial<Type2SlideData>
data: Partial<Type2SlideData>
}
const Type2SlideLayout: React.FC<Type2SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const isGridLayout = items.length >= 4
const { title, items } = slideData;
const isGridLayout = items?.length && items?.length >= 4
const renderGridContent = () => {
return (
<div className="grid grid-cols-1 lg:grid-cols-2 relative gap-6 md:gap-12 mt-4 lg:mt-12">
{items.map((item, index) => (
{items?.map((item, index) => (
<div key={index} className="w-full relative p-3 lg:p-6 rounded-md"
style={{
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
}}
>
<div className="space-y-2">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -72,19 +72,19 @@ const Type2SlideLayout: React.FC<Type2SlideLayoutProps> = ({ data: slideData })
const renderHorizontalContent = () => {
return (
<div className="flex flex-col lg:flex-row mt-4 lg:mt-12 w-full relative gap-12">
{items.map((item, index) => (
{items?.map((item, index) => (
<div key={index} className="w-full relative p-3 lg:p-6 rounded-md"
style={{
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
}}
>
<div className="space-y-2 lg:space-y-4">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -98,9 +98,9 @@ const Type2SlideLayout: React.FC<Type2SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center lg:pb-8 w-full">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Main Title'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
</div>
{isGridLayout ? renderGridContent() : renderHorizontalContent()}

View file

@ -39,12 +39,11 @@ export const Schema = type2TimelineSlideSchema
export type Type2TimelineSlideData = z.infer<typeof type2TimelineSlideSchema>
interface Type2TimelineSlideLayoutProps {
data?: Partial<Type2TimelineSlideData>
data: Partial<Type2TimelineSlideData>
}
const Type2TimelineSlideLayout: React.FC<Type2TimelineSlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const numberTranslations: string[] = ['01', '02', '03', '04', '05', '06']
const { title, items } = slideData;
const renderTimelineContent = () => {
return (
@ -55,27 +54,27 @@ const Type2TimelineSlideLayout: React.FC<Type2TimelineSlideLayoutProps> = ({ dat
<div className="absolute z-10 top-1/2 w-[87%] left-1/2 -translate-x-1/2 h-[2px] bg-blue-600" />
{/* Timeline Numbers */}
{items.map((_, index) => (
{items && items.map((_, index) => (
<div
key={`timeline-${index}`}
className="relative z-10 w-12 h-12 rounded-full bg-blue-600 px-1 text-white flex items-center justify-center font-bold text-lg"
>
<span>{numberTranslations[index] || `0${index + 1}`}</span>
<span> `0${index + 1}`</span>
</div>
))}
</div>
{/* Timeline Content */}
<div className="flex justify-between gap-8">
{items.map((item, index) => (
{items && items.map((item, index) => (
<div key={index} className="flex-1 text-center relative">
<div className="space-y-4">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -89,9 +88,9 @@ const Type2TimelineSlideLayout: React.FC<Type2TimelineSlideLayoutProps> = ({ dat
className=" rounded-sm max-w-[1280px] w-full shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] flex flex-col items-center justify-center max-h-[720px] aspect-video bg-white relative z-20 mx-auto"
>
<div className="text-center lg:pb-8 w-full">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Main Title'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
</div>
{renderTimelineContent()}

View file

@ -55,11 +55,11 @@ export const Schema = type3SlideSchema
export type Type3SlideData = z.infer<typeof type3SlideSchema>
interface Type3SlideLayoutProps {
data?: Partial<Type3SlideData>
data: Partial<Type3SlideData>
}
const Type3SlideLayout: React.FC<Type3SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const { title, items } = slideData;
const getGridCols = (length: number) => {
switch (length) {
@ -77,13 +77,13 @@ const Type3SlideLayout: React.FC<Type3SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center mb-4 lg:mb-16 w-full">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Featured Content'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
</div>
<div className={`grid grid-cols-1 lg:grid-cols-2 ${getGridCols(items.length)} gap-3 lg:gap-6 w-full`}>
{items.map((item, index) => (
<div className={`grid grid-cols-1 lg:grid-cols-2 ${getGridCols(items?.length || 0)} gap-3 lg:gap-6 w-full`}>
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -102,12 +102,12 @@ const Type3SlideLayout: React.FC<Type3SlideLayoutProps> = ({ data: slideData })
{/* Content */}
<div className="space-y-2 p-3 lg:p-6">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
))}

View file

@ -1,6 +1,6 @@
import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart';
import React from 'react'
import { BarChart, Bar, LineChart, Line, PieChart, Pie, AreaChart, Area, ScatterChart, Scatter, XAxis, YAxis, CartesianGrid, Cell, ResponsiveContainer } from "recharts";
import { BarChart, Bar, LineChart, Line, PieChart, Pie, AreaChart, Area, ScatterChart, Scatter, XAxis, YAxis, CartesianGrid, Cell } from "recharts";
import * as z from "zod";
export const layoutId = 'type4-slide'
@ -77,17 +77,14 @@ export const Schema = type4SlideSchema
export type Type4SlideData = z.infer<typeof type4SlideSchema>
interface Type4SlideLayoutProps {
data?: Partial<Type4SlideData>
data: Partial<Type4SlideData>
}
const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData }) => {
const chartData = slideData?.data || [];
const chartType = slideData?.chartType || 'line';
const color = slideData?.color || '#3b82f6';
const dataKey = slideData?.dataKey || 'value';
const categoryKey = slideData?.categoryKey || 'name';
const showLegend = slideData?.showLegend || false;
const showTooltip = slideData?.showTooltip || true;
const { title, description, data, dataKey, categoryKey, color, showLegend = false, showTooltip = true, chartType = 'bar' } = slideData;
const chartData = data || [];
const renderChart = () => {
const commonProps = {
data: chartData,
@ -103,7 +100,7 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
<YAxis />
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
<Bar dataKey={dataKey} fill={color} radius={[4, 4, 0, 0]} />
<Bar dataKey={dataKey || 'value'} fill={color} radius={[4, 4, 0, 0]} />
</BarChart>
);
@ -117,7 +114,7 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
<Line
type="monotone"
dataKey={dataKey}
dataKey={dataKey || 'value'}
stroke={color}
strokeWidth={3}
dot={{ fill: color, strokeWidth: 2, r: 4 }}
@ -135,7 +132,7 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
<Area
type="monotone"
dataKey={dataKey}
dataKey={dataKey || 'value'}
stroke={color}
fill={color}
fillOpacity={0.6}
@ -154,7 +151,7 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
cy="40%"
outerRadius={70}
fill={color}
dataKey={dataKey}
dataKey={dataKey || 'value'}
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
>
{chartData.map((entry, index) => (
@ -172,7 +169,7 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
<YAxis dataKey="y" type="number" />
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
<Scatter dataKey="value" fill={color} />
<Scatter dataKey={dataKey || 'value'} fill={color} />
</ScatterChart>
);
@ -186,9 +183,9 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
className=" rounded-sm w-full max-w-[1280px] px-3 py-[10px] sm:px-12 lg:px-20 sm:py-[40px] lg:py-[86px] shadow-lg max-h-[720px] flex flex-col items-center justify-center aspect-video bg-white relative z-20 mx-auto"
>
<h1 className="text-2xl sm:text-3xl lg:text-4xl xl:text-5xl font-bold text-gray-900 leading-tight mb-4 lg:mb-8">
{slideData?.title || 'Chart Analysis'}
</h1>
{title && <h1 className="text-2xl sm:text-3xl lg:text-4xl xl:text-5xl font-bold text-gray-900 leading-tight mb-4 lg:mb-8">
{title}
</h1>}
<div className={`flex w-full items-center `}>
<div className="w-full">
@ -199,9 +196,9 @@ const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData })
</div>
</div>
<div className="w-full text-center">
<p className={`text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal`}>
{slideData?.description || 'This chart shows important data trends and insights that help understand the current situation and make informed decisions.'}
</p>
{description && <p className={`text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal`}>
{description}
</p>}
</div>
</div>
</div>

View file

@ -42,11 +42,12 @@ export const Schema = type5SlideSchema
export type Type5SlideData = z.infer<typeof type5SlideSchema>
interface Type5SlideLayoutProps {
data?: Partial<Type5SlideData>
data: Partial<Type5SlideData>
}
const Type5SlideLayout: React.FC<Type5SlideLayoutProps> = ({ data: slideData }) => {
const { title, description, items } = slideData;
return (
<div
className="rounded-sm w-full max-w-[1280px] font-inter shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] flex flex-col items-center justify-center max-h-[720px] aspect-video bg-white relative z-20 mx-auto"
@ -55,13 +56,13 @@ const Type5SlideLayout: React.FC<Type5SlideLayoutProps> = ({ data: slideData })
<div className="flex flex-col lg:flex-row gap-4 sm:gap-18 md:gap-16 items-center w-full">
{/* Left section - Title and Description */}
<div className="lg:w-1/2 lg:space-y-8 ">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Key Points'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{slideData?.description || 'Here is the main description that provides context and introduction to the numbered points on the right side.'}
</p>
{description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{description}
</p>}
</div>
{/* Right section - Numbered items */}
@ -80,12 +81,12 @@ const Type5SlideLayout: React.FC<Type5SlideLayoutProps> = ({ data: slideData })
{`0${index + 1}`}
</div>
<div className="space-y-1">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
</div>

View file

@ -61,12 +61,12 @@ export const Schema = type6SlideSchema
export type Type6SlideData = z.infer<typeof type6SlideSchema>
interface Type6SlideLayoutProps {
data?: Partial<Type6SlideData>
data: Partial<Type6SlideData>
}
const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const isGridLayout = items.length >= 4
const { title, items } = slideData;
const isGridLayout = items && items.length >= 4
const getGridCols = (length: number) => {
switch (length) {
@ -82,8 +82,8 @@ const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData })
const renderGridContent = () => {
return (
<div className={`grid grid-cols-1 ${items.length > 4 ? 'md:grid-cols-3' : 'md:grid-cols-2'} gap-4 sm:gap-6 lg:gap-8 mt-4 lg:mt-12 w-full`}>
{items.map((item, index) => (
<div className={`grid grid-cols-1 ${items && items.length > 4 ? 'md:grid-cols-3' : 'md:grid-cols-2'} gap-4 sm:gap-6 lg:gap-8 mt-4 lg:mt-12 w-full`}>
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -114,8 +114,8 @@ const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData })
const renderHorizontalContent = () => {
return (
<div className={`grid grid-cols-1 sm:grid-cols-2 ${getGridCols(items.length)} w-full gap-3 lg:gap-8 mt-4 lg:mt-12`}>
{items.map((item, index) => (
<div className={`grid grid-cols-1 sm:grid-cols-2 ${getGridCols(items?.length || 0)} w-full gap-3 lg:gap-8 mt-4 lg:mt-12`}>
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -129,12 +129,12 @@ const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData })
</div>
</div>
<div className="lg:space-y-4 mt-2 lg:mt-4">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold text-center">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold text-center">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal text-center">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal text-center">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -148,9 +148,9 @@ const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center sm:pb-2 lg:pb-8 w-full">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Our Services'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
</div>
{isGridLayout ? renderGridContent() : renderHorizontalContent()}

View file

@ -66,12 +66,12 @@ export const Schema = type7SlideSchema
export type Type7SlideData = z.infer<typeof type7SlideSchema>
interface Type7SlideLayoutProps {
data?: Partial<Type7SlideData>
data: Partial<Type7SlideData>
}
const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const isGridLayout = items.length >= 4
const { title, items } = slideData;
const isGridLayout = items && items.length >= 4
const getGridCols = (length: number) => {
switch (length) {
@ -87,8 +87,8 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
const renderGridContent = () => {
return (
<div className={`grid grid-cols-1 ${items.length > 4 ? 'md:grid-cols-3' : 'md:grid-cols-2'} gap-4 sm:gap-6 lg:gap-8 mt-4 lg:mt-12 w-full`}>
{items.map((item, index) => (
<div className={`grid grid-cols-1 ${items && items.length > 4 ? 'md:grid-cols-3' : 'md:grid-cols-2'} gap-4 sm:gap-6 lg:gap-8 mt-4 lg:mt-12 w-full`}>
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -107,12 +107,12 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
</div>
</div>
<div>
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold mb-2">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold mb-2">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
</div>
@ -123,8 +123,8 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
const renderHorizontalContent = () => {
return (
<div className={`grid grid-cols-1 sm:grid-cols-2 ${getGridCols(items.length)} w-full gap-3 lg:gap-8 mt-4 lg:mt-12`}>
{items.map((item, index) => (
<div className={`grid grid-cols-1 sm:grid-cols-2 ${getGridCols(items?.length || 0)} w-full gap-3 lg:gap-8 mt-4 lg:mt-12`}>
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -134,20 +134,20 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center mb-4">
<div className="w-16 h-16 lg:w-20 lg:h-20 bg-blue-600 rounded-lg flex items-center justify-center mx-auto mb-4 overflow-hidden">
<img
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
className="w-full h-full object-cover"
/>
/>}
</div>
</div>
<div className="lg:space-y-4 mt-2 lg:mt-4">
<h3 className="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 leading-tight text-center">
{item.heading && <h3 className="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 leading-tight text-center">
{item.heading}
</h3>
<p className="text-sm sm:text-base lg:text-lg text-gray-700 leading-relaxed text-center">
</h3>}
{item.description && <p className="text-sm sm:text-base lg:text-lg text-gray-700 leading-relaxed text-center">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -160,9 +160,9 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
className=" rounded-sm w-full max-w-[1280px] font-inter shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] flex flex-col items-center justify-center max-h-[720px] aspect-video bg-white relative z-20 mx-auto"
>
<div className="text-center sm:pb-2 lg:pb-8 w-full">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Our Services'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
</div>
{isGridLayout ? renderGridContent() : renderHorizontalContent()}

View file

@ -61,18 +61,18 @@ export const Schema = type8SlideSchema
export type Type8SlideData = z.infer<typeof type8SlideSchema>
interface Type8SlideLayoutProps {
data?: Partial<Type8SlideData>
data: Partial<Type8SlideData>
}
const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
const { title, description, items } = slideData;
const renderItems = () => {
if (items.length === 2) {
if (items && items.length === 2) {
// Vertical stacked layout for 2 items
return (
<div className="space-y-4 lg:space-y-8">
{items.map((item, index) => (
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -82,20 +82,20 @@ const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center mb-4">
<div className="w-16 h-16 lg:w-20 lg:h-20 bg-blue-600 rounded-lg flex items-center justify-center mx-auto mb-4 overflow-hidden">
<img
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
className="w-full h-full object-cover"
/>
/>}
</div>
</div>
<div className="space-y-1 lg:space-y-3">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold text-center">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold text-center">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal text-center">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal text-center">
{item.description}
</p>
</p>}
</div>
</div>
))}
@ -105,7 +105,7 @@ const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData })
// Horizontal layout with side icons for 3+ items
return (
<div className="space-y-4 lg:space-y-8">
{items.map((item, index) => (
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -116,20 +116,20 @@ const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData })
<div className="flex items-start gap-4">
<div className="w-[64px] h-[64px]">
<div className="w-full h-full bg-blue-600 rounded-lg flex items-center justify-center overflow-hidden">
<img
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
className="w-full h-full object-cover"
/>
/>}
</div>
</div>
<div className="w-[calc(100%-70px)] lg:space-y-3">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
</div>
@ -146,13 +146,13 @@ const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData })
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-8 lg:gap-16 items-center w-full">
{/* Left section - Title and Description */}
<div className="space-y-2 lg:space-y-6">
<h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{slideData?.title || 'Key Features'}
</h1>
{title && <h1 className="text-gray-900 text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
{title}
</h1>}
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{slideData?.description || 'Here is the main description that provides context and introduces the key features outlined on the right side.'}
</p>
{description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{description}
</p>}
</div>
{/* Right section - Items */}

View file

@ -97,17 +97,11 @@ export const Schema = type9SlideSchema
export type Type9SlideData = z.infer<typeof type9SlideSchema>
interface Type9SlideLayoutProps {
data?: Partial<Type9SlideData>
data: Partial<Type9SlideData>
}
const Type9SlideLayout: React.FC<Type9SlideLayoutProps> = ({ data: slideData }) => {
const chartData = slideData?.data || [];
const chartType = slideData?.chartType || 'line';
const color = slideData?.color || '#3b82f6';
const dataKey = slideData?.dataKey || 'value';
const categoryKey = slideData?.categoryKey || 'name';
const showLegend = slideData?.showLegend || false;
const showTooltip = slideData?.showTooltip || true;
const { title, items, chartData, chartType = 'line', color = '#3b82f6', dataKey = 'value', categoryKey = 'name', showLegend = false, showTooltip = true } = slideData;
const renderChart = () => {
const commonProps = {
data: chartData,
@ -177,7 +171,7 @@ const Type9SlideLayout: React.FC<Type9SlideLayoutProps> = ({ data: slideData })
dataKey={dataKey}
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
>
{chartData.map((entry, index) => (
{chartData.map((entry: any, index: number) => (
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
))}
</Pie>
@ -206,9 +200,9 @@ const Type9SlideLayout: React.FC<Type9SlideLayoutProps> = ({ data: slideData })
className=" rounded-sm w-full max-w-[1280px] px-3 py-[10px] sm:px-12 lg:px-20 sm:py-[40px] lg:py-[86px] shadow-lg max-h-[720px] flex flex-col items-center justify-center aspect-video bg-white relative z-20 mx-auto"
>
<h1 className="text-2xl text-start sm:text-3xl lg:text-4xl xl:text-5xl font-bold text-gray-900 leading-tight mb-4 lg:mb-8">
{slideData?.title || 'Chart Analysis'}
</h1>
{title && <h1 className="text-2xl text-start sm:text-3xl lg:text-4xl xl:text-5xl font-bold text-gray-900 leading-tight mb-4 lg:mb-8">
{title}
</h1>}
<div className={`flex gap-6 w-full items-center `}>
<div className="w-1/2">
@ -220,7 +214,7 @@ const Type9SlideLayout: React.FC<Type9SlideLayoutProps> = ({ data: slideData })
</div>
<div className="lg:w-1/2 relative">
<div className="space-y-3 lg:space-y-6">
{slideData?.items?.map((item, index) => (
{items && items.map((item, index) => (
<div
key={index}
style={{
@ -233,12 +227,12 @@ const Type9SlideLayout: React.FC<Type9SlideLayoutProps> = ({ data: slideData })
{`0${index + 1}`}
</div>
<div className="space-y-1">
<h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading && <h3 className="text-gray-900 text-base sm:text-lg lg:text-[24px] leading-[26px] lg:leading-[32px] font-bold">
{item.heading}
</h3>
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
</h3>}
{item.description && <p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
{item.description}
</p>
</p>}
</div>
</div>
</div>

View file

@ -74,7 +74,7 @@ export const Schema = z.object({
// Type inference
type SchemaType = z.infer<typeof Schema>;
// Component definition
// Component definitionz
const AboutUsSlide = ({ data }: { data: Partial<SchemaType> }) => {
const { sectionTitle, sectionSubtitle, organizationDescription, additionalContext, featuredImage, showVisualAccents, showColorBlocks, showAccentSquare } = data;