diff --git a/servers/nextjs/presentation-layouts/classic/Type10SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type10SlideLayout.tsx new file mode 100644 index 00000000..5acad87d --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type10SlideLayout.tsx @@ -0,0 +1,269 @@ +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 + +interface Type10SlideLayoutProps { + data: Partial +} + +const Type10SlideLayout: React.FC = ({ 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 ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'line': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'area': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'pie': + return ( + + {showTooltip && } />} + {showLegend && } />} + `${name} ${(percent * 100).toFixed(0)}%`} + > + {chartData.map((entry: any, index: number) => ( + + ))} + + + ); + + case 'scatter': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + default: + return
Unsupported chart type
; + } + }; + + return ( +
+
+ + {title &&

+ {title || 'Chart Analysis'} +

} + +
+
+
+
+ + {renderChart()} + +
+
+
+
+ {items && items.map((item, index) => ( +
+
+
+
+ {item.icon?.__icon_url__ && {item.icon?.__icon_query__} +
+
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+
+ ))} +
+
+
+
+ ) +} + +export default Type10SlideLayout + diff --git a/servers/nextjs/presentation-layouts/classic/Type1SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type1SlideLayout.tsx new file mode 100644 index 00000000..75b945ed --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type1SlideLayout.tsx @@ -0,0 +1,65 @@ +import React from 'react' +import * as z from "zod"; +import { ImageSchema } from '@/presentation-layouts/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 + +interface Type1SlideLayoutProps { + data: Partial +} + +const Type1SlideLayout: React.FC = ({ data: slideData }) => { + const { title, description, image } = slideData; + return ( +
+
+
+ {/* Title */} + {title &&

+ {title} +

} + + {/* Description */} + {description &&

+ {description} +

} +
+ + {/* Image */} +
+ {image && {image?.__image_prompt__} +
+
+
+ ) +} + +export default Type1SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type2NumberedSlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type2NumberedSlideLayout.tsx new file mode 100644 index 00000000..76457ca6 --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type2NumberedSlideLayout.tsx @@ -0,0 +1,124 @@ +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 + +interface Type2NumberedSlideLayoutProps { + data: Partial +} + +const Type2NumberedSlideLayout: React.FC = ({ 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 ( +
+ {items?.map((item, index) => ( +
+
+
+ {numberTranslations[index] || `0${index + 1}`} +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+
+ ))} +
+ ) + } + + const renderHorizontalContent = () => { + return ( +
+ {items?.map((item, index) => ( +
+
+ {numberTranslations[index] || `0${index + 1}`} +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+ ) + } + + return ( +
+
+ {title &&

+ {title} +

} +
+ + {isGridLayout ? renderGridContent() : renderHorizontalContent()} +
+ ) +} + +export default Type2NumberedSlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type2SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type2SlideLayout.tsx new file mode 100644 index 00000000..275a6fe7 --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type2SlideLayout.tsx @@ -0,0 +1,111 @@ +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 + +interface Type2SlideLayoutProps { + data: Partial +} + +const Type2SlideLayout: React.FC = ({ data: slideData }) => { + const { title, items } = slideData; + const isGridLayout = items?.length && items?.length >= 4 + + const renderGridContent = () => { + return ( +
+ {items?.map((item, index) => ( +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+ ) + } + + const renderHorizontalContent = () => { + return ( +
+ {items?.map((item, index) => ( +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+ ) + } + + return ( +
+
+ {title &&

+ {title} +

} +
+ + {isGridLayout ? renderGridContent() : renderHorizontalContent()} +
+ ) +} + +export default Type2SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type2TimelineSlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type2TimelineSlideLayout.tsx new file mode 100644 index 00000000..0a62e82a --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type2TimelineSlideLayout.tsx @@ -0,0 +1,101 @@ +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 + +interface Type2TimelineSlideLayoutProps { + data: Partial +} + +const Type2TimelineSlideLayout: React.FC = ({ data: slideData }) => { + const { title, items } = slideData; + + const renderTimelineContent = () => { + return ( +
+ {/* Timeline Header with Numbers and Line */} +
+ {/* Horizontal Line */} +
+ + {/* Timeline Numbers */} + {items && items.map((_, index) => ( +
+ {index + 1} +
+ ))} +
+ + {/* Timeline Content */} +
+ {items && items.map((item, index) => ( +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+
+ ) + } + + return ( +
+
+ {title &&

+ {title} +

} +
+ + {renderTimelineContent()} +
+ ) +} + +export default Type2TimelineSlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type3SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type3SlideLayout.tsx new file mode 100644 index 00000000..f520e7f5 --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type3SlideLayout.tsx @@ -0,0 +1,119 @@ +import React from 'react' +import * as z from "zod"; +import { ImageSchema } from '@/presentation-layouts/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 + +interface Type3SlideLayoutProps { + data: Partial +} + +const Type3SlideLayout: React.FC = ({ 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 ( +
+
+ {title &&

+ {title} +

} +
+ +
+ {items && items.map((item, index) => ( +
+ {/* Image */} +
+ {item.image?.__image_prompt__ +
+ + {/* Content */} +
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+
+ ) +} + +export default Type3SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type4SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type4SlideLayout.tsx new file mode 100644 index 00000000..da9ac603 --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type4SlideLayout.tsx @@ -0,0 +1,209 @@ +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 + +interface Type4SlideLayoutProps { + data: Partial +} + +const Type4SlideLayout: React.FC = ({ 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 ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'line': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'area': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'pie': + return ( + + {showTooltip && } />} + {showLegend && } />} + `${name} ${(percent * 100).toFixed(0)}%`} + > + {chartData.map((entry, index) => ( + + ))} + + + ); + + case 'scatter': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + default: + return
Unsupported chart type
; + } + }; + + return ( +
+ {title &&

+ {title} +

} + +
+
+
+ + {renderChart()} + +
+
+
+ {description &&

+ {description} +

} +
+
+
+ ) +} + +export default Type4SlideLayout + diff --git a/servers/nextjs/presentation-layouts/classic/Type5SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type5SlideLayout.tsx new file mode 100644 index 00000000..75fc2daa --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type5SlideLayout.tsx @@ -0,0 +1,101 @@ +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 + +interface Type5SlideLayoutProps { + data: Partial +} + +const Type5SlideLayout: React.FC = ({ data: slideData }) => { + + const { title, description, items } = slideData; + return ( +
+
+ {/* Left section - Title and Description */} +
+ {title &&

+ {title} +

} + + {description &&

+ {description} +

} +
+ + {/* Right section - Numbered items */} +
+
+ {slideData?.items?.map((item, index) => ( +
+
+
+ {`0${index + 1}`} +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+
+ ))} +
+
+
+
+ ) +} + +export default Type5SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type6SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type6SlideLayout.tsx new file mode 100644 index 00000000..004dadd3 --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type6SlideLayout.tsx @@ -0,0 +1,161 @@ +import React from 'react' +import * as z from "zod"; +import { IconSchema } from '@/presentation-layouts/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 + +interface Type6SlideLayoutProps { + data: Partial +} + +const Type6SlideLayout: React.FC = ({ 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 ( +
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) => ( +
+
+
+
+ {item.icon.__icon_query__} +
+
+
+

+ {item.heading} +

+

+ {item.description} +

+
+
+
+ ))} +
+ ) + } + + const renderHorizontalContent = () => { + return ( +
+ {items && items.map((item, index) => ( +
+
+
+ {item.icon.__icon_query__} +
+
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+ ) + } + + return ( +
+
+ {title &&

+ {title} +

} +
+ + {isGridLayout ? renderGridContent() : renderHorizontalContent()} +
+ ) +} + +export default Type6SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type7SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type7SlideLayout.tsx new file mode 100644 index 00000000..818e12d1 --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type7SlideLayout.tsx @@ -0,0 +1,173 @@ +import React from 'react' +import * as z from "zod"; +import { IconSchema } from '@/presentation-layouts/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 + +interface Type7SlideLayoutProps { + data: Partial +} + +const Type7SlideLayout: React.FC = ({ 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 ( +
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) => ( +
+
+
+
+ {item.icon?.__icon_query__ +
+
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+
+ ))} +
+ ) + } + + const renderHorizontalContent = () => { + return ( +
+ {items && items.map((item, index) => ( +
+
+
+ {item.icon?.__icon_url__ && {item.icon?.__icon_query__} +
+
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+ ) + } + + return ( +
+
+ {title &&

+ {title} +

} +
+ + {isGridLayout ? renderGridContent() : renderHorizontalContent()} +
+ ) +} + +export default Type7SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type8SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type8SlideLayout.tsx new file mode 100644 index 00000000..37002b4b --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type8SlideLayout.tsx @@ -0,0 +1,167 @@ +import React from 'react' +import * as z from "zod"; +import { IconSchema } from '@/presentation-layouts/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 + +interface Type8SlideLayoutProps { + data: Partial +} + +const Type8SlideLayout: React.FC = ({ data: slideData }) => { + const { title, description, items } = slideData; + + const renderItems = () => { + if (items && items.length === 2) { + // Vertical stacked layout for 2 items + return ( +
+ {items && items.map((item, index) => ( +
+
+
+ {item.icon?.__icon_url__ && {item.icon?.__icon_query__} +
+
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+ ))} +
+ ) + } else { + // Horizontal layout with side icons for 3+ items + return ( +
+ {items && items.map((item, index) => ( +
+
+
+
+ {item.icon?.__icon_url__ && {item.icon?.__icon_query__} +
+
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+
+ ))} +
+ ) + } + } + + return ( +
+
+ {/* Left section - Title and Description */} +
+ {title &&

+ {title} +

} + + {description &&

+ {description} +

} +
+ + {/* Right section - Items */} +
+ {renderItems()} +
+
+
+ ) +} + +export default Type8SlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/Type9SlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/Type9SlideLayout.tsx new file mode 100644 index 00000000..bdb8e29a --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/Type9SlideLayout.tsx @@ -0,0 +1,253 @@ +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 + +interface Type9SlideLayoutProps { + data: Partial +} + +const Type9SlideLayout: React.FC = ({ 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 ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'line': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'area': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + case 'pie': + return ( + + + {showTooltip && } />} + {showLegend && } />} + `${name} ${(percent * 100).toFixed(0)}%`} + > + {chartData && chartData.map((entry: any, index: number) => ( + + ))} + + + + ); + + case 'scatter': + return ( + + + + + {showTooltip && } />} + {showLegend && } />} + + + ); + + default: + return
Unsupported chart type
; + } + }; + + return ( +
+ {title &&

+ {title} +

} + +
+
+
+ + {renderChart()} + +
+
+
+
+ {items && items.map((item, index) => ( +
+
+
+ {`0${index + 1}`} +
+
+ {item.heading &&

+ {item.heading} +

} + {item.description &&

+ {item.description} +

} +
+
+
+ ))} +
+
+
+
+ ) +} + +export default Type9SlideLayout + diff --git a/servers/nextjs/presentation-layouts/classic/TypeMermaidSlideLayout.tsx b/servers/nextjs/presentation-layouts/classic/TypeMermaidSlideLayout.tsx new file mode 100644 index 00000000..7f97809a --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/TypeMermaidSlideLayout.tsx @@ -0,0 +1,136 @@ +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 + +interface TypeMermaidSlideLayoutProps { + data: Partial +} + +const TypeMermaidSlideLayout: React.FC = ({ data: slideData }) => { + const { title, description, mermaidCode, theme } = slideData; + const mermaidRef = useRef(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 = ` +
+
+

Error rendering diagram

+

Please check your Mermaid syntax

+
+
+ `; + } + } + }; + + loadMermaid(); + }, [mermaidCode, theme]); + + return ( +
+ {/* Title */} + {title && ( +

+ {title} +

+ )} + + {/* Description */} + {description && ( +

+ {description} +

+ )} + + {/* Mermaid Diagram Container */} +
+
+
+ + {/* Fallback content if no mermaid code is provided */} + {!mermaidCode && ( +
+
+

No diagram to display

+

Please provide Mermaid diagram code

+
+
+ )} +
+ ) +} + +export default TypeMermaidSlideLayout \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/classic/settings.json b/servers/nextjs/presentation-layouts/classic/settings.json new file mode 100644 index 00000000..af6e3e7d --- /dev/null +++ b/servers/nextjs/presentation-layouts/classic/settings.json @@ -0,0 +1,5 @@ +{ + "description": "Default layout for presentations", + "ordered": false, + "default": false +} \ No newline at end of file