diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide01RoadmapCover.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide01RoadmapCover.tsx new file mode 100644 index 00000000..52f779b8 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide01RoadmapCover.tsx @@ -0,0 +1,51 @@ +import * as z from "zod"; + +export const slideLayoutId = "code-roadmap-cover-slide"; +export const slideLayoutName = "Code Roadmap Cover Slide"; +export const slideLayoutDescription = + "A centered opening slide with company name, roadmap title, and supporting subtitle."; + +export const Schema = z.object({ + companyName: z.string().min(2).max(28).default("COMPANY NAME").meta({ + description: "Organization name shown above the slide title.", + }), + title: z.string().min(8).max(28).default("Development Roadmap").meta({ + description: "Primary slide heading.", + }), + subtitle: z + .string() + .min(24) + .max(92) + .default( + "We transform ideas into market-ready solutions through systematic development processes." + ) + .meta({ + description: "Supporting subtitle shown under the heading.", + }), + pageLabel: z.string().min(3).max(8).default("1 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide01RoadmapCover = ({ data }: { data: Partial }) => { + + return ( +
+
+

{data.companyName}

+

+ {data.title} +

+

{data.subtitle}

+
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide01RoadmapCover; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide02CodeExplanationSplit.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide02CodeExplanationSplit.tsx new file mode 100644 index 00000000..fdee3e06 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide02CodeExplanationSplit.tsx @@ -0,0 +1,99 @@ +import * as z from "zod"; + + +export const slideLayoutId = "code-explanation-split-slide"; +export const slideLayoutName = "Code Explanation Split Slide"; +export const slideLayoutDescription = + "A two-column slide with a code panel on the left and descriptive explanation on the right."; + +export const Schema = z.object({ + title: z.string().min(8).max(24).default("Code + Explanation").meta({ + description: "Slide heading shown at the top-left.", + }), + codeSnippet: z.object({ + language: z.string().min(2).max(10), + fileName: z.string().min(3).max(30), + content: z.string().min(20).max(520), + }).default({ + language: "tsx", + fileName: "components/UserAuth.tsx", + content: `import { useState } from "react"; +import { login } from "@/lib/auth"; + +export function UserAuth() { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + const user = await login(email, password); + console.log("Logged in:", user); + }; + + return null; +} + +`, + }).meta({ + description: "Code sample shown in the left panel.", + }), + explanationTitle: z.string().min(4).max(20).default("Explanation").meta({ + description: "Heading shown above the explanatory paragraph.", + }), + explanation: z + .string() + .min(40) + .max(360) + .default( + "This component manages credentials as local state and submits them through an async handler. The login utility abstracts network details while the handler keeps the UI flow predictable. Keep validation and side effects isolated so changes remain safe when authentication requirements evolve." + ) + .meta({ + description: "Explanation paragraph shown in the right column.", + }), + pageLabel: z.string().min(3).max(8).default("2 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide02CodeExplanationSplit = ({ + data, +}: { + data: Partial; +}) => { + + return ( +
+ +
+

{data.title}

+ +
+
+

{data.codeSnippet?.fileName}

+
+
+              
+                {data.codeSnippet?.content}
+              
+            
+
+ +
+

{data.explanationTitle}

+

+ {data.explanation} +

+
+
+
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide02CodeExplanationSplit; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide03ApiRequestResponse.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide03ApiRequestResponse.tsx new file mode 100644 index 00000000..42e9f206 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide03ApiRequestResponse.tsx @@ -0,0 +1,128 @@ +import * as z from "zod"; + + +export const slideLayoutId = "code-api-request-response-slide"; +export const slideLayoutName = "Code API Request Response Slide"; +export const slideLayoutDescription = + "An API-focused slide with endpoint metadata, request payload, and response payload."; + +export const Schema = z.object({ + title: z.string().min(8).max(26).default("API Request / Response").meta({ + description: "Main heading shown at the top-left.", + }), + method: z.enum(["GET", "POST", "PATCH", "DELETE"]).default("POST").meta({ + description: "HTTP method badge text.", + }), + endpoint: z.string().min(8).max(48).default("/api/v1/users/authenticate").meta({ + description: "Endpoint path text.", + }), + headers: z + .array(z.string().min(12).max(44)) + .min(2) + .max(2) + .default(["Content-Type: application/json", "Authorization: Bearer "]) + .meta({ + description: "Two header lines shown in the endpoint card.", + }), + requestSnippet: z.object({ + language: z.string().min(2).max(10), + fileName: z.string().min(3).max(24), + content: z.string().min(20).max(220), + }).default({ + language: "json", + fileName: "request.json", + content: `{ + "email": "user@example.com user@example.com user@example.com user@example.com user@example.com" , + "password": "securepassword123" +}`, + }).meta({ + description: "Request payload example.", + }), + responseSnippet: z.object({ + language: z.string().min(2).max(10), + fileName: z.string().min(3).max(24), + content: z.string().min(20).max(620), + }).default({ + language: "json", + fileName: "response.json", + content: `{ + "success": true, + "user": { + "id": "usr_1234567890", + "email": "user@example.com", + "name": "John Doe", + "role": "admin" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "expiresIn": 3600 +}`, + }).meta({ + description: "Response payload example.", + }), + pageLabel: z.string().min(3).max(8).default("3 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide03ApiRequestResponse = ({ + data, +}: { + data: Partial; +}) => { + + return ( +
+ +
+

{data.title}

+ +
+
+
+
+

+ {data.method} +

+

{data.endpoint}

+
+

Headers

+
+ {data.headers?.map((item) => ( +

{item}

+ ))} +
+
+ +
+

{data.requestSnippet?.fileName}

+
+
+                
+                  {data.requestSnippet?.content}
+                
+              
+
+
+ +
+

{data.responseSnippet?.fileName}

+
+
+              
+                {data.responseSnippet?.content}
+              
+            
+
+
+
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide03ApiRequestResponse; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide04FeatureGrid.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide04FeatureGrid.tsx new file mode 100644 index 00000000..b7700234 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide04FeatureGrid.tsx @@ -0,0 +1,140 @@ +import * as z from "zod"; + +const FeatureCardSchema = z.object({ + title: z.string().min(3).max(20).meta({ + description: "Feature title shown on each card.", + }), + description: z.string().min(18).max(82).meta({ + description: "Supporting feature description.", + }), + icon: z.object({ + __icon_url__: z.string().min(10).max(180).meta({ + description: "URL to icon", + }), + __icon_query__: z.string().min(3).max(28).meta({ + description: "Query used to search the icon", + }), + }).default({ + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }).meta({ + description: "Icon used for each feature bullet in plan cards.", + }), +}); + +export const slideLayoutId = "code-feature-grid-slide"; +export const slideLayoutName = "Code Feature Grid Slide"; +export const slideLayoutDescription = + "A six-card feature summary grid with icon badges and compact descriptions."; + +export const Schema = z.object({ + title: z.string().min(6).max(20).default("Feature Grid").meta({ + description: "Slide title shown above the grid.", + }), + features: z + .array(FeatureCardSchema) + .min(3) + .max(6) + .default([ + { + title: "Modern Stack", + description: "Built with React, TypeScript, and Tailwind CSS for maximum developer experience.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Component Library", + description: "Reusable UI components with consistent design patterns.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "CLI Tools", + description: "Command-line utilities for scaffolding and automation.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Analytics", + description: "Built-in tracking and performance monitoring.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Version Control", + description: "Git-based workflow with automated deployments.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Best Practices", + description: "Following industry standards and modern development patterns.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + ]) + .meta({ + description: "Six feature cards displayed in a 3x2 grid.", + }), + pageLabel: z.string().min(3).max(8).default("4 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide04FeatureGrid = ({ data }: { data: Partial }) => { + + + return ( +
+ + +

{data.title}

+ +
+ {data?.features?.map((feature) => ( +
+
+

{feature.title}

+ + {feature.icon.__icon_query__} + +
+

{feature.description}

+
+ ))} +
+ + +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide04FeatureGrid; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide05ComparisonTable.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide05ComparisonTable.tsx new file mode 100644 index 00000000..f76a12c0 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide05ComparisonTable.tsx @@ -0,0 +1,95 @@ +import * as z from "zod"; + +const ComparisonRowSchema = z.object({ + feature: z.string().min(4).max(20).meta({ + description: "Feature label shown in the first column.", + }), + react: z.string().min(1).max(12).meta({ + description: "React cell value.", + }), + vue: z.string().min(1).max(12).meta({ + description: "Vue cell value.", + }), + angular: z.string().min(1).max(12).meta({ + description: "Angular cell value.", + }), +}); + +export const slideLayoutId = "code-comparison-table-slide"; +export const slideLayoutName = "Code Comparison Table Slide"; +export const slideLayoutDescription = + "A framework comparison table with feature rows and highlighted compatibility marks."; + +export const Schema = z.object({ + title: z.string().min(6).max(18).default("Comparison").meta({ + description: "Slide title shown above the table.", + }), + rows: z + .array(ComparisonRowSchema) + .min(6) + .max(6) + .default([ + { feature: "Component-based", react: "check", vue: "check", angular: "check" }, + { feature: "TypeScript Support", react: "check", vue: "check", angular: "check" }, + { feature: "Learning Curve", react: "Medium", vue: "Easy", angular: "Steep" }, + { feature: "Bundle Size", react: "40KB", vue: "34KB", angular: "167KB" }, + { feature: "Performance", react: "Excellent", vue: "Excellent", angular: "Good" }, + { feature: "Community Size", react: "Huge", vue: "Large", angular: "Large" }, + ]) + .meta({ + description: "Six comparison rows shown in the table.", + }), + pageLabel: z.string().min(3).max(8).default("5 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +function renderCell(value: string) { + if (value.toLowerCase() === "check") { + return ; + } + + return {value}; +} + +const CodeSlide05ComparisonTable = ({ data }: { data: Partial }) => { + + return ( +
+ +

{data.title}

+ +
+
+

Feature

+

React

+

Vue

+

Angular

+
+ +
+ {data?.rows?.map((row) => ( +
+

{row.feature}

+
{renderCell(row.react)}
+
{renderCell(row.vue)}
+
{renderCell(row.angular)}
+
+ ))} +
+ +
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide05ComparisonTable; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide06Workflow.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide06Workflow.tsx new file mode 100644 index 00000000..15ad1f1a --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide06Workflow.tsx @@ -0,0 +1,121 @@ +import { Fragment } from "react"; +import * as z from "zod"; + +const WorkflowStepSchema = z.object({ + title: z.string().min(3).max(12).meta({ + description: "Step title shown in each workflow card.", + }), + description: z.string().min(18).max(58).meta({ + description: "Short step description text.", + }), + icon: z.object({ + __icon_url__: z.string().min(10).max(180), + __icon_query__: z.string().min(3).max(28), + }).default({ + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }), +}); + +export const slideLayoutId = "code-workflow-slide"; +export const slideLayoutName = "Code Workflow Slide"; +export const slideLayoutDescription = + "A four-step workflow slide with cards and directional arrows between steps."; + +export const Schema = z.object({ + title: z.string().min(6).max(16).default("Workflow").meta({ + description: "Slide title shown above the workflow row.", + }), + steps: z + .array(WorkflowStepSchema) + .min(4) + .max(4) + .default([ + { + title: "Design", + description: "Create wireframes and design system components.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Develop", + description: "Build features using modern frameworks and best practices.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Test & QA", + description: "Run automated tests and quality assurance checks.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + { + title: "Deploy", + description: "Ship to production with CI and CD pipeline automation.", + icon: { + __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg", + __icon_query__: "check icon", + }, + }, + ]) + .meta({ + description: "Four workflow steps shown in sequence.", + }), + pageLabel: z.string().min(3).max(8).default("6 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide06Workflow = ({ data }: { data: Partial }) => { + + return ( +
+ +

{data.title}

+ +
+ {data?.steps?.map((step, index) => ( + +
+
+ {step.icon.__icon_query__} +
+

{step.title}

+

{step.description}

+
+ {index < (data?.steps?.length || 0) - 1 && ( + + + + + )} +
+ ))} + +
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide06Workflow; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide07UseCaseList.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide07UseCaseList.tsx new file mode 100644 index 00000000..69013541 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide07UseCaseList.tsx @@ -0,0 +1,70 @@ +import * as z from "zod"; + +export const slideLayoutId = "code-use-case-list-slide"; +export const slideLayoutName = "Code Use Case List Slide"; +export const slideLayoutDescription = + "A two-column numbered use-case list with eight compact items."; + +export const Schema = z.object({ + title: z.string().min(6).max(16).default("Usecase").meta({ + description: "Slide title shown above the numbered list.", + }), + items: z + .array(z.string().min(16).max(58)) + .min(4) + .max(8) + .default([ + "Use pre-built component library for UI consistency", + "Integrate REST API with TypeScript for type safety", + "Implement real-time updates using WebSocket", + "Deploy to production with automated CI/CD pipeline", + "Enable role-based permissions for protected actions", + "Generate docs automatically from route contracts", + "Track release health with telemetry dashboards", + "Add rollback strategy for high-risk deployments", + ]) + .meta({ + description: "Eight use-case items shown in two columns.", + }), + pageLabel: z.string().min(3).max(8).default("7 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide07UseCaseList = ({ data }: { data: Partial }) => { + + return ( +
+ + +

{data.title}

+ +
+ {data?.items?.map((item, index) => ( +
+ + {index + 1} + +

{item}

+
+ ))} +
+ + +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide07UseCaseList; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide08CodeExplanationText.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide08CodeExplanationText.tsx new file mode 100644 index 00000000..0cf80abb --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide08CodeExplanationText.tsx @@ -0,0 +1,51 @@ +import * as z from "zod"; + +export const slideLayoutId = "code-explanation-text-slide"; +export const slideLayoutName = "Code Explanation Text Slide"; +export const slideLayoutDescription = + "A text-only explanation slide with generous whitespace for narrative documentation."; + +export const Schema = z.object({ + title: z.string().min(8).max(24).default("Code + Explanation").meta({ + description: "Main slide title shown at the top-left.", + }), + explanationTitle: z.string().min(4).max(20).default("Explanation").meta({ + description: "Subheading above the paragraph body.", + }), + explanation: z + .string() + .min(60) + .max(360) + .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: "Long-form explanation body.", + }), + pageLabel: z.string().min(3).max(8).default("8 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide08CodeExplanationText = ({ data }: { data: Partial }) => { + + return ( +
+ + +

{data.title}

+
+

{data.explanationTitle}

+

{data.explanation}

+
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide08CodeExplanationText; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide09TableOfContent.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide09TableOfContent.tsx new file mode 100644 index 00000000..aa72323d --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide09TableOfContent.tsx @@ -0,0 +1,94 @@ +import * as z from "zod"; + +export const slideLayoutId = "code-table-of-content-slide"; +export const slideLayoutName = "Code Table Of Content Slide"; +export const slideLayoutDescription = + "A two-column table of contents with numbered entries and folder-style bullets."; + +export const Schema = z.object({ + title: z.string().min(8).max(24).default("Table of Content").meta({ + description: "Slide heading shown above the index list.", + }), + items: z + .array(z.object({ + number: z.string().min(2).max(2), + label: z.string().min(3).max(16), + description: z.string().min(3).max(18), + })) + .min(12) + .max(12) + .default([ + { number: "01", label: "Content 1", description: "Section summary" }, + { number: "02", label: "Content 2", description: "Section summary" }, + { number: "03", label: "Content 3", description: "Section summary" }, + { number: "04", label: "Content 4", description: "Section summary" }, + { number: "05", label: "Content 5", description: "Section summary" }, + { number: "06", label: "Content 6", description: "Section summary" }, + { number: "07", label: "Content 7", description: "Section summary" }, + { number: "08", label: "Content 8", description: "Section summary" }, + { number: "09", label: "Content 9", description: "Section summary" }, + { number: "10", label: "Content 10", description: "Section summary" }, + { number: "11", label: "Content 11", description: "Section summary" }, + { number: "12", label: "Content 12", description: "Section summary" }, + ]) + .meta({ + description: "Left-column table of contents entries.", + }), + + pageLabel: z.string().min(3).max(8).default("9 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +function TocColumn({ items }: { items: { number: string; label: string, description?: string }[] }) { + return ( +
+ {items.map((item, index) => { + + + return ( +
+
+ +
+
+ +

{item.number}

+

{item.label}

+ {item.description &&

{item.description}

} +
+
+ ); + })} +
+ ); +} + +const CodeSlide09TableOfContent = ({ data }: { data: Partial }) => { + const leftItems = data?.items?.slice(0, data?.items?.length / 2); + const rightItems = data?.items?.slice(data?.items?.length / 2); + + + return ( +
+ + +
+

{data.title}

+ +
+ + +
+
+ +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide09TableOfContent; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide10MetricsSplit.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide10MetricsSplit.tsx new file mode 100644 index 00000000..66569317 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide10MetricsSplit.tsx @@ -0,0 +1,90 @@ +import * as z from "zod"; + +const MetricSchema = z.object({ + value: z.string().min(2).max(8).meta({ + description: "Primary metric value.", + }), + label: z.string().min(3).max(14).meta({ + description: "Metric label text.", + }), + period: z.string().min(3).max(16).meta({ + description: "Metric period text.", + }), +}); + +export const slideLayoutId = "code-metrics-split-slide"; +export const slideLayoutName = "Code Metrics Split Slide"; +export const slideLayoutDescription = + "A metrics slide with narrative text on the left and two stat cards on the right."; + +export const Schema = z.object({ + title: z.string().min(6).max(18).default("Metrics").meta({ + description: "Slide title shown at the top-left.", + }), + explanationTitle: z.string().min(4).max(16).default("Explanation").meta({ + description: "Heading above the explanatory paragraph.", + }), + explanation: z + .string() + .min(60) + .max(320) + .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: "Body text for the narrative section.", + }), + metrics: z + .array(MetricSchema) + .min(2) + .max(2) + .default([ + { value: "50k+", label: "Active Users", period: "Last 12 months" }, + { value: "50k+", label: "Active Users", period: "Last 12 months" }, + ]) + .meta({ + description: "Two metric cards shown in the right column.", + }), + pageLabel: z.string().min(3).max(8).default("10 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide10MetricsSplit = ({ data }: { data: Partial }) => { + const slideData = Schema.parse(data); + + return ( +
+ + +

{slideData.title}

+
+
+

{slideData.explanationTitle}

+

{slideData.explanation}

+
+ +
+ {slideData.metrics.map((metric, index) => ( +
+

{metric.value}

+

{metric.label}

+

{metric.period}

+
+ ))} +
+
+ +
+ {slideData.pageLabel} +
+
+ ); +}; + +export default CodeSlide10MetricsSplit; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide11MetricsGrid.tsx b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide11MetricsGrid.tsx new file mode 100644 index 00000000..6dd3ea05 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/CodeSlide11MetricsGrid.tsx @@ -0,0 +1,76 @@ +import * as z from "zod"; + +const MetricSchema = z.object({ + value: z.string().min(2).max(8).meta({ + description: "Primary metric value.", + }), + label: z.string().min(3).max(14).meta({ + description: "Metric label text.", + }), + period: z.string().min(3).max(16).meta({ + description: "Metric period text.", + }), +}); + +export const slideLayoutId = "code-metrics-grid-slide"; +export const slideLayoutName = "Code Metrics Grid Slide"; +export const slideLayoutDescription = + "A six-card metrics grid for KPI overviews in code-focused decks."; + +export const Schema = z.object({ + title: z.string().min(6).max(18).default("Metrics").meta({ + description: "Slide heading shown above the KPI cards.", + }), + metrics: z + .array(MetricSchema) + .min(3) + .max(6) + .default([ + { value: "99.9%", label: "Uptime", period: "Last 12 months" }, + { value: "<100ms", label: "Response Time", period: "Last 12 months" }, + { value: "50k+", label: "Active Users", period: "Last 12 months" }, + { value: "99.9%", label: "Uptime", period: "Last 12 months" }, + { value: "<100ms", label: "Response Time", period: "Last 12 months" }, + { value: "50k+", label: "Active Users", period: "Last 12 months" }, + ]) + .meta({ + description: "Six KPI cards in a 3x2 grid.", + }), + pageLabel: z.string().min(3).max(8).default("11 / 11").meta({ + description: "Bottom pagination label.", + }), +}); + +export type SchemaType = z.infer; + +const CodeSlide11MetricsGrid = ({ data }: { data: Partial }) => { + + return ( +
+ + + +

{data.title}

+ +
+ {data?.metrics?.map((metric, index) => ( +
+

{metric.value}

+

{metric.label}

+

{metric.period}

+
+ ))} +
+ + +
+ {data.pageLabel} +
+
+ ); +}; + +export default CodeSlide11MetricsGrid; diff --git a/electron/servers/nextjs/app/presentation-templates/Code/settings.json b/electron/servers/nextjs/app/presentation-templates/Code/settings.json new file mode 100644 index 00000000..e73cc025 --- /dev/null +++ b/electron/servers/nextjs/app/presentation-templates/Code/settings.json @@ -0,0 +1,5 @@ +{ + "description": "Developer-focused layouts for roadmaps, APIs, code explanations, and technical metrics", + "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 4af28183..60131f0d 100644 --- a/electron/servers/nextjs/app/presentation-templates/index.tsx +++ b/electron/servers/nextjs/app/presentation-templates/index.tsx @@ -3,6 +3,19 @@ import { TemplateWithData, TemplateGroupSettings, createTemplateEntry, TemplateL // TODO: Step 1: Import All templates Layouts Here (like the ones below) +// Code templates +import CodeSlide01RoadmapCover, { Schema as CodeRoadmapCoverSchema, slideLayoutId as CodeRoadmapCoverId, slideLayoutName as CodeRoadmapCoverName, slideLayoutDescription as CodeRoadmapCoverDesc } from "./Code/CodeSlide01RoadmapCover"; +import CodeSlide02CodeExplanationSplit, { Schema as CodeExplanationSplitSchema, slideLayoutId as CodeExplanationSplitId, slideLayoutName as CodeExplanationSplitName, slideLayoutDescription as CodeExplanationSplitDesc } from "./Code/CodeSlide02CodeExplanationSplit"; +import CodeSlide03ApiRequestResponse, { Schema as CodeApiRequestResponseSchema, slideLayoutId as CodeApiRequestResponseId, slideLayoutName as CodeApiRequestResponseName, slideLayoutDescription as CodeApiRequestResponseDesc } from "./Code/CodeSlide03ApiRequestResponse"; +import CodeSlide04FeatureGrid, { Schema as CodeFeatureGridSchema, slideLayoutId as CodeFeatureGridId, slideLayoutName as CodeFeatureGridName, slideLayoutDescription as CodeFeatureGridDesc } from "./Code/CodeSlide04FeatureGrid"; +import CodeSlide05ComparisonTable, { Schema as CodeComparisonTableSchema, slideLayoutId as CodeComparisonTableId, slideLayoutName as CodeComparisonTableName, slideLayoutDescription as CodeComparisonTableDesc } from "./Code/CodeSlide05ComparisonTable"; +import CodeSlide06Workflow, { Schema as CodeWorkflowSchema, slideLayoutId as CodeWorkflowId, slideLayoutName as CodeWorkflowName, slideLayoutDescription as CodeWorkflowDesc } from "./Code/CodeSlide06Workflow"; +import CodeSlide07UseCaseList, { Schema as CodeUseCaseListSchema, slideLayoutId as CodeUseCaseListId, slideLayoutName as CodeUseCaseListName, slideLayoutDescription as CodeUseCaseListDesc } from "./Code/CodeSlide07UseCaseList"; +import CodeSlide08CodeExplanationText, { Schema as CodeExplanationTextSchema, slideLayoutId as CodeExplanationTextId, slideLayoutName as CodeExplanationTextName, slideLayoutDescription as CodeExplanationTextDesc } from "./Code/CodeSlide08CodeExplanationText"; +import CodeSlide09TableOfContent, { Schema as CodeTableOfContentSchema, slideLayoutId as CodeTableOfContentId, slideLayoutName as CodeTableOfContentName, slideLayoutDescription as CodeTableOfContentDesc } from "./Code/CodeSlide09TableOfContent"; +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"; + // 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"; @@ -175,6 +188,7 @@ import neoGeneralSettings from "./neo-general/settings.json"; 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"; // Helper to create template entry @@ -182,6 +196,20 @@ import neoSwiftSettings from "./neo-swift/settings.json"; // TODO: Step 3: Create template entries for each template (like the ones below) +export const codeTemplates: TemplateWithData[] = [ + createTemplateEntry(CodeSlide01RoadmapCover, CodeRoadmapCoverSchema, CodeRoadmapCoverId, CodeRoadmapCoverName, CodeRoadmapCoverDesc, "code", "CodeSlide01RoadmapCover"), + createTemplateEntry(CodeSlide02CodeExplanationSplit, CodeExplanationSplitSchema, CodeExplanationSplitId, CodeExplanationSplitName, CodeExplanationSplitDesc, "code", "CodeSlide02CodeExplanationSplit"), + createTemplateEntry(CodeSlide03ApiRequestResponse, CodeApiRequestResponseSchema, CodeApiRequestResponseId, CodeApiRequestResponseName, CodeApiRequestResponseDesc, "code", "CodeSlide03ApiRequestResponse"), + createTemplateEntry(CodeSlide04FeatureGrid, CodeFeatureGridSchema, CodeFeatureGridId, CodeFeatureGridName, CodeFeatureGridDesc, "code", "CodeSlide04FeatureGrid"), + createTemplateEntry(CodeSlide05ComparisonTable, CodeComparisonTableSchema, CodeComparisonTableId, CodeComparisonTableName, CodeComparisonTableDesc, "code", "CodeSlide05ComparisonTable"), + createTemplateEntry(CodeSlide06Workflow, CodeWorkflowSchema, CodeWorkflowId, CodeWorkflowName, CodeWorkflowDesc, "code", "CodeSlide06Workflow"), + createTemplateEntry(CodeSlide07UseCaseList, CodeUseCaseListSchema, CodeUseCaseListId, CodeUseCaseListName, CodeUseCaseListDesc, "code", "CodeSlide07UseCaseList"), + createTemplateEntry(CodeSlide08CodeExplanationText, CodeExplanationTextSchema, CodeExplanationTextId, CodeExplanationTextName, CodeExplanationTextDesc, "code", "CodeSlide08CodeExplanationText"), + createTemplateEntry(CodeSlide09TableOfContent, CodeTableOfContentSchema, CodeTableOfContentId, CodeTableOfContentName, CodeTableOfContentDesc, "code", "CodeSlide09TableOfContent"), + createTemplateEntry(CodeSlide10MetricsSplit, CodeMetricsSplitSchema, CodeMetricsSplitId, CodeMetricsSplitName, CodeMetricsSplitDesc, "code", "CodeSlide10MetricsSplit"), + createTemplateEntry(CodeSlide11MetricsGrid, CodeMetricsGridSchema, CodeMetricsGridId, CodeMetricsGridName, CodeMetricsGridDesc, "code", "CodeSlide11MetricsGrid"), +]; + export const neoGeneralTemplates: TemplateWithData[] = [ createTemplateEntry(TextSplitWithEmphasisBlockLayout, TextSplitWithEmphasisBlockSchema, TextSplitWithEmphasisBlockId, TextSplitWithEmphasisBlockName, TextSplitWithEmphasisBlockDesc, 'neo-general', 'TextSplitWithEmphasisBlock'), @@ -352,8 +380,7 @@ export const allLayouts: TemplateWithData[] = [ ...modernTemplates, ...standardTemplates, ...swiftTemplates, - - + ...codeTemplates, ]; @@ -416,7 +443,13 @@ export const templates: TemplateLayoutsWithSettings[] = [ settings: swiftSettings as TemplateGroupSettings, layouts: swiftTemplates, }, - + { + id: "code", + name: "Code", + description: codeSettings.description, + settings: codeSettings as TemplateGroupSettings, + layouts: codeTemplates, + }, ]; // Helper to get templates by group ID