diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx index 12ec7a05..6aff587f 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx @@ -15,7 +15,7 @@ import { } from "@/components/ui/popover"; import { PresentationGenerationApi } from "../../services/api/presentation-generation"; import { OverlayLoader } from "@/components/ui/overlay-loader"; -import { useDispatch, useSelector } from "react-redux"; +import { useSelector } from "react-redux"; import Link from "next/link"; @@ -24,7 +24,6 @@ import { toast } from "sonner"; import Announcement from "@/components/Announcement"; -import { getStaticFileUrl } from "../../utils/others"; import { PptxPresentationModel } from "@/types/pptx_models"; import HeaderNav from "../../components/HeaderNab"; @@ -64,7 +63,8 @@ const Header = ({ } const pptx_path = await PresentationGenerationApi.exportAsPPTX(pptx_model); if (pptx_path) { - window.open(pptx_path, '_self'); + // window.open(pptx_path, '_self'); + downloadLink(pptx_path); } else { throw new Error("No path returned from export"); } @@ -97,7 +97,8 @@ const Header = ({ if (response.ok) { const { path: pdfPath } = await response.json(); - window.open(pdfPath, '_blank'); + // window.open(pdfPath, '_blank'); + downloadLink(pdfPath); } else { throw new Error("Failed to export PDF"); } @@ -112,6 +113,18 @@ const Header = ({ setShowLoader(false); } }; + const downloadLink = (path: string) => { + // if we have popup access give direct download if not redirect to the path + if (window.opener) { + window.open(path, '_blank'); + } else { + const link = document.createElement('a'); + link.href = path; + link.download = path.split('/').pop() || 'download'; + document.body.appendChild(link); + link.click(); + } + }; const ExportOptions = ({ mobile }: { mobile: boolean }) => (
diff --git a/servers/nextjs/app/api/layouts/route.ts b/servers/nextjs/app/api/layouts/route.ts index 6fe1a392..fbd73104 100644 --- a/servers/nextjs/app/api/layouts/route.ts +++ b/servers/nextjs/app/api/layouts/route.ts @@ -40,6 +40,7 @@ export async function GET() { const settingsContent = await fs.readFile(settingsPath, 'utf-8') settings = JSON.parse(settingsContent) as GroupSetting } catch (settingsError) { + console.warn(`No settings.json found for group ${groupName} or invalid JSON`) // Provide default settings if setting.json is missing or invalid settings = { @@ -47,8 +48,7 @@ export async function GET() { ordered: false, isDefault: false } - // write the settings to the file - fs.writeFile(settingsPath, JSON.stringify(settings, null, 2)) + } if (layoutFiles.length > 0) { diff --git a/servers/nextjs/app/dashboard/components/PresentationCard.tsx b/servers/nextjs/app/dashboard/components/PresentationCard.tsx index 55294912..385a7ded 100644 --- a/servers/nextjs/app/dashboard/components/PresentationCard.tsx +++ b/servers/nextjs/app/dashboard/components/PresentationCard.tsx @@ -39,9 +39,7 @@ export const PresentationCard = ({ e.preventDefault(); e.stopPropagation(); - toast.loading("Deleting presentation", { - description: "Please wait while we delete the presentation", - }); + const response = await DashboardApi.deletePresentation(id); if (response) { diff --git a/servers/nextjs/components/ui/overlay-loader.tsx b/servers/nextjs/components/ui/overlay-loader.tsx index cc6b9217..f64995d9 100644 --- a/servers/nextjs/components/ui/overlay-loader.tsx +++ b/servers/nextjs/components/ui/overlay-loader.tsx @@ -36,6 +36,9 @@ export const OverlayLoader = ({ return (
; + +export default function ExampleComponent({ data }: { data: SchemaType }) { + const { title, subtitle, metrics, chartImage, trendIcon } = data; + return ( +
+
+ {title &&

{title}

} + {subtitle &&

{subtitle}

} +
+ +
+ {chartImage?.__image_url__ && ( +
+ {chartImage.__image_prompt__} +
+ )} + + {metrics && metrics.length > 0 && ( +
+

Key Metrics

+ {metrics.map((metric, index) => ( +
+
+ {metric.label} + {trendIcon?.__icon_url__ && ( + {metric.trend} + )} +
+ + {metric.value} + +
+ ))} +
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/SlideStructure.tsx b/servers/nextjs/presentation-layouts/SlideStructure.tsx new file mode 100644 index 00000000..907244f0 --- /dev/null +++ b/servers/nextjs/presentation-layouts/SlideStructure.tsx @@ -0,0 +1,36 @@ +import * as z from "zod"; +// Note: +// If you want to use Image and Icon Must Use these Schemas. +// Image and icons are only media support for PDF and PPTX. +import { ImageSchema, IconSchema } from "./defaultSchemes"; + + +// Schema definition +export const Schema = z.object({ + // Note: + // Schema fields + // Each fields must have a default value (this is important for Layout-preview) + // Each fields must have a meta description + // Each fields must have a min and max length, length must support the layout design. + // Each Array fields must have a min and max length + +}) + +// Type inference +type SchemaType = z.infer; + + +// Component definition +const SlideStructure = ({ data }: { data: Partial }) => { + // Note: + // Data is already parse so not need to parse again. + // Must have consistent aspect ratio (16:9) and max-width 1280px. + // Validate each data before rendering using && operator or optional chaining + // These layout are exported as PDF and PPTX so must be optimized for both. + // Component design, layout, styles, etc. + // Content must be properly fit in the container, if need adjust the lenght of the content and items in Schema. + // See ExampleComponent.tsx for more details. + // Font Size must fit the desing and and the content must be properly fit in the container. +}; + +export default SlideStructure; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/general/ChartWithBulletsSlideLayout.tsx b/servers/nextjs/presentation-layouts/general/ChartWithBulletsSlideLayout.tsx index 336fa73b..4e1f49aa 100644 --- a/servers/nextjs/presentation-layouts/general/ChartWithBulletsSlideLayout.tsx +++ b/servers/nextjs/presentation-layouts/general/ChartWithBulletsSlideLayout.tsx @@ -91,7 +91,6 @@ const chartWithBulletsSlideSchema = z.object({ export const Schema = chartWithBulletsSlideSchema -console.log(z.toJSONSchema(chartWithBulletsSlideSchema)) export type ChartWithBulletsSlideData = z.infer diff --git a/servers/nextjs/presentation-layouts/pitch-deck/AboutUsSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/AboutUsSlide.tsx new file mode 100644 index 00000000..5e3399a6 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/AboutUsSlide.tsx @@ -0,0 +1,154 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + + mainTitle: z.string() + .min(5) + .max(15) + .default("ABOUT US") + .meta({ + description: "Main title for the about us section", + }), + + subtitle: z.string() + .min(10) + .max(20) + .default("GET TO KNOW US BETTER") + .meta({ + description: "Subtitle describing the section", + }), + + companyDescription: z.string() + .min(100) + .max(200) + .default("At our company, we believe in the transformative power of compelling storytelling, data-driven strategies, and cutting-edge creativity. Our mission is simple: to empower businesses with strategic marketing solutions that not only elevate brand visibility but also drive tangible growth and success.") + .meta({ + description: "Main company description paragraph", + }), + + additionalText: z.string() + .min(50) + .max(200) + .default("What sets us apart is not just our expertise but our commitment to understanding the unique DNA of each client.") + .meta({ + description: "Additional descriptive text", + }), + + businessImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Business person analyzing charts and graphs with pen in hand" + }).meta({ + description: "Business analytics image showing data analysis", + }), + + showDecoCircle: z.boolean() + .default(true) + .meta({ + description: "Show decorative circle element", + }), + + showTealAccent: z.boolean() + .default(true) + .meta({ + description: "Show teal accent areas", + }), + + showBeigSquare: z.boolean() + .default(true) + .meta({ + description: "Show beige square decoration", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const AboutUsSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, companyDescription, additionalText, businessImage, showDecoCircle, showTealAccent, showBeigSquare } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Content */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} + + {/* Decorative gray line */} +
+
+ + {/* Description Text */} + {companyDescription && ( +

+ {companyDescription} +

+ + )} + + {/* Additional Text */} + {additionalText && ( +
+

+ {additionalText} +

+
+ )} +
+ + {/* Right Side - Image and Decorative Elements */} +
+ {/* Yellow Square - Top Right */} + {showBeigSquare && ( +
+ )} + + {/* Decorative Circle - On Yellow Square */} + {showDecoCircle && ( +
+ )} + + {/* Business Image - Left positioned */} + {businessImage?.__image_url__ && ( +
+ {businessImage.__image_prompt__} +
+ )} + + {/* Teal Accent Areas */} + {showTealAccent && ( + <> + {/* Vertical Teal Strip - Center */} +
+ + + )} +
+
+
+ ); +}; + +export default AboutUsSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/BusinessModelSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/BusinessModelSlide.tsx new file mode 100644 index 00000000..f1cf461b --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/BusinessModelSlide.tsx @@ -0,0 +1,222 @@ +import * as z from "zod"; +import { ImageSchema, IconSchema } from "../defaultSchemes"; +import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'; +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from "recharts"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("BUSINESS MODEL") + .meta({ + description: "Main title for the business model section", + }), + + subtitle: z.string() + .min(10) + .max(25) + .default("OUR BUSINESS MODEL") + .meta({ + description: "Subtitle describing the business model", + }), + + description: z.string() + .min(50) + .max(300) + .default("Our business model thrives on delivering value through strategic innovation, client-centric solutions, and a dynamic blend of creativity and analytics.") + .meta({ + description: "Description of the business model", + }), + + businessImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "Business professionals analyzing charts and data on tablet and computer" + }).meta({ + description: "Business analytics header image", + }), + + chartData: z.array(z.object({ + name: z.string(), + series1: z.number(), + series2: z.number(), + series3: z.number() + })).min(3).max(6).default([ + { name: "Item 1", series1: 5, series2: 4, series3: 3 }, + { name: "Item 2", series1: 8, series2: 7, series3: 4 }, + { name: "Item 3", series1: 15, series2: 10, series3: 5 }, + { name: "Item 4", series1: 18, series2: 15, series3: 8 }, + { name: "Item 5", series1: 22, series2: 20, series3: 8 } + ]).meta({ + description: "Chart data for business metrics", + }), + + showYellowAccent: z.boolean() + .default(true) + .meta({ + description: "Show yellow accent decoration", + }), + + showTealAccents: z.boolean() + .default(true) + .meta({ + description: "Show teal accent decorations", + }), +}) + +// Chart configuration +const chartConfig = { + series1: { + label: "Series 1", + color: "#1D9A8A", + }, + series2: { + label: "Series 2", + color: "#E8F4B8", + }, + series3: { + label: "Series 3", + color: "#A8C97F", + }, +}; + +// Type inference +type SchemaType = z.infer; + +// Component definition +const BusinessModelSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, description, businessImage, chartData, showYellowAccent, showTealAccents } = data; + + return ( +
+ {/* Header Image with Teal Decorative Elements */} +
+ {/* Business Image */} + {businessImage?.__image_url__ && ( +
+ {businessImage.__image_prompt__} +
+ )} + + {/* Teal Decorative Accents */} + {showTealAccents && ( + <> + {/* Top left teal block */} +
+ {/* Top right teal block */} +
+ + )} + + {/* Yellow Accent */} + {showYellowAccent && ( +
+ )} +
+ + {/* Content Section */} +
+ {/* Left Side - Title and Description */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

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

+ {description} +

+
+ )} +
+ + {/* Right Side - Chart */} +
+ {/* Chart Legend */} +
+
+
+ Series 1 +
+
+
+ Series 2 +
+
+
+ Series 3 +
+
+ + {/* Chart Container */} + {chartData && chartData.length > 0 && ( +
+ + + + + + + } /> + + + + + + +
+ )} +
+
+
+ ); +}; + +export default BusinessModelSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/HelloFriendsSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/HelloFriendsSlide.tsx new file mode 100644 index 00000000..402f293e --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/HelloFriendsSlide.tsx @@ -0,0 +1,157 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("HELLO FRIENDS!") + .meta({ + description: "Main greeting title", + }), + + subtitle: z.string() + .min(5) + .max(20) + .default("GREETING FROM US") + .meta({ + description: "Subtitle for the greeting", + }), + + welcomeText: z.string() + .min(50) + .max(300) + .default("Ladies and gentlemen, a warm welcome to our business pitch deck presentation. Your time and attention are greatly appreciated. Today, we're excited to share our vision, accomplishments, and the exciting roadmap ahead. Let's embark on this journey together, and thank you for considering an investment in our innovative venture.") + .meta({ + description: "Main welcome message text", + }), + + officeImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1497366216548-37526070297c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Modern office workspace with desk, computer, and large window view" + }).meta({ + description: "Office workspace image in circular frame", + }), + + buttonText: z.string() + .min(3) + .max(20) + .default("Thank you") + .meta({ + description: "Text for the call-to-action button", + }), + + showSpeechBubble: z.boolean() + .default(true) + .meta({ + description: "Show decorative speech bubble", + }), + + showDecoCircle: z.boolean() + .default(true) + .meta({ + description: "Show decorative circle element", + }), + +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const HelloFriendsSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, welcomeText, officeImage, buttonText, showSpeechBubble, showDecoCircle } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Teal Background */} +
+ {/* Speech Bubble */} + {showSpeechBubble && ( +
+
+
+
+
+
+
+ {/* Speech bubble tail */} +
+
+
+
+
+ )} + + {/* Decorative Circle */} + {showDecoCircle && ( +
+ )} +
+ + {/* Right Side - White Background */} +
+ {/* Content */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} + + {/* Decorative underline */} +
+
+ + {/* Welcome Text */} + {welcomeText && ( +
+

+ {welcomeText} +

+
+ )} + + {/* Thank You Button */} + {buttonText && ( +
+ +
+ )} +
+
+
+ + {/* Overlapping Circular Office Image */} + {officeImage?.__image_url__ && ( +
+
+ {officeImage.__image_prompt__} +
+
+ )} +
+ ); +}; + +export default HelloFriendsSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/MarketSizeSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/MarketSizeSlide.tsx new file mode 100644 index 00000000..be6daa20 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/MarketSizeSlide.tsx @@ -0,0 +1,155 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("MARKET SIZE") + .meta({ + description: "Main title for the market size section", + }), + + subtitle: z.string() + .min(10) + .max(25) + .default("OUR CLIENTS COME FROM EVERYWHERE") + .meta({ + description: "Subtitle describing global reach", + }), + + globalDescription: z.string() + .min(50) + .max(200) + .default("With a global perspective, our marketing agency has proudly served multinational clients, delivering tailored strategies that transcend borders and cultures, ensuring consistent brand success on a worldwide scale.") + .meta({ + description: "Description of global market presence", + }), + + worldMapImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1516245834210-c4c142787335?ixlib=rb-4.0.3&auto=format&fit=crop&w=1200&q=80", + __image_prompt__: "World map with location pins showing global business presence" + }).meta({ + description: "World map image showing global reach", + }), + + marketDefinitions: z.array(z.object({ + acronym: z.string().min(2).max(10), + fullName: z.string().min(10).max(50), + description: z.string().min(50).max(300) + })).min(3).max(3).default([ + { + acronym: "TAM", + fullName: "Total Available Market (TAM)", + description: "The Total Available Market (TAM) represents the entire potential demand for our product or service, reflecting the vast landscape of opportunities awaiting exploration and market capture." + }, + { + acronym: "SAM", + fullName: "Serviceable Available Market (SAM)", + description: "The Serviceable Available Market (SAM) represents the specific segment of the Total Available Market where our product or service can be realistically and effectively offered, defining the target audience for our strategic market approach." + }, + { + acronym: "SOM", + fullName: "Serviceable Obtainable Market (SOM)", + description: "The Serviceable Obtainable Market (SOM) signifies the realistic and achievable portion of the Serviceable Available Market where our business aims to capture market share, emphasizing our practical and strategic approach to market penetration." + } + ]).meta({ + description: "Market size definitions for TAM, SAM, and SOM", + }), + + showYellowUnderline: z.boolean() + .default(true) + .meta({ + description: "Show yellow decorative underline", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const MarketSizeSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, globalDescription, worldMapImage, marketDefinitions, showYellowUnderline } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Teal Background with Map */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} + + {/* Yellow Decorative Underline */} + {showYellowUnderline && ( +
+ )} +
+ + {/* World Map Image */} + {worldMapImage?.__image_url__ && ( +
+
+ {worldMapImage.__image_prompt__} +
+
+ )} + + {/* Global Description */} + {globalDescription && ( +
+

+ {globalDescription} +

+
+ )} +
+ + {/* Right Side - White Background with Market Definitions */} +
+ {/* Market Definitions */} + {marketDefinitions && marketDefinitions.length >= 3 && ( +
+ {marketDefinitions.slice(0, 3).map((definition, index) => ( +
+ {/* Header with rounded background */} +
+

+ {definition.fullName} +

+
+ + {/* Description */} +

+ {definition.description} +

+
+ ))} +
+ )} +
+
+
+ ); +}; + +export default MarketSizeSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/OurServiceSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/OurServiceSlide.tsx new file mode 100644 index 00000000..4a7f7e45 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/OurServiceSlide.tsx @@ -0,0 +1,145 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(10) + .default("OUR SERVICE") + .meta({ + description: "Main title for the service section", + }), + + + + services: z.array(z.object({ + title: z.string().min(5).max(40), + description: z.string().min(30).max(100), + image: ImageSchema + })).min(3).max(3).default([ + { + title: "Strategic Brand Development", + description: "Our agency specializes in strategic brand development, ensuring that your brand not only resonates with your target audience but also stands out in a crowded market.", + image: { + __image_url__: "https://images.unsplash.com/photo-1553877522-43269d4ea984?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Business team working on brand strategy with documents and tablet" + } + }, + { + title: "Data-Driven Marketing", + description: "Our data-driven approach ensures that every campaign is backed by insights, maximizing ROI and driving tangible results.", + image: { + __image_url__: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Business analytics with charts, graphs and keyboard on desk" + } + }, + { + title: "Creative Content Production", + description: "Content is king, and our agency excels in producing creative, engaging, and impactful content that resonates with your audience.", + image: { + __image_url__: "https://images.unsplash.com/photo-1542744094-3a31f272c490?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Creative professional working on laptop with design and content" + } + } + ]).meta({ + description: "Three main services with titles, descriptions and images", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C", + __image_prompt__: "Clean modern company logo icon in white" + }).meta({ + description: "Company logo icon", + }), + + companyName: z.string() + .min(2) + .max(25) + .default("Company Name") + .meta({ + description: "Company name for branding", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const OurServiceSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, services, companyLogo, companyName } = data; + + return ( +
+ {/* Header with Title and Company Branding */} +
+ {/* Top Section */} +
+ {/* Left - Title */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} +
+ + {/* Right - Teal Background with Company Branding */} +
+
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+
+
+ + {/* Bottom Section - Services Grid */} +
+ {services && services.length >= 3 && ( +
+ {services.slice(0, 3).map((service, index) => ( +
+ {/* Service Image */} +
+ {service.image.__image_prompt__} +
+ + {/* Service Content */} +
+

+ {service.title} +

+

+ {service.description} +

+
+
+ ))} +
+ )} +
+
+
+ ); +}; + +export default OurServiceSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/ProblemsSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/ProblemsSlide.tsx new file mode 100644 index 00000000..1060cae6 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/ProblemsSlide.tsx @@ -0,0 +1,155 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(20) + .default("PROBLEMS") + .meta({ + description: "Main title for the problems section", + }), + + subtitle: z.string() + .min(10) + .max(25) + .default("WE WILL SOLVE THE PROBLEMS") + .meta({ + description: "Subtitle describing the section", + }), + + problems: z.array(z.object({ + number: z.string().min(1).max(3), + title: z.string().min(5).max(40), + description: z.string().min(20).max(200) + })).min(2).max(3).default([ + { + number: "01", + title: "Lack of Brand Visibility", + description: "Many businesses struggle with gaining visibility in a saturated market. Our solution involves a comprehensive analysis of your brand, audience, and competitors, leading to the development of a strategic branding." + }, + { + number: "02", + title: "Ineffective Digital Presence", + description: "Weak online presence can hinder business growth. Our agency offers an integrated approach to digital marketing, covering SEO optimization, social media management, content marketing, and more." + }, + { + number: "03", + title: "Lack of Targeted Lead Generation", + description: "Many businesses struggle with generating quality leads that convert into customers. Our solution involves a meticulous understanding of your target audience, allowing us to develop highly targeted lead generation campaigns." + } + ]).meta({ + description: "List of problems with numbers, titles and descriptions", + }), + + workspaceImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Clean modern workspace with laptop, plant, and documents on desk" + }).meta({ + description: "Workspace image showing business environment", + }), + + showDecoCircle: z.boolean() + .default(true) + .meta({ + description: "Show decorative circle element", + }), + + showTealAccent: z.boolean() + .default(true) + .meta({ + description: "Show teal accent block", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const ProblemsSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, problems, workspaceImage, showDecoCircle, showTealAccent } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Content */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} +
+ + {/* Problems List */} + {problems && problems.length > 0 && ( +
+ {problems.map((problem, index) => ( +
+ {/* Number Circle */} +
+ + {problem.number} + +
+ + {/* Content */} +
+

+ {problem.title} +

+

+ {problem.description} +

+
+
+ ))} +
+ )} +
+ + {/* Right Side - Image and Decorative Elements */} +
+ {/* Decorative Circle */} + {showDecoCircle && ( +
+ )} + + {/* Workspace Image */} + {workspaceImage?.__image_url__ && ( +
+ {workspaceImage.__image_prompt__} +
+ )} + + {/* Teal Accent Block - Right Edge */} + {showTealAccent && ( +
+ )} +
+
+ + {/* Bottom Teal Stripe */} +
+
+ ); +}; + +export default ProblemsSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/SolutionsSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/SolutionsSlide.tsx new file mode 100644 index 00000000..6e140485 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/SolutionsSlide.tsx @@ -0,0 +1,179 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("SOLUTIONS") + .meta({ + description: "Main title for the solutions section", + }), + + subtitle: z.string() + .min(10) + .max(25) + .default("SOLUTIONS OF THE PROBLEMS") + .meta({ + description: "Subtitle describing the section", + }), + + solutions: z.array(z.object({ + number: z.string().min(1).max(3), + title: z.string().min(5).max(40), + description: z.string().min(20).max(300) + })).min(2).max(3).default([ + { + number: "01", + title: "Lack of Brand Visibility", + description: "By defining your unique value proposition and creating a consistent brand identity, we ensure your business stands out and remains memorable in the minds of your target audience." + }, + { + number: "02", + title: "Ineffective Digital Presence", + description: "Through data-driven insights, we tailor strategies to maximize online visibility, engage your audience, and drive meaningful interactions, converting online engagements into tangible business outcomes." + }, + { + number: "03", + title: "Lack of Targeted Lead Generation", + description: "By leveraging strategic content, paid advertising, and personalized engagement tactics, we ensure that your marketing efforts are focused on reaching and converting the right audience." + } + ]).meta({ + description: "List of solutions with numbers, titles and descriptions", + }), + + workspaceImages: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Business person working on laptop with charts and analytics" + }).meta({ + description: "Two workspace images for left side", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/1D9A8A/FFFFFF?text=C", + __image_prompt__: "Clean modern company logo icon" + }).meta({ + description: "Company logo icon", + }), + + companyName: z.string() + .min(2) + .max(25) + .default("Company Name") + .meta({ + description: "Company name for branding", + }), + + showYellowUnderline: z.boolean() + .default(true) + .meta({ + description: "Show yellow decorative underline", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const SolutionsSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, solutions, workspaceImages, companyLogo, companyName, showYellowUnderline } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Images and Branding */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} + + {/* Yellow Decorative Underline */} + {showYellowUnderline && ( +
+ )} +
+ + {/* Images */} + {workspaceImages && ( +
+ + + +
+ {workspaceImages.__image_prompt__} +
+
+ )} + + {/* Company Branding */} +
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+
+ + {/* Right Side - Teal Background with Solutions */} +
+ {/* Solutions List */} + {solutions && solutions.length > 0 && ( +
+ {solutions.map((solution, index) => ( +
+ {/* Number Circle */} +
+ + {solution.number} + +
+ + {/* Content */} +
+

+ {solution.title} +

+

+ {solution.description} +

+
+
+ ))} +
+ )} +
+
+
+ ); +}; + +export default SolutionsSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/StatisticCircularSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/StatisticCircularSlide.tsx new file mode 100644 index 00000000..4ed6688b --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/StatisticCircularSlide.tsx @@ -0,0 +1,229 @@ +import * as z from "zod"; +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("STATISTIC") + .meta({ + description: "Main title for the statistic section", + }), + + subtitle: z.string() + .min(10) + .max(25) + .default("CLIENT'S SATISFACTION") + .meta({ + description: "Subtitle describing the statistic focus", + }), + + description: z.string() + .min(100) + .max(400) + .default("At the heart of our success lies the unwavering satisfaction of our clients. We take pride in fostering lasting partnerships, consistently exceeding expectations, and delivering results that not only meet but surpass the unique objectives of each client we serve.") + .meta({ + description: "Description of client satisfaction approach", + }), + + circularMetric: z.object({ + value: z.number().min(0).max(100), + label: z.string().min(5).max(30), + percentage: z.string().min(2).max(5) + }).default({ + value: 90, + label: "CLIENT'S REPEAT ORDER", + percentage: "90%" + }).meta({ + description: "Main circular chart metric", + }), + + statisticBlocks: z.array(z.object({ + percentage: z.string().min(2).max(5), + description: z.string().min(20).max(150), + backgroundColor: z.enum(["teal", "beige"]) + })).min(2).max(2).default([ + { + percentage: "90%", + description: "Our client loyalty speaks volumes as evidenced by a robust repeat order rate", + backgroundColor: "teal" + }, + { + percentage: "99%", + description: "Our paramount focus on client satisfaction is the bedrock of our agency's success.", + backgroundColor: "beige" + } + ]).meta({ + description: "Two statistic blocks with percentages and descriptions", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C", + __image_prompt__: "Clean modern company logo icon in white" + }).meta({ + description: "Company logo icon", + }), + + companyName: z.string() + .min(2) + .max(25) + .default("Company Name") + .meta({ + description: "Company name for branding", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const StatisticCircularSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, description, circularMetric, statisticBlocks, companyLogo, companyName } = data; + + const getBackgroundClass = (bg: string) => { + switch (bg) { + case "teal": return "bg-teal-600 text-white"; + case "beige": return "bg-yellow-200 text-gray-900"; + default: return "bg-gray-200 text-gray-900"; + } + }; + + // Calculate stroke dash array for circular progress + const radius = 150; + const circumference = 2 * Math.PI * radius; + const strokeDasharray = circumference; + const strokeDashoffset = circumference - (circumference * (circularMetric?.value || 90) / 100); + + return ( +
+ {/* Main Content Area */} +
+ {/* Header Section */} +
+ {/* Left - Title */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} +
+ + {/* Right - Company Branding */} +
+
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+
+
+ + {/* Content Section */} +
+ {/* Left Side - Circular Chart */} +
+
+ {/* Circular Progress SVG */} + + {/* Background circle */} + + {/* Progress circle */} + + + + {/* Center Content */} +
+ {circularMetric?.label && ( +

+ {circularMetric.label} +

+ )} + {circularMetric?.percentage && ( + + {circularMetric.percentage} + + )} +
+
+
+ + {/* Right Side - Content and Statistics */} +
+ {/* Description */} +
+ {description && ( +

+ {description} +

+ )} +
+ + {/* Statistics Blocks */} + {statisticBlocks && statisticBlocks.length > 0 && ( +
+ {statisticBlocks.map((block, index) => ( +
+ {/* Percentage Block */} +
+ + {block.percentage} + +
+ + {/* Description Block */} +
+

+ {block.description} +

+
+
+ ))} +
+ )} +
+
+
+
+ ); +}; + +export default StatisticCircularSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/StatisticDualChartSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/StatisticDualChartSlide.tsx new file mode 100644 index 00000000..6578a6df --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/StatisticDualChartSlide.tsx @@ -0,0 +1,330 @@ +import * as z from "zod"; +import { ImageSchema, IconSchema } from "../defaultSchemes"; +import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'; +import { BarChart, Bar, AreaChart, Area, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from "recharts"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("STATISTIC") + .meta({ + description: "Main title for the statistic section", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C", + __image_prompt__: "Clean modern company logo icon in white" + }).meta({ + description: "Company logo icon", + }), + + companyName: z.string() + .min(2) + .max(25) + .default("Company Name") + .meta({ + description: "Company name for branding", + }), + + barChartData: z.array(z.object({ + name: z.string(), + series1: z.number(), + series2: z.number(), + series3: z.number() + })).min(5).max(5).default([ + { name: "Item 1", series1: 5, series2: 5, series3: 8 }, + { name: "Item 2", series1: 8, series2: 8, series3: 15 }, + { name: "Item 3", series1: 15, series2: 10, series3: 18 }, + { name: "Item 4", series1: 18, series2: 14, series3: 22 }, + { name: "Item 5", series1: 22, series2: 20, series3: 8 } + ]).meta({ + description: "Bar chart data for customer satisfaction", + }), + + areaChartData: z.array(z.object({ + name: z.string(), + series1: z.number(), + series2: z.number(), + series3: z.number() + })).min(5).max(5).default([ + { name: "Item 1", series1: 20, series2: 30, series3: 15 }, + { name: "Item 2", series1: 40, series2: 45, series3: 35 }, + { name: "Item 3", series1: 45, series2: 50, series3: 80 }, + { name: "Item 4", series1: 50, series2: 45, series3: 85 }, + { name: "Item 5", series1: 80, series2: 75, series3: 120 } + ]).meta({ + description: "Area chart data for repeat order rate", + }), + + leftChartTitle: z.string() + .min(5) + .max(40) + .default("Our Customer's Satisfaction") + .meta({ + description: "Title for the left chart", + }), + + leftChartDescription: z.string() + .min(20) + .max(200) + .default("An impressive client satisfaction rate underscores our unwavering commitment to delivering exceptional service and exceeding expectations.") + .meta({ + description: "Description for the left chart", + }), + + rightChartTitle: z.string() + .min(5) + .max(40) + .default("Repeat Order Rate") + .meta({ + description: "Title for the right chart", + }), + + rightChartDescription: z.string() + .min(20) + .max(200) + .default("Our remarkable client repeat order rate of 123 times are testament to the quality of our products/services and the trust our clients place in our ability.") + .meta({ + description: "Description for the right chart", + }), +}) + +// Chart configuration +const chartConfig = { + series1: { + label: "Series 1", + color: "#1D9A8A", + }, + series2: { + label: "Series 2", + color: "#A8C97F", + }, + series3: { + label: "Series 3", + color: "#E8F4B8", + }, +}; + +// Type inference +type SchemaType = z.infer; + +// Component definition +const StatisticDualChartSlide = ({ data }: { data: Partial }) => { + + const { + mainTitle, + companyLogo, + companyName, + barChartData, + areaChartData, + leftChartTitle, + leftChartDescription, + rightChartTitle, + rightChartDescription + } = data; + + return ( +
+ {/* Header Section */} +
+ {/* Title */} + {mainTitle && ( +

+ {mainTitle} +

+ )} + + {/* Company Branding */} +
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+
+ + {/* Content Section */} +
+ {/* Left Chart Section */} +
+ {/* Chart Legend */} +
+
+
+ Series 1 +
+
+
+ Series 2 +
+
+
+ Series 3 +
+
+ + {/* Bar Chart */} + {barChartData && barChartData.length > 0 && ( +
+ + + + + + + } /> + + + + + + +
+ )} + + {/* Chart Description */} +
+ {leftChartTitle && ( +

+ {leftChartTitle} +

+ )} + {leftChartDescription && ( +

+ {leftChartDescription} +

+ )} +
+
+ + {/* Right Chart Section */} +
+ {/* Chart Legend */} +
+
+
+ Series 1 +
+
+
+ Series 2 +
+
+
+ Series 3 +
+
+ + {/* Area Chart */} + {areaChartData && areaChartData.length > 0 && ( +
+ + + + + + + } /> + + + + + + +
+ )} + + {/* Chart Description */} +
+ {rightChartTitle && ( +

+ {rightChartTitle} +

+ )} + {rightChartDescription && ( +

+ {rightChartDescription} +

+ )} +
+
+
+
+ ); +}; + +export default StatisticDualChartSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/StatisticSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/StatisticSlide.tsx new file mode 100644 index 00000000..535ee86c --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/StatisticSlide.tsx @@ -0,0 +1,262 @@ +import * as z from "zod"; +import { ImageSchema, IconSchema } from "../defaultSchemes"; +import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'; +import { LineChart, Line, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from "recharts"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(12) + .default("STATISTIC") + .meta({ + description: "Main title for the statistic section", + }), + + subtitle: z.string() + .min(10) + .max(18) + .default("CLIENT'S SATISFACTION") + .meta({ + description: "Subtitle describing the statistic focus", + }), + + description: z.string() + .min(80) + .max(200) + .default("At the heart of our success lies the unwavering satisfaction of our clients. We take pride in fostering lasting partnerships, consistently exceeding expectations, and delivering results that not only meet but surpass the unique objectives of each client we serve.") + .meta({ + description: "Description of client satisfaction approach", + }), + + businessImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Business team meeting discussing charts and documents at table" + }).meta({ + description: "Business meeting image showing team collaboration", + }), + + chartData: z.array(z.object({ + name: z.string(), + series1: z.number(), + series2: z.number(), + series3: z.number() + })).min(5).max(5).default([ + { name: "Item 1", series1: 18, series2: 0, series3: 0 }, + { name: "Item 2", series1: 30, series2: 12, series3: 8 }, + { name: "Item 3", series1: 26, series2: 38, series3: 20 }, + { name: "Item 4", series1: 40, series2: 30, series3: 35 }, + { name: "Item 5", series1: 42, series2: 45, series3: 32 } + ]).meta({ + description: "Line chart data for satisfaction metrics", + }), + + bulletPoints: z.array(z.object({ + text: z.string().min(20).max(100), + color: z.enum(["teal", "beige", "light"]) + })).min(3).max(3).default([ + { + text: "From brand positioning and messaging to visual identity, we guide you through every step.", + color: "teal" + }, + { + text: "Navigate the path to increased sales with our insightful report and offering a strategic roadmap.", + color: "beige" + }, + { + text: "Amplify your revenue streams, engage customers, and unlock the full potential of your business.", + color: "light" + } + ]).meta({ + description: "Three bullet points with different colored indicators", + }), + + showYellowUnderline: z.boolean() + .default(true) + .meta({ + description: "Show yellow decorative underline", + }), + + +}) + +// Chart configuration +const chartConfig = { + series1: { + label: "Series 1", + color: "#1D9A8A", + }, + series2: { + label: "Series 2", + color: "#A8C97F", + }, + series3: { + label: "Series 3", + color: "#E8F4B8", + }, +}; + +// Type inference +type SchemaType = z.infer; + +// Component definition +const StatisticSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, subtitle, description, businessImage, chartData, bulletPoints, showYellowUnderline } = data; + + const getColorClass = (color: string) => { + switch (color) { + case "teal": return "bg-teal-600"; + case "beige": return "bg-yellow-300"; + case "light": return "bg-gray-300"; + default: return "bg-gray-300"; + } + }; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Teal Background with Content and Image */} +
+ {/* Top Content Section */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} + + {/* Yellow Decorative Underline */} + {showYellowUnderline && ( +
+ )} +
+ + {/* Description */} + {description && ( +
+

+ {description} +

+
+ )} +
+ + {/* Bottom Business Image */} +
+ {businessImage?.__image_url__ && ( + + {businessImage.__image_prompt__} + + )} + + +
+
+ + {/* Right Side - Chart and Bullet Points */} +
+ {/* Chart Section */} +
+ {/* Chart Legend */} +
+
+
+ Series 1 +
+
+
+ Series 2 +
+
+
+ Series 3 +
+
+ + {/* Chart Container */} + {chartData && chartData.length > 0 && ( +
+ + + + + + + } /> + + + + + + +
+ )} +
+ + {/* Bullet Points Section */} +
+ {bulletPoints && bulletPoints.length > 0 && ( + <> + {bulletPoints.map((point, index) => ( +
+
+

+ {point.text} +

+
+ ))} + + )} +
+
+
+
+ ); +}; + +export default StatisticSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/TableOfContentsSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/TableOfContentsSlide.tsx new file mode 100644 index 00000000..0abf8ebd --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/TableOfContentsSlide.tsx @@ -0,0 +1,161 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + + mainTitle: z.string() + .min(5) + .max(20) + .default("TABLE OF CONTENT") + .meta({ + description: "Main title for the table of contents", + }), + + subtitle: z.string() + .min(10) + .max(25) + .default("PITCH DECK PRESENTATION") + .meta({ + description: "Subtitle describing the presentation type", + }), + + contentItems: z.array(z.object({ + number: z.string().min(1).max(3), + title: z.string().min(3).max(30) + })).min(4).max(8).default([ + { number: "01", title: "Hello Friends!" }, + { number: "02", title: "About Us" }, + { number: "03", title: "What We Believe" }, + { number: "04", title: "Problems & Solutions" }, + { number: "05", title: "Market Size" }, + { number: "06", title: "Statistic" } + ]).meta({ + description: "List of content items with numbers and titles", + }), + + heroImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1498050108023-c5249f4df085?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Modern laptop and office workspace on wooden desk" + }).meta({ + description: "Hero image showing professional workspace", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/1D9A8A/FFFFFF?text=C", + __image_prompt__: "Clean modern company logo icon" + }).meta({ + description: "Company logo icon", + }), + + companyName: z.string() + .min(2) + .max(25) + .default("Company Name") + .meta({ + description: "Company name for branding", + }), + + decorativeCircle: z.boolean() + .default(true) + .meta({ + description: "Show decorative circle element", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const TableOfContentsSlide = ({ data }: { data: Partial }) => { + + + const { mainTitle, subtitle, contentItems, heroImage, companyLogo, companyName, decorativeCircle } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Content */} +
+ {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {/* Decorative underline */} +
+ + {subtitle && ( +

+ {subtitle} +

+ )} +
+ + {/* Content Items */} + {contentItems && contentItems.length > 0 && ( +
+ {contentItems.map((item, index) => ( +
+
+ + {item.number} + +
+
+ {item.title} +
+
+ ))} +
+ )} +
+ + {/* Right Side - Image and Branding */} +
+ {/* Hero Image */} + {heroImage?.__image_url__ && ( +
+ {heroImage.__image_prompt__} +
+ )} + + {/* Decorative Circle */} + {decorativeCircle && ( +
+ )} + + {/* Company Branding */} +
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+
+
+
+ ); +}; + +export default TableOfContentsSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/TestimonialSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/TestimonialSlide.tsx new file mode 100644 index 00000000..71b672ff --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/TestimonialSlide.tsx @@ -0,0 +1,180 @@ +import * as z from "zod"; +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + mainTitle: z.string() + .min(5) + .max(15) + .default("TESTIMONIAL") + .meta({ + description: "Main title for the testimonial section", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C", + __image_prompt__: "Clean modern company logo icon in white" + }).meta({ + description: "Company logo icon", + }), + + companyName: z.string() + .min(2) + .max(25) + .default("Company Name") + .meta({ + description: "Company name for branding", + }), + + testimonials: z.array(z.object({ + text: z.string().min(30).max(200), + clientName: z.string().min(2).max(30), + clientPhoto: ImageSchema, + rating: z.number().min(1).max(5), + backgroundColor: z.enum(["beige", "teal", "light"]) + })).min(3).max(3).default([ + { + text: "In a world flooded with marketing noise, this company stands out as a beacon of creativity and effectiveness.", + clientName: "Benjamin Shah", + clientPhoto: { + __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 headshot of smiling businessman" + }, + rating: 5, + backgroundColor: "beige" + }, + { + text: "The level of expertise and personalized attention to our unique needs has made them an invaluable partner.", + clientName: "Murad Naser", + clientPhoto: { + __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 headshot of confident businessman with beard" + }, + rating: 5, + backgroundColor: "teal" + }, + { + text: "I've been thoroughly impressed with the exceptional level of service and creativity they bring to the table.", + clientName: "Drew Feig", + clientPhoto: { + __image_url__: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80", + __image_prompt__: "Professional headshot of smiling young businessman" + }, + rating: 5, + backgroundColor: "light" + } + ]).meta({ + description: "Three client testimonials with photos and ratings", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const TestimonialSlide = ({ data }: { data: Partial }) => { + + const { mainTitle, companyLogo, companyName, testimonials } = data; + + const getBackgroundClass = (bg: string) => { + switch (bg) { + case "teal": return "bg-teal-600 text-white"; + case "beige": return "bg-yellow-100 text-gray-900"; + case "light": return "bg-gray-100 text-gray-900"; + default: return "bg-gray-100 text-gray-900"; + } + }; + + const getStarColor = (bg: string) => { + return bg === "teal" ? "text-yellow-400" : "text-yellow-500"; + }; + + const renderStars = (rating: number, backgroundColor: string) => { + return ( +
+ {[...Array(5)].map((_, index) => ( + + + + ))} +
+ ); + }; + + return ( +
+ {/* Header Section */} +
+ {/* Title */} + {mainTitle && ( +

+ {mainTitle} +

+ )} + + {/* Company Branding */} +
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+
+ + {/* Testimonials Section */} +
+ {testimonials && testimonials.length > 0 && ( +
+ {testimonials.map((testimonial, index) => ( +
+ {/* Stars */} + {renderStars(testimonial.rating, testimonial.backgroundColor)} + + {/* Testimonial Text */} +

+ {testimonial.text} +

+ + {/* Client Photo */} + {testimonial.clientPhoto?.__image_url__ && ( +
+ {testimonial.clientPhoto.__image_prompt__} +
+ )} + + {/* Client Name */} +

+ {testimonial.clientName} +

+
+ ))} +
+ )} +
+
+ ); +}; + +export default TestimonialSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/ThankYouSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/ThankYouSlide.tsx new file mode 100644 index 00000000..695c51ad --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/ThankYouSlide.tsx @@ -0,0 +1,183 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + + companyName: z.string() + .min(2) + .max(15) + .default("Company Name") + .meta({ + description: "Company name displayed prominently", + }), + + mainTitle: z.string() + .min(5) + .max(20) + .default("THANK YOU") + .meta({ + description: "Main thank you title in large bold letters", + }), + + subtitle: z.string() + .min(10) + .max(40) + .default("FOR YOUR NICE ATTENTION") + .meta({ + description: "Subtitle thanking the audience", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=C", + __image_prompt__: "Company logo - geometric green icon" + }).meta({ + description: "Company logo icon", + }), + + contactInfo: z.object({ + telephone: z.string().min(10).max(20).default("+123-456-7890"), + address: z.string().min(10).max(50).default("123 Anywhere St., Any City, ST 12345"), + website: z.string().min(10).max(30).default("www.reallygreatsite.com") + }).default({ + telephone: "+123-456-7890", + address: "123 Anywhere St., Any City, ST 12345", + website: "www.reallygreatsite.com" + }).meta({ + description: "Company contact information", + }), + + presentationDate: z.string() + .min(5) + .max(20) + .default("December 2023") + .meta({ + description: "Date of the presentation", + }), + + decorativeCircle: z.boolean() + .default(true) + .meta({ + description: "Show decorative circle element", + }), + + arrowButton: z.boolean() + .default(true) + .meta({ + description: "Show navigation arrow button", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const ThankYouSlide = ({ data }: { data: Partial }) => { + + const { companyName, mainTitle, subtitle, companyLogo, contactInfo, presentationDate, decorativeCircle, arrowButton } = data; + + return ( +
+ {/* Header with Logo and Arrow */} +
+ {/* Company Logo and Name */} +
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+ + {/* Arrow Button */} + {arrowButton && ( +
+ + + +
+ )} +
+ + {/* Decorative Circle */} + {decorativeCircle && ( +
+ )} + + {/* Main Content */} +
+
+ {/* Main Title */} + {mainTitle && ( +

+ {mainTitle} +

+ )} + + {/* Subtitle with Circle Bullet */} + {subtitle && ( +
+
+

+ {subtitle} +

+
+ )} +
+
+ + {/* Footer with Contact Info */} +
+
+
+ {/* Telephone */} + {contactInfo?.telephone && ( +
+
Telephone
+
{contactInfo.telephone}
+
+ )} + + {/* Address */} + {contactInfo?.address && ( +
+
Address
+
{contactInfo.address}
+
+ )} + + {/* Website */} + {contactInfo?.website && ( +
+
Website
+
{contactInfo.website}
+
+ )} +
+ + {/* Presentation Date */} + {presentationDate && ( +
+
+ {presentationDate} +
+
+ )} +
+
+
+ ); +}; + +export default ThankYouSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/TitleSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/TitleSlide.tsx new file mode 100644 index 00000000..6b1d41e9 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/TitleSlide.tsx @@ -0,0 +1,184 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + + companyName: z.string() + .min(2) + .max(15) + .default("Thynk Unlimited") + .meta({ + description: "Company name displayed prominently", + }), + + mainTitle: z.string() + .min(5) + .max(15) + .default("PITCH DECK") + .meta({ + description: "Main title in large bold letters", + }), + + subtitle: z.string() + .min(10) + .max(40) + .default("BUSINESS PRESENTATION") + .meta({ + description: "Subtitle describing the presentation type", + }), + + companyLogo: ImageSchema.default({ + __image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=T", + __image_prompt__: "Thynk Unlimited logo - geometric green icon" + }).meta({ + description: "Company logo icon", + }), + + contactInfo: z.object({ + telephone: z.string().min(10).max(20).default("+123-456-7890"), + address: z.string().min(10).max(50).default("123 Anywhere St., Any City, ST 12345"), + website: z.string().min(10).max(30).default("www.reallygreatsite.com") + }).default({ + telephone: "+123-456-7890", + address: "123 Anywhere St., Any City, ST 12345", + website: "www.reallygreatsite.com" + }).meta({ + description: "Company contact information", + }), + + presentationDate: z.string() + .min(5) + .max(20) + .default("December 2023") + .meta({ + description: "Date of the presentation", + }), + + decorativeCircle: z.boolean() + .default(true) + .meta({ + description: "Show decorative circle element", + }), + + arrowButton: z.boolean() + .default(true) + .meta({ + description: "Show navigation arrow button", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const ThynkTitleSlide = ({ data }: { data: Partial }) => { + + + const { companyName, mainTitle, subtitle, companyLogo, contactInfo, presentationDate, decorativeCircle, arrowButton } = data; + + return ( +
+ {/* Header with Logo and Arrow */} +
+ {/* Company Logo and Name */} +
+ {companyLogo?.__image_url__ && ( +
+ {companyLogo.__image_prompt__} +
+ )} + {companyName && ( + + {companyName} + + )} +
+ + {/* Arrow Button */} + {arrowButton && ( +
+ + + +
+ )} +
+ + {/* Decorative Circle */} + {decorativeCircle && ( +
+ )} + + {/* Main Content */} +
+
+ {/* Main Title */} + {mainTitle && ( +

+ {mainTitle} +

+ )} + + {/* Subtitle with Circle Bullet */} + {subtitle && ( +
+
+

+ {subtitle} +

+
+ )} +
+
+ + {/* Footer with Contact Info */} +
+
+
+ {/* Telephone */} + {contactInfo?.telephone && ( +
+
Telephone
+
{contactInfo.telephone}
+
+ )} + + {/* Address */} + {contactInfo?.address && ( +
+
Address
+
{contactInfo.address}
+
+ )} + + {/* Website */} + {contactInfo?.website && ( +
+
Website
+
{contactInfo.website}
+
+ )} +
+ + {/* Presentation Date */} + {presentationDate && ( +
+
+ {presentationDate} +
+
+ )} +
+
+
+ ); +}; + +export default ThynkTitleSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/WhatWeBelieveSlide.tsx b/servers/nextjs/presentation-layouts/pitch-deck/WhatWeBelieveSlide.tsx new file mode 100644 index 00000000..0ab76e6f --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/WhatWeBelieveSlide.tsx @@ -0,0 +1,159 @@ +import * as z from "zod"; + +import { ImageSchema, IconSchema } from "../defaultSchemes"; + +// Schema definition +export const Schema = z.object({ + + + mainTitle: z.string() + .min(5) + .max(15) + .default("WHAT WE BELIEVE") + .meta({ + description: "Main title for the beliefs section", + }), + + subtitle: z.string() + .min(10) + .max(30) + .default("ABOUT OUR VISION AND MISSION") + .meta({ + description: "Subtitle describing the section", + }), + + visionTitle: z.string() + .min(3) + .max(15) + .default("VISION") + .meta({ + description: "Vision section title", + }), + + visionText: z.string() + .min(50) + .max(300) + .default("Our vision is to be the catalyst for transformative marketing solutions that redefine industry standards. We envision a future where brands not only captivate their audience but also inspire meaningful connections.") + .meta({ + description: "Vision statement text", + }), + + missionTitle: z.string() + .min(3) + .max(15) + .default("MISSION") + .meta({ + description: "Mission section title", + }), + + missionText: z.string() + .min(50) + .max(400) + .default("Our mission is to deliver strategic and impactful marketing solutions that propel businesses to new heights of success. We are committed to leveraging our expertise in data-driven insights, creative storytelling, and cutting-edge technology to craft bespoke campaigns.") + .meta({ + description: "Mission statement text", + }), + + teamImage: ImageSchema.default({ + __image_url__: "https://images.unsplash.com/photo-1522202176988-66273c2fd55f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80", + __image_prompt__: "Business team collaboration meeting with documents and discussion" + }).meta({ + description: "Team collaboration image", + }), + + showYellowAccent: z.boolean() + .default(true) + .meta({ + description: "Show yellow accent block", + }), +}) + +// Type inference +type SchemaType = z.infer; + +// Component definition +const WhatWeBelieveSlide = ({ data }: { data: Partial }) => { + + + const { mainTitle, subtitle, visionTitle, visionText, missionTitle, missionText, teamImage, showYellowAccent } = data; + + return ( +
+ {/* Main Content Area */} +
+ {/* Left Side - Image */} +
+ {/* Team Image */} + {teamImage?.__image_url__ && ( +
+ {teamImage.__image_prompt__} +
+ )} + + {/* Yellow Accent Block - Bottom Left */} + {showYellowAccent && ( +
+ )} + + {/* Teal Accent Block - Bottom */} +
+
+ + {/* Right Side - Content */} +
+
+ + {/* Title Section */} +
+ {mainTitle && ( +

+ {mainTitle} +

+ )} + + {subtitle && ( +

+ {subtitle} +

+ )} +
+ + {/* Vision Section */} +
+ {visionTitle && ( +

+ {visionTitle} +

+ )} + {visionText && ( +

+ {visionText} +

+ )} +
+ +
+ {/* Mission Section with Teal Background */} +
+ {missionTitle && ( +

+ {missionTitle} +

+ )} + {missionText && ( +

+ {missionText} +

+ )} +
+
+
+
+ ); +}; + +export default WhatWeBelieveSlide; \ No newline at end of file diff --git a/servers/nextjs/presentation-layouts/pitch-deck/setting.json b/servers/nextjs/presentation-layouts/pitch-deck/setting.json new file mode 100644 index 00000000..4b565369 --- /dev/null +++ b/servers/nextjs/presentation-layouts/pitch-deck/setting.json @@ -0,0 +1,5 @@ +{ + "description": "This is a new pitch deck layout with a focus on simplicity and clarity.", + "ordered": false, + "isDefault": false +} \ No newline at end of file