diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationAboutSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationAboutSlide.tsx new file mode 100644 index 00000000..b8502868 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationAboutSlide.tsx @@ -0,0 +1,112 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-about-slide"; +export const slideLayoutName = "Education About Slide"; +export const slideLayoutDescription = + "A left text column with company introduction and a right-side visual grid made from one repeated image and tinted text panels."; + +export const Schema = z.object({ + companyName: z.string().min(3).max(22).default("Company Name").meta({ + description: "Main heading in the left content column.", + }), + intro: z.string().min(40).max(120).default( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et." + ).meta({ + description: "Bold intro text shown beneath the company heading.", + }), + body: z.string().min(120).max(280).default( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi." + ).meta({ + description: "Body paragraph in the left content section.", + }), + topPanelText: z.string().min(20).max(70).default("Insert info about the company.").meta({ + description: "Short text inside the top-right dark panel. ", + }), + bottomPanelText: z.string().min(20).max(70).default("Insert info about the company and your mission statement.").meta({ + description: "Short text inside the bottom-right dark panel.", + }), + topFeatureImage: z.object({ + __image_url__: z.string().default("https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80"), + __image_prompt__: z.string().min(10).max(200).default("Office team collaboration"), + }).default({ + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Office team collaboration", + }).meta({ + description: "Single image reused in the right-side visual grid.", + }), + bottomFeatureImage: z.object({ + __image_url__: z.string().default("https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80"), + __image_prompt__: z.string().min(10).max(200).default("Office team collaboration"), + }).default({ + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Office team collaboration", + }).meta({ + description: "Single image reused in the right-side visual grid.", + }), +}); + +export type SchemaType = z.infer; + +const EducationAboutSlide = ({ data }: { data: Partial }) => { + + + return (<> + + +
+
+
+

+ {data.companyName} +

+

+ {data.intro} +

+

+ {data.body} +

+
+ +
+
+ {data.topFeatureImage?.__image_prompt__} +
+

+ {data.topPanelText} +

+
+
+ +
+
+ +
+ {data.bottomFeatureImage?.__image_prompt__} +
+ +
+
+

+ {data.bottomPanelText} +

+
+
+
+
+
+ + ); +}; + +export default EducationAboutSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationContentSplitSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationContentSplitSlide.tsx new file mode 100644 index 00000000..0061b169 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationContentSplitSlide.tsx @@ -0,0 +1,75 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-content-split-slide"; +export const slideLayoutName = "Education Content Split Slide"; +export const slideLayoutDescription = + "A left collage built from one repeated image and a right content block containing heading, tagline, and paragraph text."; + +export const Schema = z.object({ + heading: z.string().min(3).max(16).default("Heading").meta({ + description: "Main right-side heading.", + }), + tagline: z.string().min(3).max(12).default("TAGLINE").meta({ + description: "Small uppercase label shown under the heading.", + }), + body: z.string().min(80).max(300).default( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." + ).meta({ + description: "Main descriptive paragraph on the right side.", + }), + collageImage: z.object({ + __image_url__: z.string().default("https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80"), + __image_prompt__: z.string().min(10).max(200).default("Business team around a laptop"), + }).default({ + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Business team around a laptop", + }).meta({ + description: "Single image reused to create the left collage composition.", + }), +}); + +export type SchemaType = z.infer; + +const EducationContentSplitSlide = ({ data }: { data: Partial }) => { + const { heading, tagline, body, collageImage } = data; + + return ( +
+
+
+
+ {collageImage?.__image_prompt__} +
+
+
{collageImage?.__image_prompt__}
+
{collageImage?.__image_prompt__}
+
+
+ +
+

{data.heading}

+

+ {data.tagline} +

+

{body}

+
+
+
+ ); +}; + +export default EducationContentSplitSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationCoverSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationCoverSlide.tsx new file mode 100644 index 00000000..5e1ced4e --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationCoverSlide.tsx @@ -0,0 +1,54 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-cover-slide"; +export const slideLayoutName = "Education Cover Slide"; +export const slideLayoutDescription = + "A full-bleed cover slide with a single background image, a strong violet overlay, and centered company/title text."; + +export const Schema = z.object({ + companyName: z.string().min(3).max(24).default("COMPANY NAME").meta({ + description: "Small uppercase company label shown above the main title.", + }), + title: z.string().min(6).max(32).default("PowerPoint Template").meta({ + description: "Main centered title of the cover slide.", + }), + backgroundImage: z.object({ + __image_url__: z.string().default("https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&w=1920&q=80"), + __image_prompt__: z.string().min(10).max(200).default("City business district buildings"), + }).default({ + __image_url__: + "https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&w=1920&q=80", + __image_prompt__: "City business district buildings", + }).meta({ + description: "Single background image used across the cover.", + }), +}); + +export type SchemaType = z.infer; + +const EducationCoverSlide = ({ data }: { data: Partial }) => { + const { companyName, title, backgroundImage } = data; + + return ( +
+ {backgroundImage?.__image_prompt__} + +
+ + +
+

{data.companyName}

+

+ {title} +

+
+
+ ); +}; + +export default EducationCoverSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationImageGallerySlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationImageGallerySlide.tsx new file mode 100644 index 00000000..0f12403b --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationImageGallerySlide.tsx @@ -0,0 +1,79 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-image-gallery-slide"; +export const slideLayoutName = "Education Image Gallery Slide"; +export const slideLayoutDescription = + "A slide with a left image collage (one repeated image) and right text block for gallery heading and description."; + +export const Schema = z.object({ + title: z.string().min(3).max(16).default("Image Gallery").meta({ + description: "Heading on the right side.", + }), + body: z.string().min(70).max(200).default( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris." + ).meta({ + description: "Supporting paragraph shown below the heading.", + }), + galleryImages: z.array(z.object({ + __image_url__: z.string(), + __image_prompt__: z.string(), + })).max(5).min(5).default(Array(5).fill({ + __image_url__: "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Office team collaboration", + })).meta({ + description: "Image gallery images.", + }), +}); + +export type SchemaType = z.infer; + +const EducationImageGallerySlide = ({ data }: { data: Partial }) => { + + const { title, body, galleryImages } = data; + + return ( +
+
+
+ {galleryImages?.[0].__image_prompt__} + {galleryImages?.[1].__image_prompt__} + {galleryImages?.[2].__image_prompt__} + {galleryImages?.[3].__image_prompt__} + {galleryImages?.[4].__image_prompt__} +
+ +
+

+ {title} +

+

+ {body} +

+
+
+
+ ); +}; + +export default EducationImageGallerySlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationReportDonutSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationReportDonutSlide.tsx new file mode 100644 index 00000000..7bff8123 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationReportDonutSlide.tsx @@ -0,0 +1,130 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-report-donut-slide"; +export const slideLayoutName = "Education Report Donut Slide"; +export const slideLayoutDescription = + "A report slide with left-side title/content and a right-side donut chart with legend values."; + +const SegmentSchema = z.object({ + label: z.string().min(3).max(12).meta({ + description: "Legend label for one donut chart segment.", + }), + value: z.number().min(1).max(100).meta({ + description: "Percentage value for one chart segment.", + }), + color: z.string().min(4).max(20).meta({ + description: "Hex color value for one chart segment.", + }), +}); + +export const Schema = z.object({ + title: z.string().min(3).max(14).default("Report").meta({ + description: "Main heading in the left content area.", + }), + body: z.string().min(80).max(220).default( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris." + ).meta({ + description: "Main report paragraph on the left.", + }), + footnote: z.string().min(20).max(110).default( + "(Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt.)" + ).meta({ + description: "Footnote text shown at the bottom of the left area.", + }), + chartTitle: z.string().min(8).max(26).default("Students by Grade Level").meta({ + description: "Heading shown above the donut chart.", + }), + dateRange: z.string().min(8).max(22).default("Apr 10 - Apr 17").meta({ + description: "Date range label under the chart heading.", + }), + segments: z + .array(SegmentSchema) + .min(4) + .max(4) + .default([ + { label: "Option A", value: 17.07, color: "#4A15A8" }, + { label: "Option B", value: 45.23, color: "#5B45AD" }, + { label: "Option C", value: 21.61, color: "#876FC1" }, + { label: "Option D", value: 16.36, color: "#A89ACF" }, + ]) + .meta({ + description: "Four donut segments with labels and percentages.", + }), + +}); + +export type SchemaType = z.infer; + +const EducationReportDonutSlide = ({ data }: { data: Partial }) => { + const { title, body, footnote, chartTitle, dateRange, segments } = data; + + const total = segments?.reduce((sum, item) => sum + item.value, 0) || 0; + let cursor = 0; + const conicStops = segments + ?.map((segment) => { + const start = cursor; + const span = total > 0 ? (segment.value / total) * 100 : 0; + cursor += span; + return `${segment.color} ${start}% ${cursor}%`; + }) + .join(", "); + + return ( +
+
+
+
+ + +
+ +
+

+ {title} +

+ +

+ {body} +

+
+ +

+ {footnote} +

+
+ +
+

+ {chartTitle} +

+

{dateRange}

+ +
+
+
+
+
+ +
+ {segments?.map((segment, index) => ( +
+ + {segment.label} + + {segment.value.toFixed(2)}% + +
+ ))} +
+
+
+ +
+ ); +}; + +export default EducationReportDonutSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationServicesSplitSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationServicesSplitSlide.tsx new file mode 100644 index 00000000..ac5bc8fd --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationServicesSplitSlide.tsx @@ -0,0 +1,146 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-services-split-slide"; +export const slideLayoutName = "Education Services Split Slide"; +export const slideLayoutDescription = + "A services layout with left heading, one repeated image column, and two stacked service description blocks on the right."; + +const ServiceSchema = z.object({ + serviceImage: z.object({ + __image_url__: z.string(), + __image_prompt__: z.string(), + }).default({ + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Team meeting image reused across two rows", + }).meta({ + description: "Single image reused in the middle column.", + }), + heading: z.string().min(3).max(18).meta({ + description: "Service heading shown in the right column.", + }), + tagline: z.string().min(3).max(12).meta({ + description: "Short label under each service heading.", + }), + body: z.string().min(40).max(90).meta({ + description: "Service description paragraph.", + }), +}); + +export const Schema = z.object({ + title: z.string().min(4).max(12).default("Services").meta({ + description: "Main slide title shown on the left.", + }), + sections: z + .array(ServiceSchema) + .min(2) + .max(4) + .default([ + { + serviceImage: { + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Team meeting image reused across two rows", + }, + heading: "Service 1", + tagline: "TAGLINE", + body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.", + }, + { + serviceImage: { + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Team meeting image reused across two rows", + }, + heading: "Service 2", + tagline: "TAGLINE", + body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.", + }, + { + serviceImage: { + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Team meeting image reused across two rows", + }, + heading: "Service 3", + tagline: "TAGLINE", + body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.", + }, + { + serviceImage: { + __image_url__: + "https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Team meeting image reused across two rows", + }, + heading: "Service 4", + tagline: "TAGLINE", + body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.", + }, + ]) + .meta({ + description: "Two stacked service content sections on the right side.", + }), + +}); + +export type SchemaType = z.infer; + +const EducationServicesSplitSlide = ({ data }: { data: Partial }) => { + const { title, sections } = data; + + + return ( +
+
+
+

+ {title} +

+
+ + + +
+ {sections?.map((section, index) => ( +
+
+ + {section.serviceImage.__image_prompt__} +
+
+

{section.heading}

+

+ {section.tagline} +

+

+ {section.body} +

+
+
+ ))} +
+
+
+ ); +}; + +export default EducationServicesSplitSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx new file mode 100644 index 00000000..bd599daa --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx @@ -0,0 +1,153 @@ +import * as z from "zod"; + +export const slideLayoutId = "education-statistics-grid-slide"; +export const slideLayoutName = "Education Statistics Grid Slide"; +export const slideLayoutDescription = + "A two-column layout with a left title block and a right 2x4 grid of statistics cards, using one subtle background image texture."; + +const StatisticSchema = z.object({ + value: z.string().min(1).max(8).meta({ + description: "Main metric value shown at the top of one card.", + }), + label: z.string().min(3).max(22).meta({ + description: "Label shown under the value.", + }), +}); + +export const Schema = z.object({ + title: z.string().min(4).max(14).default("Statistics").meta({ + description: "Main title shown in the left column.", + }), + description: z.string().min(40).max(120).default( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + ).meta({ + description: "Supporting line shown under the left title.", + }), + stats: z + .array(StatisticSchema) + .min(2) + .max(8) + .default([ + { value: "120", label: "Sales Team Strength" }, + { value: "15", label: "Senior Sales Officer" }, + { value: "1", label: "National Manager" }, + { value: "25", label: "Sales Officers" }, + { value: "2", label: "Regional Manager" }, + { value: "50", label: "Distributor Reps" }, + { value: "5", label: "Zonal Manager" }, + { value: "20", label: "Merchandising Team" }, + ]) + .meta({ + description: "Eight statistic cards shown in a 2-column, 4-row grid.", + }), + +}); + +export type SchemaType = z.infer; + + + +const EducationStatisticsGridSlide = ({ data }: { data: Partial }) => { + + + return ( +
+ + +
+
+
+

+ {data.title} +

+

+ {data.description} +

+
+
+ + {data.stats && data.stats?.length <= 4 &&
+ {data.stats?.map((stat, index) => ( +
+

+ {stat?.value} +

+

+ {stat?.label} +

+
+ ))} +
} + + {/* {stats && stats?.length > 4 && stats?.length <= 8 &&
+ {stats?.map((stat, index) => ( +
+

+ {stat.value} +

+

+ {stat.label} +

+
+ ))} +
} */} + + {data.stats && data.stats?.length > 4 && data.stats?.length <= 8 && (() => { + const rightArray = data.stats?.slice(0, Math.floor(data.stats?.length / 2)); + const leftArray = data.stats?.slice(Math.floor(data.stats?.length / 2)); + + return ( +
+
+ + {leftArray?.map((stat: any, index: number) => ( +
+

+ {stat?.value} +

+

+ {stat?.label} +

+
+ ))} +
+ + +
+ + {rightArray?.map((stat: any, index: number) => ( +
+

+ {stat.value} +

+

+ {stat.label} +

+
+ ))} +
+
+ ); + })()} +
+
+ ); +}; + +export default EducationStatisticsGridSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationTableOfContentsSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationTableOfContentsSlide.tsx new file mode 100644 index 00000000..e6e18552 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationTableOfContentsSlide.tsx @@ -0,0 +1,81 @@ +import * as z from "zod"; + + +export const slideLayoutId = "education-table-of-contents-slide"; +export const slideLayoutName = "Education Table Of Contents Slide"; +export const slideLayoutDescription = + "A split layout with a left title panel and a right list of numbered sections, with one subtle background image overlay."; + +const TocItemSchema = z.object({ + number: z.string().min(2).max(3).meta({ + description: "Section number displayed before each section title.", + }), + label: z.string().min(3).max(30).meta({ + description: "Section title shown in the right column list.", + }), +}); + +export const Schema = z.object({ + titleLine1: z.string().min(4).max(12).default("Table of").meta({ + description: "First line of the left-side heading.", + }), + titleLine2: z.string().min(4).max(12).default("Contents").meta({ + description: "Second line of the left-side heading.", + }), + items: z + .array(TocItemSchema) + .min(8) + .max(8) + .default([ + { number: "03", label: "ABOUT" }, + { number: "04", label: "TIMELINE" }, + { number: "05", label: "GROUP OF COMPANIES" }, + { number: "06", label: "SERVICES" }, + { number: "07", label: "IMAGE GALLERY" }, + { number: "08", label: "STATISTICS" }, + { number: "09", label: "REPORT" }, + { number: "10", label: "CONCLUSION" }, + ]) + .meta({ + description: "Eight table-of-content entries listed on the right.", + }), + +}); + +export type SchemaType = z.infer; + +const EducationTableOfContentsSlide = ({ data }: { data: Partial }) => { + + return ( +
+ + +
+
+

+ {data.titleLine1} +
+ {data.titleLine2} +

+
+ +
+
+ {data.items?.map((item, index) => ( +
+ + {item.number} + + + {item.label} + +
+ ))} +
+
+
+
+ ); +}; + +export default EducationTableOfContentsSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationTimelineSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationTimelineSlide.tsx new file mode 100644 index 00000000..0871cf62 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationTimelineSlide.tsx @@ -0,0 +1,182 @@ +import * as z from "zod"; + +export const slideLayoutId = "education-timeline-slide"; +export const slideLayoutName = "Education Timeline Slide"; +export const slideLayoutDescription = + "A timeline slide with a title, a horizontal progress line, and year-based milestones with short descriptions."; + +const MilestoneSchema = z.object({ + year: z.string().min(4).max(6).meta({ + description: "Year label displayed under each timeline marker.", + }), + description: z.string().min(20).max(50).meta({ + description: "Short text shown under each year label.", + }), +}); + +export const Schema = z.object({ + title: z.string().min(4).max(14).default("Timeline").meta({ + description: "Main timeline heading shown at the top-left.", + }), + milestones: z + .array(MilestoneSchema) + .min(6) + .max(12) + .default([ + { year: "2022", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1994", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1993", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1991", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1991", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " }, + { year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + { year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, + ]) + .meta({ + description: "Timeline milestones displayed left to right.", + }), +}); + +export type SchemaType = z.infer; + +const EducationTimelineSlide = ({ data }: { data: Partial }) => { + + const { title, milestones } = data; + + const isSixOrLess = milestones?.length && milestones?.length <= 6; + + return ( +
+
+

+ {title} +

+
+ + {isSixOrLess ? ( + + ) : ( + + )} +
+ ); +}; + +function TimelineUpToSix({ + milestones, +}: { + milestones: any; +}) { + + + return ( +
+
+ {milestones.map((milestone: any, index: number) => ( +
+
+ +
+ {index !== milestones.length - 1 &&
} +
+

+ {milestone.year} +

+

+ {milestone.description} +

+
+ ))} +
+ +
+ ); +} + +function TimelineMoreThanSix({ + milestones, +}: { + milestones: SchemaType["milestones"]; +}) { + const topItems = milestones.slice(0, 6); + const bottomItems = milestones.slice(6); + + return ( +
+ {/* vertical connector on left */} + + + + + + + {/* bottom horizontal line */} + {/*
*/} +
+
+ {topItems.map((milestone: any, index: number) => ( +
+
+ +
+ {index !== milestones.length - 1 &&
} +
+
+ +

+ {milestone.year} +

+

+ {milestone.description} +

+
+
+ ))} +
+ +
+ + {/* bottom row */} +
+ {bottomItems.map((_, colIndex) => { + const item = bottomItems[colIndex]; + if (!item) return
; + + return ( +
+
+ {/* {colIndex === 0 &&
} */} + {true &&
} +
+
+
+ +

+ {item.year} +

+

+ {item.description} +

+
+
+ ); + })} +
+
+ ); +} + +export default EducationTimelineSlide; diff --git a/electron/servers/nextjs/app/presentation-templates/Education/settings.json b/electron/servers/nextjs/app/presentation-templates/Education/settings.json new file mode 100644 index 00000000..42d837e2 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Education/settings.json @@ -0,0 +1,5 @@ +{ + "description": "School and training layouts for covers, outlines, timelines, statistics, and visual storytelling", + "ordered": false, + "default": false +} diff --git a/electron/servers/nextjs/app/presentation-templates/index.tsx b/electron/servers/nextjs/app/presentation-templates/index.tsx index 60131f0d..bbf1872b 100644 --- a/electron/servers/nextjs/app/presentation-templates/index.tsx +++ b/electron/servers/nextjs/app/presentation-templates/index.tsx @@ -16,6 +16,17 @@ import CodeSlide09TableOfContent, { Schema as CodeTableOfContentSchema, slideLay import CodeSlide10MetricsSplit, { Schema as CodeMetricsSplitSchema, slideLayoutId as CodeMetricsSplitId, slideLayoutName as CodeMetricsSplitName, slideLayoutDescription as CodeMetricsSplitDesc } from "./Code/CodeSlide10MetricsSplit"; import CodeSlide11MetricsGrid, { Schema as CodeMetricsGridSchema, slideLayoutId as CodeMetricsGridId, slideLayoutName as CodeMetricsGridName, slideLayoutDescription as CodeMetricsGridDesc } from "./Code/CodeSlide11MetricsGrid"; +// Education templates +import EducationCoverSlide, { Schema as EduCoverSchema, slideLayoutId as EduCoverId, slideLayoutName as EduCoverName, slideLayoutDescription as EduCoverDesc } from "./Education/EducationCoverSlide"; +import EducationTableOfContentsSlide, { Schema as EduTocSchema, slideLayoutId as EduTocId, slideLayoutName as EduTocName, slideLayoutDescription as EduTocDesc } from "./Education/EducationTableOfContentsSlide"; +import EducationAboutSlide, { Schema as EduAboutSchema, slideLayoutId as EduAboutId, slideLayoutName as EduAboutName, slideLayoutDescription as EduAboutDesc } from "./Education/EducationAboutSlide"; +import EducationContentSplitSlide, { Schema as EduContentSplitSchema, slideLayoutId as EduContentSplitId, slideLayoutName as EduContentSplitName, slideLayoutDescription as EduContentSplitDesc } from "./Education/EducationContentSplitSlide"; +import EducationImageGallerySlide, { Schema as EduImageGallerySchema, slideLayoutId as EduImageGalleryId, slideLayoutName as EduImageGalleryName, slideLayoutDescription as EduImageGalleryDesc } from "./Education/EducationImageGallerySlide"; +import EducationReportDonutSlide, { Schema as EduReportDonutSchema, slideLayoutId as EduReportDonutId, slideLayoutName as EduReportDonutName, slideLayoutDescription as EduReportDonutDesc } from "./Education/EducationReportDonutSlide"; +import EducationServicesSplitSlide, { Schema as EduServicesSplitSchema, slideLayoutId as EduServicesSplitId, slideLayoutName as EduServicesSplitName, slideLayoutDescription as EduServicesSplitDesc } from "./Education/EducationServicesSplitSlide"; +import EducationStatisticsGridSlide, { Schema as EduStatisticsGridSchema, slideLayoutId as EduStatisticsGridId, slideLayoutName as EduStatisticsGridName, slideLayoutDescription as EduStatisticsGridDesc } from "./Education/EducationStatisticsGridSlide"; +import EducationTimelineSlide, { Schema as EduTimelineSchema, slideLayoutId as EduTimelineId, slideLayoutName as EduTimelineName, slideLayoutDescription as EduTimelineDesc } from "./Education/EducationTimelineSlide"; + // General templates import GeneralIntroSlideLayout, { Schema as GeneralIntroSchema, layoutId as GeneralIntroId, layoutName as GeneralIntroName, layoutDescription as GeneralIntroDesc } from "./general/IntroSlideLayout"; import BasicInfoSlideLayout, { Schema as BasicInfoSchema, layoutId as BasicInfoId, layoutName as BasicInfoName, layoutDescription as BasicInfoDesc } from "./general/BasicInfoSlideLayout"; @@ -189,6 +200,7 @@ import neoStandardSettings from "./neo-standard/settings.json"; import neoModernSettings from "./neo-modern/settings.json"; import neoSwiftSettings from "./neo-swift/settings.json"; import codeSettings from "./Code/settings.json"; +import educationSettings from "./Education/settings.json"; // Helper to create template entry @@ -210,6 +222,18 @@ export const codeTemplates: TemplateWithData[] = [ createTemplateEntry(CodeSlide11MetricsGrid, CodeMetricsGridSchema, CodeMetricsGridId, CodeMetricsGridName, CodeMetricsGridDesc, "code", "CodeSlide11MetricsGrid"), ]; +export const educationTemplates: TemplateWithData[] = [ + createTemplateEntry(EducationCoverSlide, EduCoverSchema, EduCoverId, EduCoverName, EduCoverDesc, "education", "EducationCoverSlide"), + createTemplateEntry(EducationTableOfContentsSlide, EduTocSchema, EduTocId, EduTocName, EduTocDesc, "education", "EducationTableOfContentsSlide"), + createTemplateEntry(EducationAboutSlide, EduAboutSchema, EduAboutId, EduAboutName, EduAboutDesc, "education", "EducationAboutSlide"), + createTemplateEntry(EducationContentSplitSlide, EduContentSplitSchema, EduContentSplitId, EduContentSplitName, EduContentSplitDesc, "education", "EducationContentSplitSlide"), + createTemplateEntry(EducationImageGallerySlide, EduImageGallerySchema, EduImageGalleryId, EduImageGalleryName, EduImageGalleryDesc, "education", "EducationImageGallerySlide"), + createTemplateEntry(EducationReportDonutSlide, EduReportDonutSchema, EduReportDonutId, EduReportDonutName, EduReportDonutDesc, "education", "EducationReportDonutSlide"), + createTemplateEntry(EducationServicesSplitSlide, EduServicesSplitSchema, EduServicesSplitId, EduServicesSplitName, EduServicesSplitDesc, "education", "EducationServicesSplitSlide"), + createTemplateEntry(EducationStatisticsGridSlide, EduStatisticsGridSchema, EduStatisticsGridId, EduStatisticsGridName, EduStatisticsGridDesc, "education", "EducationStatisticsGridSlide"), + createTemplateEntry(EducationTimelineSlide, EduTimelineSchema, EduTimelineId, EduTimelineName, EduTimelineDesc, "education", "EducationTimelineSlide"), +]; + export const neoGeneralTemplates: TemplateWithData[] = [ createTemplateEntry(TextSplitWithEmphasisBlockLayout, TextSplitWithEmphasisBlockSchema, TextSplitWithEmphasisBlockId, TextSplitWithEmphasisBlockName, TextSplitWithEmphasisBlockDesc, 'neo-general', 'TextSplitWithEmphasisBlock'), @@ -381,6 +405,7 @@ export const allLayouts: TemplateWithData[] = [ ...standardTemplates, ...swiftTemplates, ...codeTemplates, + ...educationTemplates, ]; @@ -450,6 +475,13 @@ export const templates: TemplateLayoutsWithSettings[] = [ settings: codeSettings as TemplateGroupSettings, layouts: codeTemplates, }, + { + id: "education", + name: "Education", + description: educationSettings.description, + settings: educationSettings as TemplateGroupSettings, + layouts: educationTemplates, + }, ]; // Helper to get templates by group ID