delete: remove chalss and classic-dark theme
This commit is contained in:
parent
f72b3280ed
commit
d3209e4b9f
21 changed files with 0 additions and 2750 deletions
|
|
@ -1,87 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ImageSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'classic-dark-title-slide'
|
||||
export const layoutName = 'Classic Dark Title Slide'
|
||||
export const layoutDescription = 'A modern title slide with dark gradient background, gradient text, and geographical elements.'
|
||||
|
||||
const titleSlideSchema = z.object({
|
||||
title: z.string().min(3).max(100).default('Nepal\'s Imports and\nExports: A Data-Driven\nOverview').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
subtitle: z.string().min(3).max(100).default('Key Trade Statistics and Trends (2022–2025)').meta({
|
||||
description: "Subtitle text",
|
||||
}),
|
||||
presenter: z.string().min(3).max(50).default('[Your Name]').meta({
|
||||
description: "Presenter name",
|
||||
}),
|
||||
date: z.string().min(3).max(50).default('April 13, 2025').meta({
|
||||
description: "Presentation date",
|
||||
}),
|
||||
image: ImageSchema.default({
|
||||
__image_url__: 'https://images.pexels.com/photos/9669089/pexels-photo-9669089.jpeg',
|
||||
__image_prompt__: 'Map of Nepal with gradient coloring from orange to red-brown'
|
||||
}).meta({
|
||||
description: "Image of the title slide of the presentation",
|
||||
}),
|
||||
})
|
||||
|
||||
export const Schema = titleSlideSchema
|
||||
|
||||
export type TitleSlideData = z.infer<typeof titleSlideSchema>
|
||||
|
||||
interface TitleSlideLayoutProps {
|
||||
data: Partial<TitleSlideData>
|
||||
}
|
||||
|
||||
const TitleSlideLayout: React.FC<TitleSlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, subtitle, presenter, date, image } = slideData;
|
||||
|
||||
return (
|
||||
<div className="w-full h-full shadow-lg flex items-center aspect-video relative z-20 mx-auto bg-gray-900">
|
||||
|
||||
<div className="flex w-full h-full">
|
||||
{/* Left side - Text content */}
|
||||
<div className="flex flex-col flex-1 items-start justify-center space-y-6 p-10">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-4xl leading-tight font-bold text-purple-400">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Subtitle */}
|
||||
{subtitle && (
|
||||
<p className="text-white text-xl leading-relaxed font-normal opacity-90">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Presenter and date */}
|
||||
<div className="text-white text-base leading-relaxed font-normal opacity-75">
|
||||
Presenter: {presenter} | {date}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right side - Visual elements */}
|
||||
<div className="flex flex-col flex-1 items-end justify-center relative">
|
||||
{image && (
|
||||
<div className="w-full h-full">
|
||||
<img
|
||||
src={image.__image_url__}
|
||||
alt={image.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
style={{
|
||||
filter: 'drop-shadow(0 4px 8px rgba(0,0,0,0.3))'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TitleSlideLayout
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart';
|
||||
import { PieChart, Pie, Cell } from "recharts";
|
||||
|
||||
export const layoutId = 'classic-dark-piechart-and-metrics'
|
||||
export const layoutName = 'Classic Dark Pie Chart and Metrics'
|
||||
export const layoutDescription = 'A modern slide with dark background, metrics on the left, and pie chart visualization on the right.'
|
||||
|
||||
const chartDataSchema = z.object({
|
||||
name: z.string().min(2).max(30).meta({ description: "Data point name" }),
|
||||
value: z.number().meta({ description: "Data point value" }),
|
||||
});
|
||||
|
||||
const pieChartAndMetricsSchema = z.object({
|
||||
title: z.string().min(3).max(80).default('Introduction to Nepal\'s Trade').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(100).default('Nepal\'s landlocked geography heavily influences its trade, fostering reliance on India and China.').meta({
|
||||
description: "Description text",
|
||||
}),
|
||||
metrics: z.array(z.object({
|
||||
label: z.string().meta({ description: "Metric label" }),
|
||||
value: z.string().meta({ description: "Metric value" }),
|
||||
percentage: z.string().optional().meta({ description: "Optional percentage" }),
|
||||
})).min(2).max(4).default([
|
||||
{ label: 'Exports (2023)', value: '$2.85 billion', percentage: '6.76% of GDP' },
|
||||
{ label: 'Imports (2023)', value: '$17.39 billion', percentage: '42.64% of GDP' },
|
||||
{ label: 'GDP (2022)', value: '$40.83 billion' },
|
||||
{ label: 'Trade Deficit (2022)', value: '-$12.44 billion' },
|
||||
]).meta({
|
||||
description: "List of key metrics",
|
||||
}),
|
||||
chartData: z.array(chartDataSchema).min(2).max(4).default([
|
||||
{ name: 'Imports', value: 42.64 },
|
||||
{ name: 'Exports', value: 6.76 },
|
||||
{ name: 'Other GDP', value: 50.6 },
|
||||
]).meta({
|
||||
description: "Pie chart data",
|
||||
})
|
||||
})
|
||||
|
||||
const chartConfig = {
|
||||
value: {
|
||||
label: "Value",
|
||||
},
|
||||
name: {
|
||||
label: "Name",
|
||||
},
|
||||
};
|
||||
|
||||
const CHART_COLORS = [
|
||||
'#8b5cf6',
|
||||
'#3b82f6',
|
||||
'#a855f7',
|
||||
];
|
||||
|
||||
export const Schema = pieChartAndMetricsSchema
|
||||
|
||||
export type PieChartAndMetricsData = z.infer<typeof pieChartAndMetricsSchema>
|
||||
|
||||
interface PieChartAndMetricsLayoutProps {
|
||||
data: Partial<PieChartAndMetricsData>
|
||||
}
|
||||
|
||||
const PieChartAndMetricsLayout: React.FC<PieChartAndMetricsLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, description, metrics, chartData } = slideData;
|
||||
|
||||
const CustomLegend = () => (
|
||||
<div className="flex justify-center space-x-8 mt-4">
|
||||
{chartData?.map((entry, index) => (
|
||||
<div key={index} className="flex items-center space-x-2">
|
||||
<div
|
||||
className="w-4 h-4 rounded-sm"
|
||||
style={{ backgroundColor: CHART_COLORS[index % CHART_COLORS.length] }}
|
||||
/>
|
||||
<span className="text-white text-lg font-medium">{entry.name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
const renderPieChart = () => {
|
||||
return (
|
||||
<PieChart>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Pie
|
||||
data={chartData}
|
||||
fill="#8b5cf6"
|
||||
outerRadius="50%"
|
||||
dataKey="value"
|
||||
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
|
||||
labelLine={false}
|
||||
fontSize={18}
|
||||
>
|
||||
{chartData?.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full h-full shadow-lg flex items-center aspect-video relative z-20 mx-auto bg-gray-900">
|
||||
|
||||
<div className="flex w-full h-full">
|
||||
{/* Left side - Text content and metrics */}
|
||||
<div className="flex flex-col basis-1/2 items-start justify-start space-y-8 p-12">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-5xl leading-tight font-bold text-purple-400">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
<p className="text-white text-2xl leading-relaxed font-normal opacity-90">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Metrics */}
|
||||
{metrics && metrics.length > 0 && (
|
||||
<div className="space-y-4">
|
||||
{metrics.map((metric, index) => (
|
||||
<div key={index} className="text-white text-xl leading-relaxed font-normal">
|
||||
<span className="opacity-90">• {metric.label}: </span>
|
||||
<span className="font-bold text-purple-300">{metric.value}</span>
|
||||
{metric.percentage && (
|
||||
<span className="opacity-75"> ({metric.percentage})</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right side - Chart */}
|
||||
<div className="flex flex-col basis-1/2 items-center justify-center">
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<ChartContainer config={chartConfig} className="h-[500px] w-[500px]">
|
||||
{renderPieChart()}
|
||||
</ChartContainer>
|
||||
<CustomLegend />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PieChartAndMetricsLayout
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart';
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Cell } from "recharts";
|
||||
|
||||
export const layoutId = 'classic-dark-bar-graph'
|
||||
export const layoutName = 'Classic Dark Bar Graph'
|
||||
export const layoutDescription = 'A modern slide with dark background, gradient title, bar chart visualization, and footer text.'
|
||||
|
||||
const barDataSchema = z.object({
|
||||
name: z.string().min(2).max(30).meta({ description: "Product name" }),
|
||||
value: z.number().meta({ description: "Export value in millions" }),
|
||||
});
|
||||
|
||||
const barGraphSchema = z.object({
|
||||
title: z.string().min(3).max(80).default('Export Overview: Key Products').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(120).default('Nepal\'s total exports were $1.3 billion in 2022, a 21% decrease from 2021, but showed a 47.5% YoY increase by Nov 2024.').meta({
|
||||
description: "Description text",
|
||||
}),
|
||||
chartData: z.array(barDataSchema).min(2).max(6).default([
|
||||
{ name: 'Soybean Oil (non-crude)', value: 180 },
|
||||
{ name: 'Palm Oil (non-crude)', value: 180 },
|
||||
{ name: 'Carpets/Textile Floor...', value: 80 },
|
||||
{ name: 'Cardamom', value: 50 },
|
||||
{ name: 'Felt Products', value: 40 },
|
||||
]).meta({
|
||||
description: "Bar chart data",
|
||||
}),
|
||||
})
|
||||
|
||||
const chartConfig = {
|
||||
value: {
|
||||
label: "Value ($M)",
|
||||
},
|
||||
name: {
|
||||
label: "Product",
|
||||
},
|
||||
};
|
||||
|
||||
const BAR_COLORS = [
|
||||
'#8b5cf6', // Dark purple for top products
|
||||
'#8b5cf6', // Dark purple for top products
|
||||
'#a855f7', // Light purple for other products
|
||||
'#a855f7', // Light purple for other products
|
||||
'#a855f7', // Light purple for other products
|
||||
];
|
||||
|
||||
export const Schema = barGraphSchema
|
||||
|
||||
export type BarGraphData = z.infer<typeof barGraphSchema>
|
||||
|
||||
interface BarGraphLayoutProps {
|
||||
data: Partial<BarGraphData>
|
||||
}
|
||||
|
||||
const BarGraphLayout: React.FC<BarGraphLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, description, chartData } = slideData;
|
||||
|
||||
const CustomLegend = () => (
|
||||
<div className="flex justify-center space-x-8 mt-8">
|
||||
{chartData?.map((entry, index) => (
|
||||
<div key={index} className="flex items-center space-x-2">
|
||||
<div
|
||||
className="w-4 h-4 rounded-sm"
|
||||
style={{ backgroundColor: BAR_COLORS[index % BAR_COLORS.length] }}
|
||||
/>
|
||||
<span className="text-white text-lg font-medium">{entry.name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
const renderBarChart = () => {
|
||||
return (
|
||||
<BarChart
|
||||
data={chartData}
|
||||
margin={{ top: 0, right: 30, left: 20, bottom: 0 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
height={100}
|
||||
tick={{ fill: '#ffffff', fontSize: 16, fontWeight: 600 }}
|
||||
tickFormatter={(value) => {
|
||||
if (value.length > 15) {
|
||||
return value.substring(0, 15) + '...';
|
||||
}
|
||||
return value;
|
||||
}}
|
||||
/>
|
||||
<YAxis
|
||||
tick={{ fill: '#ffffff', fontSize: 16, fontWeight: 600 }}
|
||||
tickFormatter={(value) => value.toFixed(0)}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar
|
||||
dataKey="value"
|
||||
fill="#8b5cf6"
|
||||
radius={[4, 4, 0, 0]}
|
||||
>
|
||||
{chartData?.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={BAR_COLORS[index % BAR_COLORS.length]} />
|
||||
))}
|
||||
</Bar>
|
||||
</BarChart>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full h-full shadow-lg flex items-center aspect-video relative z-20 mx-auto bg-gray-900">
|
||||
|
||||
<div className="flex flex-col w-full h-full">
|
||||
{/* Header section */}
|
||||
<div className="flex flex-col items-start justify-start space-y-6 p-12">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-5xl leading-tight font-bold text-purple-400">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
<p className="text-white text-2xl leading-relaxed font-normal opacity-90">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Chart section */}
|
||||
<div className="flex flex-col flex-1 items-center justify-center px-12">
|
||||
<div className="w-full h-full flex flex-col items-center justify-center space-y-4">
|
||||
<ChartContainer config={chartConfig} className="h-[300px] w-full">
|
||||
{renderBarChart()}
|
||||
</ChartContainer>
|
||||
<CustomLegend />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BarGraphLayout
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ImageSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'classic-dark-comparison'
|
||||
export const layoutName = 'Classic Dark Comparison'
|
||||
export const layoutDescription = 'A modern slide with dark background, image on the left (2/5), and comparison content on the right (3/5).'
|
||||
|
||||
const comparisonItemSchema = z.object({
|
||||
name: z.string().min(3).max(30).meta({ description: "Commodity name" }),
|
||||
value: z.string().min(3).max(30).meta({ description: "Value" }),
|
||||
when: z.string().min(3).max(30).meta({ description: "When the value was recorded" }),
|
||||
details: z.string().min(3).max(50).optional().meta({ description: "Additional details" }),
|
||||
});
|
||||
|
||||
const comparisonSectionSchema = z.object({
|
||||
title: z.string().min(3).max(50).meta({ description: "Section title" }),
|
||||
items: z.array(comparisonItemSchema).min(1).max(3).meta({ description: "List of items in the section" }),
|
||||
});
|
||||
|
||||
const comparisonSchema = z.object({
|
||||
title: z.string().min(3).max(80).default('Key Commodities in Focus').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
comparisonSections: z.array(comparisonSectionSchema).min(2).max(2).default([
|
||||
{
|
||||
title: 'Exports',
|
||||
items: [
|
||||
{ name: 'Soybean Oil', value: '$186.91 million', when: '2022' },
|
||||
{ name: 'Cardamom', value: '$46.64 million', when: '2022', details: 'primarily to India' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Imports',
|
||||
items: [
|
||||
{ name: 'Crude Soybean Oil', value: '$347.77 million', when: '2022' },
|
||||
{ name: 'Petroleum Products', value: '$3.15 billion', when: '2022', details: '22% of total imports' },
|
||||
{ name: 'Vehicles/Parts', value: '$526 million', when: '2022', details: 'down 45% from 2021' },
|
||||
]
|
||||
}
|
||||
]).meta({
|
||||
description: "Comparison sections with title and data items",
|
||||
}),
|
||||
image: ImageSchema.default({
|
||||
__image_url__: 'https://images.pexels.com/photos/9669089/pexels-photo-9669089.jpeg',
|
||||
__image_prompt__: 'Map of South Asia showing Nepal and neighboring countries with trade routes highlighted'
|
||||
}).meta({
|
||||
description: "Comparison visualization image",
|
||||
}),
|
||||
})
|
||||
|
||||
export const Schema = comparisonSchema
|
||||
|
||||
export type ComparisonData = z.infer<typeof comparisonSchema>
|
||||
|
||||
interface ComparisonLayoutProps {
|
||||
data: Partial<ComparisonData>
|
||||
}
|
||||
|
||||
const ComparisonLayout: React.FC<ComparisonLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, comparisonSections, image } = slideData;
|
||||
|
||||
return (
|
||||
<div className="w-full h-full shadow-lg flex items-center aspect-video relative z-20 mx-auto bg-gray-900">
|
||||
|
||||
<div className="flex w-full h-full">
|
||||
{/* Left side - Image (2/5) */}
|
||||
<div className="flex flex-col basis-2/5 h-full">
|
||||
{image && (
|
||||
<div className="w-full h-full">
|
||||
<img
|
||||
src={image.__image_url__}
|
||||
alt={image.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
style={{
|
||||
filter: 'drop-shadow(0 4px 8px rgba(0,0,0,0.3))'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right side - Content (3/5) */}
|
||||
<div className="flex flex-col basis-3/5 items-start justify-start space-y-8 p-12">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-5xl leading-tight font-bold text-purple-400">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Comparison Sections */}
|
||||
<div className="flex w-full space-x-12 flex pt-10">
|
||||
{comparisonSections && comparisonSections.map((section, sectionIndex) => (
|
||||
<div key={sectionIndex} className="flex flex-col flex-1 space-y-4">
|
||||
<h2 className="text-3xl leading-tight font-semibold text-purple-300">
|
||||
{section.title}
|
||||
</h2>
|
||||
{section.items && section.items.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
{section.items.map((item, index) => (
|
||||
<div key={index} className="text-white text-lg leading-relaxed font-normal">
|
||||
<span className="opacity-90">• <span className="font-bold">{item.name}</span>: {item.value} ({item.when})</span>
|
||||
{item.details && (
|
||||
<span className="opacity-75">, {item.details}</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ComparisonLayout
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { IconSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'classic-dark-metrics'
|
||||
export const layoutName = 'Classic Dark Metrics'
|
||||
export const layoutDescription = 'A modern slide with dark background, metric cards arranged in a grid with icons and data.'
|
||||
|
||||
const metricItemSchema = z.object({
|
||||
title: z.string().min(3).max(50).meta({ description: "Metric title" }),
|
||||
value: z.string().min(3).max(30).meta({ description: "Metric value" }),
|
||||
percentage: z.string().min(3).max(30).meta({ description: "Percentage value" }),
|
||||
icon: IconSchema.meta({ description: "Icon for the metric" }),
|
||||
});
|
||||
|
||||
const metricsSchema = z.object({
|
||||
title: z.string().min(3).max(80).default('Top Export Destinations').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(120).default('Nepal exports 760 products to 132 countries, with a strong focus on regional trade.').meta({
|
||||
description: "Description text",
|
||||
}),
|
||||
metrics: z.array(metricItemSchema).min(2).max(6).default([
|
||||
{
|
||||
title: 'India',
|
||||
value: '$935 million',
|
||||
percentage: '71.93%',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'star rating'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'United States',
|
||||
value: '$147 million',
|
||||
percentage: '11.32%',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'flag country'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Germany',
|
||||
value: '$33 million',
|
||||
percentage: '2.51%',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'user person'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Turkey',
|
||||
value: '$26 million',
|
||||
percentage: '2.01%',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'pen tool'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'United Kingdom',
|
||||
value: '$24 million',
|
||||
percentage: '1.83%',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'message chat'
|
||||
}
|
||||
},
|
||||
]).meta({
|
||||
description: "Metric cards data",
|
||||
}),
|
||||
})
|
||||
|
||||
export const Schema = metricsSchema
|
||||
|
||||
export type MetricsData = z.infer<typeof metricsSchema>
|
||||
|
||||
interface MetricsLayoutProps {
|
||||
data: Partial<MetricsData>
|
||||
}
|
||||
|
||||
const MetricsLayout: React.FC<MetricsLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, description, metrics } = slideData;
|
||||
|
||||
return (
|
||||
<div className="w-full h-full shadow-lg flex items-center aspect-video relative z-20 mx-auto bg-gray-900">
|
||||
|
||||
<div className="flex flex-col w-full h-full">
|
||||
{/* Header section */}
|
||||
<div className="flex flex-col items-start justify-start space-y-6 p-10">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-5xl leading-tight font-bold text-purple-400">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
<p className="text-white text-xl leading-relaxed font-normal opacity-90">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Metrics Cards Grid */}
|
||||
<div className="flex flex-col flex-1 items-center justify-center px-12">
|
||||
<div className="grid grid-cols-3 gap-x-8 gap-y-12 w-full max-w-4xl">
|
||||
{metrics && metrics.map((metric, index) => (
|
||||
<div key={index} className="flex flex-col items-center">
|
||||
{/* Metric Card with overlapping icon */}
|
||||
<div className="relative w-full bg-gray-800 rounded-lg p-6 text-center border border-purple-500 border-opacity-30 shadow-lg">
|
||||
{/* Icon overlapping the top */}
|
||||
<div className="absolute -top-8 left-1/2 transform -translate-x-1/2 w-16 h-16 bg-purple-600 rounded-full flex items-center justify-center shadow-lg">
|
||||
<img
|
||||
src={metric.icon.__icon_url__}
|
||||
alt={metric.icon.__icon_query__}
|
||||
className="w-6 h-6 object-contain text-white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content with top padding for icon space */}
|
||||
<div className="pt-8">
|
||||
<h3 className="text-2xl font-bold text-white mb-2">
|
||||
{metric.title}
|
||||
</h3>
|
||||
<p className="text-lg text-white opacity-90">
|
||||
{metric.value} ({metric.percentage})
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MetricsLayout
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ImageSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'classic-dark-bullet-point-with-description'
|
||||
export const layoutName = 'Classic Dark Bullet Point with Description'
|
||||
export const layoutDescription = 'A modern slide with dark background, image on the left (2/5), and bullet points with descriptions in boxes on the right (3/5).'
|
||||
|
||||
const bulletPointSchema = z.object({
|
||||
title: z.string().min(3).max(60).meta({ description: "Bullet point title" }),
|
||||
content: z.string().min(10).max(120).meta({ description: "Bullet point content (max 150 characters)" }),
|
||||
});
|
||||
|
||||
const bulletPointWithDescriptionSchema = z.object({
|
||||
title: z.string().min(3).max(80).default('Trade Policies and Challenges').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
bulletPoints: z.array(bulletPointSchema).min(2).max(3).default([
|
||||
{
|
||||
title: 'Tariffs',
|
||||
content: 'Effectively Applied Tariff (2022): 11.59%. Most Favored Nation Tariff (2022): 12.87%. Duty-free imports: $412.11 million.'
|
||||
},
|
||||
{
|
||||
title: 'Forex Reserves',
|
||||
content: '$8.18 billion in 2019, covering 8 months of imports.'
|
||||
},
|
||||
{
|
||||
title: 'Import Ban Impact',
|
||||
content: 'Luxury goods ban (Apr-Dec 2022) cut deficit by 15.45% but reduced export earnings by 21.44%.'
|
||||
}
|
||||
]).meta({
|
||||
description: "Bullet points with descriptions (max 3 items)",
|
||||
}),
|
||||
image: ImageSchema.default({
|
||||
__image_url__: 'https://images.pexels.com/photos/9669089/pexels-photo-9669089.jpeg',
|
||||
__image_prompt__: 'Stylized mountainous landscape with trade arrows and network connections, dark gradient background with orange sun and purple mountains'
|
||||
}).meta({
|
||||
description: "Visual representation image",
|
||||
}),
|
||||
})
|
||||
|
||||
export const Schema = bulletPointWithDescriptionSchema
|
||||
|
||||
export type BulletPointWithDescriptionData = z.infer<typeof bulletPointWithDescriptionSchema>
|
||||
|
||||
interface BulletPointWithDescriptionLayoutProps {
|
||||
data: Partial<BulletPointWithDescriptionData>
|
||||
}
|
||||
|
||||
const BulletPointWithDescriptionLayout: React.FC<BulletPointWithDescriptionLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, bulletPoints, image } = slideData;
|
||||
|
||||
return (
|
||||
<div className="w-full h-full shadow-lg flex items-center aspect-video relative z-20 mx-auto bg-gray-900">
|
||||
|
||||
<div className="flex w-full h-full">
|
||||
{/* Left side - Image (2/5) */}
|
||||
<div className="flex flex-col basis-2/5 h-full">
|
||||
{image && (
|
||||
<div className="w-full h-full">
|
||||
<img
|
||||
src={image.__image_url__}
|
||||
alt={image.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
style={{
|
||||
filter: 'drop-shadow(0 4px 8px rgba(0,0,0,0.3))'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right side - Content (3/5) */}
|
||||
<div className="flex flex-col basis-3/5 items-start justify-start space-y-8 p-10">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-5xl leading-tight font-bold text-purple-400">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Bullet Points */}
|
||||
{bulletPoints && bulletPoints.length > 0 && (
|
||||
<div className="space-y-6 w-full h-full flex flex-col justify-center">
|
||||
{bulletPoints.map((point, index) => (
|
||||
<div key={index} className="w-full bg-gray-800 rounded-lg py-2 px-4 border border-gray-600 border-opacity-30">
|
||||
<h3 className="text-2xl font-bold text-white mb-4">
|
||||
{point.title}
|
||||
</h3>
|
||||
<p className="text-white text-lg leading-relaxed font-normal opacity-90">
|
||||
{point.content}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BulletPointWithDescriptionLayout
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"description": "Classic dark layout for presentations",
|
||||
"ordered": false,
|
||||
"default": false
|
||||
}
|
||||
|
|
@ -1,269 +0,0 @@
|
|||
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 * as z from "zod";
|
||||
import { IconSchema } from '../defaultSchemes';
|
||||
|
||||
export const layoutId = 'type4-slide'
|
||||
export const layoutName = 'Type4 Slide'
|
||||
export const layoutDescription = 'A chart-focused layout with title, chart visualization, and description text.'
|
||||
|
||||
const chartDataSchema = z.object({
|
||||
name: z.string().meta({ description: "Data point name" }),
|
||||
value: z.number().meta({ description: "Data point value" }),
|
||||
category: z.string().optional().meta({ description: "Category for grouping" }),
|
||||
x: z.number().optional().meta({ description: "X coordinate for scatter plots" }),
|
||||
y: z.number().optional().meta({ description: "Y coordinate for scatter plots" }),
|
||||
});
|
||||
|
||||
|
||||
const type10SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Chart Analysis').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(8).max(40).default('This is a description of the chart analysis').meta({
|
||||
description: " Short description of the chart analysis",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
icon: IconSchema.meta({
|
||||
description: "Item icon",
|
||||
}),
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
})
|
||||
})).min(2).max(3).default(() => [
|
||||
{
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'A beautiful road in the mountains'
|
||||
},
|
||||
heading: 'First Key Point',
|
||||
description: 'Detailed explanation of the first important point that supports the main topic'
|
||||
},
|
||||
{
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'A beautiful road in the mountains'
|
||||
},
|
||||
heading: 'Second Key Point',
|
||||
description: 'Detailed explanation of the second important point with relevant information'
|
||||
}
|
||||
]).meta({
|
||||
description: "List of numbered items (2-3 items)",
|
||||
}),
|
||||
chartData: z.any().optional().meta({
|
||||
description: "Chart data object",
|
||||
}),
|
||||
isFullSizeChart: z.boolean().default(false).meta({
|
||||
description: "Whether to display chart in full size mode",
|
||||
}),
|
||||
chartType: z.enum(['bar', 'line', 'pie', 'area', 'scatter']).default('line').meta({
|
||||
description: "Type of chart to display",
|
||||
}),
|
||||
data: z.array(chartDataSchema).min(2).max(10).default([
|
||||
{ name: '2021', value: 5 },
|
||||
{ name: '2022', value: 12 },
|
||||
{ name: '2023', value: 18 },
|
||||
{ name: '2024', value: 23 },
|
||||
{ name: '2025', value: 26 },
|
||||
]).meta({
|
||||
description: "Chart data points",
|
||||
}),
|
||||
dataKey: z.string().default('value').meta({
|
||||
description: "Key field for chart values",
|
||||
}),
|
||||
categoryKey: z.string().default('name').meta({
|
||||
description: "Key field for chart categories",
|
||||
}),
|
||||
color: z.string().default('#3b82f6').meta({
|
||||
description: "Primary color for chart elements",
|
||||
}),
|
||||
showLegend: z.boolean().default(false).meta({
|
||||
description: "Whether to show chart legend",
|
||||
}),
|
||||
showTooltip: z.boolean().default(true).meta({
|
||||
description: "Whether to show chart tooltip",
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
const chartConfig = {
|
||||
value: {
|
||||
label: "Value",
|
||||
},
|
||||
name: {
|
||||
label: "Name",
|
||||
},
|
||||
};
|
||||
const CHART_COLORS = [
|
||||
'#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6',
|
||||
'#06b6d4', '#84cc16', '#f97316', '#ec4899', '#6366f1'
|
||||
];
|
||||
|
||||
export const Schema = type10SlideSchema
|
||||
|
||||
export type Type10SlideData = z.infer<typeof type10SlideSchema>
|
||||
|
||||
interface Type10SlideLayoutProps {
|
||||
data: Partial<Type10SlideData>
|
||||
}
|
||||
|
||||
const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, items, data, chartType = 'line', color = '#3b82f6', dataKey = 'value', categoryKey = 'name', showLegend = false, showTooltip = true } = slideData;
|
||||
const chartData = data || [];
|
||||
const renderChart = () => {
|
||||
const commonProps = {
|
||||
data: chartData,
|
||||
margin: { top: 10, right: 20, left: 0, bottom: 30 },
|
||||
};
|
||||
|
||||
switch (chartType) {
|
||||
case 'bar':
|
||||
return (
|
||||
<BarChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Bar dataKey={dataKey} fill={color} radius={[4, 4, 0, 0]} />
|
||||
</BarChart>
|
||||
);
|
||||
|
||||
case 'line':
|
||||
return (
|
||||
<LineChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey={dataKey}
|
||||
stroke={color}
|
||||
strokeWidth={3}
|
||||
dot={{ fill: color, strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
</LineChart>
|
||||
);
|
||||
|
||||
case 'area':
|
||||
return (
|
||||
<AreaChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey={dataKey}
|
||||
stroke={color}
|
||||
fill={color}
|
||||
fillOpacity={0.6}
|
||||
/>
|
||||
</AreaChart>
|
||||
);
|
||||
|
||||
case 'pie':
|
||||
return (
|
||||
<PieChart margin={{ top: 10, right: 10, left: 10, bottom: 10 }}>
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Pie
|
||||
data={chartData}
|
||||
cx="50%"
|
||||
cy="40%"
|
||||
outerRadius={70}
|
||||
fill={color}
|
||||
dataKey={dataKey}
|
||||
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
|
||||
>
|
||||
{chartData.map((entry: any, index: number) => (
|
||||
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
);
|
||||
|
||||
case 'scatter':
|
||||
return (
|
||||
<ScatterChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="x" type="number" />
|
||||
<YAxis dataKey="y" type="number" />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Scatter dataKey="value" fill={color} />
|
||||
</ScatterChart>
|
||||
);
|
||||
|
||||
default:
|
||||
return <div>Unsupported chart type</div>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
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"
|
||||
|
||||
>
|
||||
<div className='w-full flex flex-col items-start justify-start'>
|
||||
|
||||
{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 `}>
|
||||
<div className="w-1/2">
|
||||
<div className="flex-1 bg-white rounded-lg shadow-sm border border-gray-100 p-4">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
{renderChart()}
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</div>
|
||||
<div className="lg:w-1/2 relative">
|
||||
<div className="space-y-3 lg:space-y-6">
|
||||
{items && items.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<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">
|
||||
{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">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type10SlideLayout
|
||||
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ImageSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'type1-slide'
|
||||
export const layoutName = 'Type1 Slide'
|
||||
export const layoutDescription = 'A clean two-column layout with title and description on the left and a featured image on the right.'
|
||||
|
||||
const type1SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Hot NOT Reload Working!').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(130).default('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.').meta({
|
||||
description: "Main description text",
|
||||
}),
|
||||
image: ImageSchema.default({
|
||||
__image_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
|
||||
__image_prompt__: 'A beautiful road in the mountains'
|
||||
}).meta({
|
||||
description: "Main slide image",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type1SlideSchema
|
||||
|
||||
export type Type1SlideData = z.infer<typeof type1SlideSchema>
|
||||
|
||||
interface Type1SlideLayoutProps {
|
||||
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"
|
||||
|
||||
>
|
||||
<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 */}
|
||||
{title && <h1 className=" text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold">
|
||||
{title}
|
||||
</h1>}
|
||||
|
||||
{/* Description */}
|
||||
{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]">
|
||||
{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>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type1SlideLayout
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
|
||||
export const layoutId = 'type2-numbered-slide'
|
||||
export const layoutName = 'Type2 Numbered Slide'
|
||||
export const layoutDescription = 'A content layout with title and numbered content items with large numerals and shadow boxes.'
|
||||
|
||||
const type2NumberedSlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Main Title').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(100).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'First Point',
|
||||
description: 'Description for the first key point that explains important details'
|
||||
},
|
||||
{
|
||||
heading: 'Second Point',
|
||||
description: 'Description for the second key point with relevant information'
|
||||
},
|
||||
{
|
||||
heading: 'Third Point',
|
||||
description: 'Description for the third key point highlighting crucial aspects'
|
||||
}
|
||||
]).meta({
|
||||
description: "List of content items (2-4 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type2NumberedSlideSchema
|
||||
|
||||
export type Type2NumberedSlideData = z.infer<typeof type2NumberedSlideSchema>
|
||||
|
||||
interface Type2NumberedSlideLayoutProps {
|
||||
data: Partial<Type2NumberedSlideData>
|
||||
}
|
||||
|
||||
const Type2NumberedSlideLayout: React.FC<Type2NumberedSlideLayoutProps> = ({ data: slideData }) => {
|
||||
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) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="w-full relative shadow-lg rounded-lg p-3 lg:p-6"
|
||||
>
|
||||
<div className="flex gap-3">
|
||||
<div className="text-[32px] leading-[40px] px-1 font-bold mb-4 text-blue-600">
|
||||
{numberTranslations[index] || `0${index + 1}`}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="w-full relative shadow-lg rounded-lg p-3 lg:p-6"
|
||||
>
|
||||
<div className="text-[32px] leading-[40px] font-semibold lg:mb-4 text-blue-600">
|
||||
{numberTranslations[index] || `0${index + 1}`}
|
||||
</div>
|
||||
<div className="space-y-2 lg:space-y-4">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
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">
|
||||
{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()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type2NumberedSlideLayout
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
|
||||
export const layoutId = 'type2-slide'
|
||||
export const layoutName = 'Type2 Slide'
|
||||
export const layoutDescription = 'A flexible content layout with title and multiple content items in default presentation style.'
|
||||
|
||||
const type2SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Main Title').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'First Point',
|
||||
description: 'Description for the first key point that explains important details'
|
||||
},
|
||||
{
|
||||
heading: 'Second Point',
|
||||
description: 'Description for the second key point with relevant information'
|
||||
},
|
||||
{
|
||||
heading: 'Third Point',
|
||||
description: 'Description for the third key point highlighting crucial aspects'
|
||||
}
|
||||
]).meta({
|
||||
description: "List of content items (2-4 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type2SlideSchema
|
||||
|
||||
export type Type2SlideData = z.infer<typeof type2SlideSchema>
|
||||
|
||||
interface Type2SlideLayoutProps {
|
||||
data: Partial<Type2SlideData>
|
||||
}
|
||||
|
||||
const Type2SlideLayout: React.FC<Type2SlideLayoutProps> = ({ data: slideData }) => {
|
||||
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) => (
|
||||
<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">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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) => (
|
||||
<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">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
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">
|
||||
{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()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type2SlideLayout
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
|
||||
export const layoutId = 'type2-timeline-slide'
|
||||
export const layoutName = 'Type2 Timeline Slide'
|
||||
export const layoutDescription = 'A timeline layout with title and content items arranged horizontally with numbered circles and connecting line.'
|
||||
|
||||
const type2TimelineSlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Main Title').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'First Point',
|
||||
description: 'Description for the first key point that explains important details'
|
||||
},
|
||||
{
|
||||
heading: 'Second Point',
|
||||
description: 'Description for the second key point with relevant information'
|
||||
},
|
||||
{
|
||||
heading: 'Third Point',
|
||||
description: 'Description for the third key point highlighting crucial aspects'
|
||||
}
|
||||
]).meta({
|
||||
description: "List of content items (2-4 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type2TimelineSlideSchema
|
||||
|
||||
export type Type2TimelineSlideData = z.infer<typeof type2TimelineSlideSchema>
|
||||
|
||||
interface Type2TimelineSlideLayoutProps {
|
||||
data: Partial<Type2TimelineSlideData>
|
||||
}
|
||||
|
||||
const Type2TimelineSlideLayout: React.FC<Type2TimelineSlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, items } = slideData;
|
||||
|
||||
const renderTimelineContent = () => {
|
||||
return (
|
||||
<div className="w-full flex flex-col relative mt-4 lg:mt-16">
|
||||
{/* Timeline Header with Numbers and Line */}
|
||||
<div className="relative flex justify-between w-[85%] mx-auto items-center mb-8 px-8">
|
||||
{/* Horizontal Line */}
|
||||
<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 && 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> {index + 1}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Timeline Content */}
|
||||
<div className="flex justify-between gap-8">
|
||||
{items && items.map((item, index) => (
|
||||
<div key={index} className="flex-1 text-center relative">
|
||||
<div className="space-y-4">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
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">
|
||||
{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()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type2TimelineSlideLayout
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { ImageSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'type3-slide'
|
||||
export const layoutName = 'Type3 Slide'
|
||||
export const layoutDescription = 'A centered title with a grid of image cards, each containing a heading and description.'
|
||||
|
||||
const type3SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Featured Content').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
}),
|
||||
image: ImageSchema.meta({
|
||||
description: "Item image",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'First Feature',
|
||||
description: 'Description for the first featured item with detailed information',
|
||||
image: {
|
||||
__image_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
|
||||
__image_prompt__: 'A beautiful road in the mountains'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Second Feature',
|
||||
description: 'Description for the second featured item with relevant details',
|
||||
image: {
|
||||
__image_url__: 'https://cdn.pixabay.com/photo/2016/02/19/11/19/office-1209640_1280.jpg',
|
||||
__image_prompt__: 'Modern office workspace'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Third Feature',
|
||||
description: 'Description for the third featured item with important points',
|
||||
image: {
|
||||
__image_url__: 'https://cdn.pixabay.com/photo/2017/08/10/08/47/laptop-2619235_1280.jpg',
|
||||
__image_prompt__: 'Laptop with code on screen'
|
||||
}
|
||||
}
|
||||
]).meta({
|
||||
description: "List of featured items (2-4 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type3SlideSchema
|
||||
|
||||
export type Type3SlideData = z.infer<typeof type3SlideSchema>
|
||||
|
||||
interface Type3SlideLayoutProps {
|
||||
data: Partial<Type3SlideData>
|
||||
}
|
||||
|
||||
const Type3SlideLayout: React.FC<Type3SlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, items } = slideData;
|
||||
|
||||
const getGridCols = (length: number) => {
|
||||
switch (length) {
|
||||
case 1: return 'lg:grid-cols-1';
|
||||
case 2: return 'lg:grid-cols-2';
|
||||
case 3: return 'lg:grid-cols-3';
|
||||
case 4: return 'lg:grid-cols-4';
|
||||
default: return 'lg:grid-cols-1';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className=" shadow-lg rounded-sm w-full max-w-[1280px] px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] font-inter flex flex-col items-center justify-center max-h-[720px] aspect-video bg-white relative z-20 mx-auto"
|
||||
|
||||
>
|
||||
<div className="text-center mb-4 lg:mb-16 w-full">
|
||||
{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 || 0)} gap-3 lg:gap-6 w-full`}>
|
||||
{items && items.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="flex flex-col w-full rounded-lg overflow-hidden relative"
|
||||
>
|
||||
{/* Image */}
|
||||
<div className="max-md:h-[140px] max-lg:h-[180px] h-48 w-full">
|
||||
<img
|
||||
src={item.image?.__image_url__ || ''}
|
||||
alt={item.image?.__image_prompt__ || item.heading}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="space-y-2 p-3 lg:p-6">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type3SlideLayout
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
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 } from "recharts";
|
||||
import * as z from "zod";
|
||||
|
||||
export const layoutId = 'type4-slide'
|
||||
export const layoutName = 'Type4 Slide'
|
||||
export const layoutDescription = 'A chart-focused layout with title, chart visualization, and description text.'
|
||||
|
||||
const chartDataSchema = z.object({
|
||||
name: z.string().meta({ description: "Data point name" }),
|
||||
value: z.number().meta({ description: "Data point value" }),
|
||||
category: z.string().optional().meta({ description: "Category for grouping" }),
|
||||
x: z.number().optional().meta({ description: "X coordinate for scatter plots" }),
|
||||
y: z.number().optional().meta({ description: "Y coordinate for scatter plots" }),
|
||||
});
|
||||
|
||||
|
||||
const type4SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Chart Analysis').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(130).default('This chart shows important data trends and insights that help understand the current situation and make informed decisions.').meta({
|
||||
description: "Description text for the chart",
|
||||
}),
|
||||
chartData: z.any().optional().meta({
|
||||
description: "Chart data object",
|
||||
}),
|
||||
isFullSizeChart: z.boolean().default(false).meta({
|
||||
description: "Whether to display chart in full size mode",
|
||||
}),
|
||||
chartType: z.enum(['bar', 'line', 'pie', 'area', 'scatter']).default('bar').meta({
|
||||
description: "Type of chart to display",
|
||||
}),
|
||||
data: z.array(chartDataSchema).min(2).max(10).default([
|
||||
{ name: '2021', value: 5 },
|
||||
{ name: '2022', value: 12 },
|
||||
{ name: '2023', value: 18 },
|
||||
{ name: '2024', value: 23 },
|
||||
{ name: '2025', value: 26 },
|
||||
]).meta({
|
||||
description: "Chart data points",
|
||||
}),
|
||||
dataKey: z.string().default('value').meta({
|
||||
description: "Key field for chart values",
|
||||
}),
|
||||
categoryKey: z.string().default('name').meta({
|
||||
description: "Key field for chart categories",
|
||||
}),
|
||||
color: z.string().default('#3b82f6').meta({
|
||||
description: "Primary color for chart elements",
|
||||
}),
|
||||
showLegend: z.boolean().default(false).meta({
|
||||
description: "Whether to show chart legend",
|
||||
}),
|
||||
showTooltip: z.boolean().default(true).meta({
|
||||
description: "Whether to show chart tooltip",
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
const chartConfig = {
|
||||
value: {
|
||||
label: "Value",
|
||||
},
|
||||
name: {
|
||||
label: "Name",
|
||||
},
|
||||
};
|
||||
const CHART_COLORS = [
|
||||
'#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6',
|
||||
'#06b6d4', '#84cc16', '#f97316', '#ec4899', '#6366f1'
|
||||
];
|
||||
|
||||
export const Schema = type4SlideSchema
|
||||
|
||||
export type Type4SlideData = z.infer<typeof type4SlideSchema>
|
||||
|
||||
interface Type4SlideLayoutProps {
|
||||
data: Partial<Type4SlideData>
|
||||
}
|
||||
|
||||
const Type4SlideLayout: React.FC<Type4SlideLayoutProps> = ({ data: slideData }) => {
|
||||
|
||||
const { title, description, data, dataKey, categoryKey, color, showLegend = false, showTooltip = true, chartType = 'bar' } = slideData;
|
||||
|
||||
const chartData = data || [];
|
||||
const renderChart = () => {
|
||||
const commonProps = {
|
||||
data: chartData,
|
||||
margin: { top: 10, right: 20, left: 0, bottom: 30 },
|
||||
};
|
||||
|
||||
switch (chartType) {
|
||||
case 'bar':
|
||||
return (
|
||||
<BarChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Bar dataKey={dataKey || 'value'} fill={color} radius={[4, 4, 0, 0]} />
|
||||
</BarChart>
|
||||
);
|
||||
|
||||
case 'line':
|
||||
return (
|
||||
<LineChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey={dataKey || 'value'}
|
||||
stroke={color}
|
||||
strokeWidth={3}
|
||||
dot={{ fill: color, strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
</LineChart>
|
||||
);
|
||||
|
||||
case 'area':
|
||||
return (
|
||||
<AreaChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey={dataKey || 'value'}
|
||||
stroke={color}
|
||||
fill={color}
|
||||
fillOpacity={0.6}
|
||||
/>
|
||||
</AreaChart>
|
||||
);
|
||||
|
||||
case 'pie':
|
||||
return (
|
||||
<PieChart margin={{ top: 10, right: 10, left: 10, bottom: 10 }}>
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Pie
|
||||
data={chartData}
|
||||
cx="50%"
|
||||
cy="40%"
|
||||
outerRadius={70}
|
||||
fill={color}
|
||||
dataKey={dataKey || 'value'}
|
||||
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
|
||||
>
|
||||
{chartData.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
);
|
||||
|
||||
case 'scatter':
|
||||
return (
|
||||
<ScatterChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="x" type="number" />
|
||||
<YAxis dataKey="y" type="number" />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Scatter dataKey={dataKey || 'value'} fill={color} />
|
||||
</ScatterChart>
|
||||
);
|
||||
|
||||
default:
|
||||
return <div>Unsupported chart type</div>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
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"
|
||||
|
||||
>
|
||||
{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">
|
||||
<div className="flex-1 bg-white rounded-lg shadow-sm border border-gray-100 p-4">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
{renderChart()}
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full text-center">
|
||||
{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>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type4SlideLayout
|
||||
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
|
||||
export const layoutId = 'type5-slide'
|
||||
export const layoutName = 'Type5 Slide'
|
||||
export const layoutDescription = 'A two-column layout with title and description on the left, and numbered items with large numerals on the right.'
|
||||
|
||||
const type5SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Key Points').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(130).default('Here is the main description that provides context and introduction to the numbered points on the right side.').meta({
|
||||
description: "Main description text",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'First Key Point',
|
||||
description: 'Detailed explanation of the first important point that supports the main topic'
|
||||
},
|
||||
{
|
||||
heading: 'Second Key Point',
|
||||
description: 'Detailed explanation of the second important point with relevant information'
|
||||
},
|
||||
{
|
||||
heading: 'Third Key Point',
|
||||
description: 'Detailed explanation of the third important point that concludes the discussion'
|
||||
}
|
||||
]).meta({
|
||||
description: "List of numbered items (2-3 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type5SlideSchema
|
||||
|
||||
export type Type5SlideData = z.infer<typeof type5SlideSchema>
|
||||
|
||||
interface Type5SlideLayoutProps {
|
||||
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"
|
||||
|
||||
>
|
||||
<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 ">
|
||||
{title && <h1 className="text-gray-900 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">
|
||||
{description}
|
||||
</p>}
|
||||
</div>
|
||||
|
||||
{/* Right section - Numbered items */}
|
||||
<div className="lg:w-1/2 relative">
|
||||
<div className="space-y-3 lg:space-y-6">
|
||||
{slideData?.items?.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<div className="flex gap-6">
|
||||
<div className="text-[26px] lg:text-[32px] leading-[40px] px-1 font-bold mb-4 text-blue-600">
|
||||
{`0${index + 1}`}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type5SlideLayout
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { IconSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'type6-slide'
|
||||
export const layoutName = 'Type6 Slide'
|
||||
export const layoutDescription = 'A centered title with a flexible grid of icon-based content items, adapting layout based on item count.'
|
||||
|
||||
const type6SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Our Services').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
}),
|
||||
icon: IconSchema,
|
||||
})).min(2).max(6).default([
|
||||
{
|
||||
heading: 'Professional Service',
|
||||
description: 'High-quality professional services tailored to your specific needs and requirements',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Professional Service'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Expert Consultation',
|
||||
description: 'Expert advice and consultation from experienced professionals in the field',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Expert Consultation'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Quality Assurance',
|
||||
description: 'Comprehensive quality assurance processes to ensure excellent results',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Quality Assurance'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Customer Support',
|
||||
description: 'Dedicated customer support available to assist you throughout the process',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Customer Support'
|
||||
}
|
||||
}
|
||||
]).meta({
|
||||
description: "List of service items (2-6 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type6SlideSchema
|
||||
|
||||
export type Type6SlideData = z.infer<typeof type6SlideSchema>
|
||||
|
||||
interface Type6SlideLayoutProps {
|
||||
data: Partial<Type6SlideData>
|
||||
}
|
||||
|
||||
const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, items } = slideData;
|
||||
const isGridLayout = items && items.length >= 4
|
||||
|
||||
const getGridCols = (length: number) => {
|
||||
switch (length) {
|
||||
case 1: return 'lg:grid-cols-1';
|
||||
case 2: return 'lg:grid-cols-2';
|
||||
case 3: return 'lg:grid-cols-3';
|
||||
case 4: return 'lg:grid-cols-4';
|
||||
case 5: return 'lg:grid-cols-5';
|
||||
case 6: return 'lg:grid-cols-6';
|
||||
default: return 'lg:grid-cols-1';
|
||||
}
|
||||
}
|
||||
|
||||
const renderGridContent = () => {
|
||||
return (
|
||||
<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={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="w-full rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<div className="flex items-start gap-2 mg:gap-4">
|
||||
<div className="flex-shrink-0 lg:w-16">
|
||||
<div className="w-12 h-12 lg:w-16 lg:h-16 bg-blue-600 rounded-lg flex items-center justify-center text-white text-xl lg:text-2xl">
|
||||
<img src={item.icon.__icon_url__} className='w-full h-full object-contain' alt={item.icon.__icon_query__} />
|
||||
</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>
|
||||
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const renderHorizontalContent = () => {
|
||||
return (
|
||||
<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={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="w-full rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<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 text-white text-2xl lg:text-3xl mx-auto mb-4">
|
||||
<img src={item.icon.__icon_url__} className='w-full h-full object-contain' alt={item.icon.__icon_query__} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="lg:space-y-4 mt-2 lg:mt-4">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
>
|
||||
<div className="text-center sm:pb-2 lg:pb-8 w-full">
|
||||
{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()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type6SlideLayout
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { IconSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'type7-slide'
|
||||
export const layoutName = 'Type7 Slide'
|
||||
export const layoutDescription = 'A centered title with a flexible grid of icon-based content items, adapting layout based on item count.'
|
||||
|
||||
const type7SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Our Services').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
}),
|
||||
icon: IconSchema.default({
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Default icon'
|
||||
}).meta({
|
||||
description: "Icon for the item",
|
||||
})
|
||||
})).min(2).max(6).default([
|
||||
{
|
||||
heading: 'Professional Service',
|
||||
description: 'High-quality professional services tailored to your specific needs and requirements',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Professional service icon'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Expert Consultation',
|
||||
description: 'Expert advice and consultation from experienced professionals in the field',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Expert consultation icon'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Quality Assurance',
|
||||
description: 'Comprehensive quality assurance processes to ensure excellent results',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Quality assurance icon'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Customer Support',
|
||||
description: 'Dedicated customer support available to assist you throughout the process',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Customer support icon'
|
||||
}
|
||||
}
|
||||
]).meta({
|
||||
description: "List of service items (2-6 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type7SlideSchema
|
||||
|
||||
export type Type7SlideData = z.infer<typeof type7SlideSchema>
|
||||
|
||||
interface Type7SlideLayoutProps {
|
||||
data: Partial<Type7SlideData>
|
||||
}
|
||||
|
||||
const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, items } = slideData;
|
||||
const isGridLayout = items && items.length >= 4
|
||||
|
||||
const getGridCols = (length: number) => {
|
||||
switch (length) {
|
||||
case 1: return 'lg:grid-cols-1';
|
||||
case 2: return 'lg:grid-cols-2';
|
||||
case 3: return 'lg:grid-cols-3';
|
||||
case 4: return 'lg:grid-cols-4';
|
||||
case 5: return 'lg:grid-cols-5';
|
||||
case 6: return 'lg:grid-cols-6';
|
||||
default: return 'lg:grid-cols-1';
|
||||
}
|
||||
}
|
||||
|
||||
const renderGridContent = () => {
|
||||
return (
|
||||
<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={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="w-full rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<div className="flex items-start gap-2 md:gap-4">
|
||||
<div className="flex-shrink-0 lg:w-16">
|
||||
<div className="w-12 h-12 lg:w-16 lg:h-16 bg-blue-600 rounded-lg flex items-center justify-center overflow-hidden">
|
||||
<img
|
||||
src={item.icon?.__icon_url__ || ''}
|
||||
alt={item.icon?.__icon_query__ || item.heading}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const renderHorizontalContent = () => {
|
||||
return (
|
||||
<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={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="w-full rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<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">
|
||||
{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">
|
||||
{item.heading && <h3 className="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 leading-tight text-center">
|
||||
{item.heading}
|
||||
</h3>}
|
||||
{item.description && <p className="text-sm sm:text-base lg:text-lg text-gray-700 leading-relaxed text-center">
|
||||
{item.description}
|
||||
</p>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
>
|
||||
<div className="text-center sm:pb-2 lg:pb-8 w-full">
|
||||
{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()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type7SlideLayout
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
import React from 'react'
|
||||
import * as z from "zod";
|
||||
import { IconSchema } from '@/presentation-templates/defaultSchemes';
|
||||
|
||||
export const layoutId = 'type8-slide'
|
||||
export const layoutName = 'Type8 Slide'
|
||||
export const layoutDescription = 'A two-column layout with title and description on the left, and icon-based items on the right.'
|
||||
|
||||
const type8SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Key Features').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(130).default('Here is the main description that provides context and introduces the key features outlined on the right side.').meta({
|
||||
description: "Main description text",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
}),
|
||||
icon: IconSchema.default({
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Default icon'
|
||||
}).meta({
|
||||
description: "Icon for the item",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'Advanced Features',
|
||||
description: 'Cutting-edge functionality designed to enhance productivity and user experience',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Advanced features icon'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Reliable Performance',
|
||||
description: 'Consistent and dependable performance across all platforms and devices',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Reliable performance icon'
|
||||
}
|
||||
},
|
||||
{
|
||||
heading: 'Secure Environment',
|
||||
description: 'Enterprise-grade security measures to protect your data and privacy',
|
||||
icon: {
|
||||
__icon_url__: '/static/icons/placeholder.png',
|
||||
__icon_query__: 'Secure environment icon'
|
||||
}
|
||||
}
|
||||
]).meta({
|
||||
description: "List of featured items (2-3 items)",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = type8SlideSchema
|
||||
|
||||
export type Type8SlideData = z.infer<typeof type8SlideSchema>
|
||||
|
||||
interface Type8SlideLayoutProps {
|
||||
data: Partial<Type8SlideData>
|
||||
}
|
||||
|
||||
const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, description, items } = slideData;
|
||||
|
||||
const renderItems = () => {
|
||||
if (items && items.length === 2) {
|
||||
// Vertical stacked layout for 2 items
|
||||
return (
|
||||
<div className="space-y-4 lg:space-y-8">
|
||||
{items && items.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<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">
|
||||
{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">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
// Horizontal layout with side icons for 3+ items
|
||||
return (
|
||||
<div className="space-y-4 lg:space-y-8">
|
||||
{items && items.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<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">
|
||||
{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">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className=" shadow-lg w-full max-w-[1280px] rounded-sm font-inter px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] flex items-center justify-center max-h-[720px] aspect-video bg-white relative z-20 mx-auto"
|
||||
>
|
||||
<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">
|
||||
{title && <h1 className="text-gray-900 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">
|
||||
{description}
|
||||
</p>}
|
||||
</div>
|
||||
|
||||
{/* Right section - Items */}
|
||||
<div className="relative">
|
||||
{renderItems()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type8SlideLayout
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
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 * as z from "zod";
|
||||
|
||||
export const layoutId = 'type4-slide'
|
||||
export const layoutName = 'Type4 Slide'
|
||||
export const layoutDescription = 'A chart-focused layout with title, chart visualization, and description text.'
|
||||
|
||||
const chartDataSchema = z.object({
|
||||
name: z.string().meta({ description: "Data point name" }),
|
||||
value: z.number().meta({ description: "Data point value" }),
|
||||
category: z.string().optional().meta({ description: "Category for grouping" }),
|
||||
x: z.number().optional().meta({ description: "X coordinate for scatter plots" }),
|
||||
y: z.number().optional().meta({ description: "Y coordinate for scatter plots" }),
|
||||
});
|
||||
|
||||
|
||||
const type9SlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Chart Analysis').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
heading: z.string().min(2).max(50).meta({
|
||||
description: "Item heading",
|
||||
}),
|
||||
description: z.string().min(10).max(130).meta({
|
||||
description: "Item description",
|
||||
})
|
||||
})).min(2).max(3).default([
|
||||
{
|
||||
heading: 'First Key Point',
|
||||
description: 'Detailed explanation of the first important point that supports the main topic'
|
||||
},
|
||||
{
|
||||
heading: 'Second Key Point',
|
||||
description: 'Detailed explanation of the second important point with relevant information'
|
||||
},
|
||||
{
|
||||
heading: 'Third Key Point',
|
||||
description: 'Detailed explanation of the third important point that concludes the discussion'
|
||||
}
|
||||
]).meta({
|
||||
description: "List of numbered items (2-3 items)",
|
||||
}),
|
||||
chartData: z.any().optional().meta({
|
||||
description: "Chart data object",
|
||||
}),
|
||||
isFullSizeChart: z.boolean().default(false).meta({
|
||||
description: "Whether to display chart in full size mode",
|
||||
}),
|
||||
chartType: z.enum(['bar', 'line', 'pie', 'area', 'scatter']).default('pie').meta({
|
||||
description: "Type of chart to display",
|
||||
}),
|
||||
data: z.array(chartDataSchema).min(2).max(10).default([
|
||||
{ name: '2021', value: 5 },
|
||||
{ name: '2022', value: 12 },
|
||||
{ name: '2023', value: 18 },
|
||||
{ name: '2024', value: 23 },
|
||||
{ name: '2025', value: 26 },
|
||||
]).meta({
|
||||
description: "Chart data points",
|
||||
}),
|
||||
dataKey: z.string().default('value').meta({
|
||||
description: "Key field for chart values",
|
||||
}),
|
||||
categoryKey: z.string().default('name').meta({
|
||||
description: "Key field for chart categories",
|
||||
}),
|
||||
color: z.string().default('#3b82f6').meta({
|
||||
description: "Primary color for chart elements",
|
||||
}),
|
||||
showLegend: z.boolean().default(false).meta({
|
||||
description: "Whether to show chart legend",
|
||||
}),
|
||||
showTooltip: z.boolean().default(true).meta({
|
||||
description: "Whether to show chart tooltip",
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
const chartConfig = {
|
||||
value: {
|
||||
label: "Value",
|
||||
},
|
||||
name: {
|
||||
label: "Name",
|
||||
},
|
||||
};
|
||||
const CHART_COLORS = [
|
||||
'#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6',
|
||||
'#06b6d4', '#84cc16', '#f97316', '#ec4899', '#6366f1'
|
||||
];
|
||||
|
||||
export const Schema = type9SlideSchema
|
||||
|
||||
export type Type9SlideData = z.infer<typeof type9SlideSchema>
|
||||
|
||||
interface Type9SlideLayoutProps {
|
||||
data: Partial<Type9SlideData>
|
||||
}
|
||||
|
||||
const Type9SlideLayout: React.FC<Type9SlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, items, data, chartType = 'line', color = '#3b82f6', dataKey = 'value', categoryKey = 'name', showLegend = false, showTooltip = true } = slideData;
|
||||
const chartData = data || [];
|
||||
const renderChart = () => {
|
||||
const commonProps = {
|
||||
data: chartData,
|
||||
margin: { top: 10, right: 20, left: 0, bottom: 30 },
|
||||
};
|
||||
|
||||
switch (chartType) {
|
||||
case 'bar':
|
||||
return (
|
||||
<BarChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Bar dataKey={dataKey} fill={color} radius={[4, 4, 0, 0]} />
|
||||
</BarChart>
|
||||
);
|
||||
|
||||
case 'line':
|
||||
return (
|
||||
<LineChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey={dataKey}
|
||||
stroke={color}
|
||||
strokeWidth={3}
|
||||
dot={{ fill: color, strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
</LineChart>
|
||||
);
|
||||
|
||||
case 'area':
|
||||
return (
|
||||
<AreaChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={categoryKey} />
|
||||
<YAxis />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey={dataKey}
|
||||
stroke={color}
|
||||
fill={color}
|
||||
fillOpacity={0.6}
|
||||
/>
|
||||
</AreaChart>
|
||||
);
|
||||
|
||||
case 'pie':
|
||||
return (
|
||||
<ResponsiveContainer >
|
||||
<PieChart margin={{ top: 0, right: 0, left: 0, bottom: 0 }}>
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Pie
|
||||
isAnimationActive={false}
|
||||
data={chartData}
|
||||
cx="50%"
|
||||
cy="40%"
|
||||
outerRadius={80}
|
||||
fill={color}
|
||||
dataKey={dataKey}
|
||||
|
||||
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
|
||||
>
|
||||
{chartData && chartData.map((entry: any, index: number) => (
|
||||
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
|
||||
case 'scatter':
|
||||
return (
|
||||
<ScatterChart {...commonProps}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="x" type="number" />
|
||||
<YAxis dataKey="y" type="number" />
|
||||
{showTooltip && <ChartTooltip content={<ChartTooltipContent />} />}
|
||||
{showLegend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
<Scatter dataKey="value" fill={color} />
|
||||
</ScatterChart>
|
||||
);
|
||||
|
||||
default:
|
||||
return <div>Unsupported chart type</div>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
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"
|
||||
|
||||
>
|
||||
{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">
|
||||
<div className="flex-1 bg-white rounded-lg shadow-sm border border-gray-100 p-4">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
{renderChart()}
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</div>
|
||||
<div className="lg:w-1/2 relative">
|
||||
<div className="space-y-3 lg:space-y-6">
|
||||
{items && items.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
boxShadow: "0 2px 10px 0 rgba(43, 43, 43, 0.2)",
|
||||
}}
|
||||
className="rounded-lg p-3 lg:p-6 relative"
|
||||
>
|
||||
<div className="flex gap-6">
|
||||
<div className="text-[26px] lg:text-[32px] leading-[40px] px-1 font-bold mb-4 text-blue-600">
|
||||
{`0${index + 1}`}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{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>}
|
||||
{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>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Type9SlideLayout
|
||||
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
import React, { useEffect, useRef } from 'react'
|
||||
import * as z from "zod";
|
||||
|
||||
export const layoutId = 'type-mermaid-slide'
|
||||
export const layoutName = 'Mermaid Chart Slide'
|
||||
export const layoutDescription = 'A clean layout for displaying Mermaid diagrams with title and optional description.'
|
||||
|
||||
const typeMermaidSlideSchema = z.object({
|
||||
title: z.string().min(3).max(50).default('Process Flow').meta({
|
||||
description: "Main title of the slide",
|
||||
}),
|
||||
description: z.string().min(10).max(200).optional().meta({
|
||||
description: "Optional description text to provide context for the diagram",
|
||||
}),
|
||||
mermaidCode: z.string().min(10).default(`graph LR
|
||||
A[Start] --> B{Is it working?}
|
||||
B -->|Yes| C[Great!]
|
||||
B -->|No| D[Fix it]
|
||||
D --> B
|
||||
C --> E[End]`).meta({
|
||||
description: "Mermaid diagram code, and it must be a graph LR",
|
||||
}),
|
||||
theme: z.enum(['default', 'dark', 'forest', 'neutral']).default('default').meta({
|
||||
description: "Mermaid theme to use",
|
||||
})
|
||||
})
|
||||
|
||||
export const Schema = typeMermaidSlideSchema
|
||||
|
||||
export type TypeMermaidSlideData = z.infer<typeof typeMermaidSlideSchema>
|
||||
|
||||
interface TypeMermaidSlideLayoutProps {
|
||||
data: Partial<TypeMermaidSlideData>
|
||||
}
|
||||
|
||||
const TypeMermaidSlideLayout: React.FC<TypeMermaidSlideLayoutProps> = ({ data: slideData }) => {
|
||||
const { title, description, mermaidCode, theme } = slideData;
|
||||
const mermaidRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const loadMermaid = async () => {
|
||||
try {
|
||||
// Dynamically import mermaid
|
||||
const mermaid = (await import('mermaid')).default;
|
||||
|
||||
// Initialize mermaid with the selected theme
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: theme || 'default',
|
||||
themeVariables: {
|
||||
primaryColor: '#3b82f6',
|
||||
primaryTextColor: '#1f2937',
|
||||
primaryBorderColor: '#e5e7eb',
|
||||
lineColor: '#6b7280',
|
||||
secondaryColor: '#f3f4f6',
|
||||
tertiaryColor: '#ffffff'
|
||||
},
|
||||
flowchart: {
|
||||
useMaxWidth: true,
|
||||
htmlLabels: true,
|
||||
curve: 'basis'
|
||||
}
|
||||
});
|
||||
|
||||
if (mermaidRef.current && mermaidCode) {
|
||||
// Clear previous content
|
||||
mermaidRef.current.innerHTML = '';
|
||||
|
||||
// Create a unique ID for this diagram
|
||||
const diagramId = `mermaid-${Date.now()}`;
|
||||
|
||||
// Render the diagram
|
||||
const { svg } = await mermaid.render(diagramId, mermaidCode);
|
||||
mermaidRef.current.innerHTML = svg;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading or rendering mermaid:', error);
|
||||
if (mermaidRef.current) {
|
||||
mermaidRef.current.innerHTML = `
|
||||
<div class="flex items-center justify-center h-full text-red-500">
|
||||
<div class="text-center">
|
||||
<p class="text-lg font-semibold">Error rendering diagram</p>
|
||||
<p class="text-sm mt-2">Please check your Mermaid syntax</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loadMermaid();
|
||||
}, [mermaidCode, theme]);
|
||||
|
||||
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 flex-col items-center justify-center aspect-video bg-white relative z-20 mx-auto">
|
||||
{/* Title */}
|
||||
{title && (
|
||||
<h1 className="text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold text-gray-900 mb-4 lg:mb-8 text-center">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal mb-6 lg:mb-8 text-center max-w-4xl">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Mermaid Diagram Container */}
|
||||
<div className="flex-1 w-full flex items-center justify-center">
|
||||
<div
|
||||
ref={mermaidRef}
|
||||
className="w-full h-full flex items-center justify-center min-h-[300px] max-h-[400px] overflow-hidden"
|
||||
style={{
|
||||
// Ensure the SVG scales properly
|
||||
maxWidth: '100%',
|
||||
maxHeight: '100%'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Fallback content if no mermaid code is provided */}
|
||||
{!mermaidCode && (
|
||||
<div className="flex-1 w-full flex items-center justify-center">
|
||||
<div className="text-center text-gray-500">
|
||||
<p className="text-lg font-semibold">No diagram to display</p>
|
||||
<p className="text-sm mt-2">Please provide Mermaid diagram code</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TypeMermaidSlideLayout
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"description": "Default layout for presentations",
|
||||
"ordered": false,
|
||||
"default": false
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue