Merge pull request #127 from presenton/feat/new_layout
style(nextjs): New layouts styles & description tuned
This commit is contained in:
commit
0b32eab54b
22 changed files with 1367 additions and 1360 deletions
|
|
@ -61,7 +61,7 @@ const TiptapText: React.FC<TiptapTextProps> = ({
|
|||
return (
|
||||
<div className="relative z-50 w-full">
|
||||
<BubbleMenu editor={editor} tippyOptions={{ duration: 100 }}>
|
||||
<div className="flex bg-white rounded-lg shadow-lg p-2 gap-1 border border-gray-200 z-50">
|
||||
<div className="flex text-black bg-white rounded-lg shadow-lg p-2 gap-1 border border-gray-200 z-50">
|
||||
<button
|
||||
onClick={() => editor?.chain().focus().toggleBold().run()}
|
||||
className={`p-1 rounded hover:bg-gray-100 transition-colors ${editor?.isActive("bold") ? "bg-blue-100 text-blue-600" : ""
|
||||
|
|
|
|||
|
|
@ -99,8 +99,7 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
|
|||
const root = ReactDOM.createRoot(tiptapContainer);
|
||||
root.render(
|
||||
<TiptapText
|
||||
key={JSON.stringify(slideData)}
|
||||
content={dataPath.originalText}
|
||||
content={trimmedText}
|
||||
onContentChange={(content: string) => {
|
||||
if (dataPath && onContentChange) {
|
||||
onContentChange(content, dataPath.path, slideIndex);
|
||||
|
|
|
|||
|
|
@ -184,9 +184,11 @@ const Header = ({
|
|||
);
|
||||
|
||||
return (
|
||||
<div className="bg-[#5146E5] w-full shadow-lg sticky top-0 z-50">
|
||||
<div style={{
|
||||
zIndex: 1000,
|
||||
}} className="bg-[#5146E5] w-full shadow-lg sticky top-0 z-50">
|
||||
<OverlayLoader
|
||||
show={showLoader}
|
||||
show={false}
|
||||
text="Exporting presentation..."
|
||||
showProgress={true}
|
||||
duration={40}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"use client";
|
||||
import React, { useState } from "react";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "@/store/store";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
|
@ -18,8 +18,13 @@ import {
|
|||
} from "../hooks";
|
||||
import { PresentationPageProps } from "../types";
|
||||
import LoadingState from "./LoadingState";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
|
||||
const PresentationPage: React.FC<PresentationPageProps> = ({ presentation_id }) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const isPresentMode = searchParams.get("mode") === "present";
|
||||
const stream = searchParams.get("stream");
|
||||
// State management
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selectedSlide, setSelectedSlide] = useState(0);
|
||||
|
|
@ -45,20 +50,7 @@ const PresentationPage: React.FC<PresentationPageProps> = ({ presentation_id })
|
|||
setLoading,
|
||||
setError
|
||||
);
|
||||
const {
|
||||
isPresentMode,
|
||||
stream,
|
||||
currentSlide,
|
||||
handleSlideClick,
|
||||
toggleFullscreen,
|
||||
handlePresentExit,
|
||||
handleSlideChange,
|
||||
} = usePresentationNavigation(
|
||||
presentation_id,
|
||||
selectedSlide,
|
||||
setSelectedSlide,
|
||||
setIsFullscreen
|
||||
);
|
||||
|
||||
|
||||
// Initialize streaming
|
||||
usePresentationStreaming(
|
||||
|
|
@ -75,12 +67,49 @@ const PresentationPage: React.FC<PresentationPageProps> = ({ presentation_id })
|
|||
handleSlideChange(newSlide, presentationData);
|
||||
};
|
||||
|
||||
const handleSlideClick = useCallback((index: number) => {
|
||||
console.log("handleSlideClick", index);
|
||||
const slideElement = document.getElementById(`slide-${index}`);
|
||||
if (slideElement) {
|
||||
slideElement.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
setSelectedSlide(index);
|
||||
}
|
||||
}, [setSelectedSlide]);
|
||||
|
||||
const toggleFullscreen = useCallback(() => {
|
||||
if (!document.fullscreenElement) {
|
||||
document.documentElement.requestFullscreen();
|
||||
setIsFullscreen(true);
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
setIsFullscreen(false);
|
||||
}
|
||||
}, [setIsFullscreen]);
|
||||
|
||||
const handlePresentExit = useCallback(() => {
|
||||
setIsFullscreen(false);
|
||||
router.push(`/presentation?id=${presentation_id}`);
|
||||
}, [router, presentation_id, setIsFullscreen]);
|
||||
|
||||
const handleSlideChange = useCallback((newSlide: number, presentationData: any) => {
|
||||
if (newSlide >= 0 && newSlide < presentationData?.slides.length!) {
|
||||
setSelectedSlide(newSlide);
|
||||
router.push(
|
||||
`/presentation?id=${presentation_id}&mode=present&slide=${newSlide}`,
|
||||
{ scroll: false }
|
||||
);
|
||||
}
|
||||
}, [router, presentation_id, setSelectedSlide]);
|
||||
|
||||
// Presentation Mode View
|
||||
if (isPresentMode) {
|
||||
return (
|
||||
<PresentationMode
|
||||
slides={presentationData?.slides!}
|
||||
currentSlide={currentSlide}
|
||||
currentSlide={selectedSlide}
|
||||
|
||||
isFullscreen={isFullscreen}
|
||||
onFullscreenToggle={toggleFullscreen}
|
||||
|
|
@ -122,7 +151,7 @@ const PresentationPage: React.FC<PresentationPageProps> = ({ presentation_id })
|
|||
|
||||
</div>
|
||||
|
||||
<Header presentation_id={presentation_id} currentSlide={currentSlide} />
|
||||
<Header presentation_id={presentation_id} currentSlide={selectedSlide} />
|
||||
<Help />
|
||||
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -263,8 +263,8 @@ const SidePanel = ({
|
|||
className={` cursor-pointer ring-2 p-1 rounded-md transition-all duration-200 ${selectedSlide === index ? ' ring-[#5141e5]' : 'ring-gray-200'
|
||||
}`}
|
||||
>
|
||||
<div className=" bg-white relative overflow-hidden aspect-video">
|
||||
<div className="absolute bg-gray-100/5 z-40 top-0 left-0 w-full h-full" />
|
||||
<div className=" bg-white pointer-events-none relative overflow-hidden aspect-video">
|
||||
<div className="absolute bg-gray-100/5 z-50 top-0 left-0 w-full h-full" />
|
||||
<div className="transform scale-[0.2] flex justify-center items-center origin-top-left w-[500%] h-[500%]">
|
||||
{renderSlideContent(slide, false)}
|
||||
</div>
|
||||
|
|
@ -274,7 +274,7 @@ const SidePanel = ({
|
|||
) : (
|
||||
<SortableContext
|
||||
items={
|
||||
presentationData?.slides.map((slide: any) => slide.id!) || []
|
||||
presentationData?.slides.map((slide: any) => slide.id || `${slide.index}`) || []
|
||||
}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export function SortableSlide({ slide, index, selectedSlide, onSlideClick, rende
|
|||
transform,
|
||||
transition,
|
||||
isDragging
|
||||
} = useSortable({ id: slide.id! });
|
||||
} = useSortable({ id: slide.id || `${slide.index}` });
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
|
|
@ -30,15 +30,19 @@ export function SortableSlide({ slide, index, selectedSlide, onSlideClick, rende
|
|||
};
|
||||
|
||||
const handleMouseDown = () => {
|
||||
console.log("mouse down");
|
||||
setMouseDownTime(Date.now());
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
console.log("mouse up");
|
||||
const mouseUpTime = Date.now();
|
||||
const timeDiff = mouseUpTime - mouseDownTime;
|
||||
console.log("timeDiff", timeDiff);
|
||||
|
||||
// If the mouse was down for less than 200ms, consider it a click
|
||||
if (timeDiff < 200 && !isDragging) {
|
||||
// If the mouse was down for less than 300ms, consider it a click
|
||||
if (timeDiff < 300 && !isDragging) {
|
||||
console.log("clicked");
|
||||
onSlideClick(slide.index);
|
||||
}
|
||||
};
|
||||
|
|
@ -51,12 +55,13 @@ export function SortableSlide({ slide, index, selectedSlide, onSlideClick, rende
|
|||
{...listeners}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseUp={handleMouseUp}
|
||||
className={` cursor-pointer border-[3px] p-1 shadow-lg rounded-md transition-all duration-200 ${selectedSlide === index ? ' border-[#5141e5]' : 'border-gray-300'
|
||||
|
||||
className={` cursor-pointer border-[3px] relative p-1 shadow-lg rounded-md transition-all duration-200 ${selectedSlide === index ? ' border-[#5141e5]' : 'border-gray-300'
|
||||
}`}
|
||||
>
|
||||
<div className=" slide-box relative overflow-hidden aspect-video">
|
||||
<div className="absolute bg-transparent z-40 top-0 left-0 w-full h-full" />
|
||||
<div className="transform scale-[0.2] flex justify-center items-center origin-top-left w-[500%] h-[500%]">
|
||||
<div className=" slide-box relative z-50 overflow-hidden aspect-video">
|
||||
<div className="absolute bg-transparent z-50 top-0 left-0 w-full h-full" />
|
||||
<div className="transform scale-[0.2] flex pointer-events-none justify-center items-center origin-top-left w-[500%] h-[500%]">
|
||||
{renderSlideContent(slide, false)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,66 +1,73 @@
|
|||
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
|
||||
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(25)
|
||||
.default("ABOUT US")
|
||||
.meta({
|
||||
description: "Main title for the about us section",
|
||||
description: "Main section heading - can be used for any organizational introduction",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
.min(10)
|
||||
.max(20)
|
||||
sectionSubtitle: z.string()
|
||||
.min(5)
|
||||
.max(40)
|
||||
.default("GET TO KNOW US BETTER")
|
||||
.meta({
|
||||
description: "Subtitle describing the section",
|
||||
description: "Supporting subtitle that invites audience engagement and builds connection",
|
||||
}),
|
||||
|
||||
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()
|
||||
organizationDescription: 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.")
|
||||
.max(300)
|
||||
.default("We believe in the transformative power of innovation, strategic thinking, and cutting-edge solutions. Our mission is simple: to empower organizations with comprehensive strategies that not only elevate performance but also drive tangible growth and success.")
|
||||
.meta({
|
||||
description: "Additional descriptive text",
|
||||
description: "Primary description of the organization's mission, values, and approach",
|
||||
}),
|
||||
|
||||
businessImage: ImageSchema.default({
|
||||
additionalContext: z.string()
|
||||
.min(30)
|
||||
.max(150)
|
||||
.default("What sets us apart is not just our expertise but our commitment to understanding the unique needs of each client.")
|
||||
.meta({
|
||||
description: "Additional context or differentiating statement about the organization",
|
||||
}),
|
||||
|
||||
featuredImage: 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"
|
||||
__image_prompt__: "Professional business team analyzing data and working collaboratively"
|
||||
}).meta({
|
||||
description: "Business analytics image showing data analysis",
|
||||
description: "Primary visual that represents the organization's work or environment",
|
||||
}),
|
||||
|
||||
showDecoCircle: z.boolean()
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative circle element",
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
|
||||
showTealAccent: z.boolean()
|
||||
showColorBlocks: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show teal accent areas",
|
||||
description: "Whether to show colored background blocks for visual hierarchy",
|
||||
}),
|
||||
|
||||
showBeigSquare: z.boolean()
|
||||
showAccentSquare: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show beige square decoration",
|
||||
description: "Whether to display the accent square decoration element",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -70,7 +77,7 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const AboutUsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, companyDescription, additionalText, businessImage, showDecoCircle, showTealAccent, showBeigSquare } = data;
|
||||
const { sectionTitle, sectionSubtitle, organizationDescription, additionalContext, featuredImage, showVisualAccents, showColorBlocks, showAccentSquare } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
|
|
@ -80,15 +87,15 @@ const AboutUsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="w-3/5 relative bg-white px-16 py-12 flex flex-col justify-center">
|
||||
{/* Title Section */}
|
||||
<div className="mb-0">
|
||||
{mainTitle && (
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide mb-6">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
|
|
@ -97,18 +104,18 @@ const AboutUsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</div>
|
||||
|
||||
{/* Description Text */}
|
||||
{companyDescription && (
|
||||
{organizationDescription && (
|
||||
<p className="text-base leading-relaxed text-gray-700 max-w-xl">
|
||||
{companyDescription}
|
||||
{organizationDescription}
|
||||
</p>
|
||||
|
||||
)}
|
||||
|
||||
{/* Additional Text */}
|
||||
{additionalText && (
|
||||
{additionalContext && (
|
||||
<div>
|
||||
<p className="text-base leading-relaxed text-gray-700 max-w-xl">
|
||||
{additionalText}
|
||||
{additionalContext}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -117,28 +124,28 @@ const AboutUsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{/* Right Side - Image and Decorative Elements */}
|
||||
<div className="w-2/5 relative">
|
||||
{/* Yellow Square - Top Right */}
|
||||
{showBeigSquare && (
|
||||
{showAccentSquare && (
|
||||
<div className="absolute bottom-0 right-0 w-24 h-24 bg-yellow-300 z-20"></div>
|
||||
)}
|
||||
|
||||
{/* Decorative Circle - On Yellow Square */}
|
||||
{showDecoCircle && (
|
||||
{showVisualAccents && (
|
||||
<div className="absolute top-6 right-6 w-6 h-6 border-2 border-teal-600 rounded-full z-30"></div>
|
||||
)}
|
||||
|
||||
{/* Business Image - Left positioned */}
|
||||
{businessImage?.__image_url__ && (
|
||||
{featuredImage?.__image_url__ && (
|
||||
<div className="absolute right-36 top-1/2 -translate-y-1/2 h-[500px] w-[350px] z-20 shadow-lg">
|
||||
<img
|
||||
src={businessImage.__image_url__}
|
||||
alt={businessImage.__image_prompt__}
|
||||
src={featuredImage.__image_url__}
|
||||
alt={featuredImage.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teal Accent Areas */}
|
||||
{showTealAccent && (
|
||||
{showColorBlocks && (
|
||||
<>
|
||||
{/* Vertical Teal Strip - Center */}
|
||||
<div className="absolute top-0 right-0 bottom-16 h-full w-[300px] bg-teal-600 z-10"></div>
|
||||
|
|
|
|||
|
|
@ -1,67 +1,66 @@
|
|||
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";
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid } from "recharts";
|
||||
|
||||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("BUSINESS MODEL")
|
||||
.meta({
|
||||
description: "Main title for the business model section",
|
||||
description: "Main section heading - adapt to presentation topic (e.g., 'Revenue Strategy', 'Funding Model', 'Implementation Plan', 'Solution Framework')",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(25)
|
||||
.default("OUR BUSINESS MODEL")
|
||||
.max(60)
|
||||
.default("SUSTAINABLE REVENUE AND VALUE CREATION")
|
||||
.meta({
|
||||
description: "Subtitle describing the business model",
|
||||
description: "Supporting subtitle that describes the approach - adapt to topic (e.g., 'Carbon Reduction Strategy', 'Healthcare Delivery Model', 'Educational Framework')",
|
||||
}),
|
||||
|
||||
description: z.string()
|
||||
modelDescription: 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.")
|
||||
.default("Our business model focuses on creating sustainable value through multiple revenue streams, strategic partnerships, and customer-centric solutions. We prioritize long-term relationships and scalable growth opportunities.")
|
||||
.meta({
|
||||
description: "Description of the business model",
|
||||
description: "IMPORTANT: Provide topic-specific description of the model/approach. For global warming: describe carbon reduction strategies, renewable energy adoption, sustainability metrics. For healthcare: treatment protocols, patient care models. For education: learning methodologies, curriculum design. Always provide concrete, relevant details for the presentation topic.",
|
||||
}),
|
||||
|
||||
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"
|
||||
headerVisual: ImageSchema.default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1559136555-9303baea8ebd?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
__image_prompt__: "Business strategy meeting with charts, graphs and team collaboration"
|
||||
}).meta({
|
||||
description: "Business analytics header image",
|
||||
description: "Header visual representing the topic area - ADAPT the image prompt to match presentation topic (e.g., 'Climate scientists analyzing global warming data', 'Medical team reviewing patient care protocols', 'Teachers planning educational curriculum')",
|
||||
}),
|
||||
|
||||
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 }
|
||||
category: z.string().min(3).max(25),
|
||||
value: z.number().min(0).max(100),
|
||||
color: z.string().min(3).max(20).optional()
|
||||
})).min(2).max(6).default([
|
||||
{ category: "Product Sales", value: 45, color: "#22C55E" },
|
||||
{ category: "Services", value: 30, color: "#0891B2" },
|
||||
{ category: "Partnerships", value: 15, color: "#FDE047" },
|
||||
{ category: "Licensing", value: 10, color: "#F97316" }
|
||||
]).meta({
|
||||
description: "Chart data for business metrics",
|
||||
description: "CRITICAL: Provide actual data relevant to the presentation topic. For global warming: CO2 emission sources (Transport 29%, Energy 25%, Industry 21%, Agriculture 24%), temperature rise by decade, renewable energy adoption rates. For healthcare: treatment success rates, patient demographics, cost breakdowns. For education: student performance metrics, learning outcomes, resource allocation. Always use REAL topic-specific data with appropriate categories and realistic values.",
|
||||
}),
|
||||
|
||||
showYellowAccent: z.boolean()
|
||||
showChart: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show yellow accent decoration",
|
||||
description: "Whether to display the data visualization - typically keep true for data-driven presentations",
|
||||
}),
|
||||
|
||||
showTealAccents: z.boolean()
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show teal accent decorations",
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -87,134 +86,100 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const BusinessModelSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, description, businessImage, chartData, showYellowAccent, showTealAccents } = data;
|
||||
const { sectionTitle, sectionSubtitle, modelDescription, headerVisual, chartData, showChart, showVisualAccents } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Header Image with Teal Decorative Elements */}
|
||||
<div className="relative h-1/3">
|
||||
{/* Business Image */}
|
||||
{businessImage?.__image_url__ && (
|
||||
<div className="absolute inset-0">
|
||||
<img
|
||||
src={businessImage.__image_url__}
|
||||
alt={businessImage.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Header Image Section */}
|
||||
{headerVisual?.__image_url__ && (
|
||||
<div className="h-32 w-full relative">
|
||||
<img
|
||||
src={headerVisual.__image_url__}
|
||||
alt={headerVisual.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black bg-opacity-40"></div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teal Decorative Accents */}
|
||||
{showTealAccents && (
|
||||
<>
|
||||
{/* Top left teal block */}
|
||||
<div className="absolute top-0 left-0 w-20 h-full bg-teal-600 z-10"></div>
|
||||
{/* Top right teal block */}
|
||||
<div className="absolute top-0 right-0 w-32 h-full bg-teal-600 z-10"></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Yellow Accent */}
|
||||
{showYellowAccent && (
|
||||
<div className="absolute top-0 right-32 w-24 h-16 bg-yellow-300 z-15"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Content Section */}
|
||||
<div className="h-2/3 flex">
|
||||
{/* Left Side - Title and Description */}
|
||||
<div className="w-1/2 px-16 py-8 flex flex-col justify-center bg-gray-50">
|
||||
{/* Main Content Area */}
|
||||
<div className="flex h-[calc(100%-8rem)]">
|
||||
{/* Left Side - Content */}
|
||||
<div className="w-1/2 px-16 py-8 flex flex-col justify-start">
|
||||
{/* Title Section */}
|
||||
<div className="mb-6">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide mb-6">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
{/* Model Description */}
|
||||
{modelDescription && (
|
||||
<div>
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{description}
|
||||
{modelDescription}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Visual Accents */}
|
||||
{showVisualAccents && (
|
||||
<>
|
||||
<div className="absolute bottom-8 left-8 w-6 h-6 bg-yellow-300 rounded-full"></div>
|
||||
<div className="absolute top-40 right-1/2 w-4 h-4 bg-teal-600 rounded-full"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - Chart */}
|
||||
<div className="w-1/2 px-8 py-8 flex flex-col justify-center bg-white">
|
||||
{/* Chart Legend */}
|
||||
<div className="flex items-center justify-end mb-4 space-x-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-teal-600 rounded-full"></div>
|
||||
<span className="text-sm text-gray-600">Series 1</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-yellow-200 rounded-full"></div>
|
||||
<span className="text-sm text-gray-600">Series 2</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-green-400 rounded-full"></div>
|
||||
<span className="text-sm text-gray-600">Series 3</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-1/2 px-8 py-8 flex flex-col justify-center">
|
||||
{showChart && chartData && chartData.length > 0 && (
|
||||
<div className="h-80 w-full">
|
||||
<ChartContainer
|
||||
config={{
|
||||
value: {
|
||||
label: "Value",
|
||||
color: "hsl(var(--chart-1))",
|
||||
},
|
||||
}}
|
||||
className="h-full w-full"
|
||||
>
|
||||
|
||||
<BarChart data={chartData} margin={{ top: 20, right: 20, bottom: 20, left: 20 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
|
||||
<XAxis
|
||||
dataKey="category"
|
||||
stroke="#6b7280"
|
||||
fontSize={12}
|
||||
angle={-45}
|
||||
textAnchor="end"
|
||||
height={60}
|
||||
/>
|
||||
<YAxis stroke="#6b7280" fontSize={12} />
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar
|
||||
dataKey="value"
|
||||
fill="#0891b2"
|
||||
radius={[4, 4, 0, 0]}
|
||||
/>
|
||||
</BarChart>
|
||||
|
||||
{/* Chart Container */}
|
||||
{chartData && chartData.length > 0 && (
|
||||
<div className="flex-1">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={chartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
barCategoryGap="20%"
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar
|
||||
dataKey="series1"
|
||||
fill="#1D9A8A"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={20}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="series2"
|
||||
fill="#E8F4B8"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={20}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="series3"
|
||||
fill="#A8C97F"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={20}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom accent strip */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-2 bg-teal-600"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,57 +5,56 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("WELCOME!")
|
||||
.meta({
|
||||
description: "Main greeting or welcome message - can be 'Hello!', 'Welcome!', 'Greetings!', or similar",
|
||||
}),
|
||||
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(60)
|
||||
.default("WE'RE EXCITED TO SHARE OUR STORY")
|
||||
.meta({
|
||||
description: "Supporting message that sets the tone and builds connection with the audience",
|
||||
}),
|
||||
|
||||
welcomeMessage: z.string()
|
||||
.min(30)
|
||||
.max(200)
|
||||
.default("Thank you for joining us today. We're thrilled to have this opportunity to connect with you and share our journey, insights, and vision for the future.")
|
||||
.meta({
|
||||
description: "Main welcome or introductory message that engages the audience personally",
|
||||
}),
|
||||
|
||||
callToActionText: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
.default("HELLO FRIENDS!")
|
||||
.max(25)
|
||||
.default("Let's Get Started")
|
||||
.meta({
|
||||
description: "Main greeting title",
|
||||
description: "Action button text that encourages audience engagement or progression",
|
||||
}),
|
||||
|
||||
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"
|
||||
speakerImage: ImageSchema.default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
__image_prompt__: "Professional presenter or team representative in business setting"
|
||||
}).meta({
|
||||
description: "Office workspace image in circular frame",
|
||||
description: "Image of the presenter, team representative, or welcoming figure",
|
||||
}),
|
||||
|
||||
buttonText: z.string()
|
||||
.min(3)
|
||||
.max(20)
|
||||
.default("Thank you")
|
||||
.meta({
|
||||
description: "Text for the call-to-action button",
|
||||
}),
|
||||
|
||||
showSpeechBubble: z.boolean()
|
||||
showDecorations: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative speech bubble",
|
||||
description: "Whether to display decorative visual elements like underlines and accents",
|
||||
}),
|
||||
|
||||
showDecoCircle: z.boolean()
|
||||
showCallToAction: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative circle element",
|
||||
description: "Whether to show the call-to-action button",
|
||||
}),
|
||||
|
||||
})
|
||||
|
||||
// Type inference
|
||||
|
|
@ -64,7 +63,7 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const HelloFriendsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, welcomeText, officeImage, buttonText, showSpeechBubble, showDecoCircle } = data;
|
||||
const { sectionTitle, sectionSubtitle, welcomeMessage, callToActionText, speakerImage, showDecorations, showCallToAction } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
|
|
@ -73,26 +72,7 @@ const HelloFriendsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{/* Left Side - Teal Background */}
|
||||
<div className="w-1/3 relative bg-teal-600">
|
||||
{/* Speech Bubble */}
|
||||
{showSpeechBubble && (
|
||||
<div className="absolute top-16 left-16 z-20">
|
||||
<div className="w-16 h-10 bg-yellow-200 rounded-2xl relative">
|
||||
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex space-x-1">
|
||||
<div className="w-2 h-2 bg-teal-600 rounded-full"></div>
|
||||
<div className="w-2 h-2 bg-teal-600 rounded-full"></div>
|
||||
<div className="w-2 h-2 bg-teal-600 rounded-full"></div>
|
||||
</div>
|
||||
{/* Speech bubble tail */}
|
||||
<div className="absolute bottom-0 left-6 transform translate-y-full">
|
||||
<div className="w-0 h-0 border-l-4 border-r-4 border-t-8 border-l-transparent border-r-transparent border-t-yellow-200"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Decorative Circle */}
|
||||
{showDecoCircle && (
|
||||
<div className="absolute bottom-16 left-16 w-8 h-8 border-4 border-white rounded-full z-20"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - White Background */}
|
||||
|
|
@ -101,36 +81,38 @@ const HelloFriendsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="pl-32 pr-16 py-12 h-full flex flex-col justify-center">
|
||||
{/* Title Section */}
|
||||
<div className="mb-8">
|
||||
{mainTitle && (
|
||||
{sectionTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide mb-6">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Decorative underline */}
|
||||
<div className="w-32 h-1 bg-yellow-300 mb-8"></div>
|
||||
{showDecorations && (
|
||||
<div className="w-32 h-1 bg-yellow-300 mb-8"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Welcome Text */}
|
||||
{welcomeText && (
|
||||
{welcomeMessage && (
|
||||
<div className="mb-8">
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{welcomeText}
|
||||
{welcomeMessage}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Thank You Button */}
|
||||
{buttonText && (
|
||||
{showCallToAction && (
|
||||
<div>
|
||||
<button className="bg-teal-600 hover:bg-teal-700 text-white font-semibold px-8 py-3 rounded-full transition-colors duration-200">
|
||||
{buttonText}
|
||||
{callToActionText}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -139,12 +121,12 @@ const HelloFriendsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</div>
|
||||
|
||||
{/* Overlapping Circular Office Image */}
|
||||
{officeImage?.__image_url__ && (
|
||||
{speakerImage?.__image_url__ && (
|
||||
<div className="absolute top-1/2 left-72 transform -translate-x-1/2 -translate-y-1/2 z-30">
|
||||
<div className="w-96 h-96 rounded-full overflow-hidden bg-white p-2 shadow-2xl">
|
||||
<img
|
||||
src={officeImage.__image_url__}
|
||||
alt={officeImage.__image_prompt__}
|
||||
src={speakerImage.__image_url__}
|
||||
alt={speakerImage.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-full"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,65 +5,63 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
.default("MARKET SIZE")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("MARKET ANALYSIS")
|
||||
.meta({
|
||||
description: "Main title for the market size section",
|
||||
description: "Main section heading - can be 'Market Size', 'Market Opportunity', 'Industry Overview', or similar",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(25)
|
||||
.default("OUR CLIENTS COME FROM EVERYWHERE")
|
||||
.max(60)
|
||||
.default("UNDERSTANDING THE OPPORTUNITY LANDSCAPE")
|
||||
.meta({
|
||||
description: "Subtitle describing global reach",
|
||||
description: "Supporting subtitle that frames the market discussion and opportunity scope",
|
||||
}),
|
||||
|
||||
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([
|
||||
marketType: z.string().min(3).max(30),
|
||||
marketDescription: z.string().min(20).max(150),
|
||||
marketValue: z.string().min(3).max(25).optional()
|
||||
})).min(2).max(4).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."
|
||||
marketType: "Total Addressable Market (TAM)",
|
||||
marketDescription: "The overall revenue opportunity available if we achieved 100% market share across all segments and geographies.",
|
||||
marketValue: "$50B"
|
||||
},
|
||||
{
|
||||
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."
|
||||
marketType: "Serviceable Addressable Market (SAM)",
|
||||
marketDescription: "The portion of TAM targeted by our products and services within our geographic reach.",
|
||||
marketValue: "$15B"
|
||||
},
|
||||
{
|
||||
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."
|
||||
marketType: "Serviceable Obtainable Market (SOM)",
|
||||
marketDescription: "The portion of SAM that we can realistically capture based on our resources and market conditions.",
|
||||
marketValue: "$3B"
|
||||
}
|
||||
]).meta({
|
||||
description: "Market size definitions for TAM, SAM, and SOM",
|
||||
description: "List of market definitions and opportunities with descriptions and potential values",
|
||||
}),
|
||||
|
||||
visualRepresentation: ImageSchema.default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1597149962419-0d900ac2b46c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
__image_prompt__: "World map showing global market reach and geographic distribution"
|
||||
}).meta({
|
||||
description: "Visual that represents market scope - could be a world map, chart, or geographic visualization",
|
||||
}),
|
||||
|
||||
showYellowUnderline: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show yellow decorative underline",
|
||||
description: "Whether to display the decorative yellow underline accent",
|
||||
}),
|
||||
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -73,81 +71,84 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const MarketSizeSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, globalDescription, worldMapImage, marketDefinitions, showYellowUnderline } = data;
|
||||
const { sectionTitle, sectionSubtitle, marketDefinitions, visualRepresentation, showYellowUnderline, showVisualAccents } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Main Content Area */}
|
||||
<div className="h-full flex">
|
||||
{/* Left Side - Teal Background with Map */}
|
||||
<div className="w-1/2 relative bg-teal-600 px-16 py-12 flex flex-col text-white">
|
||||
{/* Left Side - Content */}
|
||||
<div className="w-3/5 relative bg-white px-16 py-12 flex flex-col justify-start">
|
||||
{/* Title Section */}
|
||||
<div className="mb-8">
|
||||
{mainTitle && (
|
||||
<h1 className="text-5xl lg:text-6xl font-black leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold tracking-wide mb-4">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Yellow Decorative Underline */}
|
||||
{showYellowUnderline && (
|
||||
<div className="w-24 h-1 bg-yellow-300 "></div>
|
||||
<div className="w-24 h-1 bg-yellow-300 mb-8"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* World Map Image */}
|
||||
{worldMapImage?.__image_url__ && (
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<div className="w-full max-w-md">
|
||||
<img
|
||||
src={worldMapImage.__image_url__}
|
||||
alt={worldMapImage.__image_prompt__}
|
||||
className="w-full h-auto object-contain opacity-90"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Global Description */}
|
||||
{globalDescription && (
|
||||
<div>
|
||||
<p className="text-base leading-relaxed">
|
||||
{globalDescription}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - White Background with Market Definitions */}
|
||||
<div className="w-1/2 relative bg-white px-16 py-12 flex flex-col justify-center">
|
||||
{/* Market Definitions */}
|
||||
{marketDefinitions && marketDefinitions.length >= 3 && (
|
||||
<div className="space-y-8">
|
||||
{marketDefinitions.slice(0, 3).map((definition, index) => (
|
||||
<div key={index} className="mb-8">
|
||||
{/* Header with rounded background */}
|
||||
<div className="bg-teal-600 text-white px-6 py-3 rounded-full mb-4">
|
||||
<h3 className="text-lg font-bold text-center">
|
||||
{definition.fullName}
|
||||
{/* Market Definitions List */}
|
||||
{marketDefinitions && marketDefinitions.length > 0 && (
|
||||
<div className="space-y-6">
|
||||
{marketDefinitions.map((market, index) => (
|
||||
<div key={index} className="border-l-4 border-teal-600 pl-6">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3 className="text-lg font-bold text-gray-900">
|
||||
{market.marketType}
|
||||
</h3>
|
||||
{market.marketValue && (
|
||||
<span className="text-xl font-bold text-teal-600">
|
||||
{market.marketValue}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-base leading-relaxed text-gray-700 px-2">
|
||||
{definition.description}
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{market.marketDescription}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - Visual Representation */}
|
||||
<div className="w-2/5 relative bg-gray-50">
|
||||
{/* Visual Accents */}
|
||||
{showVisualAccents && (
|
||||
<>
|
||||
{/* Decorative circles */}
|
||||
<div className="absolute top-8 right-8 w-6 h-6 bg-teal-600 rounded-full opacity-60 z-20"></div>
|
||||
<div className="absolute bottom-12 left-8 w-4 h-4 bg-yellow-300 rounded-full z-20"></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Visual Representation */}
|
||||
{visualRepresentation?.__image_url__ && (
|
||||
<div className="absolute inset-8 z-15 shadow-lg">
|
||||
<img
|
||||
src={visualRepresentation.__image_url__}
|
||||
alt={visualRepresentation.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom accent strip */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-3 bg-teal-600"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,62 +5,39 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(10)
|
||||
.default("OUR SERVICE")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("OUR SERVICES")
|
||||
.meta({
|
||||
description: "Main title for the service section",
|
||||
description: "Main section heading - can be 'Our Services', 'What We Offer', 'Service Portfolio', or similar",
|
||||
}),
|
||||
|
||||
|
||||
|
||||
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")
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(60)
|
||||
.default("COMPREHENSIVE SOLUTIONS TAILORED FOR SUCCESS")
|
||||
.meta({
|
||||
description: "Company name for branding",
|
||||
description: "Supporting subtitle that describes the service approach or value proposition",
|
||||
}),
|
||||
|
||||
serviceHighlight: ImageSchema.default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1556761175-b413da4baf72?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
__image_prompt__: "Professional service delivery or team working on client solutions"
|
||||
}).meta({
|
||||
description: "Visual that represents service delivery, expertise, or client collaboration",
|
||||
}),
|
||||
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
|
||||
showColorBlocks: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to show colored background sections for visual hierarchy",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -70,74 +47,60 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const OurServiceSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, services, companyLogo, companyName } = data;
|
||||
const { sectionTitle, sectionSubtitle, serviceHighlight, showVisualAccents, showColorBlocks } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-gray-100 relative overflow-hidden">
|
||||
{/* Header with Title and Company Branding */}
|
||||
<div className="h-full flex flex-col">
|
||||
{/* Top Section */}
|
||||
<div className="flex ">
|
||||
{/* Left - Title */}
|
||||
<div className="w-2/3 px-16 py-12 bg-gray-100">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
</h1>
|
||||
)}
|
||||
</div>
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Main Content Area */}
|
||||
<div className="h-full flex">
|
||||
{/* Left - Title */}
|
||||
<div className="w-1/2 px-16 py-12 bg-gray-100">
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Right - Teal Background with Company Branding */}
|
||||
<div className="w-1/3 bg-teal-600 px-16 py-12 flex items-center justify-end">
|
||||
<div className="flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
<div className="w-10 h-10">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
<span className="text-xl font-bold text-white">
|
||||
{companyName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide">
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Visual Accents */}
|
||||
{showVisualAccents && (
|
||||
<>
|
||||
{/* Decorative elements */}
|
||||
<div className="absolute bottom-16 left-16 w-8 h-8 bg-yellow-300 rounded-full"></div>
|
||||
<div className="absolute top-20 right-20 w-4 h-4 bg-teal-600 rounded-full"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bottom Section - Services Grid */}
|
||||
<div className="flex-1 px-16 py-8 bg-white">
|
||||
{services && services.length >= 3 && (
|
||||
<div className="grid grid-cols-3 gap-8 h-full">
|
||||
{services.slice(0, 3).map((service, index) => (
|
||||
<div key={index} className="flex flex-col">
|
||||
{/* Service Image */}
|
||||
<div className="h-48 w-full mb-6">
|
||||
<img
|
||||
src={service.image.__image_url__}
|
||||
alt={service.image.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Service Content */}
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-bold text-teal-700 mb-4 leading-tight">
|
||||
{service.title}
|
||||
</h3>
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{service.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{/* Right - Service Highlight */}
|
||||
<div className="w-1/2 relative">
|
||||
{/* Service Highlight Image */}
|
||||
{serviceHighlight?.__image_url__ && (
|
||||
<div className="h-full w-full">
|
||||
<img
|
||||
src={serviceHighlight.__image_url__}
|
||||
alt={serviceHighlight.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Color overlay if enabled */}
|
||||
{showColorBlocks && (
|
||||
<div className="absolute inset-0 bg-teal-600 bg-opacity-20"></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom accent strip */}
|
||||
{showColorBlocks && (
|
||||
<div className="absolute bottom-0 left-0 right-0 h-3 bg-teal-600"></div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,63 +5,63 @@ 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)
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(25)
|
||||
.default("WE WILL SOLVE THE PROBLEMS")
|
||||
.default("CHALLENGES")
|
||||
.meta({
|
||||
description: "Subtitle describing the section",
|
||||
description: "Main section heading - can be 'Problems', 'Challenges', 'Issues', or similar",
|
||||
}),
|
||||
|
||||
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([
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(50)
|
||||
.default("KEY CHALLENGES TO ADDRESS")
|
||||
.meta({
|
||||
description: "Supporting subtitle that frames the problem discussion",
|
||||
}),
|
||||
|
||||
challengeItems: z.array(z.object({
|
||||
itemNumber: z.string().min(1).max(3),
|
||||
challengeTitle: z.string().min(5).max(40),
|
||||
challengeDescription: z.string().min(20).max(200)
|
||||
})).min(2).max(4).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."
|
||||
itemNumber: "01",
|
||||
challengeTitle: "Inefficient Processes",
|
||||
challengeDescription: "Current workflows and systems lack optimization, leading to wasted resources and reduced productivity across all operational areas."
|
||||
},
|
||||
{
|
||||
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."
|
||||
itemNumber: "02",
|
||||
challengeTitle: "Limited Scalability",
|
||||
challengeDescription: "Existing infrastructure and methodologies cannot accommodate growth, creating bottlenecks that hinder expansion and progress."
|
||||
},
|
||||
{
|
||||
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."
|
||||
itemNumber: "03",
|
||||
challengeTitle: "Resource Constraints",
|
||||
challengeDescription: "Limited availability of key resources including time, budget, and skilled personnel creates barriers to achieving desired outcomes."
|
||||
}
|
||||
]).meta({
|
||||
description: "List of problems with numbers, titles and descriptions",
|
||||
description: "List of key challenges or problems with numbered identification and detailed descriptions",
|
||||
}),
|
||||
|
||||
workspaceImage: ImageSchema.default({
|
||||
supportingVisual: 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"
|
||||
__image_prompt__: "Professional workspace showing analysis and problem-solving activities"
|
||||
}).meta({
|
||||
description: "Workspace image showing business environment",
|
||||
description: "Visual that supports the problem discussion - could show analysis, challenges, or work environment",
|
||||
}),
|
||||
|
||||
showDecoCircle: z.boolean()
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative circle element",
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
|
||||
showTealAccent: z.boolean()
|
||||
showColorBlocks: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show teal accent block",
|
||||
description: "Whether to show colored accent blocks for visual hierarchy",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const ProblemsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, problems, workspaceImage, showDecoCircle, showTealAccent } = data;
|
||||
const { sectionTitle, sectionSubtitle, challengeItems, supportingVisual, showVisualAccents, showColorBlocks } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
|
|
@ -81,38 +81,38 @@ const ProblemsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="w-3/5 relative bg-white px-16 py-12 flex flex-col justify-start">
|
||||
{/* Title Section */}
|
||||
<div className="mb-12">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Problems List */}
|
||||
{problems && problems.length > 0 && (
|
||||
{/* Challenge Items List */}
|
||||
{challengeItems && challengeItems.length > 0 && (
|
||||
<div className="space-y-8">
|
||||
{problems.map((problem, index) => (
|
||||
{challengeItems.map((item, index) => (
|
||||
<div key={index} className="flex items-start space-x-6">
|
||||
{/* Number Circle */}
|
||||
<div className="w-16 h-16 bg-yellow-200 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-teal-700 font-bold text-xl">
|
||||
{problem.number}
|
||||
{item.itemNumber}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-bold text-gray-900 mb-3">
|
||||
{problem.title}
|
||||
{item.challengeTitle}
|
||||
</h3>
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{problem.description}
|
||||
{item.challengeDescription}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -124,23 +124,23 @@ const ProblemsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{/* Right Side - Image and Decorative Elements */}
|
||||
<div className="w-2/5 relative">
|
||||
{/* Decorative Circle */}
|
||||
{showDecoCircle && (
|
||||
{showVisualAccents && (
|
||||
<div className="absolute top-12 left-8 w-8 h-8 border-4 border-teal-600 rounded-full z-20"></div>
|
||||
)}
|
||||
|
||||
{/* Workspace Image */}
|
||||
{workspaceImage?.__image_url__ && (
|
||||
{/* Supporting Visual */}
|
||||
{supportingVisual?.__image_url__ && (
|
||||
<div className="absolute top-8 right-8 bottom-20 left-4 z-15 shadow-lg">
|
||||
<img
|
||||
src={workspaceImage.__image_url__}
|
||||
alt={workspaceImage.__image_prompt__}
|
||||
src={supportingVisual.__image_url__}
|
||||
alt={supportingVisual.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teal Accent Block - Right Edge */}
|
||||
{showTealAccent && (
|
||||
{showColorBlocks && (
|
||||
<div className="absolute top-0 right-0 bottom-0 w-16 bg-teal-600 z-10"></div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,72 +5,76 @@ 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)
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(25)
|
||||
.default("SOLUTIONS OF THE PROBLEMS")
|
||||
.default("OUR SOLUTIONS")
|
||||
.meta({
|
||||
description: "Subtitle describing the section",
|
||||
description: "Main section heading - can be 'Solutions', 'Our Approach', 'How We Help', or similar",
|
||||
}),
|
||||
|
||||
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([
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(50)
|
||||
.default("COMPREHENSIVE SOLUTIONS FOR YOUR NEEDS")
|
||||
.meta({
|
||||
description: "Supporting subtitle that frames the solution discussion",
|
||||
}),
|
||||
|
||||
solutionItems: z.array(z.object({
|
||||
itemNumber: z.string().min(1).max(3),
|
||||
solutionTitle: z.string().min(5).max(40),
|
||||
solutionDescription: z.string().min(20).max(200)
|
||||
})).min(2).max(4).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."
|
||||
itemNumber: "01",
|
||||
solutionTitle: "Process Optimization",
|
||||
solutionDescription: "Streamline workflows and implement efficient systems that reduce waste, improve productivity, and maximize resource utilization across all operational areas."
|
||||
},
|
||||
{
|
||||
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."
|
||||
itemNumber: "02",
|
||||
solutionTitle: "Scalable Infrastructure",
|
||||
solutionDescription: "Build robust, flexible systems and methodologies that can grow with your organization, eliminating bottlenecks and supporting expansion efforts."
|
||||
},
|
||||
{
|
||||
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."
|
||||
itemNumber: "03",
|
||||
solutionTitle: "Resource Management",
|
||||
solutionDescription: "Strategic allocation and optimization of available resources including time, budget, and personnel to achieve maximum impact and desired outcomes."
|
||||
}
|
||||
]).meta({
|
||||
description: "List of solutions with numbers, titles and descriptions",
|
||||
description: "List of key solutions or approaches with numbered identification and detailed 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"
|
||||
primaryVisual: ImageSchema.default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1560472354-b33ff0c44a43?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
__image_prompt__: "Modern workspace with team collaboration and strategic planning"
|
||||
}).meta({
|
||||
description: "Two workspace images for left side",
|
||||
description: "Primary visual representing teamwork, strategy, or solution implementation",
|
||||
}),
|
||||
|
||||
companyLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/1D9A8A/FFFFFF?text=C",
|
||||
__image_prompt__: "Clean modern company logo icon"
|
||||
brandingVisual: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/150x80/22C55E/FFFFFF?text=LOGO",
|
||||
__image_prompt__: "Organization logo or brand mark"
|
||||
}).meta({
|
||||
description: "Company logo icon",
|
||||
description: "Logo or branding element to maintain visual identity",
|
||||
}),
|
||||
|
||||
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",
|
||||
description: "Whether to display the decorative yellow underline accent",
|
||||
}),
|
||||
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
|
||||
showColorBlocks: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to show colored background blocks for visual hierarchy",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -80,25 +84,50 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const SolutionsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, solutions, workspaceImages, companyLogo, companyName, showYellowUnderline } = data;
|
||||
const { sectionTitle, sectionSubtitle, solutionItems, primaryVisual, brandingVisual, showYellowUnderline, showVisualAccents, showColorBlocks } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Main Content Area */}
|
||||
<div className="h-full flex">
|
||||
{/* Left Side - Images and Branding */}
|
||||
<div className="w-1/2 relative bg-gray-100 px-16 py-12 flex flex-col">
|
||||
<div className="w-2/5 relative bg-gray-100 flex flex-col">
|
||||
{/* Top Image Area */}
|
||||
{primaryVisual?.__image_url__ && (
|
||||
<div className="flex-1 relative">
|
||||
<img
|
||||
src={primaryVisual.__image_url__}
|
||||
alt={primaryVisual.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Bottom Branding Area */}
|
||||
<div className="h-24 bg-white flex items-center justify-center px-8">
|
||||
{brandingVisual?.__image_url__ && (
|
||||
<img
|
||||
src={brandingVisual.__image_url__}
|
||||
alt={brandingVisual.__image_prompt__}
|
||||
className="h-12 object-contain"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side - Content */}
|
||||
<div className="w-3/5 relative bg-teal-600 px-16 py-12 flex flex-col justify-start">
|
||||
{/* Title Section */}
|
||||
<div className="mb-8">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-white leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide mb-4">
|
||||
{subtitle}
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-100 tracking-wide mb-4">
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
|
|
@ -108,70 +137,52 @@ const SolutionsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Images */}
|
||||
{workspaceImages && (
|
||||
<div className="flex-1 space-y-6">
|
||||
|
||||
|
||||
|
||||
<div className="h-full w-full">
|
||||
<img
|
||||
src={workspaceImages.__image_url__}
|
||||
alt={workspaceImages.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-lg shadow-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Company Branding */}
|
||||
<div className="mt-8 flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
<div className="w-10 h-10">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
<span className="text-xl font-bold text-teal-700">
|
||||
{companyName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side - Teal Background with Solutions */}
|
||||
<div className="w-1/2 relative bg-teal-600 px-16 py-12 flex flex-col justify-center">
|
||||
{/* Solutions List */}
|
||||
{solutions && solutions.length > 0 && (
|
||||
{/* Solution Items List */}
|
||||
{solutionItems && solutionItems.length > 0 && (
|
||||
<div className="space-y-8">
|
||||
{solutions.map((solution, index) => (
|
||||
<div key={index} className="flex items-start space-x-4">
|
||||
{solutionItems.map((item, index) => (
|
||||
<div key={index} className="flex items-start space-x-6">
|
||||
{/* Number Circle */}
|
||||
<div className="w-12 h-12 bg-yellow-200 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-teal-700 font-bold text-lg">
|
||||
{solution.number}
|
||||
<div className="w-16 h-16 bg-yellow-300 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-teal-700 font-bold text-xl">
|
||||
{item.itemNumber}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-bold text-white mb-3">
|
||||
{solution.title}
|
||||
{item.solutionTitle}
|
||||
</h3>
|
||||
<p className="text-base leading-relaxed text-white">
|
||||
{solution.description}
|
||||
<p className="text-base leading-relaxed text-gray-100">
|
||||
{item.solutionDescription}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Visual Accents */}
|
||||
{showVisualAccents && (
|
||||
<>
|
||||
{/* Decorative circles */}
|
||||
<div className="absolute top-8 right-8 w-4 h-4 bg-yellow-300 rounded-full"></div>
|
||||
<div className="absolute bottom-16 right-12 w-3 h-3 bg-yellow-200 rounded-full"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Color blocks for visual hierarchy */}
|
||||
{showColorBlocks && (
|
||||
<>
|
||||
{/* Bottom accent strip */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-3 bg-yellow-300"></div>
|
||||
{/* Side accent */}
|
||||
<div className="absolute top-0 left-0 bottom-0 w-1 bg-yellow-400"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,31 +4,38 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
.default("STATISTIC")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(20)
|
||||
.default("CLIENT SATISFACTION")
|
||||
.meta({
|
||||
description: "Main title for the statistic section",
|
||||
description: "Main section heading - adapt to presentation topic (e.g., 'Climate Progress', 'Treatment Success', 'Learning Achievement', 'Project Completion')",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(25)
|
||||
.default("CLIENT'S SATISFACTION")
|
||||
.max(35)
|
||||
.default("MEASURING OUR IMPACT AND SUCCESS")
|
||||
.meta({
|
||||
description: "Subtitle describing the statistic focus",
|
||||
description: "Supporting subtitle that provides context - adapt to topic (e.g., 'Tracking Climate Action Progress', 'Monitoring Patient Recovery Rates', 'Assessing Educational Outcomes')",
|
||||
}),
|
||||
|
||||
description: z.string()
|
||||
.min(100)
|
||||
.max(400)
|
||||
.min(2)
|
||||
.max(230)
|
||||
.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",
|
||||
description: "Name of the organization or entity being measured",
|
||||
}),
|
||||
|
||||
circularMetric: z.object({
|
||||
brandLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
|
||||
__image_prompt__: "Professional organization logo - clean and modern design"
|
||||
}).meta({
|
||||
description: "Logo or brand mark representing the organization",
|
||||
}),
|
||||
|
||||
satisfactionRate: z.object({
|
||||
value: z.number().min(0).max(100),
|
||||
label: z.string().min(5).max(30),
|
||||
percentage: z.string().min(2).max(5)
|
||||
|
|
@ -37,7 +44,7 @@ export const Schema = z.object({
|
|||
label: "CLIENT'S REPEAT ORDER",
|
||||
percentage: "90%"
|
||||
}).meta({
|
||||
description: "Main circular chart metric",
|
||||
description: "CRITICAL: Provide topic-specific circular progress metric. For global warming: {value: 33, label: 'CO2 REDUCTION ACHIEVED', percentage: '33%'} or {value: 78, label: 'RENEWABLE ENERGY ADOPTION', percentage: '78%'}. For healthcare: {value: 95, label: 'PATIENT RECOVERY RATE', percentage: '95%'} or {value: 87, label: 'TREATMENT SUCCESS RATE', percentage: '87%'}. For education: {value: 92, label: 'GRADUATION SUCCESS RATE', percentage: '92%'}. Use realistic percentages and meaningful labels.",
|
||||
}),
|
||||
|
||||
statisticBlocks: z.array(z.object({
|
||||
|
|
@ -56,7 +63,7 @@ export const Schema = z.object({
|
|||
backgroundColor: "beige"
|
||||
}
|
||||
]).meta({
|
||||
description: "Two statistic blocks with percentages and descriptions",
|
||||
description: "ESSENTIAL: Provide two topic-relevant supporting statistics. For global warming: [{percentage: '1.1°C', description: 'Global temperature increase since pre-industrial times represents urgent need for climate action', backgroundColor: 'teal'}, {percentage: '410ppm', description: 'Current atmospheric CO2 levels are the highest in human history requiring immediate intervention', backgroundColor: 'beige'}]. For healthcare: [{percentage: '85%', description: 'Early detection rates have improved significantly with advanced screening technologies', backgroundColor: 'teal'}, {percentage: '72h', description: 'Average patient response time demonstrates our commitment to rapid care delivery', backgroundColor: 'beige'}]. Always provide factual, impactful statistics.",
|
||||
}),
|
||||
|
||||
companyLogo: ImageSchema.default({
|
||||
|
|
@ -69,7 +76,7 @@ export const Schema = z.object({
|
|||
companyName: z.string()
|
||||
.min(2)
|
||||
.max(25)
|
||||
.default("Company Name")
|
||||
.default("Deskpro")
|
||||
.meta({
|
||||
description: "Company name for branding",
|
||||
}),
|
||||
|
|
@ -81,7 +88,7 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const StatisticCircularSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, subtitle, description, circularMetric, statisticBlocks, companyLogo, companyName } = data;
|
||||
const { sectionTitle, sectionSubtitle, description, brandLogo, satisfactionRate, statisticBlocks, companyLogo, companyName } = data;
|
||||
|
||||
const getBackgroundClass = (bg: string) => {
|
||||
switch (bg) {
|
||||
|
|
@ -95,7 +102,7 @@ const StatisticCircularSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
const radius = 150;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
const strokeDasharray = circumference;
|
||||
const strokeDashoffset = circumference - (circumference * (circularMetric?.value || 90) / 100);
|
||||
const strokeDashoffset = circumference - (circumference * (satisfactionRate?.value || 90) / 100);
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
|
|
@ -105,15 +112,15 @@ const StatisticCircularSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="flex h-32">
|
||||
{/* Left - Title */}
|
||||
<div className="w-1/2 px-16 py-8 bg-gray-100 flex flex-col justify-center">
|
||||
{mainTitle && (
|
||||
{sectionTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-2">
|
||||
{mainTitle}
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -172,14 +179,14 @@ const StatisticCircularSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
|
||||
{/* Center Content */}
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
||||
{circularMetric?.label && (
|
||||
{satisfactionRate?.label && (
|
||||
<p className="text-sm font-semibold text-gray-800 mb-4 text-center max-w-32 leading-tight">
|
||||
{circularMetric.label}
|
||||
{satisfactionRate.label}
|
||||
</p>
|
||||
)}
|
||||
{circularMetric?.percentage && (
|
||||
{satisfactionRate?.percentage && (
|
||||
<span className="text-7xl font-black text-teal-700">
|
||||
{circularMetric.percentage}
|
||||
{satisfactionRate.percentage}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,34 @@
|
|||
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";
|
||||
import { BarChart, Bar, AreaChart, Area, XAxis, YAxis, CartesianGrid } from "recharts";
|
||||
|
||||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
.default("STATISTIC")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("PERFORMANCE METRICS")
|
||||
.meta({
|
||||
description: "Main title for the statistic section",
|
||||
description: "Main section heading - adapt to presentation topic (e.g., 'Climate Analysis', 'Health Outcomes', 'Research Data', 'Impact Assessment')",
|
||||
}),
|
||||
|
||||
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()
|
||||
organizationName: z.string()
|
||||
.min(2)
|
||||
.max(25)
|
||||
.default("Company Name")
|
||||
.max(30)
|
||||
.default("Your Organization")
|
||||
.meta({
|
||||
description: "Company name for branding",
|
||||
description: "Name of the organization or entity presenting the data",
|
||||
}),
|
||||
|
||||
brandLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
|
||||
__image_prompt__: "Professional organization logo - clean and modern design"
|
||||
}).meta({
|
||||
description: "Logo or brand mark representing the organization",
|
||||
}),
|
||||
|
||||
barChartData: z.array(z.object({
|
||||
name: z.string(),
|
||||
series1: z.number(),
|
||||
|
|
@ -41,7 +41,7 @@ export const Schema = z.object({
|
|||
{ 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",
|
||||
description: "CRITICAL: Provide topic-specific data for the left bar chart. For global warming: 5 years of data (2020-2024) with CO2 emissions by sector (Transport, Industry, Energy) with actual values. For healthcare: Patient outcomes across 5 categories (Prevention, Treatment, Recovery) with real percentages. For education: Student performance across 5 metrics (Reading, Math, Science) with grade levels. Use realistic data patterns and values.",
|
||||
}),
|
||||
|
||||
areaChartData: z.array(z.object({
|
||||
|
|
@ -56,7 +56,7 @@ export const Schema = z.object({
|
|||
{ 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",
|
||||
description: "CRITICAL: Provide topic-specific data for the right area chart. For global warming: Cumulative data over 5 time periods showing renewable energy adoption, carbon reduction efforts, and policy implementations with realistic growth trends. For healthcare: Cumulative patient care metrics showing improvement over time. For education: Progressive learning outcomes showing student advancement. Ensure data shows meaningful trends relevant to the topic.",
|
||||
}),
|
||||
|
||||
leftChartTitle: z.string()
|
||||
|
|
@ -64,7 +64,7 @@ export const Schema = z.object({
|
|||
.max(40)
|
||||
.default("Our Customer's Satisfaction")
|
||||
.meta({
|
||||
description: "Title for the left chart",
|
||||
description: "IMPORTANT: Provide topic-specific title for left chart. For global warming: 'Global CO2 Emissions by Sector', 'Temperature Rise by Region', 'Renewable Energy Adoption'. For healthcare: 'Patient Treatment Outcomes', 'Healthcare Quality Metrics', 'Recovery Success Rates'. For education: 'Student Performance by Subject', 'Learning Progress Assessment', 'Academic Achievement Trends'.",
|
||||
}),
|
||||
|
||||
leftChartDescription: z.string()
|
||||
|
|
@ -72,7 +72,7 @@ export const Schema = z.object({
|
|||
.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",
|
||||
description: "ESSENTIAL: Provide topic-relevant description explaining the left chart data. For global warming: Explain emission sources, trends, and implications. For healthcare: Describe treatment effectiveness and patient outcomes. For education: Explain performance metrics and learning indicators. Make it informative and specific to the data shown.",
|
||||
}),
|
||||
|
||||
rightChartTitle: z.string()
|
||||
|
|
@ -80,7 +80,7 @@ export const Schema = z.object({
|
|||
.max(40)
|
||||
.default("Repeat Order Rate")
|
||||
.meta({
|
||||
description: "Title for the right chart",
|
||||
description: "IMPORTANT: Provide topic-specific title for right chart. For global warming: 'Climate Action Progress', 'Carbon Reduction Timeline', 'Sustainability Milestones'. For healthcare: 'Patient Recovery Timeline', 'Treatment Progress Tracking', 'Health Improvement Trajectory'. For education: 'Learning Progress Over Time', 'Student Development Path', 'Academic Growth Timeline'.",
|
||||
}),
|
||||
|
||||
rightChartDescription: z.string()
|
||||
|
|
@ -88,7 +88,7 @@ export const Schema = z.object({
|
|||
.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",
|
||||
description: "ESSENTIAL: Provide topic-relevant description explaining the right chart's cumulative/timeline data. For global warming: Describe progress in climate action, policy impact, or environmental improvements. For healthcare: Explain patient journey and recovery progression. For education: Describe learning advancement and skill development over time. Make it specific and data-driven.",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -114,43 +114,33 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const StatisticDualChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const {
|
||||
mainTitle,
|
||||
companyLogo,
|
||||
companyName,
|
||||
barChartData,
|
||||
areaChartData,
|
||||
leftChartTitle,
|
||||
leftChartDescription,
|
||||
rightChartTitle,
|
||||
rightChartDescription
|
||||
} = data;
|
||||
const { sectionTitle, organizationName, brandLogo, barChartData, areaChartData, leftChartTitle, leftChartDescription, rightChartTitle, rightChartDescription } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Header Section */}
|
||||
<div className="h-20 bg-teal-600 px-16 py-4 flex justify-between items-center">
|
||||
{/* Title */}
|
||||
{mainTitle && (
|
||||
{sectionTitle && (
|
||||
<h1 className="text-4xl font-black text-white">
|
||||
{mainTitle}
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Company Branding */}
|
||||
<div className="flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
{brandLogo?.__image_url__ && (
|
||||
<div className="w-8 h-8">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
src={brandLogo.__image_url__}
|
||||
alt={brandLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
{organizationName && (
|
||||
<span className="text-lg font-bold text-white">
|
||||
{companyName}
|
||||
{organizationName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -180,45 +170,45 @@ const StatisticDualChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{barChartData && barChartData.length > 0 && (
|
||||
<div className="flex-1 mb-6">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={barChartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
barCategoryGap="20%"
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar
|
||||
dataKey="series1"
|
||||
fill="#1D9A8A"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={15}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="series2"
|
||||
fill="#A8C97F"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={15}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="series3"
|
||||
fill="#E8F4B8"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={15}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
<BarChart
|
||||
data={barChartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
barCategoryGap="20%"
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar
|
||||
dataKey="series1"
|
||||
fill="#1D9A8A"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={15}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="series2"
|
||||
fill="#A8C97F"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={15}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="series3"
|
||||
fill="#E8F4B8"
|
||||
radius={[2, 2, 0, 0]}
|
||||
barSize={15}
|
||||
/>
|
||||
</BarChart>
|
||||
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -260,50 +250,50 @@ const StatisticDualChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{areaChartData && areaChartData.length > 0 && (
|
||||
<div className="flex-1 mb-6">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart
|
||||
data={areaChartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="series3"
|
||||
stackId="1"
|
||||
stroke="#1D9A8A"
|
||||
fill="#1D9A8A"
|
||||
fillOpacity={0.8}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="series2"
|
||||
stackId="1"
|
||||
stroke="#A8C97F"
|
||||
fill="#A8C97F"
|
||||
fillOpacity={0.8}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="series1"
|
||||
stackId="1"
|
||||
stroke="#E8F4B8"
|
||||
fill="#E8F4B8"
|
||||
fillOpacity={0.8}
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
<AreaChart
|
||||
data={areaChartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="series3"
|
||||
stackId="1"
|
||||
stroke="#1D9A8A"
|
||||
fill="#1D9A8A"
|
||||
fillOpacity={0.8}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="series2"
|
||||
stackId="1"
|
||||
stroke="#A8C97F"
|
||||
fill="#A8C97F"
|
||||
fillOpacity={0.8}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="series1"
|
||||
stackId="1"
|
||||
stroke="#E8F4B8"
|
||||
fill="#E8F4B8"
|
||||
fillOpacity={0.8}
|
||||
/>
|
||||
</AreaChart>
|
||||
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,57 @@
|
|||
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";
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid } from "recharts";
|
||||
|
||||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(12)
|
||||
.default("STATISTIC")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("KEY STATISTICS")
|
||||
.meta({
|
||||
description: "Main title for the statistic section",
|
||||
description: "Main section heading - adapt to presentation topic (e.g., 'Climate Data', 'Health Metrics', 'Performance Stats', 'Research Findings')",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(18)
|
||||
.default("CLIENT'S SATISFACTION")
|
||||
.max(60)
|
||||
.default("DATA-DRIVEN INSIGHTS AND PERFORMANCE")
|
||||
.meta({
|
||||
description: "Subtitle describing the statistic focus",
|
||||
description: "Supporting subtitle that frames the data - adapt to topic (e.g., 'Global Temperature Trends and Impact', 'Patient Outcomes and Recovery Rates', 'Student Achievement and Progress')",
|
||||
}),
|
||||
|
||||
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.")
|
||||
statisticValue: z.string()
|
||||
.min(1)
|
||||
.max(15)
|
||||
.default("85%")
|
||||
.meta({
|
||||
description: "Description of client satisfaction approach",
|
||||
description: "CRITICAL: Provide the most important statistic for the topic. For global warming: '1.1°C', '+2.1°C', '410ppm', '33%'. For healthcare: '95%', '72 hours', '89%'. For education: '78%', '3.2 GPA', '92%'. Use real, impactful numbers relevant to the presentation topic.",
|
||||
}),
|
||||
|
||||
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"
|
||||
statisticLabel: z.string()
|
||||
.min(5)
|
||||
.max(40)
|
||||
.default("Client Satisfaction Rate")
|
||||
.meta({
|
||||
description: "IMPORTANT: Provide topic-specific label for the main statistic. For global warming: 'Global Temperature Rise Since 1880', 'CO2 Concentration Increase', 'Arctic Ice Loss Rate'. For healthcare: 'Patient Recovery Rate', 'Treatment Success Rate', 'Early Detection Rate'. For education: 'Graduation Success Rate', 'Student Engagement Level', 'Learning Improvement Rate'.",
|
||||
}),
|
||||
|
||||
supportingVisual: ImageSchema.default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
__image_prompt__: "Business analytics dashboard with charts and data visualization"
|
||||
}).meta({
|
||||
description: "Business meeting image showing team collaboration",
|
||||
description: "ADAPT the image prompt to match the presentation topic: For global warming: 'Climate monitoring station with temperature sensors and weather equipment', 'Scientists analyzing ice core data in Arctic research facility'. For healthcare: 'Medical monitoring equipment displaying patient vital signs', 'Healthcare analytics dashboard showing treatment outcomes'. For education: 'Educational assessment data on computer screens', 'Students using digital learning platforms'.",
|
||||
}),
|
||||
|
||||
bulletPoints: z.array(z.string().min(10).max(100)).min(2).max(5).default([
|
||||
"Consistent performance improvement over 12 months",
|
||||
"High customer retention and satisfaction scores",
|
||||
"Measurable ROI across all key performance indicators",
|
||||
"Data-driven decision making and strategic optimization"
|
||||
]).meta({
|
||||
description: "ESSENTIAL: Provide topic-relevant supporting facts and insights. For global warming: 'Global average temperature has risen 1.1°C since pre-industrial times', 'Arctic sea ice is declining at 13% per decade', 'CO2 levels are highest in 3 million years', 'Renewable energy adoption increased 85% in last decade'. For healthcare: 'Early detection improves survival rates by 85%', 'Telemedicine reduced patient wait times by 60%', 'Preventive care decreased hospital readmissions by 40%'. Always provide factual, verifiable statements related to the presentation topic.",
|
||||
}),
|
||||
|
||||
chartData: z.array(z.object({
|
||||
|
|
@ -43,42 +60,26 @@ export const Schema = z.object({
|
|||
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 }
|
||||
{ name: "Jan", series1: 18, series2: 0, series3: 0 },
|
||||
{ name: "Feb", series1: 30, series2: 12, series3: 8 },
|
||||
{ name: "Mar", series1: 26, series2: 38, series3: 20 },
|
||||
{ name: "Apr", series1: 40, series2: 30, series3: 35 },
|
||||
{ name: "May", 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",
|
||||
description: "CRITICAL: Provide topic-specific time-series data for line chart. For global warming: Monthly temperature anomalies, CO2 levels, ice coverage data with realistic values. For healthcare: Patient recovery rates, treatment success metrics, diagnostic accuracy over time. For education: Student performance trends, learning progress, engagement metrics. Use realistic data patterns showing meaningful trends.",
|
||||
}),
|
||||
|
||||
showYellowUnderline: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show yellow decorative underline",
|
||||
description: "Whether to display the decorative yellow underline accent",
|
||||
}),
|
||||
|
||||
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
})
|
||||
|
||||
// Chart configuration
|
||||
|
|
@ -103,73 +104,72 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const StatisticSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
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";
|
||||
}
|
||||
};
|
||||
const { sectionTitle, sectionSubtitle, statisticValue, statisticLabel, supportingVisual, bulletPoints, chartData, showYellowUnderline, showVisualAccents } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Main Content Area */}
|
||||
<div className="h-full flex">
|
||||
{/* Left Side - Teal Background with Content and Image */}
|
||||
<div className="w-1/2 relative bg-teal-600">
|
||||
{/* Top Content Section */}
|
||||
<div className="px-16 pt-12 text-white flex-1">
|
||||
{/* Title Section */}
|
||||
<div className="mb-4">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black leading-tight mb-1">
|
||||
{mainTitle}
|
||||
</h1>
|
||||
)}
|
||||
{/* Left Side - Teal Background */}
|
||||
<div className="w-1/2 relative bg-teal-600 px-16 py-12 flex flex-col text-white">
|
||||
{/* Title Section */}
|
||||
<div className="mb-8">
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
<p className="text-base font-semibold tracking-wide mb-1">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold tracking-wide mb-4">
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Yellow Decorative Underline */}
|
||||
{showYellowUnderline && (
|
||||
<div className="w-24 h-1 bg-yellow-300 mb-4"></div>
|
||||
)}
|
||||
</div>
|
||||
{/* Yellow Decorative Underline */}
|
||||
{showYellowUnderline && (
|
||||
<div className="w-24 h-1 bg-yellow-300 mb-8"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
<div>
|
||||
<p className="text-base leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
{/* Large Statistic Display */}
|
||||
<div className="mb-8">
|
||||
{statisticValue && (
|
||||
<div className="text-8xl font-black text-yellow-300 mb-4">
|
||||
{statisticValue}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bottom Business Image */}
|
||||
<div className="relative h-80 mx-16 mt-10">
|
||||
{businessImage?.__image_url__ && (
|
||||
|
||||
<img
|
||||
src={businessImage.__image_url__}
|
||||
alt={businessImage.__image_prompt__}
|
||||
className="max-w-full w-full h-full object-cover"
|
||||
/>
|
||||
|
||||
{statisticLabel && (
|
||||
<h2 className="text-2xl font-bold">
|
||||
{statisticLabel}
|
||||
</h2>
|
||||
)}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{/* Business Image */}
|
||||
{supportingVisual?.__image_url__ && (
|
||||
<div className="flex-1 flex items-end">
|
||||
<div className="w-full h-48">
|
||||
<img
|
||||
src={supportingVisual.__image_url__}
|
||||
alt={supportingVisual.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Visual Accents */}
|
||||
{showVisualAccents && (
|
||||
<>
|
||||
<div className="absolute top-8 right-8 w-6 h-6 bg-yellow-300 rounded-full"></div>
|
||||
<div className="absolute bottom-12 left-8 w-4 h-4 bg-yellow-200 rounded-full"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - Chart and Bullet Points */}
|
||||
<div className="w-1/2 relative bg-white">
|
||||
{/* Right Side - White Background with Chart and Bullet Points */}
|
||||
<div className="w-1/2 relative bg-white px-16 py-12">
|
||||
{/* Chart Section */}
|
||||
<div className="flex-1 px-8 pt-8">
|
||||
{/* Chart Legend */}
|
||||
|
|
@ -192,47 +192,47 @@ const StatisticSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{chartData && chartData.length > 0 && (
|
||||
<div className="h-64">
|
||||
<ChartContainer config={chartConfig} className="h-full w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart
|
||||
data={chartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="series1"
|
||||
stroke="#E8F4B8"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#E8F4B8", strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="series2"
|
||||
stroke="#A8C97F"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#A8C97F", strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="series3"
|
||||
stroke="#1D9A8A"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#1D9A8A", strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
<LineChart
|
||||
data={chartData}
|
||||
margin={{ top: 10, right: 20, left: 0, bottom: 30 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 12, fill: '#666' }}
|
||||
/>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="series1"
|
||||
stroke="#E8F4B8"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#E8F4B8", strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="series2"
|
||||
stroke="#A8C97F"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#A8C97F", strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="series3"
|
||||
stroke="#1D9A8A"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#1D9A8A", strokeWidth: 2, r: 4 }}
|
||||
/>
|
||||
</LineChart>
|
||||
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -242,19 +242,28 @@ const StatisticSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="px-8 pb-6 space-y-4 mt-10">
|
||||
{bulletPoints && bulletPoints.length > 0 && (
|
||||
<>
|
||||
{bulletPoints.map((point, index) => (
|
||||
<div key={index} className="flex items-start space-x-4">
|
||||
<div className={`w-6 h-6 ${getColorClass(point.color)} rounded-full flex-shrink-0 mt-1`}></div>
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{point.text}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
{bulletPoints.map((point, index) => {
|
||||
// Rotate colors for visual variety
|
||||
const colors = ['bg-teal-600', 'bg-yellow-300', 'bg-gray-400'];
|
||||
const dotColor = colors[index % colors.length];
|
||||
|
||||
return (
|
||||
<div key={index} className="flex items-start space-x-4">
|
||||
<div className={`w-6 h-6 ${dotColor} rounded-full flex-shrink-0 mt-1`}></div>
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{point}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom accent strip */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-3 bg-yellow-300"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,63 +5,78 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(20)
|
||||
.default("TABLE OF CONTENT")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("TABLE OF CONTENTS")
|
||||
.meta({
|
||||
description: "Main title for the table of contents",
|
||||
description: "Main heading for the content overview - can be 'Agenda', 'Overview', 'Contents', or similar",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(25)
|
||||
.default("PITCH DECK PRESENTATION")
|
||||
.max(60)
|
||||
.default("PRESENTATION OVERVIEW AND AGENDA")
|
||||
.meta({
|
||||
description: "Subtitle describing the presentation type",
|
||||
description: "Supporting subtitle that explains what the audience will learn or see",
|
||||
}),
|
||||
|
||||
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" }
|
||||
itemNumber: z.string().min(1).max(3),
|
||||
contentTitle: z.string().min(3).max(40),
|
||||
contentDescription: z.string().min(10).max(100).optional()
|
||||
})).min(3).max(8).default([
|
||||
{
|
||||
itemNumber: "01",
|
||||
contentTitle: "Introduction & Welcome",
|
||||
contentDescription: "Brief overview and objectives"
|
||||
},
|
||||
{
|
||||
itemNumber: "02",
|
||||
contentTitle: "About Our Organization",
|
||||
contentDescription: "Background and mission"
|
||||
},
|
||||
{
|
||||
itemNumber: "03",
|
||||
contentTitle: "Key Challenges",
|
||||
contentDescription: "Current issues and opportunities"
|
||||
},
|
||||
{
|
||||
itemNumber: "04",
|
||||
contentTitle: "Our Solutions",
|
||||
contentDescription: "Proposed approaches and methods"
|
||||
},
|
||||
{
|
||||
itemNumber: "05",
|
||||
contentTitle: "Implementation Plan",
|
||||
contentDescription: "Timeline and next steps"
|
||||
},
|
||||
{
|
||||
itemNumber: "06",
|
||||
contentTitle: "Questions & Discussion",
|
||||
contentDescription: "Interactive engagement"
|
||||
}
|
||||
]).meta({
|
||||
description: "List of content items with numbers and titles",
|
||||
description: "List of presentation sections with numbered sequence and brief descriptions",
|
||||
}),
|
||||
|
||||
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"
|
||||
brandingVisual: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/200x100/22C55E/FFFFFF?text=BRAND",
|
||||
__image_prompt__: "Organization logo or brand visual element"
|
||||
}).meta({
|
||||
description: "Hero image showing professional workspace",
|
||||
description: "Logo or branding element displayed prominently for visual identity",
|
||||
}),
|
||||
|
||||
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()
|
||||
showDecorations: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative circle element",
|
||||
description: "Whether to display decorative visual elements like underlines and accents",
|
||||
}),
|
||||
|
||||
useColumnLayout: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to arrange content items in two columns for better space utilization",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -71,45 +86,56 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const TableOfContentsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
|
||||
const { mainTitle, subtitle, contentItems, heroImage, companyLogo, companyName, decorativeCircle } = data;
|
||||
const { sectionTitle, sectionSubtitle, contentItems, brandingVisual, showDecorations, useColumnLayout } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Main Content Area */}
|
||||
<div className="h-full flex">
|
||||
{/* Left Side - Content */}
|
||||
<div className="w-3/5 px-16 py-12 flex flex-col justify-center">
|
||||
<div className="w-3/5 px-16 py-12 flex flex-col justify-start">
|
||||
{/* Title Section */}
|
||||
<div className="mb-12">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Decorative underline */}
|
||||
<div className="w-32 h-1 bg-yellow-300 mb-6"></div>
|
||||
{showDecorations && (
|
||||
<div className="w-32 h-1 bg-yellow-300 mb-6"></div>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-medium text-gray-700 tracking-wide">
|
||||
{subtitle}
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Content Items */}
|
||||
{contentItems && contentItems.length > 0 && (
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className={`grid ${useColumnLayout ? 'grid-cols-2' : 'grid-cols-1'} gap-x-16 gap-y-8`}>
|
||||
{contentItems.map((item, index) => (
|
||||
<div key={index} className="flex items-center space-x-4">
|
||||
<div className="w-12 h-12 bg-yellow-200 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-teal-700 font-bold text-lg">
|
||||
{item.number}
|
||||
<div key={index} className="flex items-start space-x-4">
|
||||
{/* Number Circle */}
|
||||
<div className="w-10 h-10 bg-yellow-200 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-teal-700 font-bold text-sm">
|
||||
{item.itemNumber}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-gray-900 font-medium text-lg">
|
||||
{item.title}
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-bold text-gray-900 mb-1">
|
||||
{item.contentTitle}
|
||||
</h3>
|
||||
{item.contentDescription && (
|
||||
<p className="text-sm text-gray-600 leading-relaxed">
|
||||
{item.contentDescription}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -117,43 +143,33 @@ const TableOfContentsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - Image and Branding */}
|
||||
<div className="w-2/5 relative bg-teal-600">
|
||||
{/* Hero Image */}
|
||||
{heroImage?.__image_url__ && (
|
||||
<div className="absolute top-0 left-0 right-0 h-1/2">
|
||||
{/* Right Side - Branding and Visual Elements */}
|
||||
<div className="w-2/5 relative bg-gray-50 flex items-center justify-center">
|
||||
{/* Branding Visual */}
|
||||
{brandingVisual?.__image_url__ && (
|
||||
<div className="text-center">
|
||||
<img
|
||||
src={heroImage.__image_url__}
|
||||
alt={heroImage.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
src={brandingVisual.__image_url__}
|
||||
alt={brandingVisual.__image_prompt__}
|
||||
className="max-w-64 max-h-32 object-contain mx-auto"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Decorative Circle */}
|
||||
{decorativeCircle && (
|
||||
<div className="absolute bottom-24 left-1/2 transform -translate-x-1/2 w-32 h-32 bg-yellow-200 rounded-full"></div>
|
||||
{/* Decorative Elements */}
|
||||
{showDecorations && (
|
||||
<>
|
||||
{/* Decorative circles */}
|
||||
<div className="absolute top-8 right-8 w-6 h-6 bg-teal-600 rounded-full opacity-60"></div>
|
||||
<div className="absolute bottom-12 left-8 w-4 h-4 bg-yellow-300 rounded-full"></div>
|
||||
<div className="absolute top-32 left-12 w-3 h-3 bg-teal-400 rounded-full"></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Company Branding */}
|
||||
<div className="absolute bottom-8 left-8 flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
<div className="w-10 h-10">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
<span className="text-white font-bold text-xl">
|
||||
{companyName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom accent strip */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-2 bg-teal-600"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,72 +1,89 @@
|
|||
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")
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("CLIENT TESTIMONIALS")
|
||||
.meta({
|
||||
description: "Main title for the testimonial section",
|
||||
description: "Main section heading - can be 'Testimonials', 'Client Feedback', 'Reviews', or similar",
|
||||
}),
|
||||
|
||||
companyLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C",
|
||||
__image_prompt__: "Clean modern company logo icon in white"
|
||||
organizationName: z.string()
|
||||
.min(2)
|
||||
.max(30)
|
||||
.default("Your Organization")
|
||||
.meta({
|
||||
description: "Name of the organization or entity being featured",
|
||||
}),
|
||||
|
||||
brandLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
|
||||
__image_prompt__: "Professional organization logo - clean and modern design"
|
||||
}).meta({
|
||||
description: "Company logo icon",
|
||||
description: "Logo or brand mark representing the organization",
|
||||
}),
|
||||
|
||||
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,
|
||||
testimonialItems: z.array(z.object({
|
||||
clientName: z.string().min(2).max(40),
|
||||
clientTitle: z.string().min(5).max(60),
|
||||
clientCompany: z.string().min(2).max(40),
|
||||
testimonialText: z.string().min(50).max(300),
|
||||
rating: z.number().min(1).max(5),
|
||||
backgroundColor: z.enum(["beige", "teal", "light"])
|
||||
})).min(3).max(3).default([
|
||||
clientPhoto: ImageSchema
|
||||
})).min(2).max(4).default([
|
||||
{
|
||||
text: "In a world flooded with marketing noise, this company stands out as a beacon of creativity and effectiveness.",
|
||||
clientName: "Benjamin Shah",
|
||||
clientName: "Sarah Johnson",
|
||||
clientTitle: "Chief Executive Officer",
|
||||
clientCompany: "TechCorp Solutions",
|
||||
testimonialText: "Working with this team has been transformative for our business. Their expertise, dedication, and innovative approach exceeded our expectations and delivered remarkable results.",
|
||||
rating: 5,
|
||||
clientPhoto: {
|
||||
__image_url__: "https://images.unsplash.com/photo-1494790108755-2616b612b830?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
|
||||
__image_prompt__: "Professional businesswoman headshot"
|
||||
}
|
||||
},
|
||||
{
|
||||
clientName: "Michael Chen",
|
||||
clientTitle: "Director of Operations",
|
||||
clientCompany: "Global Innovations Inc",
|
||||
testimonialText: "The level of professionalism and quality of service provided was outstanding. They understood our needs perfectly and delivered solutions that truly made a difference.",
|
||||
rating: 5,
|
||||
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"
|
||||
__image_prompt__: "Professional businessman headshot"
|
||||
}
|
||||
},
|
||||
{
|
||||
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"
|
||||
},
|
||||
clientName: "Emily Rodriguez",
|
||||
clientTitle: "Marketing Manager",
|
||||
clientCompany: "Creative Dynamics",
|
||||
testimonialText: "Exceptional service and results that spoke for themselves. The team's attention to detail and commitment to excellence made our collaboration highly successful.",
|
||||
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"
|
||||
__image_url__: "https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
|
||||
__image_prompt__: "Professional woman headshot"
|
||||
}
|
||||
}
|
||||
]).meta({
|
||||
description: "Three client testimonials with photos and ratings",
|
||||
description: "List of client testimonials with ratings, photos, and detailed feedback",
|
||||
}),
|
||||
|
||||
showRatings: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to display star ratings for each testimonial",
|
||||
}),
|
||||
|
||||
showClientPhotos: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to show client photos alongside testimonials",
|
||||
}),
|
||||
})
|
||||
|
||||
// Type inference
|
||||
|
|
@ -75,101 +92,104 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const TestimonialSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { mainTitle, companyLogo, companyName, testimonials } = data;
|
||||
const { sectionTitle, organizationName, brandLogo, testimonialItems, showRatings, showClientPhotos } = 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 (
|
||||
<div className={`flex space-x-1 mb-6 ${getStarColor(backgroundColor)}`}>
|
||||
{[...Array(5)].map((_, index) => (
|
||||
<svg
|
||||
key={index}
|
||||
className="w-6 h-6 fill-current"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
// Helper function to render stars
|
||||
const renderStars = (rating: number) => {
|
||||
return Array.from({ length: 5 }, (_, i) => (
|
||||
<svg
|
||||
key={i}
|
||||
className={`w-4 h-4 ${i < rating ? 'text-yellow-400' : 'text-gray-300'}`}
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||
</svg>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-gray-50 relative overflow-hidden">
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Header Section */}
|
||||
<div className="h-20 bg-teal-600 px-16 py-4 flex justify-between items-center">
|
||||
{/* Title */}
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl font-black text-white">
|
||||
{mainTitle}
|
||||
{sectionTitle && (
|
||||
<h1 className="text-2xl font-black text-white">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Company Branding */}
|
||||
<div className="flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
{brandLogo?.__image_url__ && (
|
||||
<div className="w-8 h-8">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
src={brandLogo.__image_url__}
|
||||
alt={brandLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
<span className="text-lg font-bold text-white">
|
||||
{companyName}
|
||||
{organizationName && (
|
||||
<span className="text-base font-bold text-white">
|
||||
{organizationName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Testimonials Section */}
|
||||
<div className="flex-1 h-[calc(100%-80px)] px-16 py-12 flex items-center justify-center">
|
||||
{testimonials && testimonials.length > 0 && (
|
||||
<div className="grid grid-cols-3 gap-8 w-full max-w-6xl">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`${getBackgroundClass(testimonial.backgroundColor)} rounded-3xl p-8 flex flex-col items-center text-center h-full`}
|
||||
>
|
||||
{/* Stars */}
|
||||
{renderStars(testimonial.rating, testimonial.backgroundColor)}
|
||||
{/* Testimonials Content */}
|
||||
<div className="flex-1 px-16 py-12 bg-gray-50">
|
||||
{testimonialItems && testimonialItems.length > 0 && (
|
||||
<div className="grid grid-cols-3 gap-8 h-full">
|
||||
{testimonialItems.slice(0, 3).map((item, index) => {
|
||||
// Rotate background colors for visual variety
|
||||
const bgColors = ['bg-yellow-100', 'bg-teal-100', 'bg-gray-100'];
|
||||
const bgColor = bgColors[index % bgColors.length];
|
||||
|
||||
{/* Testimonial Text */}
|
||||
<p className="text-base leading-relaxed mb-8 flex-1 flex items-center">
|
||||
{testimonial.text}
|
||||
</p>
|
||||
return (
|
||||
<div key={index} className={`${bgColor} rounded-lg p-6 flex flex-col`}>
|
||||
{/* Stars Rating */}
|
||||
{showRatings && (
|
||||
<div className="flex space-x-1 mb-4">
|
||||
{renderStars(item.rating)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Client Photo */}
|
||||
{testimonial.clientPhoto?.__image_url__ && (
|
||||
<div className="w-20 h-20 rounded-full overflow-hidden mb-4 border-4 border-white shadow-lg">
|
||||
<img
|
||||
src={testimonial.clientPhoto.__image_url__}
|
||||
alt={testimonial.clientPhoto.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
{/* Testimonial Text */}
|
||||
<p className="text-base leading-relaxed text-gray-800 mb-6 flex-1">
|
||||
"{item.testimonialText}"
|
||||
</p>
|
||||
|
||||
{/* Client Info */}
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Client Photo */}
|
||||
{showClientPhotos && item.clientPhoto?.__image_url__ && (
|
||||
<div className="w-12 h-12 rounded-full overflow-hidden flex-shrink-0">
|
||||
<img
|
||||
src={item.clientPhoto.__image_url__}
|
||||
alt={item.clientPhoto.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Client Details */}
|
||||
<div className="flex-1">
|
||||
<h4 className="text-lg font-bold text-gray-900">
|
||||
{item.clientName}
|
||||
</h4>
|
||||
<p className="text-sm text-gray-600">
|
||||
{item.clientTitle}
|
||||
</p>
|
||||
<p className="text-sm font-semibold text-teal-600">
|
||||
{item.clientCompany}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Client Name */}
|
||||
<h3 className="text-lg font-bold">
|
||||
{testimonial.clientName}
|
||||
</h3>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,68 +5,73 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
|
||||
companyName: z.string()
|
||||
organizationName: z.string()
|
||||
.min(2)
|
||||
.max(15)
|
||||
.default("Company Name")
|
||||
.max(30)
|
||||
.default("Your Organization")
|
||||
.meta({
|
||||
description: "Company name displayed prominently",
|
||||
description: "Name of the organization, company, or entity presenting",
|
||||
}),
|
||||
|
||||
mainTitle: z.string()
|
||||
.min(5)
|
||||
.max(20)
|
||||
primaryMessage: z.string()
|
||||
.min(3)
|
||||
.max(25)
|
||||
.default("THANK YOU")
|
||||
.meta({
|
||||
description: "Main thank you title in large bold letters",
|
||||
description: "Main closing message - can be 'Thank You', 'Questions?', 'Let's Connect', or similar",
|
||||
}),
|
||||
|
||||
subtitle: z.string()
|
||||
.min(10)
|
||||
.max(40)
|
||||
.default("FOR YOUR NICE ATTENTION")
|
||||
secondaryMessage: z.string()
|
||||
.min(5)
|
||||
.max(60)
|
||||
.default("FOR YOUR TIME AND ATTENTION")
|
||||
.meta({
|
||||
description: "Subtitle thanking the audience",
|
||||
description: "Supporting message that completes the primary message or adds context",
|
||||
}),
|
||||
|
||||
companyLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=C",
|
||||
__image_prompt__: "Company logo - geometric green icon"
|
||||
brandLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
|
||||
__image_prompt__: "Professional organization logo - clean and modern design"
|
||||
}).meta({
|
||||
description: "Company logo icon",
|
||||
description: "Logo or brand mark representing the presenting organization",
|
||||
}),
|
||||
|
||||
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")
|
||||
contactDetails: z.object({
|
||||
phoneNumber: z.string().min(10).max(20).default("+1-234-567-8900"),
|
||||
physicalAddress: z.string().min(10).max(60).default("123 Business Ave, City, State 12345"),
|
||||
websiteUrl: z.string().min(10).max(40).default("www.yourorganization.com")
|
||||
}).default({
|
||||
telephone: "+123-456-7890",
|
||||
address: "123 Anywhere St., Any City, ST 12345",
|
||||
website: "www.reallygreatsite.com"
|
||||
phoneNumber: "+1-234-567-8900",
|
||||
physicalAddress: "123 Business Ave, City, State 12345",
|
||||
websiteUrl: "www.yourorganization.com"
|
||||
}).meta({
|
||||
description: "Company contact information",
|
||||
description: "Contact information for follow-up communication and connection",
|
||||
}),
|
||||
|
||||
presentationDate: z.string()
|
||||
.min(5)
|
||||
.min(3)
|
||||
.max(20)
|
||||
.default("December 2023")
|
||||
.default("Current Month Year")
|
||||
.meta({
|
||||
description: "Date of the presentation",
|
||||
description: "Date when the presentation was given or document was created",
|
||||
}),
|
||||
|
||||
decorativeCircle: z.boolean()
|
||||
showDecorations: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative circle element",
|
||||
description: "Whether to display decorative visual elements like background shapes",
|
||||
}),
|
||||
|
||||
arrowButton: z.boolean()
|
||||
showNavigationArrow: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show navigation arrow button",
|
||||
description: "Whether to show a navigation arrow for interactive presentations",
|
||||
}),
|
||||
|
||||
showContactInfo: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to display contact information in the footer",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -76,7 +81,7 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const ThankYouSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { companyName, mainTitle, subtitle, companyLogo, contactInfo, presentationDate, decorativeCircle, arrowButton } = data;
|
||||
const { organizationName, primaryMessage, secondaryMessage, brandLogo, contactDetails, presentationDate, showDecorations, showNavigationArrow, showContactInfo } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
|
|
@ -84,24 +89,24 @@ const ThankYouSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="absolute top-0 left-0 right-0 px-16 py-8 flex justify-between items-center z-20">
|
||||
{/* Company Logo and Name */}
|
||||
<div className="flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
{brandLogo?.__image_url__ && (
|
||||
<div className="w-10 h-10">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
src={brandLogo.__image_url__}
|
||||
alt={brandLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
{organizationName && (
|
||||
<span className="text-2xl font-bold text-gray-900">
|
||||
{companyName}
|
||||
{organizationName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Arrow Button */}
|
||||
{arrowButton && (
|
||||
{showNavigationArrow && (
|
||||
<div className="w-12 h-12 bg-teal-600 rounded-full flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
|
|
@ -111,7 +116,7 @@ const ThankYouSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</div>
|
||||
|
||||
{/* Decorative Circle */}
|
||||
{decorativeCircle && (
|
||||
{showDecorations && (
|
||||
<div className="absolute top-20 right-16 w-96 h-96 bg-yellow-100 rounded-full opacity-60 z-10"></div>
|
||||
)}
|
||||
|
||||
|
|
@ -119,18 +124,18 @@ const ThankYouSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="relative z-15 h-full flex flex-col justify-center px-16">
|
||||
<div className="max-w-4xl">
|
||||
{/* Main Title */}
|
||||
{mainTitle && (
|
||||
{primaryMessage && (
|
||||
<h1 className="text-8xl lg:text-9xl font-black text-teal-700 leading-none tracking-tight mb-4">
|
||||
{mainTitle}
|
||||
{primaryMessage}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Subtitle with Circle Bullet */}
|
||||
{subtitle && (
|
||||
{secondaryMessage && (
|
||||
<div className="flex items-center space-x-4 mb-12">
|
||||
<div className="w-4 h-4 bg-teal-600 rounded-full"></div>
|
||||
<h2 className="text-2xl font-bold text-gray-800 tracking-wide">
|
||||
{subtitle}
|
||||
{secondaryMessage}
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -138,44 +143,46 @@ const ThankYouSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</div>
|
||||
|
||||
{/* Footer with Contact Info */}
|
||||
<div className="absolute bottom-0 left-0 right-0 px-16 py-8 border-t-2 border-gray-300">
|
||||
<div className="flex justify-between items-center text-gray-700">
|
||||
<div className="flex space-x-16 text-sm">
|
||||
{/* Telephone */}
|
||||
{contactInfo?.telephone && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Telephone</div>
|
||||
<div>{contactInfo.telephone}</div>
|
||||
</div>
|
||||
)}
|
||||
{showContactInfo && (
|
||||
<div className="absolute bottom-0 left-0 right-0 px-16 py-8 border-t-2 border-gray-300">
|
||||
<div className="flex justify-between items-center text-gray-700">
|
||||
<div className="flex space-x-16 text-sm">
|
||||
{/* Telephone */}
|
||||
{contactDetails?.phoneNumber && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Telephone</div>
|
||||
<div>{contactDetails.phoneNumber}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Address */}
|
||||
{contactInfo?.address && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Address</div>
|
||||
<div>{contactInfo.address}</div>
|
||||
</div>
|
||||
)}
|
||||
{/* Address */}
|
||||
{contactDetails?.physicalAddress && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Address</div>
|
||||
<div>{contactDetails.physicalAddress}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Website */}
|
||||
{contactInfo?.website && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Website</div>
|
||||
<div>{contactInfo.website}</div>
|
||||
{/* Website */}
|
||||
{contactDetails?.websiteUrl && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Website</div>
|
||||
<div>{contactDetails.websiteUrl}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Presentation Date */}
|
||||
{presentationDate && (
|
||||
<div className="text-right">
|
||||
<div className="text-lg font-bold text-gray-900">
|
||||
{presentationDate}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Presentation Date */}
|
||||
{presentationDate && (
|
||||
<div className="text-right">
|
||||
<div className="text-lg font-bold text-gray-900">
|
||||
{presentationDate}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,68 +5,67 @@ import { ImageSchema, IconSchema } from "../defaultSchemes";
|
|||
// Schema definition
|
||||
export const Schema = z.object({
|
||||
|
||||
|
||||
companyName: z.string()
|
||||
organizationName: z.string()
|
||||
.min(2)
|
||||
.max(15)
|
||||
.default("Thynk Unlimited")
|
||||
.max(25)
|
||||
.default("Your Organization")
|
||||
.meta({
|
||||
description: "Company name displayed prominently",
|
||||
description: "Name of the organization, company, or entity presenting",
|
||||
}),
|
||||
|
||||
mainTitle: z.string()
|
||||
primaryTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("PRESENTATION TITLE")
|
||||
.meta({
|
||||
description: "Main headline or title for the presentation - should be impactful and attention-grabbing",
|
||||
}),
|
||||
|
||||
secondaryTitle: z.string()
|
||||
.min(5)
|
||||
.max(15)
|
||||
.default("PITCH DECK")
|
||||
.max(50)
|
||||
.default("PROFESSIONAL PRESENTATION")
|
||||
.meta({
|
||||
description: "Main title in large bold letters",
|
||||
description: "Subtitle that provides context about the presentation type or purpose",
|
||||
}),
|
||||
|
||||
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"
|
||||
brandLogo: ImageSchema.default({
|
||||
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
|
||||
__image_prompt__: "Professional organization logo - clean and modern design"
|
||||
}).meta({
|
||||
description: "Company logo icon",
|
||||
description: "Logo or brand mark representing the presenting organization",
|
||||
}),
|
||||
|
||||
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")
|
||||
contactDetails: z.object({
|
||||
phoneNumber: z.string().min(10).max(20).default("+1-234-567-8900"),
|
||||
physicalAddress: z.string().min(10).max(60).default("123 Business Ave, City, State 12345"),
|
||||
websiteUrl: z.string().min(10).max(40).default("www.yourorganization.com")
|
||||
}).default({
|
||||
telephone: "+123-456-7890",
|
||||
address: "123 Anywhere St., Any City, ST 12345",
|
||||
website: "www.reallygreatsite.com"
|
||||
phoneNumber: "+1-234-567-8900",
|
||||
physicalAddress: "123 Business Ave, City, State 12345",
|
||||
websiteUrl: "www.yourorganization.com"
|
||||
}).meta({
|
||||
description: "Company contact information",
|
||||
description: "Contact information including phone, address, and website for follow-up communication",
|
||||
}),
|
||||
|
||||
presentationDate: z.string()
|
||||
.min(5)
|
||||
.min(3)
|
||||
.max(20)
|
||||
.default("December 2023")
|
||||
.default("Current Month Year")
|
||||
.meta({
|
||||
description: "Date of the presentation",
|
||||
description: "Date when the presentation is being given or was created",
|
||||
}),
|
||||
|
||||
decorativeCircle: z.boolean()
|
||||
showDecorations: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show decorative circle element",
|
||||
description: "Whether to display decorative visual elements like background shapes",
|
||||
}),
|
||||
|
||||
arrowButton: z.boolean()
|
||||
showNavigationArrow: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show navigation arrow button",
|
||||
description: "Whether to show a navigation arrow button for presentation flow",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -77,7 +76,7 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
const ThynkTitleSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
|
||||
const { companyName, mainTitle, subtitle, companyLogo, contactInfo, presentationDate, decorativeCircle, arrowButton } = data;
|
||||
const { organizationName, primaryTitle, secondaryTitle, brandLogo, contactDetails, presentationDate, showDecorations, showNavigationArrow } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
|
|
@ -85,24 +84,24 @@ const ThynkTitleSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="absolute top-0 left-0 right-0 px-16 py-8 flex justify-between items-center z-20">
|
||||
{/* Company Logo and Name */}
|
||||
<div className="flex items-center space-x-3">
|
||||
{companyLogo?.__image_url__ && (
|
||||
{brandLogo?.__image_url__ && (
|
||||
<div className="w-10 h-10">
|
||||
<img
|
||||
src={companyLogo.__image_url__}
|
||||
alt={companyLogo.__image_prompt__}
|
||||
src={brandLogo.__image_url__}
|
||||
alt={brandLogo.__image_prompt__}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{companyName && (
|
||||
{organizationName && (
|
||||
<span className="text-2xl font-bold text-gray-900">
|
||||
{companyName}
|
||||
{organizationName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Arrow Button */}
|
||||
{arrowButton && (
|
||||
{showNavigationArrow && (
|
||||
<div className="w-12 h-12 bg-teal-600 rounded-full flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
|
|
@ -112,7 +111,7 @@ const ThynkTitleSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</div>
|
||||
|
||||
{/* Decorative Circle */}
|
||||
{decorativeCircle && (
|
||||
{showDecorations && (
|
||||
<div className="absolute top-20 right-16 w-96 h-96 bg-yellow-100 rounded-full opacity-60 z-10"></div>
|
||||
)}
|
||||
|
||||
|
|
@ -120,18 +119,18 @@ const ThynkTitleSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="relative z-15 h-full flex flex-col justify-center px-16">
|
||||
<div className="">
|
||||
{/* Main Title */}
|
||||
{mainTitle && (
|
||||
{primaryTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-none tracking-tight mb-4">
|
||||
{mainTitle}
|
||||
{primaryTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{/* Subtitle with Circle Bullet */}
|
||||
{subtitle && (
|
||||
{secondaryTitle && (
|
||||
<div className="flex items-center space-x-4 mb-12">
|
||||
<div className="w-4 h-4 bg-teal-600 rounded-full"></div>
|
||||
<h2 className="text-xl font-bold text-gray-800 tracking-wide">
|
||||
{subtitle}
|
||||
{secondaryTitle}
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -143,26 +142,26 @@ const ThynkTitleSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="flex justify-between items-center text-gray-700">
|
||||
<div className="flex space-x-16 text-sm">
|
||||
{/* Telephone */}
|
||||
{contactInfo?.telephone && (
|
||||
{contactDetails?.phoneNumber && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Telephone</div>
|
||||
<div>{contactInfo.telephone}</div>
|
||||
<div>{contactDetails.phoneNumber}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Address */}
|
||||
{contactInfo?.address && (
|
||||
{contactDetails?.physicalAddress && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Address</div>
|
||||
<div>{contactInfo.address}</div>
|
||||
<div>{contactDetails.physicalAddress}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Website */}
|
||||
{contactInfo?.website && (
|
||||
{contactDetails?.websiteUrl && (
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 mb-1">Website</div>
|
||||
<div>{contactInfo.website}</div>
|
||||
<div>{contactDetails.websiteUrl}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,66 +5,57 @@ 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)
|
||||
sectionTitle: z.string()
|
||||
.min(3)
|
||||
.max(30)
|
||||
.default("ABOUT OUR VISION AND MISSION")
|
||||
.default("OUR VISION & MISSION")
|
||||
.meta({
|
||||
description: "Subtitle describing the section",
|
||||
description: "Main section heading - can be 'Our Values', 'What We Believe', 'Our Philosophy', or similar",
|
||||
}),
|
||||
|
||||
visionTitle: z.string()
|
||||
.min(3)
|
||||
.max(15)
|
||||
.default("VISION")
|
||||
sectionSubtitle: z.string()
|
||||
.min(10)
|
||||
.max(60)
|
||||
.default("GUIDING PRINCIPLES AND CORE BELIEFS")
|
||||
.meta({
|
||||
description: "Vision section title",
|
||||
description: "Supporting subtitle that introduces the organization's foundational concepts",
|
||||
}),
|
||||
|
||||
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.")
|
||||
visionStatement: z.string()
|
||||
.min(30)
|
||||
.max(200)
|
||||
.default("We envision a future where innovative solutions transform challenges into opportunities, creating sustainable value for all stakeholders.")
|
||||
.meta({
|
||||
description: "Vision statement text",
|
||||
description: "Vision statement describing the organization's aspirational future goals and impact",
|
||||
}),
|
||||
|
||||
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"
|
||||
missionContent: z.object({
|
||||
missionTitle: z.string().min(3).max(30).default("Our Mission"),
|
||||
missionDescription: z.string().min(50).max(300).default("To deliver exceptional value through strategic innovation, collaborative partnerships, and unwavering commitment to excellence. We believe in empowering organizations with the tools, insights, and support needed to achieve sustainable growth and meaningful impact in their communities.")
|
||||
}).default({
|
||||
missionTitle: "Our Mission",
|
||||
missionDescription: "To deliver exceptional value through strategic innovation, collaborative partnerships, and unwavering commitment to excellence. We believe in empowering organizations with the tools, insights, and support needed to achieve sustainable growth and meaningful impact in their communities."
|
||||
}).meta({
|
||||
description: "Team collaboration image",
|
||||
description: "Mission section with title and detailed description of organizational purpose and approach",
|
||||
}),
|
||||
|
||||
showYellowAccent: z.boolean()
|
||||
supportingVisual: 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__: "Diverse team collaborating and planning together in modern workspace"
|
||||
}).meta({
|
||||
description: "Visual that represents collaboration, vision, or organizational culture",
|
||||
}),
|
||||
|
||||
showVisualAccents: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Show yellow accent block",
|
||||
description: "Whether to display decorative visual accent elements",
|
||||
}),
|
||||
|
||||
showColorBlocks: z.boolean()
|
||||
.default(true)
|
||||
.meta({
|
||||
description: "Whether to show colored background sections for visual hierarchy",
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -74,84 +65,88 @@ type SchemaType = z.infer<typeof Schema>;
|
|||
// Component definition
|
||||
const WhatWeBelieveSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
|
||||
const { mainTitle, subtitle, visionTitle, visionText, missionTitle, missionText, teamImage, showYellowAccent } = data;
|
||||
const { sectionTitle, sectionSubtitle, visionStatement, missionContent, supportingVisual, showVisualAccents, showColorBlocks } = data;
|
||||
|
||||
return (
|
||||
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
|
||||
{/* Main Content Area */}
|
||||
<div className="h-full flex">
|
||||
{/* Left Side - Image */}
|
||||
<div className="w-1/2 relative">
|
||||
{/* Team Image */}
|
||||
{teamImage?.__image_url__ && (
|
||||
<div className="absolute top-0 left-0 bottom-32 right-0">
|
||||
<div className="w-2/5 relative">
|
||||
{supportingVisual?.__image_url__ && (
|
||||
<div className="absolute inset-8 z-15 shadow-lg">
|
||||
<img
|
||||
src={teamImage.__image_url__}
|
||||
alt={teamImage.__image_prompt__}
|
||||
className="w-full h-full object-cover"
|
||||
src={supportingVisual.__image_url__}
|
||||
alt={supportingVisual.__image_prompt__}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Yellow Accent Block - Bottom Left */}
|
||||
{showYellowAccent && (
|
||||
<div className="absolute bottom-0 left-0 w-32 h-32 bg-yellow-300 z-10"></div>
|
||||
{/* Visual Accents */}
|
||||
{showVisualAccents && (
|
||||
<>
|
||||
{/* Decorative circles */}
|
||||
<div className="absolute top-4 right-4 w-6 h-6 bg-teal-600 rounded-full opacity-70 z-20"></div>
|
||||
<div className="absolute bottom-8 left-8 w-4 h-4 bg-yellow-300 rounded-full z-20"></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Teal Accent Block - Bottom */}
|
||||
<div className="absolute bottom-0 left-32 right-0 h-32 bg-teal-600 z-10"></div>
|
||||
</div>
|
||||
|
||||
{/* Right Side - Content */}
|
||||
<div className="w-1/2 relative bg-white ">
|
||||
<div className="px-16 py-12">
|
||||
|
||||
{/* Title Section */}
|
||||
<div className="mb-8">
|
||||
{mainTitle && (
|
||||
<h1 className="text-4xl lg:text-5xl font-black text-teal-700 leading-tight mb-4">
|
||||
{mainTitle}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{subtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide mb-8">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Vision Section */}
|
||||
<div className="mb-8">
|
||||
{visionTitle && (
|
||||
<h2 className="text-2xl font-bold text-teal-700 mb-4">
|
||||
{visionTitle}
|
||||
</h2>
|
||||
)}
|
||||
{visionText && (
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{visionText}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/* Mission Section with Teal Background */}
|
||||
<div className="bg-teal-600 p-6 absolute bottom-0 left-0 right-0 px-16 text-white">
|
||||
{missionTitle && (
|
||||
<h2 className="text-2xl font-bold mb-4">
|
||||
{missionTitle}
|
||||
</h2>
|
||||
<div className="w-3/5 relative bg-white px-16 py-12 flex flex-col justify-start">
|
||||
{/* Title Section */}
|
||||
<div className="mb-8">
|
||||
{sectionTitle && (
|
||||
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
|
||||
{sectionTitle}
|
||||
</h1>
|
||||
)}
|
||||
{missionText && (
|
||||
<p className="text-base leading-relaxed">
|
||||
{missionText}
|
||||
|
||||
{sectionSubtitle && (
|
||||
<p className="text-base font-semibold text-gray-800 tracking-wide mb-8">
|
||||
{sectionSubtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Vision Section */}
|
||||
{visionStatement && (
|
||||
<div className="mb-8">
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-4">Vision</h2>
|
||||
<p className="text-base leading-relaxed text-gray-700">
|
||||
{visionStatement}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Mission Section with Teal Background */}
|
||||
{missionContent && (
|
||||
<div className="bg-teal-600 px-8 py-6 rounded-lg">
|
||||
{missionContent.missionTitle && (
|
||||
<h2 className="text-xl font-bold text-white mb-4">
|
||||
{missionContent.missionTitle}
|
||||
</h2>
|
||||
)}
|
||||
{missionContent.missionDescription && (
|
||||
<p className="text-base leading-relaxed text-gray-100">
|
||||
{missionContent.missionDescription}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Color blocks for visual hierarchy */}
|
||||
{showColorBlocks && (
|
||||
<>
|
||||
{/* Bottom accent strip */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-2 bg-teal-600"></div>
|
||||
{/* Left accent */}
|
||||
<div className="absolute top-0 left-0 bottom-0 w-2 bg-yellow-300"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"description": "This is a new pitch deck layout with a focus on simplicity and clarity.",
|
||||
"description": "Professional presentation layouts with clean design and flexible content fields. Suitable for business pitches, organizational overviews, product presentations, and various corporate communications.",
|
||||
"ordered": false,
|
||||
"isDefault": false
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue