From 56cb9f0fe2201f4e871baab918acab2673ee9a5e Mon Sep 17 00:00:00 2001 From: sudipnext Date: Wed, 23 Jul 2025 23:06:05 +0545 Subject: [PATCH] Add modern pitch deck slide layouts for market size, validation, traction, business model, team, and thank you slides - Implemented Market Size Slide Layout with schema and default data - Created Market Validation Slide Layout with customizable comparison data - Developed Company Traction Slide Layout featuring dynamic growth statistics - Introduced Business Model Slide Layout showcasing CAC metrics - Added Modern Team Slide Layout to display team member profiles - Designed Thank You Slide Layout for closing presentations - Included a settings JSON file for modern layout configurations --- .../modern/1IntroSlideLayout.tsx | 112 +++++++ .../modern/2AboutCompanySlideLayout.tsx | 140 ++++++++ .../modern/3ProblemSlideLayout.tsx | 161 ++++++++++ .../modern/4SolutionSlideLayout.tsx | 169 ++++++++++ .../modern/5ProductOverviewSlideLayout.tsx | 301 ++++++++++++++++++ .../modern/6MarketSizeSlideLayout.tsx | 153 +++++++++ .../modern/7MarketValidationSlideLayout.tsx | 193 +++++++++++ .../modern/8CompanyTractionSlideLayout.tsx | 267 ++++++++++++++++ .../modern/9BusinessModelSlideLayout.tsx | 140 ++++++++ .../presentation-layouts/modern/setting.json | 5 + .../modern/z10TeamSlideLayout.tsx | 199 ++++++++++++ .../modern/z11ThankYouSlideLayout.tsx | 147 +++++++++ 12 files changed, 1987 insertions(+) create mode 100644 servers/nextjs/presentation-layouts/modern/1IntroSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/2AboutCompanySlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/3ProblemSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/4SolutionSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/5ProductOverviewSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/6MarketSizeSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/7MarketValidationSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/8CompanyTractionSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/9BusinessModelSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/setting.json create mode 100644 servers/nextjs/presentation-layouts/modern/z10TeamSlideLayout.tsx create mode 100644 servers/nextjs/presentation-layouts/modern/z11ThankYouSlideLayout.tsx diff --git a/servers/nextjs/presentation-layouts/modern/1IntroSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/1IntroSlideLayout.tsx new file mode 100644 index 00000000..ff02a905 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/1IntroSlideLayout.tsx @@ -0,0 +1,112 @@ +import React from "react"; +import * as z from "zod"; + +export const layoutId = "intro-pitchdeck-slide"; +export const layoutName = "Intro Pitch Deck Slide"; +export const layoutDescription = + "A visually appealing introduction slide for a pitch deck, featuring a large title, company name, date, and contact information with a modern design."; +const introPitchDeckSchema = z.object({ + title: z.string().min(2).max(15).default("Pitch Deck").meta({ + description: "Main title of the slide", + }), + description: z.string().default("").meta({ + description: "Empty description as per the design", + }), + contactNumber: z.string().default("+123-456-7890").meta({ + description: "Contact phone number displayed in footer", + }), + contactAddress: z + .string() + .default("123 Anywhere St., Any City, ST 123") + .meta({ + description: "Contact address displayed in footer", + }), + contactWebsite: z.string().default("www.reallygreatsite.com").meta({ + description: "Contact website URL displayed in footer", + }), + companyName: z.string().default("presenton").meta({ + description: "Company name displayed in header", + }), + date: z.string().default("June 13, 2038").meta({ + description: "Date of the presentation", + }), +}); + +export const Schema = introPitchDeckSchema; +export type IntroPitchDeckData = z.infer; + +interface IntroSlideLayoutProps { + data?: Partial; +} + +const IntroPitchDeckSlide: React.FC = ({ + data: slideData, +}) => { + return ( + <> + {/* Montserrat Font */} + +
+ {/* Top Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ + {/* Main Title */} +
+

+ {slideData?.title} + {/* Blue underline */} + +

+
+ + {/* Bottom Contact Row */} +
+
+ πŸ“ž + {slideData?.contactNumber} +
+
+ πŸ“ + {slideData?.contactAddress} +
+
+ 🌐 + {slideData?.contactWebsite} +
+
+
+ + ); +}; + +export default IntroPitchDeckSlide; diff --git a/servers/nextjs/presentation-layouts/modern/2AboutCompanySlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/2AboutCompanySlideLayout.tsx new file mode 100644 index 00000000..d08f439d --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/2AboutCompanySlideLayout.tsx @@ -0,0 +1,140 @@ +import React from "react"; +import * as z from "zod"; +import { ImageSchema, IconSchema } from "@/presentation-layouts/defaultSchemes"; + +export const layoutId = "about-company-slide"; +export const layoutName = "About Our Company Slide"; +export const layoutDescription = + "A slide layout providing an overview of the company, its background, and key information."; + +const aboutCompanySlideSchema = z.object({ + title: z.string().min(3).max(60).default("About Our Company").meta({ + description: "Main title of the slide", + }), + content: z + .string() + .min(50) + .max(500) + .default( + "In the presentation session, the background/introduction can be filled with information that is arranged systematically and effectively with respect to an interesting topic to be used as material for discussion at the opening of the presentation session. The introduction can provide a general overview for those who are listening to your presentation so that the key words on the topic of discussion are emphasized during this background/introductory presentation session.", + ) + .meta({ + description: "Main content text describing the company or topic", + }), + companyName: z.string().min(2).max(50).default("presenton").meta({ + description: "Company name displayed in header", + }), + date: z.string().min(5).max(30).default("June 13, 2038").meta({ + description: "Date displayed in header", + }), + image: ImageSchema.optional().meta({ + description: + "Optional supporting image for the slide (building, office, etc.)", + }), +}); + +export const Schema = aboutCompanySlideSchema; + +export type AboutCompanySlideData = z.infer; + +interface AboutCompanySlideLayoutProps { + data?: Partial; +} + +const AboutCompanySlideLayout: React.FC = ({ + data: slideData, +}) => { + return ( + <> + {/* Import fonts */} + + +
+ {/* Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ + {/* Main content area */} +
+ {/* Left side - Image */} +
+
+ {slideData?.image ? ( + {slideData.image.__image_prompt__} + ) : ( + /* Default building facade */ +
+ {/* Building structure simulation */} +
+ + {/* Horizontal lines (building floors) */} +
+ {[...Array(12)].map((_, i) => ( +
+ ))} +
+ + {/* Vertical lines (building columns) */} +
+ {[...Array(6)].map((_, i) => ( +
+ ))} +
+ + {/* Windows */} +
+ {[...Array(32)].map((_, i) => ( +
+ ))} +
+ + {/* Building edge highlight */} +
+
+ )} +
+
+ + {/* Right side - Content */} +
+

+ {slideData?.title || "About Our Company"} +

+ +
+ {slideData?.content || + "In the presentation session, the background/introduction can be filled with information that is arranged systematically and effectively with respect to an interesting topic to be used as material for discussion at the opening of the presentation session. The introduction can provide a general overview for those who are listening to your presentation so that the key words on the topic of discussion are emphasized during this background/introductory presentation session."} +
+
+
+
+ + ); +}; + +export default AboutCompanySlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/3ProblemSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/3ProblemSlideLayout.tsx new file mode 100644 index 00000000..6b244f53 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/3ProblemSlideLayout.tsx @@ -0,0 +1,161 @@ +import React from "react"; +import * as z from "zod"; +import { ImageSchema, IconSchema } from "@/presentation-layouts/defaultSchemes"; + +export const layoutId = "problem-statement-slide"; +export const layoutName = "Problem Statement Slide"; +export const layoutDescription = + "A slide layout designed to present a clear problem statement, including categories of problems, company information, and an optional image."; + +const problemStatementSlideSchema = z.object({ + title: z.string().min(3).max(40).default("Problem").meta({ + description: "Main title of the problem statement slide", + }), + description: z + .string() + .min(50) + .max(500) + .default( + "A problem needs to be discussed further and in detail because this problem is the main foundation in the initial development of a product, service, and decision making. Without a well-defined problem, it will have an impact on a job that is unfocused, unmanaged, and less relevant.", + ) + .meta({ + description: "Main content text describing the problem statement", + }), + problemCategories: z + .array( + z.object({ + title: z.string().min(3).max(30).meta({ + description: "Title of the problem category", + }), + description: z.string().min(20).max(200).meta({ + description: "Description of the problem category", + }), + icon: IconSchema.optional().meta({ + description: "Optional icon for the problem category", + }), + }), + ) + .min(2) + .max(4) + .default([ + { + title: "Inefficiency", + description: + "Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.", + icon: { + __icon_url__: + "https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/alert-triangle.js", + __icon_query__: "warning alert inefficiency", + }, + }, + { + title: "High Costs", + description: + "Outdated systems increase expenses, while small businesses struggle to expand their market reach.", + icon: { + __icon_url__: + "https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/trending-up.js", + __icon_query__: "trending up costs chart", + }, + }, + ]) + .meta({ + description: + "List of problem categories with titles, descriptions, and optional icons", + }), + companyName: z.string().min(2).max(50).default("Rimberio").meta({ + description: "Company name displayed in header", + }), + date: z.string().min(5).max(30).default("June 13, 2038").meta({ + description: "Date displayed in header", + }), +}); + +export const Schema = problemStatementSlideSchema; + +export type ProblemStatementSlideData = z.infer< + typeof problemStatementSlideSchema +>; + +interface ProblemStatementSlideLayoutProps { + data?: Partial; +} + +const ProblemStatementSlideLayout: React.FC< + ProblemStatementSlideLayoutProps +> = ({ data: slideData }) => { + const problemCategories = slideData?.problemCategories || []; + + return ( + <> + {/* Import fonts */} + + +
+ {/* Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ + {/* Main content area */} +
+ {/* Left side - Main Problem */} +
+
+

+ {slideData?.title} +

+ +
+ {slideData?.description} +
+
+
+ + {/* Right side - Problem Categories with Icons */} +
+
+ {problemCategories.map((category, index) => ( +
+
+ {category.icon?.__icon_query__} +
+
+

+ {category.title} +

+

+ {category.description} +

+
+
+ ))} +
+
+
+ + {/* Bottom border line */} +
+
+ + ); +}; + +export default ProblemStatementSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/4SolutionSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/4SolutionSlideLayout.tsx new file mode 100644 index 00000000..c8f02e06 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/4SolutionSlideLayout.tsx @@ -0,0 +1,169 @@ +import React from "react"; +import * as z from "zod"; +import { IconSchema } from "@/presentation-layouts/defaultSchemes"; + +export const layoutId = "solution-slide"; +export const layoutName = "Solution Slide"; +export const layoutDescription = + "A slide layout designed to present a solution to previously identified problems, showcasing key aspects of the solution with sections and icons."; + +const solutionSlideSchema = z.object({ + companyName: z.string().min(2).max(50).default("presenton").meta({ + description: "Company name displayed in header", + }), + date: z.string().min(5).max(50).default("June 13, 2038").meta({ + description: "Date displayed in header", + }), + title: z.string().min(3).max(40).default("Solution").meta({ + description: "Main title of the slide", + }), + mainDescription: z + .string() + .min(20) + .max(300) + .default( + "Show that we offer a solution that solves the problems previously described and identified. Make sure that the solutions we offer uphold the values of effectiveness, efficiency, and are highly relevant to the market situation and society.", + ) + .meta({ + description: "Main content text describing the solution", + }), + sections: z + .array( + z.object({ + title: z.string().min(3).max(30).meta({ + description: "Section title", + }), + description: z.string().min(5).max(80).meta({ + description: "Section description", + }), + icon: IconSchema.optional().meta({ + description: "Icon for the section", + }), + }), + ) + .min(2) + .max(4) + .default([ + { + title: "Market", + description: "Innovative and widely accepted.", + icon: { + __icon_query__: "market innovation", + __icon_url__: + "https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/globe.js", + }, + }, + { + title: "Industry", + description: "Based on sound market decisions.", + icon: { + __icon_query__: "industry building", + __icon_url__: + "https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/building.js", + }, + }, + { + title: "SEM", + description: "Driven by precise data and analysis.", + icon: { + __icon_query__: "SEM data analysis", + __icon_url__: + "https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/chart-bar.js", + }, + }, + { + title: "End User", + description: "Focused on real user impact.", + icon: { + __icon_query__: "end user impact", + __icon_url__: + "https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/user.js", + }, + }, + ]) + .meta({ + description: + "List of solution sections with titles, descriptions, and optional icons", + }), +}); + +export const Schema = solutionSlideSchema; + +export type SolutionSlideData = z.infer; + +interface SolutionSlideLayoutProps { + data?: Partial; +} + +const SolutionSlideLayout: React.FC = ({ + data: slideData, +}) => { + const sections = slideData?.sections || []; + + return ( + <> + {/* Import Google Fonts */} + + +
+ {/* Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ + {/* Main Content */} +
+ {/* Title and Description */} +
+

+ {slideData?.title} +

+

+ {slideData?.mainDescription} +

+
+ {/* Four Small Boxes in a Row */} +
+ {sections.map((section, idx) => ( +
+
+ {section?.icon?.__icon_url__ && ( + {section.icon.__icon_query__} + )} +
+

+ {section.title} +

+
+

+ {section.description} +

+
+ ))} +
+
+ + {/* Bottom Border */} +
+
+ + ); +}; + +export default SolutionSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/5ProductOverviewSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/5ProductOverviewSlideLayout.tsx new file mode 100644 index 00000000..037a8907 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/5ProductOverviewSlideLayout.tsx @@ -0,0 +1,301 @@ +import React from "react"; +import * as z from "zod"; +import { ImageSchema } from "@/presentation-layouts/defaultSchemes"; + +export const layoutId = "product-overview-slide"; +export const layoutName = "Product Overview Slide"; +export const layoutDescription = + "A slide layout designed to showcase a company's products or services, highlighting their features and benefits in a structured format."; + +const productOverviewSlideSchema = z.object({ + companyName: z.string().min(2).max(50).default("presenton").meta({ + description: "Company name displayed in header", + }), + date: z.string().min(5).max(50).default("June 13, 2038").meta({ + description: "Date displayed in header", + }), + title: z.string().min(3).max(40).default("Product Overview").meta({ + description: "Main title of the slide", + }), + mainDescription: z + .string() + .min(50) + .max(400) + .default( + "Provide an explanation of the general profile of the services we have. Arrange information about our products services in a systematic and fact-based manner. Also express our pride in the service that we have done well.", + ) + .meta({ + description: "Main content text describing the product overview", + }), + products: z + .array( + z.object({ + title: z.string().min(3).max(50).meta({ + description: "Product title", + }), + description: z.string().min(30).max(200).meta({ + description: "Product description", + }), + image: ImageSchema.meta({ + description: "Product image", + }), + isBlueBackground: z.boolean().default(false).meta({ + description: "Whether the product box has a blue background", + }), + }), + ) + .min(2) + .max(4) + .default([ + { + title: "Internet of Things", + description: + "Detail and explain each product. Our examination of community and market issues increases with additional products/services.", + image: { + __image_url__: + "https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=300&h=200&fit=crop", + __image_prompt__: "Person working on electronics with headphones", + }, + isBlueBackground: true, + }, + { + title: "Smart Home Platform", + description: + "Our alternate product category is available. Our products must work together to solve social and economic issues.", + image: { + __image_url__: + "https://images.unsplash.com/photo-1573164713988-8665fc963095?w=300&h=200&fit=crop", + __image_prompt__: + "Woman working at computer with technical equipment", + }, + isBlueBackground: true, + }, + ]) + .meta({ + description: "List of products or services to showcase", + }), +}); + +export const Schema = productOverviewSlideSchema; + +export type ProductOverviewSlideData = z.infer< + typeof productOverviewSlideSchema +>; + +interface ProductOverviewSlideLayoutProps { + data?: Partial; +} + +const ProductOverviewSlideLayout: React.FC = ({ + data: slideData, +}) => { + const products = slideData?.products || []; + + // Make the product boxes smaller + const PRODUCT_BOX_HEIGHT = 400; // px (smaller than before) + const PRODUCT_BOX_WIDTH = 200; // px (smaller than before) + const TEXT_SECTION_HEIGHT = Math.round(PRODUCT_BOX_HEIGHT * 0.56); // ~190px + const IMAGE_SECTION_HEIGHT = PRODUCT_BOX_HEIGHT - TEXT_SECTION_HEIGHT; // ~150px + + return ( + <> + {/* Import Google Fonts */} + + +
+ {/* Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ 6+ + {/* Main Content */} +
+ {/* Title and Description on the left */} +
+

+ {slideData?.title} +

+

+ {slideData?.mainDescription} +

+
+ + {/* Product Grid on the right */} +
+ {/* First Column: Normal order (Text above, Image below) */} +
+ {products[0] && ( +
+ {/* Top Section - Blue background with text */} +
+

+ {products[0].title} +

+

+ {products[0].description} +

+
+ {/* Bottom Section - Image */} +
+ { +
+
+ )} + {products[2] && ( +
+
+

+ {products[2].title} +

+

+ {products[2].description} +

+
+
+ { +
+
+ )} +
+ {/* Second Column: Reverse order (Image above, Text below) */} +
+ {products[1] && ( +
+ {/* Top Section - Image */} +
+ { +
+ {/* Bottom Section - Blue background with text */} +
+

+ {products[1].title} +

+

+ {products[1].description} +

+
+
+ )} + {products[3] && ( +
+
+ { +
+
+

+ {products[3].title} +

+

+ {products[3].description} +

+
+
+ )} +
+
+
+ {/* Bottom Border */} +
+
+ + ); +}; + +export default ProductOverviewSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/6MarketSizeSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/6MarketSizeSlideLayout.tsx new file mode 100644 index 00000000..fcc375e1 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/6MarketSizeSlideLayout.tsx @@ -0,0 +1,153 @@ +import React from "react"; +import * as z from "zod"; +import { ImageSchema } from "@/presentation-layouts/defaultSchemes"; + +export const layoutId = "market-size-pitchdeck-slide"; +export const layoutName = "Market Size Pitch Deck Slide"; +export const layoutDescription = + "A professional slide layout designed to present market size statistics, including TAM, SAM, and SOM, with a world map and key metrics."; + +const marketSizeSlideSchema = z.object({ + title: z.string().default("Market Size").meta({ + description: "Main slide title", + }), + companyName: z.string().default("Rimberio").meta({ + description: "Presenter's name", + }), + date: z.string().default("June 13, 2038").meta({ + description: "Presentation date", + }), + mapImage: ImageSchema.default({ + __image_url__: + "https://upload.wikimedia.org/wikipedia/commons/8/80/World_map_-_low_resolution.svg", // You can quickly find a world map image via a Google search or use a free resource like Wikimedia Commons + __image_prompt__: "World map with location pins or points", + }), + marketStats: z + .array( + z.object({ + label: z.string(), + value: z.string(), + description: z.string(), + }), + ) + .min(1) + .max(3) + .default([ + { + label: "Total Available Market (TAM)", + value: "1.4 Billion", + description: + "In the TAM Section, we can fill in the potential of any person who can buy an offer or the maximum amount of revenue a business can earn by selling their offer.", + }, + { + label: "Serviceable Available Market (SAM)", + value: "194 Million", + description: + "It is a part of TAM that has the potential to become a target market for the company by considering the type of product, technology available and geographical conditions.", + }, + { + label: "Serviceable Obtainable Market (SOM)", + value: "167 Million", + description: + "The SOM is a smaller fraction of the SAM that is the target of a serviceable and realistically achievable market in the short to medium term.", + }, + ]), + description: z + .string() + .default( + "Market size is the total amount of all sales and customers that can be seen directly by stakeholders. This technique is usually calculated at the end of the year, the market size can be used by companies to determine the potential of their market and business in the future. This is very useful, especially for new companies that will offer services to those who are interested in our services.", + ) + .meta({ + description: "Main description text for the slide", + }), +}); + +export const Schema = marketSizeSlideSchema; +export type MarketSizeSlideData = z.infer; + +interface MarketSizeSlideProps { + data?: Partial; +} + +const MarketSizeSlideLayout: React.FC = ({ + data: slideData, +}) => { + const stats = slideData?.marketStats || []; + + return ( + <> + {/* Montserrat Font */} + + +
+ {/* Header */} +
+ {slideData?.companyName || "Rimberio"} + {slideData?.date || "June 13, 2038"} +
+ + {/* Main Content */} +
+ {/* Title and Map on the left */} +
+
+ {/* Move the title down to align with the top of the market stats */} +

+ {slideData?.title || "Market Size"} +

+
+ Market World Map with Points +
+

+ {slideData?.description || + "Market size is the total amount of all sales and customers that can be seen directly by stakeholders. This technique is usually calculated at the end of the year, the market size can be used by companies to determine the potential of their market and business in the future."} +

+
+
+ + {/* Market Stats on the right */} +
+
+ {stats.map((stat, index) => ( +
+
+
+ {stat.label} +
+
+ {stat.value} +
+
+

+ {stat.description} +

+
+ ))} +
+
+
+
+ + ); +}; + +export default MarketSizeSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/7MarketValidationSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/7MarketValidationSlideLayout.tsx new file mode 100644 index 00000000..540c5386 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/7MarketValidationSlideLayout.tsx @@ -0,0 +1,193 @@ +import React from "react"; +import * as z from "zod"; +import { Card } from "@/components/ui/card"; +import { Table, TableHeader, TableBody } from "@/components/ui/table"; +import { ChartContainer } from "@/components/ui/chart"; +import { ImageSchema } from "@/presentation-layouts/defaultSchemes"; +import { BarChart, Bar, XAxis, YAxis, Tooltip, Cell } from "recharts"; + +export const layoutId = "market-validation-slide"; +export const layoutName = "Market Validation Slide"; +export const layoutDescription = + "A slide layout designed to present market validation data, including flexible market validation metrics, comparisons, and an optional decorative image."; + +// Make the schema generic: allow any label/value pairs for comparison +const marketValidationSchema = z.object({ + companyName: z.string().min(2).max(50).default("presenton").meta({ + description: "Company name in header", + }), + date: z.string().min(5).max(50).default("June 13, 2038").meta({ + description: "Date in header", + }), + title: z.string().min(3).max(40).default("Market Validation").meta({ + description: "Title of the slide", + }), + description: z + .string() + .min(50) + .max(400) + .default( + "It’s a market testing stage to ensure that the products produced by the company can be accepted and effectively used by the broad market. For start-up companies, we can use data already achieved by similar products from other companies.", + ) + .meta({ + description: + "Main description text for the slide explaining market validation", + }), + // Generic comparisonData: label for row, label for metric, and value + comparisonData: z + .array( + z.object({ + label: z.string().min(2).max(50).meta({ + description: + "Name of comparison entity (e.g., company, product, etc.)", + }), + metricLabel: z.string().min(2).max(50).meta({ + description: + "Label for the metric being compared (e.g., Users, Revenue, etc.)", + }), + value: z.number().min(0).meta({ + description: "Numeric value for the metric", + }), + }), + ) + .min(2) + .max(5) + .default([ + { label: "Thynk Unlimited", metricLabel: "Revenue ($K)", value: 2650 }, + { label: "Salford & Co.", metricLabel: "Revenue ($K)", value: 1850 }, + { label: "Liceria & Co.", metricLabel: "Revenue ($K)", value: 1010 }, + ]) + .meta({ + description: "Market benchmark data (generic metric)", + }), + image: ImageSchema.optional().meta({ + description: "Optional decorative image", + }), +}); + +export const Schema = marketValidationSchema; + +export type MarketValidationSlideData = z.infer; + +interface MarketValidationSlideLayoutProps { + data?: Partial; +} + +const MarketValidationSlideLayout: React.FC< + MarketValidationSlideLayoutProps +> = ({ data: slideData }) => { + const comparisonData = slideData?.comparisonData || []; + + // Chart color palette (shadcn blue and gray) + const chartColors = ["#2563eb", "#1e40af", "#60a5fa", "#93c5fd", "#dbeafe"]; + + // Determine the metric label to use (assume all rows use the same metricLabel) + const metricLabel = + comparisonData.length > 0 ? comparisonData[0].metricLabel : "Metric"; + + return ( + <> + + +
+ {/* Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ + {/* Main Content */} +
+ {/* Left Column */} +
+

+ {slideData?.title} +

+

+ {slideData?.description} +

+
+ + {/* Right Column - Chart on top, Table on bottom */} +
+ {/* Bar Chart */} + +
+ + + + + + {/* Legend removed */} + + {comparisonData.map((entry, idx) => ( + + ))} + + + +
+
+ {/* Table of comparison data */} + + + + + + + + + + {comparisonData.map((entry) => ( + + + + + ))} + +
+ {comparisonData.length > 0 ? "Name" : "Name"} + + {metricLabel} +
{entry.label} + {entry.value.toLocaleString()} +
+
+
+
+ +
+
+ + ); +}; + +export default MarketValidationSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/8CompanyTractionSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/8CompanyTractionSlideLayout.tsx new file mode 100644 index 00000000..56905cde --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/8CompanyTractionSlideLayout.tsx @@ -0,0 +1,267 @@ +import React from "react"; +import { + LineChart, + Line, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from "recharts"; +import * as z from "zod"; + +export const layoutId = "company-traction-slide"; +export const layoutName = "Company Traction Slide"; +export const layoutDescription = + "A slide layout designed to present company traction data, including growth statistics over the years, a chart visualization, and key metrics in a visually appealing format."; + +// growthStats: list of dicts, each dict is { year: string, : number, : number, ... } +const tractionSchema = z.object({ + companyName: z.string().default("presention"), + date: z.string().default("June 13, 2038"), + title: z.string().default("Company Traction"), + description: z + .string() + .default( + "Traction is a period where the company is feeling momentum during its development period. If traction momentum is not harnessed, sales figures can decline and the customer base can shrink. In general, companies will judge success by the amount of revenue and new customers they receive.", + ), + // growthStats is a list of objects, each with a 'year' and any number of metric keys (all numbers) + growthStats: z + .array( + z + .object({ + year: z.string(), + }) + .catchall(z.number()), + ) + .min(1) + .max(20) + .default([ + { + year: "2020", + artificialIntelligence: 5, + internetOfThings: 10, + others: 8, + }, + { + year: "2021", + artificialIntelligence: 10, + internetOfThings: 20, + others: 15, + }, + { + year: "2022", + artificialIntelligence: 20, + internetOfThings: 30, + others: 22, + }, + { + year: "2023", + artificialIntelligence: 28, + internetOfThings: 38, + others: 29, + }, + { + year: "2024", + artificialIntelligence: 35, + internetOfThings: 45, + others: 34, + }, + { + year: "2025", + artificialIntelligence: 45, + internetOfThings: 53, + others: 42, + }, + { + year: "2026", + artificialIntelligence: 55, + internetOfThings: 65, + others: 52, + }, + { + year: "2029", + artificialIntelligence: 55, + internetOfThings: 65, + others: 52, + }, + ]), +}); + +export const Schema = tractionSchema; +export type CompanyTractionData = z.infer; + +interface Props { + data?: Partial; +} + +// Helper: assign colors to series +const defaultColors = [ + "#1E4CD9", + "#3b82f6", + "#f59e0b", + "#10b981", + "#ef4444", + "#a21caf", + "#6366f1", + "#f43f5e", + "#fbbf24", + "#14b8a6", +]; + +function getSeriesKeys( + growthStats: Array>, +): string[] { + if (!growthStats.length) return []; + // Exclude 'year' or any non-numeric keys + const first = growthStats[0]; + return Object.keys(first).filter( + (key) => key !== "year" && typeof first[key] === "number", + ); +} + +// Compute stats for right column, generic for all series +function computeStats( + growthStats: Array>, + seriesKeys: string[], +) { + if (!growthStats.length) return []; + const first = growthStats[0]; + const last = growthStats[growthStats.length - 1]; + return seriesKeys.map((key) => { + const start = typeof first[key] === "number" ? (first[key] as number) : 0; + const end = typeof last[key] === "number" ? (last[key] as number) : 0; + const growth = start === 0 ? 0 : ((end - start) / Math.abs(start)) * 100; + return { + label: key + .replace(/([A-Z])/g, " $1") + .replace(/^./, (str) => str.toUpperCase()), + value: `${growth >= 0 ? "+" : ""}${Math.round(growth)}% growth`, + description: `${key + .replace(/([A-Z])/g, " $1") + .replace(/^./, (str) => str.toUpperCase())} growth over the period.`, + }; + }); +} + +const CompanyTractionSlideLayout: React.FC = ({ data }) => { + const growthStats = data?.growthStats || []; + + // Dynamically determine series keys + const seriesKeys = getSeriesKeys(growthStats); + + // Prepare stats for the right column, generic for all series + const stats = computeStats(growthStats, seriesKeys); + + return ( + <> + +
+ {/* Header */} +
+ {data?.companyName} + {data?.date} +
+ + {/* Main Content */} +
+ {/* Left Column - Chart with Title Below */} +
+

+ {data?.title} +

+
+
+ + + + + + + + {seriesKeys.map((key, idx) => ( + str.toUpperCase())} + dot={{ + r: 4, + fill: defaultColors[idx % defaultColors.length], + }} + activeDot={{ + r: 6, + fill: defaultColors[idx % defaultColors.length], + }} + /> + ))} + + +
+
+
+ + {/* Right Column - Description and Stats */} +
+

+ {data?.description || + "Traction is a period where the company is feeling momentum during its development period. If traction momentum is not harnessed, sales figures can decline and the customer base can shrink. In general, companies will judge success by the amount of revenue and new customers they receive."} +

+
+ {stats.map((stat, index) => ( +
+
+ {stat.label} +
+
+ {stat.value} +
+

+ {stat.description} +

+
+ ))} +
+
+
+
+
+ + ); +}; + +export default CompanyTractionSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/9BusinessModelSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/9BusinessModelSlideLayout.tsx new file mode 100644 index 00000000..199948b9 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/9BusinessModelSlideLayout.tsx @@ -0,0 +1,140 @@ +import React from "react"; +import * as z from "zod"; +import { + BarChart, + Bar, + CartesianGrid, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, + Legend, +} from "recharts"; + +export const layoutId = "business-model-slide"; +export const layoutName = "Business Model Slide"; +export const layoutDescription = + "A business model presentation slide displaying CAC metrics and monetization strategy."; + +const businessModelSchema = z.object({ + companyName: z.string().default("presenton"), + date: z.string().default("June 13, 2038"), + title: z.string().default("Business Model"), + description: z + .string() + .default( + "Describe how you monetize, who your customers are, your distribution channels or fee structure. The goal is to give an idea of how this business will sustain your product or service and explain how your company will make money and achieve its goals. This can be shown with graphs, statistics, or charts. Use the Lifetime Value (LTV) and Customer Acquisition Cost (CAC) metrics to provide a clearer picture.", + ), + cacChart: z + .array( + z.object({ + label: z.string(), + percentage: z.number(), + }), + ) + .default([ + { label: "Internet of Things", percentage: 70 }, + { label: "Artificial Intelligence", percentage: 60 }, + ]), +}); + +export const Schema = businessModelSchema; +export type BusinessModelData = z.infer; + +interface Props { + data?: Partial; +} + +const BusinessModelSlide: React.FC = ({ data }) => { + const cacChartData = + data?.cacChart && Array.isArray(data.cacChart) && data.cacChart.length > 0 + ? data.cacChart + : [ + { label: "Internet of Things", percentage: 70 }, + { label: "Artificial Intelligence", percentage: 60 }, + ]; + + return ( + <> + +
+ {/* Header */} +
+ {data?.companyName} + {data?.date} +
+ + {/* Main Content */} +
+ {/* Left Column - Chart with Title Below */} +
+

+ {data?.title} +

+
+
+ + + + + + + + + + +
+
+
+ + {/* Right Column - Description and Optional Image */} +
+

+ {data?.description} +

+
+
+
+
+ + ); +}; + +export default BusinessModelSlide; diff --git a/servers/nextjs/presentation-layouts/modern/setting.json b/servers/nextjs/presentation-layouts/modern/setting.json new file mode 100644 index 00000000..b88e362b --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/setting.json @@ -0,0 +1,5 @@ +{ + "description": "Modern white and blue business pitch deck layouts with clean, professional design", + "ordered": false, + "isDefault": false +} diff --git a/servers/nextjs/presentation-layouts/modern/z10TeamSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/z10TeamSlideLayout.tsx new file mode 100644 index 00000000..394e8c14 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/z10TeamSlideLayout.tsx @@ -0,0 +1,199 @@ +import React from "react"; +import * as z from "zod"; +import { ImageSchema } from "@/presentation-layouts/defaultSchemes"; + +export const layoutId = "modern-team-slide"; +export const layoutName = "Modern Team Slide"; +export const layoutDescription = + "A clean modern team slide showcasing team members with professional profiles and blue-white design."; + +const teamMemberSchema = z.object({ + name: z.string().min(2).max(50).meta({ + description: "Team member's full name", + }), + position: z.string().min(2).max(50).meta({ + description: "Job title or position", + }), + description: z.string().min(20).max(120).meta({ + description: "Brief professional description of the team member", + }), + image: ImageSchema, + linkedIn: z.string().optional().meta({ + description: "LinkedIn profile URL (optional)", + }), +}); + +const modernTeamSlideSchema = z.object({ + title: z.string().min(3).max(40).default("Our Team").meta({ + description: "Main title of the slide", + }), + subtitle: z.string().min(10).max(120).optional().meta({ + description: "Optional subtitle describing the team", + }), + teamMembers: z + .array(teamMemberSchema) + .min(2) + .max(4) + .default([ + { + name: "Sarah Johnson", + position: "CEO & Founder", + description: + "Strategic leader with 15+ years experience in technology and business development. Former VP at Fortune 500 company.", + image: { + __image_url__: + "https://plus.unsplash.com/premium_photo-1661589856899-6dd0871f9db6?fm=jpg&q=60&w=3000&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NXx8YnVzaW5lc3N3b21lbnxlbnwwfHwwfHx8MA%3D%3D", + __image_prompt__: "Professional businesswoman CEO headshot", + }, + }, + { + name: "Michael Chen", + position: "CTO", + description: + "Technology expert specializing in scalable architecture and AI solutions. PhD in Computer Science from MIT.", + image: { + __image_url__: + "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80", + __image_prompt__: "Professional businessman CTO headshot", + }, + }, + { + name: "Emily Rodriguez", + position: "VP of Sales", + description: + "Sales leader with proven track record of building high-performing teams and driving revenue growth in B2B markets.", + image: { + __image_url__: + "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80", + __image_prompt__: "Professional businesswoman VP headshot", + }, + }, + { + name: "David Kim", + position: "Head of Product", + description: + "Product strategist focused on user experience and market-driven solutions. Former product manager at leading tech companies.", + image: { + __image_url__: + "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80", + __image_prompt__: "Professional businessman product manager headshot", + }, + }, + ]) + .meta({ + description: "List of team members with their information", + }), + companyName: z.string().default("presenton").meta({ + description: "Company name to display in the header", + }), + date: z.string().default("June 13, 2038").meta({ + description: "Date to display in the header", + }), +}); + +export const Schema = modernTeamSlideSchema; + +export type ModernTeamSlideData = z.infer; + +interface ModernTeamSlideLayoutProps { + data?: Partial; +} + +const ModernTeamSlideLayout: React.FC = ({ + data: slideData, +}) => { + return ( + <> + {/* Import Montserrat Font */} + + +
+ {/* Header */} +
+ {slideData?.companyName} + {slideData?.date} +
+ + {/* Main Content */} +
+ {/* Title */} +

+ {slideData?.title} +

+ {/* Subtitle */} +

+ {slideData?.subtitle} +

+ {/* Team Members Row */} +
+ {slideData?.teamMembers?.map((member, idx) => ( +
+ {/* Photo */} +
+ {member.image.__image_prompt__ +
+ {/* Name */} +
+ {member.name} +
+ {/* Position Badge */} +
+ {member.position} +
+ {/* Description */} +
+ {member.description} +
+ {/* LinkedIn Link (if provided) */} + {member.linkedIn && ( + + + + + LinkedIn + + )} +
+ ))} +
+
+ {/* Bottom Divider */} +
+
+ + ); +}; + +export default ModernTeamSlideLayout; diff --git a/servers/nextjs/presentation-layouts/modern/z11ThankYouSlideLayout.tsx b/servers/nextjs/presentation-layouts/modern/z11ThankYouSlideLayout.tsx new file mode 100644 index 00000000..805aeae8 --- /dev/null +++ b/servers/nextjs/presentation-layouts/modern/z11ThankYouSlideLayout.tsx @@ -0,0 +1,147 @@ +import React from "react"; +import * as z from "zod"; + +export const layoutId = "thank-you-slide"; +export const layoutName = "Thank You Slide"; +export const layoutDescription = + "A simple, plain thank you slide for closing presentations."; + +const thankYouSlideSchema = z.object({ + title: z.string().min(3).max(40).default("Thank You!").meta({ + description: "Main thank you message", + }), + subtitle: z.string().min(0).max(100).default("").meta({ + description: "Optional subtitle or closing remark", + }), + companyName: z.string().min(2).max(50).default("Rimberio").meta({ + description: "Company name displayed in header", + }), + date: z.string().min(5).max(30).default("June 13, 2038").meta({ + description: "Date displayed in header", + }), + address: z + .string() + .min(5) + .max(100) + .default("123 Anywhere St., Any City, ST 12345") + .meta({ + description: "Company address for contact section", + }), + phone: z.string().min(5).max(30).default("+123-456-7890").meta({ + description: "Company phone number for contact section", + }), + website: z.string().min(5).max(100).default("www.reallygreatsite.com").meta({ + description: "Company website for contact section", + }), + email: z.string().default("info@reallygreatsite.com").meta({ + description: "Company email address for contact section", + }), +}); + +export const Schema = thankYouSlideSchema; + +export type ThankYouSlideData = z.infer; + +interface ThankYouSlideLayoutProps { + data?: Partial; +} + +const ThankYouSlideLayout: React.FC = ({ data }) => { + return ( + <> + {/* Import fonts */} + + +
+ {/* Header */} +
+ {data?.companyName || "Rimberio"} + {data?.date || "June 13, 2038"} +
+ + {/* Main content area */} +
+ {/* Thank You and description */} +
+

+ {data?.title || "Thank You!"} +

+ {data?.subtitle && ( +
+ {data.subtitle} +
+ )} +
+ Write down your hopes for the future of your company. Don't forget + to thank the company for the opportunity and convince related + parties to support your company. +
+
+ + {/* Footer area */} +
+ {/* Left: We are ready to assist you */} +
+
+ We are ready to assist you +
+
+ {/* Right: Contacts */} +
+
+ + πŸ“ + + {data?.address} +
+
+ + πŸ“ž + + {data?.phone} +
+
+ + 🌐 + + {data?.website} +
+
+ + βœ‰οΈ + + {data?.email} +
+
+
+
+ + {/* Bottom border line */} +
+
+ + ); +}; + +export default ThankYouSlideLayout;