add: swift template

This commit is contained in:
Suraj Jha 2025-09-09 03:53:31 +05:45
parent d3209e4b9f
commit a1b7dfd51b
No known key found for this signature in database
GPG key ID: 5AC6C16355CE2C14
10 changed files with 1696 additions and 0 deletions

View file

@ -0,0 +1,242 @@
import React from "react"
import * as z from "zod"
import { IconSchema, ImageSchema } from '@/presentation-templates/defaultSchemes';
import { RemoteSvgIcon } from "@/app/hooks/useRemoteSvgIcon";
const layoutId = "bullet-with-icons-title-description"
const layoutName = "Bullet With Icons Title Description"
const layoutDescription = "Bullet with icons with title and description and title and description for whole"
const ItemSchema = z
.object({
icon: IconSchema,
title: z.string().min(3).max(40).default("Lorem ipsum dolor"),
description: z
.string()
.min(0)
.max(160)
.default(
"Short supporting description that fits under the icon title."
),
})
.default({
icon: {
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/graduation-cap-bold.svg",
__icon_query__: "feature icon",
},
title: "Lorem ipsum dolor",
description: "Short supporting description that fits under the icon title.",
})
const Schema = z
.object({
title: z
.string()
.min(3)
.max(60)
.default("Our Infographic"),
sideHeading: z.string().min(0).max(60).default("Lorem ipsum dolor sit amet,"),
sideParagraph: z
.string()
.min(0)
.max(300)
.default(
"Concise paragraph describing context. Keep it short and readable across one or two lines."
),
items: z
.array(ItemSchema)
.min(3)
.max(4)
.default([
{
icon: {
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/graduation-cap-bold.svg",
__icon_query__: "feature icon",
},
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the first icon explaining the point.",
},
{
icon: {
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/user-bold.svg",
__icon_query__: "feature icon",
},
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the second icon explaining the point.",
},
{
icon: {
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/calendar-blank-bold.svg",
__icon_query__: "feature icon",
},
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the third icon explaining the point.",
},
{
icon: {
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/x-bold.svg",
__icon_query__: "feature icon",
},
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the fourth icon explaining the point.",
},
]),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
title: "Our Infographic",
sideHeading: "Lorem ipsum dolor sit amet,",
sideParagraph:
"Concise paragraph describing context. Keep it short and readable across one or two lines.",
items: [
{
icon: { __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/graduation-cap-bold.svg", __icon_query__: "feature icon" },
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the first icon explaining the point.",
},
{
icon: { __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/user-bold.svg", __icon_query__: "feature icon" },
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the second icon explaining the point.",
},
{
icon: { __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/calendar-blank-bold.svg", __icon_query__: "feature icon" },
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the third icon explaining the point.",
},
{
icon: { __icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/x-bold.svg", __icon_query__: "feature icon" },
title: "Lorem ipsum dolor",
description:
"Concise supporting text under the fourth icon explaining the point.",
},
],
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const InfographicFourIcons: React.FC<SlideLayoutProps> = ({ data }) => {
const slideData = data || {}
const items = slideData.items || []
const renderTitle = (title?: string) => {
if (!title) return null
const parts = title.split("\n")
return (
<>
{parts.map((p, i) => (
<div key={i}>{p}</div>
))}
</>
)
}
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{(slideData as any )?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
</div>
{/* Title + right paragraph */}
<div className="px-12 pt-2">
<div className="grid grid-cols-[1.2fr_1fr] gap-10 items-start">
<div className="text-[56px] leading-[1.05] font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>
{renderTitle(slideData.title)}
</div>
<div>
{slideData.sideHeading && (
<div className="text-[16px] mb-2 font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>
{slideData.sideHeading}
</div>
)}
{slideData.sideParagraph && (
<div className="text-[14px] leading-[1.6]" style={{ color: "var(--text-body-color, #6B7280)" }}>
{slideData.sideParagraph}
</div>
)}
</div>
</div>
</div>
{/* Icons row */}
<div className="px-12 pt-12">
<div className="grid grid-flow-col auto-cols-[260px] gap-8 justify-center">
{items.slice(0, 4).map((item, idx) => (
<div key={idx} className="flex flex-col items-center text-center">
<div className="relative">
<div
className="w-40 h-40 rounded-full flex items-center justify-center shadow"
style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}
>
{/* Icon */}
<RemoteSvgIcon
url={item.icon.__icon_url__}
strokeColor={"currentColor"}
className="w-14 h-14"
color="var(--text-heading-color, #111827)"
title={item.icon.__icon_query__}
/>
</div>
</div>
<div className="mt-5 text-[16px] font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>
{item.title}
</div>
<div className="mt-2 text-[13px] leading-[1.6] max-w-[260px]" style={{ color: "var(--text-body-color, #6B7280)" }}>
{item.description}
</div>
</div>
))}
</div>
</div>
{/* Footer (standardized like IntroSlideLayout) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default InfographicFourIcons

View file

@ -0,0 +1,200 @@
import React from "react"
import * as z from "zod"
import { RemoteSvgIcon } from "@/app/hooks/useRemoteSvgIcon";
const layoutId = "icon-bullet-list-description-slide"
const layoutName = "Icon Bullet List Description"
const layoutDescription = "Bullet list with title, description, and icon"
const IconSchema = z
.object({
__icon_url__: z
.string()
.default(
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/file-text-bold.svg"
),
__icon_query__: z.string().min(0).max(80).default("feature icon"),
})
.default({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/file-text-bold.svg",
__icon_query__: "feature icon",
})
const FeatureSchema = z
.object({
title: z.string().min(4).max(28).default("Customizable Workflows"),
body: z
.string()
.min(20)
.max(140)
.default("Lorem ipsum dolor sit amet, dolor sit amet."),
icon: IconSchema,
})
.default({
title: "Customizable Workflows",
body: "Lorem ipsum dolor sit amet, dolor sit amet.",
icon: IconSchema.parse({}),
})
const Schema = z
.object({
title: z
.string()
.min(8)
.max(48)
.default("Key Product Features"),
description: z
.string()
.min(30)
.max(200)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor."
),
features: z
.array(FeatureSchema)
.min(3)
.max(4)
.default([
FeatureSchema.parse({}),
{
title: "Multi-Device Access",
body: "Lorem ipsum dolor sit amet.",
icon: IconSchema.parse({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/devices-bold.svg",
}),
},
{
title: "Scalable Architecture",
body: "Lorem ipsum dolor sit amet.",
icon: IconSchema.parse({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/chart-line-up-bold.svg",
}),
},
{
title: "Detailed Reports",
body: "Lorem ipsum dolor sit amet.",
icon: IconSchema.parse({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/checks-bold.svg",
}),
},
]),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
title: "Key Product Features",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor.",
features: [
FeatureSchema.parse({}),
{
title: "Multi-Device Access",
body: "Lorem ipsum dolor sit amet.",
icon: IconSchema.parse({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/devices-bold.svg",
}),
},
{
title: "Scalable Architecture",
body: "Lorem ipsum dolor sit amet.",
icon: IconSchema.parse({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/chart-line-up-bold.svg",
}),
},
{
title: "Detailed Reports",
body: "Lorem ipsum dolor sit amet.",
icon: IconSchema.parse({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/checks-bold.svg",
}),
},
],
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const FeatureCards: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const features = slideData?.features || []
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{(slideData as any)?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
{/* Decorative right image area removed to keep imagery-driven design */}
<div className="px-12 pt-3">
<h1 className="text-[48px] leading-[1.1] font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>{slideData?.title}</h1>
<p className="mt-3 text-[16px] max-w-[760px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.description}</p>
</div>
{/* Cyan band */}
<div className="absolute left-0 right-0 bottom-20 h-[160px]" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}></div>
{/* Feature cards */}
<div className="relative px-12 mt-8">
<div className="grid grid-flow-col auto-cols-[260px] gap-6 justify-center">
{features.slice(0,4).map((f, i) => (
<div key={i} className="rounded-[22px] shadow-[0_16px_40px_rgba(0,0,0,0.08)] overflow-hidden" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}>
<div className="px-6 py-5">
<div className="w-10 h-10 rounded-sm flex items-center justify-center" style={{ backgroundColor: 'var(--secondary-accent-color, #FFFFFF)' }}>
<RemoteSvgIcon
url={f.icon.__icon_url__}
strokeColor={"currentColor"}
className="w-6 h-6"
color="var(--text-heading-color, #111827)"
title={f.icon.__icon_query__}
/>
</div>
<div className="mt-4 text-[18px] font-semibold whitespace-pre-line" style={{ color: 'var(--text-heading-color, #111827)' }}>{f.title}</div>
<p className="mt-3 text-[14px] leading-[1.7]" style={{ color: 'var(--text-body-color, #6B7280)' }}>{f.body}</p>
</div>
</div>
))}
</div>
</div>
{/* Footer (standardized like IntroSlideLayout) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default FeatureCards

View file

@ -0,0 +1,171 @@
import React from "react"
import * as z from "zod"
const layoutId = "image-list-description-slide"
const layoutName = "Image List Description"
const layoutDescription = "List of Images with subtitle and description with one description for the entire page"
const ImageSchema = z
.object({
__image_url__: z
.string()
.url()
.default(
"https://images.unsplash.com/photo-1522199710521-72d69614c702?w=1200&q=80&auto=format&fit=crop"
),
__image_prompt__: z
.string()
.min(0)
.max(120)
.default("abstract gradient background"),
})
.default({
__image_url__:
"https://images.unsplash.com/photo-1522199710521-72d69614c702?w=1200&q=80&auto=format&fit=crop",
__image_prompt__: "abstract gradient background",
})
const ItemSchema = z
.object({
title: z.string().min(2).max(40).default("Sample Title"),
description: z
.string()
.min(10)
.max(140)
.default("Short description for the image or item."),
image: ImageSchema,
})
.default({
title: "Sample Title",
description: "Short description for the image or item.",
image: ImageSchema.parse({}),
})
const Schema = z
.object({
titleLine1: z.string().min(3).max(24).default("Meet Our"),
titleLine2: z.string().min(3).max(24).default("Team"),
description: z
.string()
.min(20)
.max(200)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
),
items: z
.array(ItemSchema)
.min(3)
.max(6)
.default([
ItemSchema.parse({}),
ItemSchema.parse({ title: "Another Item", description: "Concise supporting text.", image: ImageSchema.parse({}) }),
ItemSchema.parse({ title: "Third Item", description: "Concise supporting text.", image: ImageSchema.parse({}) }),
]),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
titleLine1: "Meet Our",
titleLine2: "Team",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
items: [
ItemSchema.parse({}),
ItemSchema.parse({ title: "Another Item", description: "Concise supporting text.", image: ImageSchema.parse({}) }),
ItemSchema.parse({ title: "Third Item", description: "Concise supporting text.", image: ImageSchema.parse({}) }),
],
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const TeamMembers: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header: diamond + business name */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div
className="w-3 h-3 rotate-45"
style={{ backgroundColor: "var(--text-heading-color, #111827)" }}
></div>
{ (slideData as any)?.__companyName__ && <span
className="text-[16px]"
style={{ color: "var(--text-body-color, #6B7280)" }}
>
{(slideData as any)?.__companyName__}
</span>}
</div>
</div>
<div className="px-12 pt-6 grid grid-cols-[36%_64%] gap-8 items-start">
{/* Left text stack */}
<div>
<div
className="text-[56px] leading-[1.05] font-semibold"
style={{ color: "var(--text-heading-color, #111827)" }}
>
{slideData?.titleLine1}
<br />
{slideData?.titleLine2}
</div>
<p
className="mt-8 text-[16px] leading-[1.8] max-w-[300px]"
style={{ color: "var(--text-body-color, #6B7280)" }}
>
{slideData?.description}
</p>
</div>
{/* Right generic image cards */}
<div className="grid grid-cols-3 gap-10">
{items.slice(0, 3).map((it, i) => (
<div key={i} className="flex flex-col items-stretch">
{/* Photo block uses provided image */}
<div className="h-[180px] rounded-t-md overflow-hidden">
<img src={it.image.__image_url__} alt={it.image.__image_prompt__} className="w-full h-full object-cover" />
</div>
{/* Cyan details panel */}
<div className="relative -mt-[1px] rounded-b-[28px] px-6 pt-6 pb-7" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}>
<div className="text-[20px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>{it.title}</div>
<p className="mt-3 text-[14px] leading-[1.7]" style={{ color: 'var(--text-body-color, #6B7280)' }}>{it.description}</p>
</div>
</div>
))}
</div>
</div>
{/* Footer line with website and end diamond */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "#E5E7EB" }}></div>
</div>
{/* Big bottom-right diamond */}
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default TeamMembers

View file

@ -0,0 +1,177 @@
import React from "react"
import * as z from "zod"
const layoutId = "IntroSlideLayout"
const layoutName = "Intro Slide Layout"
const layoutDescription = "Intro slide with header, title, subtitle, body, image. If used for last slide, then intro card should be disabled."
const ImageSchema = z
.object({
__image_url__: z.string().url().default("https://images.unsplash.com/photo-1522199710521-72d69614c702?w=1200&q=80&auto=format&fit=crop"),
__image_prompt__: z.string().min(0).max(120).default("abstract gradient background"),
})
.default({
__image_url__:
"https://images.unsplash.com/photo-1522199710521-72d69614c702?w=1200&q=80&auto=format&fit=crop",
__image_prompt__: "abstract gradient background",
})
const Schema = z
.object({
title: z
.string()
.min(12)
.max(68)
.default("Pitch Deck")
.meta({ description: "Main slide title" }),
subtitlePrefix: z.string().min(3).max(40).default("Presentation"),
subtitleAccent: z.string().min(3).max(40).default("Template"),
paragraph: z
.string()
.min(40)
.max(200)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
),
website: z
.string()
.min(6)
.max(60)
.default("www.yourwebsite.com"),
introCard: z
.object({
enabled: z.boolean().default(false),
name: z.string().min(3).max(40).default("John Doe"),
date: z.string().min(4).max(40).default("Jan 1, 2025"),
})
.default({ enabled: true, name: "John Doe", date: "Jan 1, 2025" }),
media: z
.object({
type: z.literal("image").default("image"),
image: ImageSchema,
})
.default({ type: "image", image: ImageSchema.parse({}) }),
})
.default({
title: "Pitch Deck",
subtitlePrefix: "Presentation",
subtitleAccent: "Template",
paragraph:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
website: "www.yourwebsite.com",
introCard: { enabled: true, name: "John Doe", date: "Jan 1, 2025" },
media: { type: "image", image: ImageSchema.parse({}) },
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const IntroSlideLayout: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header: diamond + business name */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div
className="w-3 h-3 rotate-45"
style={{ backgroundColor: "var(--text-heading-color, #111827)" }}
></div>
{ (slideData as any)?.__companyName__ && <span
className="text-[16px] "
style={{ color: "var(--text-body-color, #6B7280)" }}
>
{(slideData as any)?.__companyName__}
</span>}
</div>
</div>
{/* Right panel image (replaces dark gradient box) */}
<div className="absolute top-0 right-0 h-[520px] w-[36%] overflow-hidden">
<img
src={slideData?.media?.image?.__image_url__}
alt={slideData?.media?.image?.__image_prompt__}
className="absolute inset-0 w-full h-full object-cover"
/>
</div>
{/* Vertical diamond decorations */}
<div className="absolute top-8 right-[38%] flex flex-col items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="grid grid-cols-[58%_42%] gap-10 px-12 pt-4 pb-10 items-start">
<div className="pt-4">
<h1
className="text-[64px] leading-[1.05] tracking-tight font-semibold"
style={{ color: "var(--text-heading-color, #111827)" }}
>
{slideData?.title}
</h1>
<p className="mt-5 text-[16px] leading-[1.6] max-w-[620px] " style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.paragraph}</p>
{slideData?.introCard?.enabled && (
<div
className="mt-6 inline-flex items-center gap-4 rounded-sm border px-4 py-3 "
style={{
borderColor: 'var(--primary-accent-color, #BFF4FF)',
backgroundColor: 'var(--primary-accent-color, #BFF4FF)'
}}
>
<div
className="w-2 h-6"
style={{ backgroundColor: 'var(--text-heading-color, #111827)' }}
></div>
<div className="flex items-baseline gap-3">
<span className="text-[16px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>
{slideData?.introCard?.name}
</span>
<span className="text-[14px]" style={{ color: 'var(--text-body-color, #6B7280)' }}>
{slideData?.introCard?.date}
</span>
</div>
</div>
)}
</div>
<div className="relative h-[420px]"></div>
</div>
{/* Footer line with website and end diamond */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px] " style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-body-color, #E5E7EB)" }}></div>
</div>
{/* Big bottom-right diamond */}
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default IntroSlideLayout

View file

@ -0,0 +1,178 @@
import React from "react"
import * as z from "zod"
const layoutId = "MetricsNumbers"
const layoutName = "Metrics Numbers"
const layoutDescription = "Swift: Our Impact in Numbers with three stacked metric cards"
const MetricSchema = z
.object({
value: z.string().min(1).max(8).default("10K+"),
line1: z.string().min(2).max(22).default("Total"),
line2: z.string().min(0).max(22).default("Users"),
description: z
.string()
.min(10)
.max(140)
.default("active users across multiple industries"),
})
.default({
value: "10K+",
line1: "Total",
line2: "Users",
description: "active users across multiple industries",
})
const Schema = z
.object({
title: z
.string()
.min(8)
.max(60)
.default("Our Impact in Numbers"),
leftTitle: z
.string()
.min(6)
.max(40)
.default("Proven Results\nThrough Data"),
leftBody: z
.string()
.min(30)
.max(220)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
metrics: z
.array(MetricSchema)
.min(1)
.max(4)
.default([
MetricSchema.parse({
value: "10K+",
line1: "Total",
line2: "Users",
description: "active users across multiple industries",
}),
MetricSchema.parse({
value: "150%",
line1: "Revenue",
line2: "Growth",
description: "year-over-year revenue growth",
}),
MetricSchema.parse({
value: "95%",
line1: "Customer",
line2: "Satisfaction",
description: "retention rate with an average rating of 4.8/5",
}),
]),
})
.default({
title: "Our Impact in Numbers",
leftTitle: "Proven Results\nThrough Data",
leftBody: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
website: "www.yourwebsite.com",
metrics: [
MetricSchema.parse({
value: "10K+",
line1: "Total",
line2: "Users",
description: "active users across multiple industries",
}),
MetricSchema.parse({
value: "150%",
line1: "Revenue",
line2: "Growth",
description: "year-over-year revenue growth",
}),
MetricSchema.parse({
value: "95%",
line1: "Customer",
line2: "Satisfaction",
description: "retention rate with an average rating of 4.8/5",
}),
],
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const MetricsNumbers: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const metrics = slideData?.metrics || []
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{ (slideData as any)?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
{/* Separator line like the reference */}
<div className="absolute top-0 left-1/2 w-[1px] h-full" style={{ backgroundColor: "rgba(0,0,0,0.1)" }}></div>
<div className="px-12 pt-3 grid grid-cols-[42%_58%] gap-8 items-start">
{/* Left content */}
<div>
<h1 className="text-[48px] leading-[1.1] font-semibold max-w-[420px]" style={{ color: "var(--text-heading-color, #111827)" }}>{slideData?.title}</h1>
<div className="mt-8 inline-flex items-center gap-3">
<div className="w-5 h-5 rounded-full" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
<div>
<div className="text-[20px] font-semibold whitespace-pre-line" style={{ color: "var(--text-heading-color, #111827)" }}>{slideData?.leftTitle}</div>
</div>
</div>
<p className="mt-5 text-[16px] leading-[1.8] max-w-[360px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.leftBody}</p>
</div>
{/* Right stacked metric cards */}
<div className="relative">
{/* decorative circle on the right */}
<div className="absolute top-6 -right-24 w-[220px] h-[220px] rounded-full border" style={{ borderColor: "rgba(0,0,0,0.2)" }}></div>
<div className="flex flex-col gap-6">
{metrics.slice(0,3).map((m, i) => (
<div key={i} className="rounded-[18px] px-6 py-5 grid grid-cols-[38%_62%] items-start shadow-[0_16px_40px_rgba(0,0,0,0.08)]" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}>
<div className="text-[40px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>{m.value}</div>
<div>
<div className="text-[16px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>{m.line1}</div>
{m.line2 && <div className="-mt-1 text-[16px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>{m.line2}</div>}
<p className="mt-3 text-[12px] leading-[1.6]" style={{ color: 'var(--text-body-color, #6B7280)' }}>{m.description}</p>
</div>
</div>
))}
</div>
</div>
</div>
{/* Footer (standardized like IntroSlideLayout) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default MetricsNumbers

View file

@ -0,0 +1,129 @@
import React from "react"
import * as z from "zod"
const layoutId = "simple-bullet-points-layout"
const layoutName = "Simple Bullet Points"
const layoutDescription = "Bullet Points with title and description"
const PointSchema = z
.object({
title: z.string().min(6).max(60).default("Your Title Here"),
body: z
.string()
.min(30)
.max(220)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa."
),
})
.default({ title: "Your Title Here", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa." })
const Schema = z
.object({
title: z.string().min(4).max(36).default("Our Commitment"),
statement: z
.string()
.min(20)
.max(260)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
),
points: z
.array(PointSchema)
.min(1)
.max(4)
.default([PointSchema.parse({}), PointSchema.parse({}), PointSchema.parse({}), PointSchema.parse({ title: "Your Title Here", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa." })]),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
title: "Our Commitment to Innovation",
statement: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
points: [
{ title: "Your Title Here", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa." },
{ title: "Your Title Here", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa." },
{ title: "Your Title Here", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa." },
{ title: "Your Title Here", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa." },
],
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const CommitmentTwoPoints: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const points = slideData?.points || []
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{ (slideData as any)?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
{/* Subtle background motif */}
<div
className="pointer-events-none absolute left-1/2 -translate-x-1/2 bottom-[140px] w-[900px] h-[260px]"
style={{
background:
"radial-gradient(closest-side, rgba(17,24,39,0.06), transparent 70%)",
filter: "blur(0.2px)",
}}
></div>
{/* Content grid */}
<div className="px-12 pt-4 grid grid-cols-[48%_52%] gap-10 items-start">
{/* Left heading and statement */}
<div>
<div className="text-[56px] leading-[1.05] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>
{slideData?.title}
</div>
<p className="mt-10 text-[16px] leading-[1.8] max-w-[520px]" style={{ color: 'var(--text-body-color, #6B7280)' }}>
{slideData?.statement}
</p>
</div>
{/* Right numbered points (up to 4) */}
<div className="flex flex-col gap-6">
{points.slice(0, 4).map((p, i) => (
<div key={i}>
<div className="text-[24px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>{p.title}</div>
<p className="mt-3 text-[16px] leading-[1.8]" style={{ color: 'var(--text-body-color, #6B7280)' }}>{p.body}</p>
</div>
))}
</div>
</div>
{/* Footer (align with other Swift layouts) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default CommitmentTwoPoints

View file

@ -0,0 +1,144 @@
import React from "react"
import * as z from "zod"
const layoutId = "SwiftTableOfContents"
const layoutName = "Table Of Contents"
const layoutDescription = "Swift: Table of contents with up to 10 items (title + description)"
const ToCItemSchema = z
.object({
title: z.string().min(3).max(40).default("Introduction"),
description: z
.string()
.min(0)
.max(60)
.default("A brief overview of the section."),
})
.default({ title: "Introduction", description: "A brief overview of the section." })
const Schema = z
.object({
title: z
.string()
.min(3)
.max(60)
.default("Table of Contents"),
items: z
.array(ToCItemSchema)
.min(1)
.max(10)
.default([
{ title: "Introduction", description: "A brief description of our company and goals." },
{ title: "Our Team", description: "Leadership and core contributors." },
{ title: "Timeline", description: "High-level execution plan and milestones." },
{ title: "Recommendations", description: "Key suggestions based on initial requirements." },
{ title: "Solution", description: "What we propose and why it works." },
{ title: "Market", description: "Audience, segments, and opportunity size." },
{ title: "Business Model", description: "How we create and capture value." },
{ title: "Conclusion", description: "Closing notes and next steps." },
{ title: "Business Model", description: "How we create and capture value." },
{ title: "Conclusion", description: "Closing notes and next steps." },
]),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
title: "Table of Contents",
items: [
{ title: "Introduction", description: "A brief description of our company and goals." },
{ title: "Our Team", description: "Leadership and core contributors." },
{ title: "Timeline", description: "High-level execution plan and milestones." },
{ title: "Recommendations", description: "Key suggestions based on initial requirements." },
{ title: "Solution", description: "What we propose and why it works." },
{ title: "Market", description: "Audience, segments, and opportunity size." },
{ title: "Business Model", description: "How we create and capture value." },
{ title: "Conclusion", description: "Closing notes and next steps." },
{ title: "Business Model", description: "How we create and capture value." },
{ title: "Conclusion", description: "Closing notes and next steps." },
],
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const TableOfContents: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{ (slideData as any)?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
<div className="px-12 pt-3">
<h1 className="text-[48px] leading-[1.1] font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>{slideData?.title}</h1>
</div>
{/* List */}
<div className="px-12 pt-8">
<div className="grid grid-cols-2 gap-x-12 gap-y-6 max-w-[1180px]">
{items.slice(0, 10).map((item, idx) => (
<div key={idx} className="relative">
<div className="flex items-start gap-6">
<div className="flex-none">
<div
className="leading-none font-semibold"
style={{
fontSize: 48,
color: "var(--text-heading-color, #BFF4FF)",
}}
>
{String(idx + 1).padStart(2, "0")}
</div>
</div>
<div className="min-w-0 flex-1 pt-1">
<div className="text-[22px] leading-[1.2] font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>
{item.title}
</div>
{item.description && (
<div className="mt-2 text-[14px] leading-[1.6]" style={{ color: "var(--text-body-color, #6B7280)" }}>
{item.description}
</div>
)}
</div>
</div>
<div className="mt-4 h-px" style={{ backgroundColor: "rgba(59,130,246,0.15)" }}></div>
</div>
))}
</div>
</div>
{/* Footer (standardized like IntroSlideLayout) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default TableOfContents

View file

@ -0,0 +1,279 @@
import React from "react"
import * as z from "zod"
import {
ResponsiveContainer,
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
LineChart,
Line,
PieChart,
Pie,
Cell,
} from "recharts"
const layoutId = "tableorChart"
const layoutName = "Table Or Chart"
const layoutDescription = "Swift: Generic data table with option to render a chart (bar, horizontalBar, line, pie)"
const ChartDatumSchema = z.object({
label: z.string().min(1).max(12).default("A"),
value: z.number().min(0).max(1000000).default(60),
})
const TableRowSchema = z.object({
cells: z
.array(z.string().min(0).max(200))
.min(2)
.max(10)
.default(["Row 1", "Value", "Value"])
.meta({ description: "Row cells; count should match columns length" }),
})
const Schema = z
.object({
title: z.string().min(6).max(60).default("Data Table or Chart"),
description: z
.string()
.min(20)
.max(220)
.default(
"Present structured information in a flexible table or visualize it with a chart."
),
mode: z.enum(["table", "chart"]).default("table"),
// Table configuration (generic)
columns: z
.array(z.string().min(1).max(40))
.min(2)
.max(10)
.default(["Column 1", "Column 2", "Column 3"]),
rows: z
.array(TableRowSchema)
.min(1)
.max(30)
.default([
{ cells: ["Row A", "✓", "-"] },
{ cells: ["Row B", "Text", "123"] },
{ cells: ["Row C", "More text", "456"] },
]),
// Chart configuration (parity with @standard ChartLeftTextRightLayout)
chart: z
.object({
type: z.enum(["bar", "horizontalBar", "line", "pie"]).default("line"),
data: z.array(ChartDatumSchema).min(3).max(12).default([
{ label: "A", value: 60 },
{ label: "B", value: 42 },
{ label: "C", value: 75 },
{ label: "D", value: 30 },
]),
primaryColor: z.string().default("var(--text-heading-color, #111827)"),
gridColor: z.string().default("var(--primary-accent-color, #BFF4FF)"),
pieColors: z
.array(z.string())
.min(1)
.max(10)
.default(["var(--text-heading-color, #111827)", "#3b82f6", "#f59e0b", "#10b981", "#ef4444"]),
showLabels: z.boolean().default(true),
})
.default({
type: "line",
data: [
{ label: "A", value: 60 },
{ label: "B", value: 42 },
{ label: "C", value: 75 },
{ label: "D", value: 30 },
],
primaryColor: "#1B8C2D",
gridColor: "#E5E7EB",
pieColors: ["#1B8C2D", "#3b82f6", "#f59e0b", "#10b981", "#ef4444"],
showLabels: true,
}),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
title: "Data Table or Chart",
description:
"Present structured information in a flexible table or visualize it with a chart.",
mode: "table",
columns: ["Column 1", "Column 2", "Column 3"],
rows: [
{ cells: ["Row A", "✓", "-"] },
{ cells: ["Row B", "Text", "123"] },
{ cells: ["Row C", "More text", "456"] },
],
chart: {
type: "line",
data: [
{ label: "A", value: 60 },
{ label: "B", value: 42 },
{ label: "C", value: 75 },
{ label: "D", value: 30 },
],
primaryColor: "#1B8C2D",
gridColor: "#E5E7EB",
pieColors: ["#1B8C2D", "#3b82f6", "#f59e0b", "#10b981", "#ef4444"],
showLabels: true,
},
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const TableOrChart: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const mode = slideData?.mode || "table"
const columns = slideData?.columns || []
const rows = slideData?.rows || []
const cData = slideData?.chart?.data || []
const type = slideData?.chart?.type || "bar"
const primaryColor = slideData?.chart?.primaryColor || "var(--text-heading-color, #111827)"
const gridColor = slideData?.chart?.gridColor || "var(--primary-accent-color, #BFF4FF)"
const pieColors = slideData?.chart?.pieColors || ["var(--text-heading-color, #111827)"]
const showLabels = slideData?.chart?.showLabels !== false
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Header */}
<div className="px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{(slideData as any)?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
{/* Title and description */}
<div className="px-12 pt-3">
<h1 className="text-[48px] leading-[1.1] font-semibold" style={{ color: "var(--text-heading-color, #111827)" }}>{slideData?.title}</h1>
<p className="mt-3 text-[16px] max-w-[900px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.description}</p>
</div>
{/* Content area: Table or Chart */}
<div className="px-12 pt-6">
{mode === "table" ? (
<div className="rounded-xl p-5" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}>
<div className="overflow-x-auto rounded-lg bg-white ring-1" style={{ borderColor: 'rgba(0,0,0,0.08)' }}>
<table className="w-full border-separate border-spacing-0">
<thead>
<tr>
{columns.map((col, idx) => (
<th
key={idx}
className="text-left text-[14px] font-semibold px-4 py-3 border-b first:rounded-tl-md last:rounded-tr-md"
style={{
color: 'var(--text-heading-color, #111827)',
borderColor: 'var(--secondary-accent-color, rgba(0,0,0,0.12))',
backgroundColor: 'var(--primary-accent-color, #BFF4FF)'
}}
>
{col}
</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, rIdx) => (
<tr key={rIdx} className="align-top">
{columns.map((_, cIdx) => (
<td
key={cIdx}
className={`text-[14px] px-4 py-3 border-t ${rIdx === rows.length - 1 ? 'first:rounded-bl-md last:rounded-br-md' : ''}`}
style={{
color: 'var(--text-body-color, #374151)',
borderColor: 'rgba(0,0,0,0.08)',
backgroundColor: rIdx % 2 === 0 ? 'var(--primary-accent-color, #BFF4FF)' : 'var(--tertiary-accent-color, #E5E7EB)'
}}
>
{row.cells[cIdx] || ''}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
) : (
<div className="w-full h-[360px] rounded-xl p-4" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}>
<ResponsiveContainer width="100%" height="100%">
{type === 'bar' ? (
<BarChart data={cData} margin={{ top: 10, right: 20, bottom: 10, left: 0 }}>
<CartesianGrid stroke={gridColor} strokeDasharray="3 3" />
<XAxis dataKey="label" tick={{ fill: 'var(--text-body-color, #6B7280)', fontWeight: 600 }} />
<YAxis tick={{ fill: 'var(--text-body-color, #6B7280)', fontWeight: 600 }} />
<Tooltip labelStyle={{ color: 'var(--text-body-color, #6B7280)' }} itemStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Legend wrapperStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Bar dataKey="value" fill={primaryColor} radius={[6, 6, 0, 0]} label={showLabels ? { position: 'top', fill: '#111827', fontSize: 12 } : false} />
</BarChart>
) : type === 'horizontalBar' ? (
<BarChart data={cData} layout="vertical" margin={{ top: 10, right: 20, bottom: 10, left: 20 }}>
<CartesianGrid stroke={gridColor} strokeDasharray="3 3" />
<XAxis type="number" tick={{ fill: 'var(--text-body-color, #6B7280)', fontWeight: 600 }} />
<YAxis type="category" dataKey="label" tick={{ fill: 'var(--text-body-color, #6B7280)', fontWeight: 600 }} />
<Tooltip labelStyle={{ color: 'var(--text-body-color, #6B7280)' }} itemStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Legend wrapperStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Bar dataKey="value" fill={primaryColor} radius={[0, 6, 6, 0]} label={showLabels ? { position: 'right', fill: '#111827', fontSize: 12 } : false} />
</BarChart>
) : type === 'line' ? (
<LineChart data={cData} margin={{ top: 10, right: 20, bottom: 10, left: 0 }}>
<CartesianGrid stroke={gridColor} strokeDasharray="3 3" />
<XAxis dataKey="label" tick={{ fill: 'var(--text-body-color, #6B7280)', fontWeight: 600 }} />
<YAxis tick={{ fill: 'var(--text-body-color, #6B7280)', fontWeight: 600 }} />
<Tooltip labelStyle={{ color: 'var(--text-body-color, #6B7280)' }} itemStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Legend wrapperStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Line type="monotone" dataKey="value" stroke={primaryColor} strokeWidth={3} dot={{ r: 3 }} label={showLabels ? { position: 'top', fill: '#111827', fontSize: 12 } : false} />
</LineChart>
) : (
<PieChart>
<Tooltip labelStyle={{ color: 'var(--text-body-color, #6B7280)' }} itemStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Legend wrapperStyle={{ color: 'var(--text-body-color, #6B7280)' }} />
<Pie data={cData} dataKey="value" nameKey="label" cx="50%" cy="50%" outerRadius={120} label={showLabels ? { fill: 'var(--text-body-color, #6B7280)' } : false}>
{cData.map((_, i) => (
<Cell key={i} fill={primaryColor} />
))}
</Pie>
</PieChart>
)}
</ResponsiveContainer>
</div>
)}
</div>
{/* Footer (standardized like IntroSlideLayout) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default TableOrChart

View file

@ -0,0 +1,170 @@
import React from "react"
import * as z from "zod"
const layoutId = "Timeline"
const layoutName = "Timeline"
const layoutDescription = "Timeline of cards with title, subtitle banner"
const IconSchema = z
.object({
__icon_url__: z
.string()
.default(
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/clipboard-text-bold.svg"
),
__icon_query__: z.string().min(0).max(80).default("timeline icon"),
})
.default({
__icon_url__:
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/bold/clipboard-text-bold.svg",
__icon_query__: "timeline icon",
})
const ItemSchema = z
.object({
year: z.string().min(3).max(6).default("2018"),
heading: z.string().min(3).max(28).default("Founded in 2020"),
body: z
.string()
.min(10)
.max(160)
.default("Lorem ipsum dolor"),
icon: IconSchema,
})
.default({ year: "2018", heading: "Founded in 2020", body: "Lorem ipsum dolor", icon: IconSchema.parse({}) })
const Schema = z
.object({
title: z
.string()
.min(8)
.max(60)
.default("Our Journey at a Glance"),
subtitle: z
.string()
.min(20)
.max(200)
.default(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa."
),
items: z
.array(ItemSchema)
.min(1)
.max(4)
.default([
ItemSchema.parse({ year: "2018", heading: "Founded in 2020", body: "Lorem ipsum dolor" }),
ItemSchema.parse({ year: "2019", heading: "First Product in 2021", body: "Lorem ipsum dolor" }),
ItemSchema.parse({ year: "2020", heading: "Key Milestone in 2022", body: "Lorem ipsum dolor" }),
ItemSchema.parse({ year: "2021", heading: "Global Expansion in 2024", body: "Lorem ipsum dolor" }),
]),
website: z.string().min(6).max(60).default("www.yourwebsite.com"),
})
.default({
title: "Our Journey at a Glance",
subtitle:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.",
items: [
ItemSchema.parse({ year: "2018", heading: "Founded in 2020", body: "Lorem ipsum dolor" }),
ItemSchema.parse({ year: "2019", heading: "First Product in 2021", body: "Lorem ipsum dolor" }),
ItemSchema.parse({ year: "2020", heading: "Key Milestone in 2022", body: "Lorem ipsum dolor" }),
ItemSchema.parse({ year: "2021", heading: "Global Expansion in 2024", body: "Lorem ipsum dolor" }),
],
website: "www.yourwebsite.com",
})
type SlideData = z.infer<typeof Schema>
interface SlideLayoutProps {
data?: Partial<SlideData>
}
const Timeline: React.FC<SlideLayoutProps> = ({ data: slideData }) => {
const items = slideData?.items || []
return (
<>
<link
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<div
className=" w-full rounded-sm max-w-[1280px] shadow-lg max-h-[720px] aspect-video relative z-20 mx-auto overflow-hidden"
style={{
fontFamily: "var(--heading-font-family,Albert Sans)",
backgroundColor: "var(--card-background-color, #FFFFFF)",
}}
>
{/* Keep white background to match Swift layouts */}
{/* Header: diamond + business name */}
<div className="relative px-12 pt-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
{(slideData as any)?.__companyName__ && <span className="text-[16px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{(slideData as any)?.__companyName__}</span>}
</div>
</div>
{/* Right vertical diamonds */}
<div className="absolute top-16 right-6 flex flex-col items-center gap-3">
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
<div className="w-3 h-3 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
{/* Title */}
<div className="relative px-12 pt-3 flex flex-col items-center">
<h1 className="text-[48px] leading-[1.1] font-semibold text-center" style={{ color: "var(--text-heading-color, #111827)" }}>{slideData?.title}</h1>
{/* Subtitle banner */}
<div className="mt-5 max-w-[720px] w-full rounded-md text-center px-6 py-3" style={{
borderColor: "rgba(0,0,0,0.25)",
color: "var(--text-body-color, #6B7280)",
backgroundColor: "var(--primary-accent-color, #BFF4FF)",
}}>
<span className="text-[16px]">{slideData?.subtitle}</span>
</div>
</div>
{/* Horizontal timeline */}
<div className="relative px-12 pt-10">
{/* center line */}
<div className="absolute left-12 right-12 top-1/2 h-[4px]" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}></div>
<div className="relative flex justify-center gap-10">
{items.slice(0, 4).map((it, idx) => (
<div key={idx} className="relative flex flex-col items-center">
{/* year badge - placed close to the card */}
<div className="mb-2 px-5 py-2 rounded-md text-white text-[16px] font-semibold" style={{ backgroundColor: 'var(--text-heading-color, #111827)' }}>{it.year}</div>
{/* connector dot */}
<div className="w-5 h-5 rounded-full border-4" style={{ backgroundColor: 'var(--card-background-color, #FFFFFF)', borderColor: 'var(--primary-accent-color, #BFF4FF)' }}></div>
{/* card container */}
<div className="mt-4">
<div className="rounded-[16px] bg-white shadow-[0_16px_40px_rgba(0,0,0,0.08)] px-6 pt-6 pb-5 text-center w-[260px]">
<div className="mx-auto w-12 h-12 rounded-full flex items-center justify-center mb-4" style={{ backgroundColor: 'var(--primary-accent-color, #BFF4FF)' }}>
<img src={it.icon.__icon_url__} alt={it.icon.__icon_query__} className="w-6 h-6 object-contain" />
</div>
<div className="text-[18px] font-semibold" style={{ color: 'var(--text-heading-color, #111827)' }}>{it.heading}</div>
<p className="mt-3 text-[14px]" style={{ color: 'var(--text-body-color, #6B7280)' }}>{it.body}</p>
</div>
</div>
</div>
))}
</div>
</div>
{/* Footer (standardized like IntroSlideLayout) */}
<div className="absolute bottom-8 left-12 right-12 flex items-center">
<span className="text-[14px]" style={{ color: "var(--text-body-color, #6B7280)" }}>{slideData?.website}</span>
<div className="ml-6 h-[2px] flex-1" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
<div className="absolute bottom-7 right-6 w-8 h-8 rotate-45" style={{ backgroundColor: "var(--text-heading-color, #111827)" }}></div>
</div>
</>
)
}
export { Schema, layoutId, layoutName, layoutDescription }
export default Timeline

View file

@ -0,0 +1,6 @@
{
"description": "Swift layouts for presentations",
"ordered": false,
"default": false
}