feat: New templates improvements
This commit is contained in:
parent
679ae31a4e
commit
4d166be0c3
26 changed files with 881 additions and 790 deletions
|
|
@ -84,7 +84,7 @@ strong {
|
|||
|
||||
@font-face {
|
||||
font-family: 'Times New Roman';
|
||||
src: url('https: //presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/times.ttf') format('truetype');
|
||||
src: url('https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/times.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ strong {
|
|||
|
||||
@font-face {
|
||||
font-family: 'Helvetica Neue';
|
||||
src: url('https: //presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/HelveticaNeueBold.otf') format('truetype');
|
||||
src: url('https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/HelveticaNeue-Bold.otf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
|
|
@ -100,7 +100,7 @@ strong {
|
|||
|
||||
@font-face {
|
||||
font-family: 'Helvetica Neue';
|
||||
src: url('https: //presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/HelveticaNeueMedium.otf') format('truetype');
|
||||
src: url('https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/HelveticaNeue-Medium.otf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
|
|
@ -108,7 +108,7 @@ strong {
|
|||
|
||||
@font-face {
|
||||
font-family: 'Helvetica Neue';
|
||||
src: url('https: //presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/HelveticaNeueRoman.otf') format('truetype');
|
||||
src: url('https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/fonts/HelveticaNeue-Roman.otf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "education-about-slide";
|
||||
export const slideLayoutName = "Education About Slide";
|
||||
export const slideLayoutId = "about-slide";
|
||||
export const slideLayoutName = "About Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A left text column with company introduction and a right-side visual grid made from one repeated image and tinted text panels.";
|
||||
"A left text column with company/instructor/presenter/institute name and title introduction and a right-side visual grid made from one repeated image and tinted text panels.";
|
||||
|
||||
export const Schema = z.object({
|
||||
companyName: z.string().min(3).max(22).default("Company Name").meta({
|
||||
name: z.string().min(3).max(22).default("Company Name").meta({
|
||||
description: "Main heading in the left content column.",
|
||||
}),
|
||||
intro: z.string().min(40).max(120).default(
|
||||
intro: z.string().min(40).max(100).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et."
|
||||
).meta({
|
||||
description: "Bold intro text shown beneath the company heading.",
|
||||
}),
|
||||
body: z.string().min(120).max(280).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi."
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
).meta({
|
||||
description: "Body paragraph in the left content section.",
|
||||
}),
|
||||
|
|
@ -28,23 +28,23 @@ export const Schema = z.object({
|
|||
}),
|
||||
topFeatureImage: z.object({
|
||||
__image_url__: z.string().default("https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80"),
|
||||
__image_prompt__: z.string().min(10).max(200).default("Office team collaboration"),
|
||||
__image_prompt__: z.string().default("Office team collaboration"),
|
||||
}).default({
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Office team collaboration",
|
||||
}).meta({
|
||||
description: "Single image reused in the right-side visual grid.",
|
||||
description: "Single image reused in the top right-side visual grid.",
|
||||
}),
|
||||
bottomFeatureImage: z.object({
|
||||
__image_url__: z.string().default("https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80"),
|
||||
__image_prompt__: z.string().min(10).max(200).default("Office team collaboration"),
|
||||
__image_prompt__: z.string().default("Office team collaboration"),
|
||||
}).default({
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Office team collaboration",
|
||||
}).meta({
|
||||
description: "Single image reused in the right-side visual grid.",
|
||||
description: "Single image reused in the bottom right-side visual grid.",
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ const EducationAboutSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="grid items-end grid-cols-[1fr_1fr]">
|
||||
<div className="px-[53px] pb-[56px] ">
|
||||
<h2 className="font-serif text-[64px] leading-[98%] tracking-[-0.02em]" style={{ color: "var(--primary-color,#101C3D)" }}>
|
||||
{data.companyName}
|
||||
{data.name}
|
||||
</h2>
|
||||
<p className="mt-[30px] max-w-[610px] text-[22px] font-semibold leading-[1.24]" style={{ color: "var(--background-text,#34394C)" }}>
|
||||
{data.intro}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,50 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "education-content-split-slide";
|
||||
export const slideLayoutName = "Education Content Split Slide";
|
||||
export const slideLayoutId = "content-split-slide";
|
||||
export const slideLayoutName = "Content Split Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A left collage built from one repeated image and a right content block containing heading, tagline, and paragraph text.";
|
||||
|
||||
export const Schema = z.object({
|
||||
heading: z.string().min(3).max(16).default("Heading").meta({
|
||||
heading: z.string().max(24).default("Heading").meta({
|
||||
description: "Main right-side heading.",
|
||||
}),
|
||||
tagline: z.string().min(3).max(12).default("TAGLINE").meta({
|
||||
tagline: z.string().max(12).default("TAGLINE").meta({
|
||||
description: "Small uppercase label shown under the heading.",
|
||||
}),
|
||||
body: z.string().min(80).max(300).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
body: z.string().max(300).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
).meta({
|
||||
description: "Main descriptive paragraph on the right side.",
|
||||
}),
|
||||
collageImage: z.object({
|
||||
images: z.array(z.object({
|
||||
__image_url__: z.string().default("https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80"),
|
||||
__image_prompt__: z.string().min(10).max(200).default("Business team around a laptop"),
|
||||
}).default({
|
||||
__image_prompt__: z.string().default("Business team around a laptop"),
|
||||
})).min(1).max(3).default([{
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Business team around a laptop",
|
||||
}).meta({
|
||||
description: "Single image reused to create the left collage composition.",
|
||||
},
|
||||
{
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Business team around a laptop",
|
||||
},
|
||||
{
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Business team around a laptop",
|
||||
},
|
||||
]).meta({
|
||||
description: "Array of images reused to create the left collage composition.",
|
||||
}),
|
||||
});
|
||||
|
||||
export type SchemaType = z.infer<typeof Schema>;
|
||||
|
||||
const EducationContentSplitSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
const { heading, tagline, body, collageImage } = data;
|
||||
const { heading, tagline, body, images } = data;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -47,20 +58,20 @@ const EducationContentSplitSlide = ({ data }: { data: Partial<SchemaType> }) =>
|
|||
<div className="w-[660px] h-full">
|
||||
<div className="h-[394px] w-full mb-[6px]">
|
||||
<img
|
||||
src={collageImage?.__image_url__}
|
||||
alt={collageImage?.__image_prompt__}
|
||||
src={images?.[0]?.__image_url__}
|
||||
alt={images?.[0]?.__image_prompt__}
|
||||
className=" h-full w-full object-cover object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full gap-[6px] h-[320px] ">
|
||||
<div className="w-[330px]"> <img
|
||||
src={collageImage?.__image_url__}
|
||||
alt={collageImage?.__image_prompt__}
|
||||
src={images?.[1]?.__image_url__}
|
||||
alt={images?.[1]?.__image_prompt__}
|
||||
className="h-full w-full object-cover "
|
||||
/></div>
|
||||
<div className="w-[330px]"> <img
|
||||
src={collageImage?.__image_url__}
|
||||
alt={collageImage?.__image_prompt__}
|
||||
src={images?.[2]?.__image_url__}
|
||||
alt={images?.[2]?.__image_prompt__}
|
||||
className="h-full w-full object-cover "
|
||||
/></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "education-cover-slide";
|
||||
export const slideLayoutName = "Education Cover Slide";
|
||||
export const slideLayoutId = "cover-slide";
|
||||
export const slideLayoutName = "Cover Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A full-bleed cover slide with a single background image, a strong violet overlay, and centered company/title text.";
|
||||
"A full-bleed cover slide with a single background image, a strong violet overlay, and centered company/instructor/presenter/institute name and title text.";
|
||||
|
||||
export const Schema = z.object({
|
||||
companyName: z.string().min(3).max(24).default("COMPANY NAME").meta({
|
||||
description: "Small uppercase company label shown above the main title.",
|
||||
name: z.string().min(3).max(16).optional().default("COMPANY NAME").meta({
|
||||
description: "Company/instructor/presenter/institute name label shown above the main title.",
|
||||
}),
|
||||
title: z.string().min(6).max(32).default("PowerPoint Template").meta({
|
||||
description: "Main centered title of the cover slide.",
|
||||
}),
|
||||
backgroundImage: z.object({
|
||||
__image_url__: z.string().default("https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&w=1920&q=80"),
|
||||
__image_prompt__: z.string().min(10).max(200).default("City business district buildings"),
|
||||
__image_prompt__: z.string().default("City business district buildings"),
|
||||
}).default({
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&w=1920&q=80",
|
||||
|
|
@ -28,7 +28,7 @@ export const Schema = z.object({
|
|||
export type SchemaType = z.infer<typeof Schema>;
|
||||
|
||||
const EducationCoverSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
const { companyName, title, backgroundImage } = data;
|
||||
const { name, title, backgroundImage } = data;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -57,8 +57,8 @@ const EducationCoverSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
className="relative z-10 flex h-full flex-col items-center justify-center text-center"
|
||||
style={{ color: "var(--primary-text,#ffffff)" }}
|
||||
>
|
||||
<p className="text-[22px] font-normal uppercase tracking-[0.64px]">{companyName}</p>
|
||||
<h1 className="mt-[12px] px-[53px] text-[64px] font-medium leading-[98%]">
|
||||
{name && <p className="text-[22px] font-normal uppercase tracking-[0.64px]">{name}</p>
|
||||
} <h1 className="mt-[12px] px-[53px] text-[64px] font-medium leading-[98%]">
|
||||
{title}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "education-image-gallery-slide";
|
||||
export const slideLayoutName = "Education Image Gallery Slide";
|
||||
export const slideLayoutId = "image-gallery-slide";
|
||||
export const slideLayoutName = "Image Gallery Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A slide with a left image collage (one repeated image) and right text block for gallery heading and description.";
|
||||
"A slide with a left image gallery and right text block for gallery heading and description.";
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(3).max(16).default("Image Gallery").meta({
|
||||
title: z.string().max(24).default("Image Gallery").meta({
|
||||
description: "Heading on the right side.",
|
||||
}),
|
||||
body: z.string().min(70).max(200).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris."
|
||||
body: z.string().max(300).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
).meta({
|
||||
description: "Supporting paragraph shown below the heading.",
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import EducationChartPrimitives, {
|
|||
type EducationChartType,
|
||||
} from "./EducationChartPrimitives";
|
||||
|
||||
export const slideLayoutId = "education-report-chart-slide";
|
||||
export const slideLayoutName = "Education Report Chart Slide";
|
||||
export const slideLayoutId = "report-chart-slide";
|
||||
export const slideLayoutName = "Report Chart Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A split education report slide with one unified schema that supports multiple Recharts chart types in the right panel.";
|
||||
"A left text column with a report title, body, footnote and a right-side chart.";
|
||||
|
||||
const ChartTypeSchema = z.enum([
|
||||
"bar",
|
||||
|
|
@ -25,7 +25,7 @@ const SimpleDataSchema = z.object({
|
|||
name: z.string().min(1).max(20).meta({
|
||||
description: "Simple chart category label.",
|
||||
}),
|
||||
value: z.number().min(-100000).max(100000).meta({
|
||||
value: z.number().meta({
|
||||
description: "Simple chart numeric value.",
|
||||
}),
|
||||
});
|
||||
|
|
@ -71,7 +71,7 @@ const UnifiedChartDataSchema = z.union([
|
|||
]);
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(3).max(20).default("Report").meta({
|
||||
title: z.string().max(24).default("Report").meta({
|
||||
description: "Left-side report title.",
|
||||
}),
|
||||
body: z.string().min(80).max(260).default(
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "education-services-split-slide";
|
||||
export const slideLayoutName = "Education Services Split Slide";
|
||||
export const slideLayoutId = "services-split-slide";
|
||||
export const slideLayoutName = "Services Split Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A services layout with left heading, one repeated image column, and two stacked service description blocks on the right.";
|
||||
"A left text column with a heading, one image column, and stacked service description blocks on the right side.";
|
||||
|
||||
const ServiceSchema = z.object({
|
||||
serviceImage: z.object({
|
||||
image: z.object({
|
||||
__image_url__: z.string(),
|
||||
__image_prompt__: z.string(),
|
||||
}).default({
|
||||
|
|
@ -15,30 +15,30 @@ const ServiceSchema = z.object({
|
|||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Team meeting image reused across two rows",
|
||||
}).meta({
|
||||
description: "Single image reused in the middle column.",
|
||||
description: "Single image in the middle column.",
|
||||
}),
|
||||
heading: z.string().min(3).max(18).meta({
|
||||
description: "Service heading shown in the right column.",
|
||||
description: "Heading shown in the right column.",
|
||||
}),
|
||||
tagline: z.string().min(3).max(12).meta({
|
||||
description: "Short label under each service heading.",
|
||||
description: "Short label under each heading.",
|
||||
}),
|
||||
body: z.string().max(40).meta({
|
||||
description: "Service description paragraph.",
|
||||
description: "Description paragraph shown below the heading and tagline.",
|
||||
}),
|
||||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(4).max(12).default("Services").meta({
|
||||
title: z.string().max(16).default("Services").meta({
|
||||
description: "Main slide title shown on the left.",
|
||||
}),
|
||||
sections: z
|
||||
.array(ServiceSchema)
|
||||
.min(2)
|
||||
.min(1)
|
||||
.max(4)
|
||||
.default([
|
||||
{
|
||||
serviceImage: {
|
||||
image: {
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Team meeting image reused across two rows",
|
||||
|
|
@ -48,7 +48,7 @@ export const Schema = z.object({
|
|||
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.",
|
||||
},
|
||||
{
|
||||
serviceImage: {
|
||||
image: {
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Team meeting image reused across two rows",
|
||||
|
|
@ -58,7 +58,7 @@ export const Schema = z.object({
|
|||
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.",
|
||||
},
|
||||
{
|
||||
serviceImage: {
|
||||
image: {
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Team meeting image reused across two rows",
|
||||
|
|
@ -68,7 +68,7 @@ export const Schema = z.object({
|
|||
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor.",
|
||||
},
|
||||
{
|
||||
serviceImage: {
|
||||
image: {
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521737604893-d14cc237f11d?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Team meeting image reused across two rows",
|
||||
|
|
@ -128,8 +128,8 @@ const EducationServicesSplitSlide = ({ data }: { data: Partial<SchemaType> }) =>
|
|||
>
|
||||
|
||||
<img
|
||||
src={section.serviceImage.__image_url__}
|
||||
alt={section.serviceImage.__image_prompt__}
|
||||
src={section.image?.__image_url__}
|
||||
alt={section.image?.__image_prompt__}
|
||||
className="h-full w-full object-cover "
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
import * as z from "zod";
|
||||
|
||||
export const slideLayoutId = "education-statistics-grid-slide";
|
||||
export const slideLayoutName = "Education Statistics Grid Slide";
|
||||
export const slideLayoutId = "statistics-grid-slide";
|
||||
export const slideLayoutName = "Statistics Grid Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A two-column layout with a left title block and a right 2x4 grid of statistics cards, using one subtle background image texture.";
|
||||
"A left text column with a title, description and a right-side grid of statistics cards,value and label each in a card";
|
||||
|
||||
const StatisticSchema = z.object({
|
||||
value: z.string().min(1).max(8).meta({
|
||||
description: "Main metric value shown at the top of one card. with max 8 characters",
|
||||
value: z.string().max(8).meta({
|
||||
description: "Main metric value shown at the top of one card.",
|
||||
}),
|
||||
label: z.string().min(3).max(20).meta({
|
||||
description: "Label shown under the value. with max 20 characters",
|
||||
label: z.string().max(20).meta({
|
||||
description: "Label shown under the value.",
|
||||
}),
|
||||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(4).max(14).default("Statistics").meta({
|
||||
description: "Main title shown in the left column. with max 14 characters",
|
||||
title: z.string().max(16).default("Statistics").meta({
|
||||
description: "Main title shown in the left column.",
|
||||
}),
|
||||
description: z.string().min(40).max(120).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. with max 120 characters"
|
||||
description: z.string().max(160).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit."
|
||||
).meta({
|
||||
description: "Supporting line shown under the left title. with max 120 characters",
|
||||
description: "Supporting line shown under the left title.",
|
||||
}),
|
||||
stats: z
|
||||
.array(StatisticSchema)
|
||||
|
|
@ -38,7 +38,7 @@ export const Schema = z.object({
|
|||
{ value: "20", label: "Merchandising Team" },
|
||||
])
|
||||
.meta({
|
||||
description: "Eight statistic cards. with max 8 cards",
|
||||
description: "statistic cards, with value and label each in a card",
|
||||
}),
|
||||
|
||||
});
|
||||
|
|
@ -58,10 +58,8 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
fontFamily: "var(--body-font-family,'Times New Roman')",
|
||||
}}
|
||||
>
|
||||
|
||||
|
||||
<div className="relative z-10 grid h-full grid-cols-[490px_1fr]">
|
||||
<div className="px-[44px] pb-[78px] pt-[96px]" style={{ backgroundColor: "var(--card-color,#f1efef)" }}>
|
||||
<div className="px-[44px] pb-[78px] pt-[96px]">
|
||||
<div className="flex h-full flex-col justify-end">
|
||||
<h2 className="font-serif text-[64px] leading-[98%] tracking-[-0.02em]" style={{ color: "var(--primary-color,#1a1752)" }}>
|
||||
{data.title}
|
||||
|
|
@ -89,22 +87,7 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
))}
|
||||
</div>}
|
||||
|
||||
{/* {stats && stats?.length > 4 && stats?.length <= 8 && <div className="grid h-full grid-cols-[repeat(auto-fill,minmax(300px,1fr))]">
|
||||
{stats?.map((stat, index) => (
|
||||
<div
|
||||
key={`${stat.value}-${index}`}
|
||||
className="px-[52px] pt-[22px]"
|
||||
style={{ backgroundColor: index % 2 === 1 ? 'var(--card-color,#5C0FD908)' : 'var(--card-color,white)' }}
|
||||
>
|
||||
<p className="font-serif text-[58px] leading-[56px]" style={{ color: "var(--background-text,#283E51)" }}>
|
||||
{stat.value}
|
||||
</p>
|
||||
<p className="mt-[12px] text-[24px]" style={{ color: "var(--background-text,#434A63)" }}>
|
||||
{stat.label}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>} */}
|
||||
|
||||
|
||||
{data.stats && data.stats?.length > 4 && data.stats?.length <= 8 && (() => {
|
||||
const rightArray = data.stats?.slice(0, Math.floor(data.stats?.length / 2));
|
||||
|
|
@ -112,7 +95,7 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
|
||||
return (
|
||||
<div className="h-full flex w-full">
|
||||
<div className="flex flex-col h-full w-full">
|
||||
<div className="flex flex-col h-full flex-1">
|
||||
|
||||
{leftArray?.map((stat: any, index: number) => (
|
||||
<div
|
||||
|
|
@ -120,7 +103,7 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
className="px-[52px] pt-[22px] h-full"
|
||||
style={{ backgroundColor: index % 2 === 0 ? 'var(--card-color,#5C0FD908)' : 'var(--card-color,white)' }}
|
||||
>
|
||||
<p className="font-serif text-[58px] leading-[56px]" style={{ color: "var(--background-text,#283E51)" }}>
|
||||
<p className=" text-[58px] leading-[56px]" style={{ color: "var(--background-text,#283E51)" }}>
|
||||
{stat?.value}
|
||||
</p>
|
||||
<p className="mt-[12px] text-[24px]" style={{ color: "var(--background-text,#434A63)" }}>
|
||||
|
|
@ -129,9 +112,7 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex flex-col flex-1">
|
||||
|
||||
{rightArray?.map((stat: any, index: number) => (
|
||||
<div
|
||||
|
|
@ -139,7 +120,7 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
className="px-[52px] pt-[22px] h-full"
|
||||
style={{ backgroundColor: index % 2 === 1 ? 'var(--card-color,#5C0FD908)' : 'var(--card-color,white)' }}
|
||||
>
|
||||
<p className="font-serif text-[58px] leading-[56px]" style={{ color: "var(--background-text,#283E51)" }}>
|
||||
<p className=" text-[58px] leading-[56px]" style={{ color: "var(--background-text,#283E51)" }}>
|
||||
{stat.value}
|
||||
</p>
|
||||
<p className="mt-[12px] text-[24px]" style={{ color: "var(--background-text,#434A63)" }}>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "education-table-of-contents-slide";
|
||||
export const slideLayoutName = "Education Table Of Contents Slide";
|
||||
export const slideLayoutId = "table-of-contents-slide";
|
||||
export const slideLayoutName = "Table Of Contents Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A split layout with a left title panel and a right list of numbered sections, with one subtle background image overlay.";
|
||||
|
||||
|
|
@ -16,28 +16,27 @@ const TocItemSchema = z.object({
|
|||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
titleLine1: z.string().min(4).max(12).default("Table of").meta({
|
||||
description: "First line of the left-side heading.",
|
||||
}),
|
||||
titleLine2: z.string().min(4).max(12).default("Contents").meta({
|
||||
description: "Second line of the left-side heading.",
|
||||
title: z.string().min(6).max(32).default("Table of Contents").meta({
|
||||
description: "Main centered title of the table of contents slide.",
|
||||
}),
|
||||
items: z
|
||||
.array(TocItemSchema)
|
||||
.min(8)
|
||||
.max(8)
|
||||
.min(1)
|
||||
.max(10)
|
||||
.default([
|
||||
{ number: "03", label: "ABOUT" },
|
||||
{ number: "04", label: "TIMELINE" },
|
||||
{ number: "05", label: "GROUP OF COMPANIES" },
|
||||
{ number: "06", label: "SERVICES" },
|
||||
{ number: "07", label: "IMAGE GALLERY" },
|
||||
{ number: "08", label: "STATISTICS" },
|
||||
{ number: "09", label: "REPORT" },
|
||||
{ number: "10", label: "CONCLUSION" },
|
||||
{ number: "01", label: "ABOUT" },
|
||||
{ number: "02", label: "TIMELINE" },
|
||||
{ number: "03", label: "GROUP OF COMPANIES" },
|
||||
{ number: "04", label: "SERVICES" },
|
||||
{ number: "05", label: "IMAGE GALLERY" },
|
||||
{ number: "06", label: "STATISTICS" },
|
||||
{ number: "07", label: "REPORT" },
|
||||
{ number: "08", label: "CONCLUSION" },
|
||||
{ number: "09", label: "QUESTIONS" },
|
||||
{ number: "10", label: "CONTACT" },
|
||||
])
|
||||
.meta({
|
||||
description: "Eight table-of-content entries listed on the right.",
|
||||
description: "table-of-content entries listed on the right.",
|
||||
}),
|
||||
|
||||
});
|
||||
|
|
@ -59,9 +58,7 @@ const EducationTableOfContentsSlide = ({ data }: { data: Partial<SchemaType> })
|
|||
<div className="relative z-10 grid h-full grid-cols-[430px_1fr]">
|
||||
<div className="px-[56px] pt-[74px]" style={{ backgroundColor: "var(--card-color,#f1efef)" }}>
|
||||
<h2 className="font-serif text-[64px] leading-[98%] tracking-[-0.02em]" style={{ color: "var(--primary-color,#1a1752)" }}>
|
||||
{data.titleLine1}
|
||||
<br />
|
||||
{data.titleLine2}
|
||||
{data.title}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import * as z from "zod";
|
||||
|
||||
export const slideLayoutId = "education-timeline-slide";
|
||||
export const slideLayoutName = "Education Timeline Slide";
|
||||
export const slideLayoutId = "timeline-slide";
|
||||
export const slideLayoutName = "Timeline Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A timeline slide with a title, a horizontal progress line, and year-based milestones with short descriptions.";
|
||||
"A slide with a title, a horizontal progress line, and short heading and description pairs.";
|
||||
|
||||
const MilestoneSchema = z.object({
|
||||
year: z.string().min(4).max(6).meta({
|
||||
description: "Year label displayed under each timeline marker.",
|
||||
heading: z.string().max(6).meta({
|
||||
description: "Heading displayed under each timeline marker.",
|
||||
}),
|
||||
description: z.string().min(20).max(50).meta({
|
||||
description: "Short text shown under each year label.",
|
||||
description: z.string().max(50).meta({
|
||||
description: "Short text shown under each heading. with max 50 characters",
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -20,20 +20,17 @@ export const Schema = z.object({
|
|||
}),
|
||||
milestones: z
|
||||
.array(MilestoneSchema)
|
||||
.min(6)
|
||||
.min(2)
|
||||
.max(12)
|
||||
.default([
|
||||
{ year: "2022", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1994", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1993", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1991", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1991", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " },
|
||||
{ year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ year: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "2022", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "1994", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "1993", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "1991", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "1991", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " },
|
||||
{ heading: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
{ heading: "1988", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." },
|
||||
])
|
||||
.meta({
|
||||
description: "Timeline milestones displayed left to right.",
|
||||
|
|
@ -50,7 +47,7 @@ const EducationTimelineSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden flex flex-col"
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#efeff1)",
|
||||
fontFamily: "var(--body-font-family,'Times New Roman')",
|
||||
|
|
@ -79,20 +76,20 @@ function TimelineUpToSix({
|
|||
|
||||
|
||||
return (
|
||||
<div className="relative z-10 mt-[80px] px-[56px]">
|
||||
<div className="relative z-10 mt-[160px] px-[56px]">
|
||||
<div
|
||||
className="grid "
|
||||
style={{ gridTemplateColumns: `repeat(${milestones.length}, minmax(0, 1fr))` }}
|
||||
>
|
||||
{milestones.map((milestone: any, index: number) => (
|
||||
<div key={`${milestone.year}-${index}`} className="">
|
||||
<div key={`${milestone.heading}-${index}`} className="">
|
||||
<div className="flex items-center ">
|
||||
|
||||
<div className="h-[22px] z-10 relative w-[22px] rounded-full" style={{ backgroundColor: "var(--primary-color,#272272)" }} />
|
||||
{index !== milestones.length - 1 && <div className="h-[3px] flex-1" style={{ backgroundColor: "var(--stroke,#d8d8dd)" }} />}
|
||||
</div>
|
||||
<p className="mt-[18px] text-[20px] font-medium leading-none" style={{ color: "var(--background-text,#3c3f4b)" }}>
|
||||
{milestone.year}
|
||||
{milestone.heading}
|
||||
</p>
|
||||
<p className=" text-[18px] leading-[1.2]" style={{ color: "var(--background-text,#3a3d4c)" }}>
|
||||
{milestone.description}
|
||||
|
|
@ -130,7 +127,7 @@ function TimelineMoreThanSix({
|
|||
style={{ gridTemplateColumns: `repeat(${topItems.length}, minmax(0, 1fr))` }}
|
||||
>
|
||||
{topItems.map((milestone: any, index: number) => (
|
||||
<div key={`${milestone.year}-${index}`} className="">
|
||||
<div key={`${milestone.heading}-${index}`} className="">
|
||||
<div className="flex items-center ">
|
||||
|
||||
<div className="h-[22px] z-10 relative w-[22px] rounded-full" style={{ backgroundColor: "var(--primary-color,#272272)" }} />
|
||||
|
|
@ -139,7 +136,7 @@ function TimelineMoreThanSix({
|
|||
<div className="pr-2 mt-[18px]">
|
||||
|
||||
<p className=" text-[20px] font-medium leading-none" style={{ color: "var(--background-text,#3c3f4b)" }}>
|
||||
{milestone.year}
|
||||
{milestone.heading}
|
||||
</p>
|
||||
<p className="mt-2 text-[18px] leading-[1.2]" style={{ color: "var(--background-text,#3a3d4c)" }}>
|
||||
{milestone.description}
|
||||
|
|
@ -162,7 +159,7 @@ function TimelineMoreThanSix({
|
|||
if (!item) return <div key={colIndex} />;
|
||||
|
||||
return (
|
||||
<div key={`${item.year}-${colIndex + 8}`} className="flex flex-col items-end">
|
||||
<div key={`${item.heading}-${colIndex + 8}`} className="flex flex-col items-end">
|
||||
<div className="flex w-full items-center ">
|
||||
{/* {colIndex === 0 && <div className="absolute h-[3px] flex-1" style={{ backgroundColor: "var(--stroke,#d8d8dd)" }} />} */}
|
||||
<div className="h-[3px] flex-1" style={{ backgroundColor: colIndex === 0 ? "transparent" : "var(--stroke,#d8d8dd)" }} />
|
||||
|
|
@ -171,7 +168,7 @@ function TimelineMoreThanSix({
|
|||
<div className="pl-2 mt-[18px]">
|
||||
|
||||
<p className=" text-right text-[20px] font-medium leading-none" style={{ color: "var(--background-text,#3c3f4b)" }}>
|
||||
{item.year}
|
||||
{item.heading}
|
||||
</p>
|
||||
<p className="mt-2 text-[18px] text-right leading-[1.2]" style={{ color: "var(--background-text,#3a3d4c)" }}>
|
||||
{item.description}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ import * as z from "zod";
|
|||
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-business-challenges-cards-slide";
|
||||
export const slideLayoutName = "Product Overview Business Challenges Cards Slide";
|
||||
export const slideLayoutId = "title-description-with-cards-text-slide";
|
||||
export const slideLayoutName = "Title Description with Cards to Text Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A business challenges slide with headline and tagline on the left, a large supporting image in the top-right area, and three vertical detail cards across the lower center-right section.";
|
||||
"A slide with a title on top and a description below, and a content section containing cards of text.";
|
||||
|
||||
const CardSchema = z.object({
|
||||
heading: z.string().min(4).max(12).meta({
|
||||
heading: z.string().max(16).meta({
|
||||
description: "Card heading for one challenge column.",
|
||||
}),
|
||||
body: z.string().max(40).meta({
|
||||
body: z.string().max(45).meta({
|
||||
description: "Card body copy for one challenge column.",
|
||||
}),
|
||||
dark: z.boolean().default(false).meta({
|
||||
|
|
@ -20,13 +20,13 @@ const CardSchema = z.object({
|
|||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(24).default("Business Challenges").meta({
|
||||
description: "Main slide title.",
|
||||
title: z.string().min(8).max(16).default("Business Challenges").meta({
|
||||
description: "Main slide title. Max 16 characters.",
|
||||
}),
|
||||
taglineLabel: z.string().min(3).max(10).default("TAGLINE").meta({
|
||||
taglineLabel: z.string().max(16).default("TAGLINE").meta({
|
||||
description: "Short label above the left-side paragraph.",
|
||||
}),
|
||||
taglineBody: z.string().max(80).default(
|
||||
taglineBody: z.string().max(100).default(
|
||||
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea."
|
||||
).meta({
|
||||
description: "Supporting paragraph on the left side.",
|
||||
|
|
@ -76,13 +76,13 @@ const BusinessChallengesCardsSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
}}
|
||||
>
|
||||
<div className=" pl-[66px] pt-[60px] pb-[28px]">
|
||||
<div className=" pl-[66px] pt-[60px] pb-[28px] pr-[40px]">
|
||||
<h2
|
||||
className="text-[80px] max-w-[406px] font-semibold leading-[108.4%] tracking-[-2.419px] text-[#15342D]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
import * as z from "zod";
|
||||
|
||||
export const slideLayoutId = "product-overview-business-challenges-grid-slide";
|
||||
export const slideLayoutName = "Product Overview Business Challenges Grid Slide";
|
||||
export const slideLayoutId = "title-with-blocks-text-slide";
|
||||
export const slideLayoutName = "Title with Blocks to Text Grid Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A slide with a light title band on top and a dark content section below containing four challenge blocks in a two-by-two grid.";
|
||||
"A slide with a title on top and a content section below containing blocks of text.";
|
||||
|
||||
const ChallengeSchema = z.object({
|
||||
heading: z.string().min(4).max(12).meta({
|
||||
description: "Short heading for a single challenge block.",
|
||||
const BlockSchema = z.object({
|
||||
heading: z.string().max(30).meta({
|
||||
description: "Short heading for a single block of text.",
|
||||
}),
|
||||
body: z.string().max(40).meta({
|
||||
description: "Description text for a single challenge block.",
|
||||
body: z.string().max(100).meta({
|
||||
description: "Description text for a single block of text.",
|
||||
}),
|
||||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(24).default("Business Challenges").meta({
|
||||
description: "Main title shown in the top band.",
|
||||
title: z.string().min(8).max(26).default("Business Challenges Business").meta({
|
||||
description: "Main title shown in the top.",
|
||||
}),
|
||||
challenges: z
|
||||
.array(ChallengeSchema)
|
||||
.min(2)
|
||||
blocks: z
|
||||
.array(BlockSchema)
|
||||
|
||||
.max(4)
|
||||
.default([
|
||||
{
|
||||
heading: "HEADING 1",
|
||||
heading: "HEADING 1 HEADING 1 HEADING 1 HEADING 1",
|
||||
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore.",
|
||||
},
|
||||
{
|
||||
|
|
@ -48,13 +48,13 @@ export const Schema = z.object({
|
|||
export type SchemaType = z.infer<typeof Schema>;
|
||||
|
||||
const BusinessChallengesGridSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
const { title, challenges } = data;
|
||||
const { title, blocks } = data;
|
||||
|
||||
return (
|
||||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px] flex flex-col"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden flex flex-col"
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -73,19 +73,19 @@ const BusinessChallengesGridSlide = ({ data }: { data: Partial<SchemaType> }) =>
|
|||
className="grid grid-cols-2 justify-between items-center flex-1 gap-y-[63px] px-[84px] py-[70px] gap-x-[63px]"
|
||||
style={{ backgroundColor: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
{challenges?.map((challenge, index) => (
|
||||
{blocks?.map((block, index) => (
|
||||
<div key={index} className="">
|
||||
<p
|
||||
className="text-[20px] font-semibold tracking-[2.074px] text-white"
|
||||
style={{ color: "var(--primary-text,#edf2f1)" }}
|
||||
>
|
||||
{challenge.heading}
|
||||
{block.heading}
|
||||
</p>
|
||||
<p
|
||||
className="mt-[24px] text-[28px] font-normal text-white"
|
||||
style={{ color: "var(--primary-text,#edf2f1)" }}
|
||||
>
|
||||
{challenge.body}
|
||||
{block.body}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,52 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-comparison-chart-slide";
|
||||
export const slideLayoutName = "Product Overview Comparison Chart Slide";
|
||||
export const slideLayoutId = "title-description-with-table-slide";
|
||||
export const slideLayoutName = "Title Description with Table Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A comparison table slide with a headline, short description, four column headers, and three data rows using check, cross, or empty cells.";
|
||||
"A slide with a title on top and a description below, and a content section containing a table with column headers and rows of text content.";
|
||||
|
||||
const CellStatusSchema = z.enum(["check", "cross", "empty"]);
|
||||
|
||||
const RowSchema = z.object({
|
||||
label: z.string().min(4).max(18).meta({
|
||||
const GeneralRowSchema = z.object({
|
||||
label: z.string().max(18).meta({
|
||||
description: "Row heading shown in the first column.",
|
||||
}),
|
||||
cell1: CellStatusSchema.default("check"),
|
||||
cell2: CellStatusSchema.default("empty"),
|
||||
cell3: CellStatusSchema.default("check"),
|
||||
cell4: CellStatusSchema.default("empty"),
|
||||
cells: z.array(CellStatusSchema).min(1).max(8).meta({
|
||||
description: "Status cells aligned with the table columns.",
|
||||
}),
|
||||
});
|
||||
|
||||
const LegacyRowSchema = z.object({
|
||||
label: z.string().max(18).meta({
|
||||
description: "Row heading shown in the first column.",
|
||||
}),
|
||||
cell1: CellStatusSchema.optional(),
|
||||
cell2: CellStatusSchema.optional(),
|
||||
cell3: CellStatusSchema.optional(),
|
||||
cell4: CellStatusSchema.optional(),
|
||||
});
|
||||
|
||||
const RowSchema = z.union([GeneralRowSchema, LegacyRowSchema]);
|
||||
|
||||
const DEFAULT_COLUMNS = ["HEADING 1", "HEADING 2", "HEADING 3", "HEADING 4"];
|
||||
const DEFAULT_ROWS: z.infer<typeof GeneralRowSchema>[] = [
|
||||
{
|
||||
label: "HEADING 1",
|
||||
cells: ["check", "cross", "check", "cross"],
|
||||
},
|
||||
{
|
||||
label: "HEADING 1",
|
||||
cells: ["check", "empty", "check", "empty"],
|
||||
},
|
||||
{
|
||||
label: "HEADING 2",
|
||||
cells: ["check", "check", "check", "check"],
|
||||
},
|
||||
];
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(20).default("Comparison Chart").meta({
|
||||
title: z.string().max(14).default("Comparison Chart").meta({
|
||||
description: "Main heading shown above the table.",
|
||||
}),
|
||||
subtitle: z.string().max(80).default(
|
||||
|
|
@ -28,42 +55,23 @@ export const Schema = z.object({
|
|||
description: "Short subtitle shown under the main heading.",
|
||||
}),
|
||||
columns: z
|
||||
.array(z.string().min(4).max(18))
|
||||
.min(4)
|
||||
.array(z.string().max(18))
|
||||
.min(1)
|
||||
.max(4)
|
||||
.default(["HEADING 1", "HEADING 1", "HEADING 2", "HEADING 3"])
|
||||
.default(DEFAULT_COLUMNS)
|
||||
.meta({
|
||||
description: "Four table column headings.",
|
||||
description: "Table column headings.",
|
||||
}),
|
||||
highlightedColumnIndex: z.number().int().min(1).max(8).default(4).meta({
|
||||
description: "1-based column index for the dark highlighted table header.",
|
||||
}),
|
||||
rows: z
|
||||
.array(RowSchema)
|
||||
|
||||
.min(1)
|
||||
.max(3)
|
||||
.default([
|
||||
{
|
||||
label: "HEADING 1",
|
||||
cell1: "check",
|
||||
cell2: "cross",
|
||||
cell3: "check",
|
||||
cell4: "cross",
|
||||
},
|
||||
{
|
||||
label: "HEADING 1",
|
||||
cell1: "check",
|
||||
cell2: "empty",
|
||||
cell3: "check",
|
||||
cell4: "empty",
|
||||
},
|
||||
{
|
||||
label: "HEADING 2",
|
||||
cell1: "check",
|
||||
cell2: "check",
|
||||
cell3: "check",
|
||||
cell4: "check",
|
||||
},
|
||||
])
|
||||
.default(DEFAULT_ROWS)
|
||||
.meta({
|
||||
description: "Three table rows with status indicators.",
|
||||
description: "Table rows with status indicators. Prefer the `cells` array format.",
|
||||
}),
|
||||
checkIcon: z.object({
|
||||
__icon_url__: z.string(),
|
||||
|
|
@ -88,6 +96,7 @@ export const Schema = z.object({
|
|||
});
|
||||
|
||||
export type SchemaType = z.infer<typeof Schema>;
|
||||
type CellStatus = z.infer<typeof CellStatusSchema>;
|
||||
|
||||
function StatusIcon({
|
||||
status,
|
||||
|
|
@ -114,13 +123,46 @@ function StatusIcon({
|
|||
}
|
||||
|
||||
const ComparisonChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
const { title, subtitle, columns, rows, checkIcon, crossIcon } = data;
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
columns,
|
||||
highlightedColumnIndex,
|
||||
rows,
|
||||
checkIcon,
|
||||
crossIcon,
|
||||
} = data;
|
||||
const safeColumns = columns && columns.length > 0 ? columns : DEFAULT_COLUMNS;
|
||||
const resolvedHighlightedColumnIndex =
|
||||
highlightedColumnIndex &&
|
||||
highlightedColumnIndex >= 1 &&
|
||||
highlightedColumnIndex <= safeColumns.length
|
||||
? highlightedColumnIndex
|
||||
: Math.min(4, safeColumns.length);
|
||||
const safeRows = rows && rows.length > 0 ? rows : DEFAULT_ROWS;
|
||||
const normalizedRows = safeRows.map((row) => {
|
||||
const rowCells =
|
||||
"cells" in row
|
||||
? row.cells
|
||||
: [row.cell1, row.cell2, row.cell3, row.cell4].filter(
|
||||
(cell): cell is CellStatus => typeof cell !== "undefined"
|
||||
);
|
||||
|
||||
return {
|
||||
label: row.label,
|
||||
cells: Array.from(
|
||||
{ length: safeColumns.length },
|
||||
(_, cellIndex) => rowCells[cellIndex] ?? "empty"
|
||||
),
|
||||
};
|
||||
});
|
||||
const tableGridColumns = `220px repeat(${safeColumns.length}, minmax(0, 1fr))`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -141,23 +183,26 @@ const ComparisonChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div className="absolute left-[54px] top-[268px] w-[1058px] ">
|
||||
<div className="mx-[54px] mt-[20px] ">
|
||||
<div
|
||||
className="grid grid-cols-[220px_repeat(4,1fr)] border-b"
|
||||
style={{ borderColor: "var(--stroke,#c5cccb)" }}
|
||||
className="grid border-b"
|
||||
style={{
|
||||
borderColor: "var(--stroke,#c5cccb)",
|
||||
gridTemplateColumns: tableGridColumns,
|
||||
}}
|
||||
>
|
||||
<div className="h-[94px] " />
|
||||
{columns?.map((column, index) => (
|
||||
<div className=" " />
|
||||
{safeColumns.map((column, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex h-[94px] items-center px-[33px] justify-center border-r text-[20px] font-semibold uppercase tracking-[0.2em]"
|
||||
className="flex items-center p-[33px] justify-center border-r text-[20px] font-semibold tracking-[0.2em]"
|
||||
style={{
|
||||
backgroundColor:
|
||||
index === 3
|
||||
index + 1 === resolvedHighlightedColumnIndex
|
||||
? "var(--primary-color,#15342D)"
|
||||
: "var(--card-color,#ffffff)",
|
||||
color:
|
||||
index === 3
|
||||
index + 1 === resolvedHighlightedColumnIndex
|
||||
? "var(--primary-text,#edf2f1)"
|
||||
: "var(--primary-color,#15342D)",
|
||||
borderColor: "var(--stroke,#c5cccb)",
|
||||
|
|
@ -168,22 +213,18 @@ const ComparisonChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
))}
|
||||
</div>
|
||||
|
||||
{rows?.map((row, index) => {
|
||||
const cells: ("check" | "cross" | "empty")[] = [
|
||||
row.cell1,
|
||||
row.cell2,
|
||||
row.cell3,
|
||||
row.cell4,
|
||||
];
|
||||
|
||||
{normalizedRows.map((row, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`grid grid-cols-[220px_repeat(4,1fr)] ${index < rows.length - 1 ? "border-b" : ""}`}
|
||||
style={{ borderColor: "var(--stroke,#c5cccb)" }}
|
||||
className={`grid ${index < normalizedRows.length - 1 ? "border-b" : ""}`}
|
||||
style={{
|
||||
borderColor: "var(--stroke,#c5cccb)",
|
||||
gridTemplateColumns: tableGridColumns,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex items-center border-r pl-[34px] text-[20px] font-semibold uppercase tracking-[0.2em]"
|
||||
className="flex items-center border-r pl-[34px] text-[20px] font-semibold tracking-[0.2em]"
|
||||
style={{
|
||||
backgroundColor: "var(--card-color,#ffffff)",
|
||||
borderColor: "var(--stroke,#c5cccb)",
|
||||
|
|
@ -193,7 +234,7 @@ const ComparisonChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{row.label}
|
||||
</div>
|
||||
|
||||
{cells?.map((status, cellIndex) => (
|
||||
{row.cells.map((status, cellIndex) => (
|
||||
<div
|
||||
key={cellIndex}
|
||||
className="flex p-[33px] items-center justify-center border-r"
|
||||
|
|
|
|||
|
|
@ -1,27 +1,59 @@
|
|||
import * as z from "zod";
|
||||
|
||||
export const slideLayoutId = "product-overview-comparison-table-with-text-slide";
|
||||
export const slideLayoutName = "Product Overview Comparison Table With Text Slide";
|
||||
export const slideLayoutId = "title-description-with-table-slide";
|
||||
export const slideLayoutName = "Title Description with Table Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A comparison table slide with a title, a subtitle, four headers, and three text rows.";
|
||||
"A comparison table slide with a title, a subtitle, column headers, and rows of text content.";
|
||||
|
||||
const RowSchema = z.object({
|
||||
cell1: z.string().max(12).meta({
|
||||
description: "First column cell text.",
|
||||
}),
|
||||
cell2: z.string().max(12).meta({
|
||||
description: "Second column cell text.",
|
||||
}),
|
||||
cell3: z.string().max(12).meta({
|
||||
description: "Third column cell text.",
|
||||
}),
|
||||
cell4: z.string().max(12).meta({
|
||||
description: "Fourth column cell text.",
|
||||
const TableCellSchema = z.string().max(40).meta({
|
||||
description: "Table cell text.",
|
||||
});
|
||||
|
||||
const GeneralRowSchema = z.object({
|
||||
cells: z.array(TableCellSchema).min(1).max(8).meta({
|
||||
description: "Row cell values matching the table columns.",
|
||||
}),
|
||||
});
|
||||
|
||||
const LegacyRowSchema = z.object({
|
||||
cell1: TableCellSchema.optional(),
|
||||
cell2: TableCellSchema.optional(),
|
||||
cell3: TableCellSchema.optional(),
|
||||
cell4: TableCellSchema.optional(),
|
||||
});
|
||||
|
||||
const RowSchema = z.union([GeneralRowSchema, LegacyRowSchema]);
|
||||
|
||||
const DEFAULT_COLUMNS = ["HEADING 1", "HEADING 1", "HEADING 2", "HEADING 3"];
|
||||
const DEFAULT_ROWS: z.infer<typeof GeneralRowSchema>[] = [
|
||||
{
|
||||
cells: [
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
],
|
||||
},
|
||||
{
|
||||
cells: [
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
],
|
||||
},
|
||||
{
|
||||
cells: [
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
"Lorem ipsum dolor sit.",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(20).default("Comparison Chart").meta({
|
||||
title: z.string().max(14).default("Comparison Chart").meta({
|
||||
description: "Main heading shown above the table.",
|
||||
}),
|
||||
subtitle: z
|
||||
|
|
@ -34,41 +66,23 @@ export const Schema = z.object({
|
|||
description: "Short subtitle shown under the main heading.",
|
||||
}),
|
||||
columns: z
|
||||
.array(z.string().max(10))
|
||||
.max(4)
|
||||
.default(["HEADING 1", "HEADING 1", "HEADING 2", "HEADING 3"])
|
||||
.array(z.string().max(20))
|
||||
.min(1)
|
||||
.max(8)
|
||||
.default(DEFAULT_COLUMNS)
|
||||
.meta({
|
||||
description: "Four table column headings.",
|
||||
description: "Table column headings.",
|
||||
}),
|
||||
highlightedHeaderIndex: z.number().int().min(1).max(4).default(4).meta({
|
||||
highlightedHeaderIndex: z.number().int().min(1).max(8).default(4).meta({
|
||||
description: "1-based column index for the dark highlighted table header.",
|
||||
}),
|
||||
rows: z
|
||||
.array(RowSchema)
|
||||
.min(3)
|
||||
.max(3)
|
||||
.default([
|
||||
{
|
||||
cell1: "Lorem ipsum dolor sit.",
|
||||
cell2: "Lorem ipsum dolor sit.",
|
||||
cell3: "Lorem ipsum dolor sit.",
|
||||
cell4: "Lorem ipsum dolor sit.",
|
||||
},
|
||||
{
|
||||
cell1: "Lorem ipsum dolor sit.",
|
||||
cell2: "Lorem ipsum dolor sit.",
|
||||
cell3: "Lorem ipsum dolor sit.",
|
||||
cell4: "Lorem ipsum dolor sit.",
|
||||
},
|
||||
{
|
||||
cell1: "Lorem ipsum dolor sit.",
|
||||
cell2: "Lorem ipsum dolor sit.",
|
||||
cell3: "Lorem ipsum dolor sit.",
|
||||
cell4: "Lorem ipsum dolor sit.",
|
||||
},
|
||||
])
|
||||
.min(1)
|
||||
.max(6)
|
||||
.default(DEFAULT_ROWS)
|
||||
.meta({
|
||||
description: "Three table rows of text content.",
|
||||
description: "Table rows of text content. Prefer the `cells` array format.",
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -76,12 +90,33 @@ export type SchemaType = z.infer<typeof Schema>;
|
|||
|
||||
const ComparisonTableWithTextSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
const { title, subtitle, columns, highlightedHeaderIndex, rows } = data;
|
||||
const safeColumns = columns && columns.length > 0 ? columns : DEFAULT_COLUMNS;
|
||||
const resolvedHighlightedHeaderIndex =
|
||||
highlightedHeaderIndex &&
|
||||
highlightedHeaderIndex >= 1 &&
|
||||
highlightedHeaderIndex <= safeColumns.length
|
||||
? highlightedHeaderIndex
|
||||
: Math.min(4, safeColumns.length);
|
||||
const safeRows = rows && rows.length > 0 ? rows : DEFAULT_ROWS;
|
||||
const normalizedRows = safeRows.map((row) => {
|
||||
const rowCells =
|
||||
"cells" in row
|
||||
? row.cells
|
||||
: [row.cell1, row.cell2, row.cell3, row.cell4].filter(
|
||||
(cell): cell is string => typeof cell === "string"
|
||||
);
|
||||
|
||||
return Array.from(
|
||||
{ length: safeColumns.length },
|
||||
(_, cellIndex) => rowCells[cellIndex] ?? ""
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#c3cccc)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -112,8 +147,8 @@ const ComparisonTableWithTextSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
>
|
||||
<thead className="w-full">
|
||||
<tr className="w-full">
|
||||
{columns?.map((column, index) => {
|
||||
const isHighlighted = index + 1 === highlightedHeaderIndex;
|
||||
{safeColumns.map((column, index) => {
|
||||
const isHighlighted = index + 1 === resolvedHighlightedHeaderIndex;
|
||||
return (
|
||||
<th
|
||||
key={`${column}-${index}`}
|
||||
|
|
@ -136,10 +171,7 @@ const ComparisonTableWithTextSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
{rows?.map((row, rowIndex) => {
|
||||
const cells = [row.cell1, row.cell2, row.cell3, row.cell4];
|
||||
const isHighlighted = rowIndex + 1 === highlightedHeaderIndex;
|
||||
|
||||
{normalizedRows.map((cells, rowIndex) => {
|
||||
return (
|
||||
<tr key={`row-${rowIndex}`}>
|
||||
{cells?.map((cell, cellIndex) => (
|
||||
|
|
@ -148,12 +180,8 @@ const ComparisonTableWithTextSlide = ({ data }: { data: Partial<SchemaType> }) =
|
|||
className=" border-r border-t bg-white p-[33px] text-left text-[18px] leading-[1.2] last:border-r-0"
|
||||
style={{
|
||||
borderColor: "var(--stroke,#bcc3c3)",
|
||||
backgroundColor: isHighlighted
|
||||
? "var(--primary-color,#05443a)"
|
||||
: "var(--card-color,#ffffff)",
|
||||
color: isHighlighted
|
||||
? "var(--primary-text,#eef2f0)"
|
||||
: "var(--primary-color,#123f38)",
|
||||
backgroundColor: "var(--card-color,#ffffff)",
|
||||
color: "var(--primary-color,#123f38)",
|
||||
}}
|
||||
>
|
||||
{cell}
|
||||
|
|
|
|||
|
|
@ -2,23 +2,23 @@ import * as z from "zod";
|
|||
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-cover-slide";
|
||||
export const slideLayoutName = "Product Overview Cover Slide";
|
||||
export const slideLayoutId = "cover-slide";
|
||||
export const slideLayoutName = "Cover Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A cover slide with a compact logo in the top-left, a date in the top-right, a two-line centered title, and a city/building image anchored to the bottom with a soft fade into the background.";
|
||||
"A cover slide with a compact logo in the top-left, a date/text/label in the top-right, a centered title, and a image anchored to the bottom with a soft fade into the background.";
|
||||
|
||||
export const Schema = z.object({
|
||||
logoImage: z.object({
|
||||
image: z.object({
|
||||
__image_url__: z.string().default("https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/images/placeholder.jpg"),
|
||||
|
||||
__image_prompt__: z.string().min(10).max(100).default("Professional logo of the company"),
|
||||
}).default({
|
||||
__image_prompt__: z.string().default("Image of the company"),
|
||||
}).optional().default({
|
||||
__image_url__:
|
||||
"https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/images/placeholder.jpg",
|
||||
__image_prompt__: "Professional logo of the company",
|
||||
__image_prompt__: "Image of the company",
|
||||
}),
|
||||
label: z.string().min(3).max(16).default("MARCH 2026").meta({
|
||||
description: "Date label shown at the top-right corner.",
|
||||
label: z.string().min(3).max(16).optional().default("MARCH 2026").meta({
|
||||
description: "Date/text/label shown at the top-right corner.",
|
||||
}),
|
||||
titleLine1: z.string().min(3).max(18).default("Social Media").meta({
|
||||
description: "First line of the cover title.",
|
||||
|
|
@ -39,13 +39,12 @@ export type SchemaType = z.infer<typeof Schema>;
|
|||
|
||||
const CoverSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
|
||||
const { logoImage, label, titleLine1, titleLine2, backgroundImage } = data;
|
||||
|
||||
return (
|
||||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -57,17 +56,17 @@ const CoverSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
>
|
||||
<div className="flex items-center justify-between">
|
||||
|
||||
<img
|
||||
src={logoImage?.__image_url__ ?? ''}
|
||||
alt={logoImage?.__image_prompt__ || ''}
|
||||
{data.image?.__image_url__ ? <img
|
||||
src={data.image?.__image_url__ ?? ''}
|
||||
alt={data.image?.__image_prompt__ || ''}
|
||||
className="h-[42px] w-[171px] object-cover"
|
||||
/>
|
||||
/> : <p></p>}
|
||||
|
||||
<p
|
||||
className="text-[18px] font-normal leading-[18.991px] text-[#15342D]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
{label}
|
||||
{data.label || ''}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -75,17 +74,17 @@ const CoverSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<h1
|
||||
className="text-center text-[100px] font-semibold leading-[108.4%] tracking-[-3.024px]"
|
||||
>
|
||||
{titleLine1}
|
||||
{data.titleLine1}
|
||||
<br />
|
||||
{titleLine2}
|
||||
{data.titleLine2}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{backgroundImage?.__image_url__ && (
|
||||
{data.backgroundImage?.__image_url__ && (
|
||||
<img
|
||||
src={backgroundImage.__image_url__ || ''}
|
||||
alt={backgroundImage.__image_prompt__ || ''}
|
||||
src={data.backgroundImage.__image_url__ || ''}
|
||||
alt={data.backgroundImage.__image_prompt__ || ''}
|
||||
className="absolute bottom-0 left-0 z-0 h-[360px] w-full object-cover"
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-image-gallery-slide";
|
||||
export const slideLayoutName = "Product Overview Image Gallery Slide";
|
||||
export const slideLayoutId = "title-description-with-image-gallery-slide";
|
||||
export const slideLayoutName = "Title Description with Image Gallery Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A gallery slide with a title and paragraph on the left and a five-image collage on the right and bottom.";
|
||||
"A text slide with a title on top and a description below, and a section containing a gallery of images.";
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().max(12).default("Image Gallery").meta({
|
||||
description: "Main gallery heading.",
|
||||
description: "Main Title of the slide",
|
||||
}),
|
||||
description: z.string().max(80).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore."
|
||||
description: z.string().max(120).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore."
|
||||
).meta({
|
||||
description: "Supporting paragraph shown under the title.",
|
||||
}),
|
||||
|
|
@ -88,7 +88,7 @@ const ImageGallerySlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px] p-[56px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden p-[56px]"
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -125,7 +125,7 @@ const ImageGallerySlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
</div>
|
||||
|
||||
|
||||
<div className="absolute bottom-[56px] w-full left-[58px] flex gap-[22px]">
|
||||
<div className="mt-[22px] w-full flex gap-[22px]">
|
||||
<img
|
||||
src={bottomWideImage?.__image_url__}
|
||||
alt={bottomWideImage?.__image_prompt__}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@ import * as z from "zod";
|
|||
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-introduction-slide";
|
||||
export const slideLayoutName = "Product Overview Introduction Slide";
|
||||
export const slideLayoutId = "introduction-slide";
|
||||
export const slideLayoutName = "Introduction Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A split slide with a large portrait image on the left and a structured introduction column on the right containing a main title and two labeled body paragraphs.";
|
||||
"A split slide with a large portrait image on the left and a structured introduction column on the right containing a title and two labeled body paragraphs.";
|
||||
|
||||
const IntroBlockSchema = z.object({
|
||||
label: z.string().min(3).max(12).meta({
|
||||
description: "Uppercase mini-heading shown above each intro paragraph.",
|
||||
description: "Uppercase mini-heading shown above each introduction paragraph.",
|
||||
}),
|
||||
body: z.string().min(40).max(96).meta({
|
||||
description: "Supporting paragraph content for the intro block.",
|
||||
body: z.string().max(180).meta({
|
||||
description: "Supporting paragraph content for the introduction block.",
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ export const Schema = z.object({
|
|||
portraitImage: z.object({
|
||||
__image_url__: z.string().url().default("https://images.unsplash.com/photo-1521119989659-a83eee488004?auto=format&fit=crop&w=1200&q=80"),
|
||||
__image_prompt__: z.string().min(10).max(100).default("Two business professionals in office"),
|
||||
}).default({
|
||||
}).optional().default({
|
||||
__image_url__:
|
||||
"https://images.unsplash.com/photo-1521119989659-a83eee488004?auto=format&fit=crop&w=1200&q=80",
|
||||
__image_prompt__: "Two business professionals in office",
|
||||
|
|
@ -32,16 +32,16 @@ export const Schema = z.object({
|
|||
}),
|
||||
blocks: z
|
||||
.array(IntroBlockSchema)
|
||||
.min(2)
|
||||
|
||||
.max(2)
|
||||
.default([
|
||||
{
|
||||
label: "TAGLINE",
|
||||
body: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea.",
|
||||
body: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea.",
|
||||
},
|
||||
{
|
||||
label: "TAGLINE",
|
||||
body: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea.",
|
||||
body: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea.",
|
||||
},
|
||||
])
|
||||
.meta({
|
||||
|
|
@ -58,7 +58,7 @@ const IntroductionSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { RemoteSvgIcon } from "@/app/hooks/useRemoteSvgIcon";
|
||||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-kpi-cards-slide";
|
||||
export const slideLayoutName = "Product Overview KPI Cards Slide";
|
||||
export const slideLayoutId = "title-with-kpi-cards-slide";
|
||||
export const slideLayoutName = "Title with KPI Cards Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A KPI overview slide with a dark-tinted background image, large title, and a two-row grid of six white KPI cards.";
|
||||
"A slide with a title on top and a content section containing a grid of KPI cards.";
|
||||
|
||||
const KpiSchema = z.object({
|
||||
value: z.string().max(5).meta({
|
||||
|
|
@ -44,7 +45,7 @@ export const Schema = z.object({
|
|||
.min(3)
|
||||
.max(6)
|
||||
.default([
|
||||
{ value: "X 5", body: "Lorem ipsum dolor sit." },
|
||||
{ value: "X 5 Lorem", body: "Lorem ipsum dolor sit. " },
|
||||
{ value: "X 5", body: "Lorem ipsum dolor sit." },
|
||||
{ value: "X 5", body: "Lorem ipsum dolor sit." },
|
||||
{ value: "X 5", body: "Lorem ipsum dolor sit." },
|
||||
|
|
@ -65,7 +66,7 @@ const KpiCardsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -107,11 +108,20 @@ const KpiCardsSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
className="flex h-[55px] w-[55px] items-center justify-center rounded-full bg-[#15342D]"
|
||||
style={{ backgroundColor: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
<img
|
||||
{/* <img
|
||||
src={kpiIcon?.__icon_url__}
|
||||
alt={kpiIcon?.__icon_query__}
|
||||
className="h-[25px] w-[25px] object-contain"
|
||||
style={{ filter: "brightness(0) invert(1)" }}
|
||||
s
|
||||
tyle={{ filter: "brightness(0) invert(1)" }}
|
||||
/> */}
|
||||
|
||||
<RemoteSvgIcon
|
||||
url={kpiIcon?.__icon_url__}
|
||||
strokeColor={"currentColor"}
|
||||
className="w-[25px] h-[25px] object-contain"
|
||||
color="var(--primary-text, #FEFEFF)"
|
||||
title={kpiIcon?.__icon_query__}
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import * as z from "zod";
|
||||
|
||||
export const slideLayoutId = "product-overview-market-opportunity-slide";
|
||||
export const slideLayoutName = "Product Overview Market Opportunity Slide";
|
||||
export const slideLayoutId = "title-description-with-lines-and-circles-slide";
|
||||
export const slideLayoutName = "Title Description with Lines and Circles";
|
||||
export const slideLayoutDescription =
|
||||
"A market opportunity slide with title and intro text on the left, four bullet lines extending toward the right, and concentric value circles as the visual focal point.";
|
||||
"A text slide with a title on top and a description below, and a content section containing a list of bullet points and a grid of circles.";
|
||||
|
||||
const BulletSchema = z.object({
|
||||
text: z.string().min(12).max(46).meta({
|
||||
|
|
@ -12,7 +12,7 @@ const BulletSchema = z.object({
|
|||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(22).default("Market Opportunity").meta({
|
||||
title: z.string().max(18).default("Market Opportunity").meta({
|
||||
description: "Main heading shown at the top-left.",
|
||||
}),
|
||||
subtitle: z.string().min(40).max(110).default(
|
||||
|
|
@ -59,7 +59,7 @@ const MarketOpportunitySlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-meet-team-slide";
|
||||
export const slideLayoutName = "Product Overview Meet Team Slide";
|
||||
export const slideLayoutId = "title-description-with-cards-slide";
|
||||
export const slideLayoutName = "Title Description with Cards Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A team introduction slide with a title and intro text on top, followed by four profile cards where one card can be highlighted with a dark footer style.";
|
||||
"A team introduction slide with a title and intro text on top, followed by a grid of profile cards where one card can be highlighted with a footer style.";
|
||||
|
||||
const MemberSchema = z.object({
|
||||
title: z.string().min(2).max(12).meta({
|
||||
|
|
@ -28,13 +28,13 @@ const MemberSchema = z.object({
|
|||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(18).default("Meet Our Team").meta({
|
||||
title: z.string().max(18).default("Meet Our Team").meta({
|
||||
description: "Main title at the top-left.",
|
||||
}),
|
||||
taglineLabel: z.string().min(3).max(10).default("TAGLINE").meta({
|
||||
taglineLabel: z.string().max(16).default("TAGLINE").meta({
|
||||
description: "Small heading above team description.",
|
||||
}),
|
||||
taglineBody: z.string().max(70).default(
|
||||
taglineBody: z.string().max(80).default(
|
||||
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea."
|
||||
).meta({
|
||||
description: "Short descriptive paragraph at top-right.",
|
||||
|
|
@ -95,7 +95,7 @@ const MeetTeamSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -134,7 +134,7 @@ const MeetTeamSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
className="h-[244px] w-full object-cover"
|
||||
/>
|
||||
<div
|
||||
className="h-[154px] p-[33px]"
|
||||
className="h-[154px] p-[23px]"
|
||||
style={{
|
||||
backgroundColor: member.highlighted
|
||||
? "var(--primary-color,#15342D)"
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-mission-vision-slide";
|
||||
export const slideLayoutName = "Product Overview Mission and Vision Slide";
|
||||
export const slideLayoutId = "text-blocks-with-image-block-slide";
|
||||
export const slideLayoutName = "Text Blocks with Image Block Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A quadrant layout with a large title in the top-left block, mission text in the top-right dark block, vision text in the bottom-left dark block, and an image in the bottom-right block.";
|
||||
"A slide with a title in the top-left block, text in the top-right , another text block in the bottom-left , and an image in the bottom-right block.";
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(8).max(20).default("Mission & Vision").meta({
|
||||
title: z.string().min(8).max(30).default("Mission & Vision").meta({
|
||||
description: "Primary heading shown in the top-left tile.",
|
||||
}),
|
||||
|
||||
missionLabel: z.string().min(3).max(10).default("MISSION").meta({
|
||||
topleftTextBlockLabel: z.string().min(3).max(20).default("MISSION").meta({
|
||||
description: "Mission section label.",
|
||||
}),
|
||||
missionBody: z.string().min(40).max(98).default(
|
||||
topleftTextBlockBody: z.string().min(40).max(98).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore."
|
||||
).meta({
|
||||
description: "Mission paragraph content.",
|
||||
}),
|
||||
visionLabel: z.string().min(3).max(10).default("VISION").meta({
|
||||
bottomleftTextBlockLabel: z.string().min(3).max(20).default("VISION").meta({
|
||||
description: "Vision section label.",
|
||||
}),
|
||||
visionBody: z.string().min(40).max(98).default(
|
||||
bottomleftTextBlockBody: z.string().min(40).max(98).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore."
|
||||
).meta({
|
||||
description: "Vision paragraph content.",
|
||||
|
|
@ -32,7 +32,7 @@ export const Schema = z.object({
|
|||
__image_prompt__: z.string(),
|
||||
}).optional().meta({
|
||||
description: "Bottom-right supporting image. Optional.",
|
||||
}).default({
|
||||
}).optional().default({
|
||||
__image_url__: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?auto=format&fit=crop&w=1400&q=80",
|
||||
__image_prompt__: "Business silhouette at window skyline",
|
||||
}),
|
||||
|
|
@ -41,13 +41,12 @@ export const Schema = z.object({
|
|||
export type SchemaType = z.infer<typeof Schema>;
|
||||
|
||||
const MissionVisionSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
||||
const { title, missionLabel, missionBody, visionLabel, visionBody, image } = data;
|
||||
|
||||
return (
|
||||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -59,7 +58,7 @@ const MissionVisionSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
className="text-[80px] font-semibold leading-[108.4%] tracking-[-2.419px] text-[#15342D]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
{title}
|
||||
{data.title}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
|
@ -71,13 +70,13 @@ const MissionVisionSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
className="text-[20px] font-semibold tracking-[2.074px] text-white"
|
||||
style={{ color: "var(--primary-text,#edf2f1)" }}
|
||||
>
|
||||
{missionLabel}
|
||||
{data.topleftTextBlockLabel}
|
||||
</p>
|
||||
<p
|
||||
className="mt-[26px] text-[28px] font-normal text-white"
|
||||
style={{ color: "var(--primary-text,#edf2f1)" }}
|
||||
>
|
||||
{missionBody}
|
||||
{data.topleftTextBlockBody}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -89,24 +88,23 @@ const MissionVisionSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
className="text-[20px] font-semibold tracking-[2.074px] text-white"
|
||||
style={{ color: "var(--primary-text,#edf2f1)" }}
|
||||
>
|
||||
{visionLabel}
|
||||
{data.bottomleftTextBlockLabel}
|
||||
</p>
|
||||
<p
|
||||
className="mt-[24px] text-[28px] font-normal text-white"
|
||||
style={{ color: "var(--primary-text,#edf2f1)" }}
|
||||
>
|
||||
{visionBody}
|
||||
{data.bottomleftTextBlockBody}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="h-full w-full overflow-hidden bg-white"
|
||||
style={{ backgroundColor: "var(--card-color,#ffffff)" }}
|
||||
>
|
||||
|
||||
{image?.__image_url__ && (
|
||||
{data.image?.__image_url__ && (
|
||||
<img
|
||||
src={image.__image_url__}
|
||||
alt={image.__image_prompt__}
|
||||
src={data.image.__image_url__}
|
||||
alt={data.image.__image_prompt__}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-our-services-slide";
|
||||
export const slideLayoutName = "Product Overview Our Services Slide";
|
||||
export const slideLayoutId = "title-description-with-image-block-slide";
|
||||
export const slideLayoutName = "Title Description with Image Block Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A services slide with title and intro copy on the left, a large image below, and a two-by-two service card matrix on the right.";
|
||||
"A slide with a title on top and a description below, and a content section containing an image and a grid of cards of text.";
|
||||
|
||||
const ServiceSchema = z.object({
|
||||
heading: z.string().min(4).max(12).meta({
|
||||
description: "Service card heading.",
|
||||
const CardSchema = z.object({
|
||||
heading: z.string().max(16).meta({
|
||||
description: "Card heading.",
|
||||
}),
|
||||
body: z.string().max(30).meta({
|
||||
description: "Service card short description.",
|
||||
description: "Card short description.",
|
||||
}),
|
||||
dark: z.boolean().default(false).meta({
|
||||
description: "Whether this service card uses the dark style.",
|
||||
isHighlighted: z.boolean().default(false).meta({
|
||||
description: "Whether this card uses the dark style.",
|
||||
}),
|
||||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(6).max(12).default("Our Services").meta({
|
||||
title: z.string().max(16).default("Our Services").meta({
|
||||
description: "Main heading shown at the top-left.",
|
||||
}),
|
||||
taglineLabel: z.string().min(3).max(10).default("TAGLINE").meta({
|
||||
taglineLabel: z.string().max(16).default("TAGLINE").meta({
|
||||
description: "Small label above left paragraph.",
|
||||
}),
|
||||
taglineBody: z.string().max(30).default(
|
||||
|
|
@ -41,17 +41,17 @@ export const Schema = z.object({
|
|||
description: "Main image shown at the lower left side.",
|
||||
}),
|
||||
services: z
|
||||
.array(ServiceSchema)
|
||||
.array(CardSchema)
|
||||
|
||||
.max(4)
|
||||
.default([
|
||||
{ heading: "HEADING 1", body: "Lorem ipsum dolor sit amet, consectetur", dark: false },
|
||||
{ heading: "HEADING 2", body: "Lorem ipsum dolor sit amet, consectetur", dark: true },
|
||||
{ heading: "HEADING 3", body: "Lorem ipsum dolor sit amet, consectetur", dark: false },
|
||||
{ heading: "HEADING 4", body: "Lorem ipsum dolor sit amet, consectetur", dark: false },
|
||||
{ heading: "HEADING 1", body: "Lorem ipsum dolor sit amet, consectetur", isHighlighted: false },
|
||||
{ heading: "HEADING 2", body: "Lorem ipsum dolor sit amet, consectetur", isHighlighted: true },
|
||||
{ heading: "HEADING 3", body: "Lorem ipsum dolor sit amet, consectetur", isHighlighted: false },
|
||||
{ heading: "HEADING 4", body: "Lorem ipsum dolor sit amet, consectetur", isHighlighted: false },
|
||||
])
|
||||
.meta({
|
||||
description: "Four service cards rendered on the right side.",
|
||||
description: "Cards rendered on the right side.",
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ const OurServicesSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] flex items-end pb-[56px] justify-between overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] flex items-end pb-[56px] justify-between overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -113,12 +113,12 @@ const OurServicesSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
|
||||
|
||||
<div className="grid grid-cols-2 gap-[22px] pr-[76px]">
|
||||
{services?.map((service, index) => (
|
||||
{services?.map((card, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className=" p-[33px]"
|
||||
style={{
|
||||
backgroundColor: service.dark
|
||||
backgroundColor: card.isHighlighted
|
||||
? "var(--primary-color,#15342D)"
|
||||
: "var(--card-color,#ececee)",
|
||||
}}
|
||||
|
|
@ -126,22 +126,22 @@ const OurServicesSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<p
|
||||
className="text-[20px] font-semibold tracking-[2.074px] text-white"
|
||||
style={{
|
||||
color: service.dark
|
||||
color: card.isHighlighted
|
||||
? "var(--primary-text,#edf2f1)"
|
||||
: "var(--primary-color,#15342D)",
|
||||
}}
|
||||
>
|
||||
{service.heading}
|
||||
{card.heading}
|
||||
</p>
|
||||
<p
|
||||
className={`${service.dark ? "text-white" : "text-[#15342DCC]"} mt-[20px] text-[28px] font-normal`}
|
||||
className={`${card.isHighlighted ? "text-white" : "text-[#15342DCC]"} mt-[20px] text-[28px] font-normal`}
|
||||
style={{
|
||||
color: service.dark
|
||||
color: card.isHighlighted
|
||||
? "var(--primary-text,#edf2f1)"
|
||||
: "var(--background-text,#15342DCC)",
|
||||
}}
|
||||
>
|
||||
{service.body}
|
||||
{card.body}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { RemoteSvgIcon } from "@/app/hooks/useRemoteSvgIcon";
|
||||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-pricing-plan-slide";
|
||||
export const slideLayoutName = "Product Overview Pricing Plan Slide";
|
||||
export const slideLayoutId = "title-cards-list-with-text-slide";
|
||||
export const slideLayoutName = "Title with Cards List with Text";
|
||||
export const slideLayoutDescription =
|
||||
"A three-column pricing slide with one emphasized center plan and feature bullet lists for each plan.";
|
||||
"A slide with a title on top and a content section containing a list of cards with text content.";
|
||||
|
||||
const PlanSchema = z.object({
|
||||
price: z.string().min(4).max(12).meta({
|
||||
|
|
@ -14,7 +15,7 @@ const PlanSchema = z.object({
|
|||
description: "Short statement describing the plan.",
|
||||
}),
|
||||
features: z
|
||||
.array(z.string().max(14))
|
||||
.array(z.string().max(16))
|
||||
|
||||
.max(4)
|
||||
.meta({
|
||||
|
|
@ -91,7 +92,7 @@ const PricingPlanSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
|
|
@ -143,12 +144,19 @@ const PricingPlanSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<div className="mt-[18px] space-y-[6px]">
|
||||
{plan.features.map((feature, featureIndex) => (
|
||||
<div key={featureIndex} className="flex items-center gap-[10px]">
|
||||
<img
|
||||
<RemoteSvgIcon
|
||||
url={featureIcon?.__icon_url__}
|
||||
strokeColor={"currentColor"}
|
||||
className="w-[28px] h-[28px] object-contain"
|
||||
color={active ? "var(--primary-text, #edf2f1)" : "var(--background-text, #15342DCC)"}
|
||||
title={featureIcon?.__icon_query__}
|
||||
/>
|
||||
{/* <img
|
||||
src={featureIcon?.__icon_url__}
|
||||
alt={featureIcon?.__icon_query__}
|
||||
className="h-[28px] w-[28px] object-contain"
|
||||
style={{ filter: active ? "brightness(0) invert(1)" : "none" }}
|
||||
/>
|
||||
/> */}
|
||||
<p
|
||||
className="text-[28px] font-normal text-[#15342DCC]"
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import { RemoteSvgIcon } from "@/app/hooks/useRemoteSvgIcon";
|
||||
import * as z from "zod";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-process-slide";
|
||||
export const slideLayoutName = "Product Overview Process Slide";
|
||||
export const slideLayoutId = "title-with-process-steps-slide";
|
||||
export const slideLayoutName = "Title with Process Steps Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A process diagram slide with five connected hexagon steps and alternating caption blocks above and below the flow.";
|
||||
"A slide with a title on top and a content section containing a process diagrams with connected hexagon steps and alternating caption blocks above and below the flow.";
|
||||
|
||||
const StepSchema = z.object({
|
||||
label: z.string().min(3).max(10).meta({
|
||||
label: z.string().max(16).meta({
|
||||
description: "Short uppercase label for a process step.",
|
||||
}),
|
||||
body: z.string().max(20).meta({
|
||||
body: z.string().max(32).meta({
|
||||
description: "Brief explanatory text for the process step.",
|
||||
}),
|
||||
icon: z.object({
|
||||
|
|
@ -26,23 +27,23 @@ const StepSchema = z.object({
|
|||
});
|
||||
|
||||
export const Schema = z.object({
|
||||
title: z.string().min(5).max(14).default("PROCESS").meta({
|
||||
title: z.string().max(14).default("PROCESS").meta({
|
||||
description: "Main title shown in the top-left corner.",
|
||||
}),
|
||||
|
||||
steps: z
|
||||
.array(StepSchema)
|
||||
.min(5)
|
||||
|
||||
.max(5)
|
||||
.default([
|
||||
{
|
||||
label: "TAGLINE", body: "Ut enim ad minim.", icon: {
|
||||
label: "TAGLINE TAGLINE", body: "Ut enim ad minim. Ut enim ad minim. ", icon: {
|
||||
__icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg",
|
||||
__icon_query__: "pulse icon",
|
||||
}, highlighted: false
|
||||
},
|
||||
{
|
||||
label: "TAGLINE", body: "Ut enim ad minim.", icon: {
|
||||
label: "TAGLINE", body: "Ut enim ad minim. Ut enim ad minim.", icon: {
|
||||
__icon_url__: "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/icons/placeholder.svg",
|
||||
__icon_query__: "upload icon",
|
||||
}, highlighted: false
|
||||
|
|
@ -67,7 +68,7 @@ export const Schema = z.object({
|
|||
},
|
||||
])
|
||||
.meta({
|
||||
description: "Five process steps rendered from left to right.",
|
||||
description: "Process steps rendered from left to right.",
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -81,13 +82,13 @@ const ProcessSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden flex flex-col "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#DAE1DE)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
}}
|
||||
>
|
||||
<div className="px-[66px] pt-[73px]">
|
||||
<div className="px-[66px] pt-[53px]">
|
||||
<h2
|
||||
className="text-[80px] font-semibold leading-[108.4%] tracking-[-2.419px] text-[#15342D]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
|
|
@ -95,10 +96,7 @@ const ProcessSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className="flex justify-center w-full px-[66px] mt-[110px] ">
|
||||
<div className="flex justify-center items-center w-full flex-1 px-[66px] ">
|
||||
{steps?.map((step, index) => {
|
||||
if (index % 2 === 0) {
|
||||
return (
|
||||
|
|
@ -109,11 +107,17 @@ const ProcessSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
>
|
||||
<div className="relative flex justify-center items-center h-[276px]">
|
||||
<div className="relative">
|
||||
<img src={step.icon.__icon_url__} alt={step.icon.__icon_query__} className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[42px] w-[42px] object-contain"
|
||||
style={{
|
||||
filter: step.highlighted ? "invert(1)" : "invert(0)",
|
||||
}}
|
||||
/>
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[42px] h-[42px] flex items-center justify-center">
|
||||
|
||||
<RemoteSvgIcon
|
||||
url={step.icon?.__icon_url__}
|
||||
strokeColor={"currentColor"}
|
||||
className="w-full h-full object-contain"
|
||||
color={step.highlighted ? "var(--primary-text, #4C68DF)" : "var(--background-text,#315f58)"}
|
||||
title={step.icon.__icon_query__}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="162" height="187" viewBox="0 0 162 187" fill="none">
|
||||
<path d="M80.8291 0L161.658 46.6667V140L80.8291 186.667L2.28882e-05 140V46.6667L80.8291 0Z" fill={step.highlighted ? "var(--primary-color,#15342D)" : "var(--card-color,#FEFEFF)"} />
|
||||
</svg>
|
||||
|
|
@ -168,7 +172,15 @@ const ProcessSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="162" height="187" viewBox="0 0 162 187" fill="none">
|
||||
<path d="M80.8291 0L161.658 46.6667V140L80.8291 186.667L2.28882e-05 140V46.6667L80.8291 0Z" fill={step.highlighted ? "var(--primary-color,#15342D)" : "var(--card-color,#FEFEFF)"} />
|
||||
</svg>
|
||||
<img src={step.icon.__icon_url__} alt={step.icon.__icon_query__} className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[42px] w-[42px] object-contain" />
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[42px] h-[42px] flex items-center justify-center">
|
||||
<RemoteSvgIcon
|
||||
url={step.icon?.__icon_url__}
|
||||
strokeColor={"currentColor"}
|
||||
className="w-full h-full object-contain"
|
||||
color={step.highlighted ? "var(--primary-text, #4C68DF)" : "var(--background-text,#315f58)"}
|
||||
title={step.icon.__icon_query__}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute top-1 right-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="231" height="134" viewBox="0 0 231 134" fill="none">
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@ import {
|
|||
Line,
|
||||
LabelList,
|
||||
} from "recharts";
|
||||
import { RemoteSvgIcon } from "@/app/hooks/useRemoteSvgIcon";
|
||||
|
||||
export const slideLayoutId = "product-overview-report-snapshot-slide";
|
||||
export const slideLayoutName = "Product Overview Report Snapshot Slide";
|
||||
export const slideLayoutId = "title-description-with-chart-and-kpi-cards-slide";
|
||||
export const slideLayoutName = "Title Description with Chart and KPI Cards Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A report summary slide with a left-edge photo strip, title and intro copy, a chart card that supports four visual styles, and KPI callout cards on the right.";
|
||||
"A text slide with a title on top and a description below, and a content section containing a chart and a grid of KPI cards.";
|
||||
|
||||
const LegacyBarSchema = z.object({
|
||||
value: z.number().min(10).max(100).meta({
|
||||
|
|
@ -335,372 +336,380 @@ const ReportSnapshotSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: "var(--background-color,#D7DEDB)",
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
}}
|
||||
>
|
||||
{sideImage?.__image_url__ && (
|
||||
<img
|
||||
src={sideImage.__image_url__}
|
||||
alt={sideImage.__image_prompt__}
|
||||
className="absolute left-0 top-0 h-full w-[232px] object-cover"
|
||||
/>
|
||||
)}
|
||||
<div className="flex gap-7 h-full">
|
||||
|
||||
<div
|
||||
className="absolute left-[268px] top-[74px] text-[#083F37]"
|
||||
style={{ color: "var(--primary-color,#083F37)" }}
|
||||
>
|
||||
<h2 className="text-[80px] font-semibold leading-[108.4%] tracking-[-2.419px]">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
<div className="mt-[14px] w-[560px]">
|
||||
<p
|
||||
className="text-[20px] font-semibold tracking-[2.074px] text-[#083F37]"
|
||||
{sideImage?.__image_url__ && (
|
||||
<img
|
||||
src={sideImage.__image_url__}
|
||||
alt={sideImage.__image_prompt__}
|
||||
className=" h-full w-[232px] object-cover"
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col flex-1 justify-center">
|
||||
<div
|
||||
className=" text-[#083F37]"
|
||||
style={{ color: "var(--primary-color,#083F37)" }}
|
||||
>
|
||||
{taglineLabel}
|
||||
</p>
|
||||
<p
|
||||
className="mt-[12px] text-[24px] mb-5 leading-[1.11] text-[#083F37]/75"
|
||||
style={{ color: "var(--background-text,#083F37BF)" }}
|
||||
>
|
||||
{taglineBody}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="text-[80px] font-semibold leading-[108.4%] tracking-[-2.419px]">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
<div
|
||||
className={`absolute bottom-[40px] left-[266px] w-[580px] bg-[#F3F3F3] px-[28px] pb-[18px] pt-[20px] ${activeChartStyle === "mini-bars" ? "h-[308px]" : "h-[350px]"
|
||||
}`}
|
||||
style={{ backgroundColor: "var(--card-color,#F3F3F3)" }}
|
||||
>
|
||||
<p
|
||||
className="mt-[14px] text-[32px] font-normal leading-[1.1] text-[#15342D]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
{chartTitle}
|
||||
</p>
|
||||
|
||||
{activeChartStyle === "mini-bars" && (
|
||||
<>
|
||||
<div className="mt-[18px] h-[166px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={resolvedMiniBars}
|
||||
margin={{ top: 0, right: 8, left: -6, bottom: 0 }}
|
||||
barCategoryGap={16}
|
||||
>
|
||||
<CartesianGrid vertical={false} stroke="var(--stroke,#D7DCDA)" strokeDasharray="3 3" />
|
||||
<XAxis dataKey="label" tick={false} axisLine={false} tickLine={false} />
|
||||
<YAxis
|
||||
width={42}
|
||||
|
||||
|
||||
tickFormatter={(value) => `$${value}`}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fill: "var(--background-text,#6C7271)", fontSize: 10 }}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="secondary"
|
||||
fill={MINI_BAR_LIGHT}
|
||||
radius={[5, 5, 0, 0]}
|
||||
isAnimationActive={false}
|
||||
maxBarSize={26}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="primary"
|
||||
fill={MINI_BAR_DARK}
|
||||
radius={[5, 5, 0, 0]}
|
||||
isAnimationActive={false}
|
||||
maxBarSize={26}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="mt-[14px] flex items-center justify-between ">
|
||||
<div className="mt-[14px] w-[560px]">
|
||||
<p
|
||||
className="text-[#6D7371] text-[18px]"
|
||||
style={{ color: "var(--background-text,#6D7371)" }}
|
||||
className="text-[20px] font-semibold tracking-[2.074px] text-[#083F37]"
|
||||
style={{ color: "var(--primary-color,#083F37)" }}
|
||||
>
|
||||
{footerLabel}
|
||||
{taglineLabel}
|
||||
</p>
|
||||
<p
|
||||
className="font-medium text-[#15342D] text-[18px]"
|
||||
className="mt-[12px] text-[24px] mb-5 leading-[1.11] text-[#083F37]/75"
|
||||
style={{ color: "var(--background-text,#083F37BF)" }}
|
||||
>
|
||||
{taglineBody}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<div
|
||||
className={` w-[580px] bg-[#F3F3F3] px-[28px] pb-[18px] pt-[20px] ${activeChartStyle === "mini-bars" ? "h-[308px]" : "h-[350px]"
|
||||
}`}
|
||||
style={{ backgroundColor: "var(--card-color,#F3F3F3)" }}
|
||||
>
|
||||
<p
|
||||
className="mt-[14px] text-[32px] font-normal leading-[1.1] text-[#15342D]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
{footerValue}
|
||||
{chartTitle}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeChartStyle === "donut" && (
|
||||
<div className="mt-[6px] flex h-[250px] items-center">
|
||||
<div className="h-[220px] w-[250px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={donutData ?? []}
|
||||
dataKey="value"
|
||||
innerRadius={48}
|
||||
outerRadius={82}
|
||||
stroke="none"
|
||||
labelLine={false}
|
||||
label={renderDonutPercentLabel}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
{(donutData ?? []).map((entry, index) => (
|
||||
<Cell key={`${entry.name}-${index}`} fill={DONUT_COLORS[index % DONUT_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="ml-[8px] flex-1 space-y-[16px] pr-[8px]">
|
||||
{(donutData ?? []).map((entry, index) => {
|
||||
const percent = Math.round((entry.value / donutTotal) * 100);
|
||||
return (
|
||||
<div key={`${entry.name}-legend-${index}`} className="flex items-center justify-between">
|
||||
{activeChartStyle === "mini-bars" && (
|
||||
<>
|
||||
<div className="mt-[18px] h-[166px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={resolvedMiniBars}
|
||||
margin={{ top: 0, right: 8, left: -6, bottom: 0 }}
|
||||
barCategoryGap={16}
|
||||
>
|
||||
<CartesianGrid vertical={false} stroke="var(--stroke,#D7DCDA)" strokeDasharray="3 3" />
|
||||
<XAxis dataKey="label" tick={false} axisLine={false} tickLine={false} />
|
||||
<YAxis
|
||||
width={42}
|
||||
|
||||
|
||||
tickFormatter={(value) => `$${value}`}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fill: "var(--background-text,#6C7271)", fontSize: 10 }}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="secondary"
|
||||
fill={MINI_BAR_LIGHT}
|
||||
radius={[5, 5, 0, 0]}
|
||||
isAnimationActive={false}
|
||||
maxBarSize={26}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="primary"
|
||||
fill={MINI_BAR_DARK}
|
||||
radius={[5, 5, 0, 0]}
|
||||
isAnimationActive={false}
|
||||
maxBarSize={26}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="mt-[14px] flex items-center justify-between ">
|
||||
<p
|
||||
className="text-[#6D7371] text-[18px]"
|
||||
style={{ color: "var(--background-text,#6D7371)" }}
|
||||
>
|
||||
{footerLabel}
|
||||
</p>
|
||||
<p
|
||||
className="font-medium text-[#15342D] text-[18px]"
|
||||
style={{ color: "var(--primary-color,#15342D)" }}
|
||||
>
|
||||
{footerValue}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeChartStyle === "donut" && (
|
||||
<div className="mt-[6px] flex h-[250px] items-center">
|
||||
<div className="h-[220px] w-[250px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={donutData ?? []}
|
||||
dataKey="value"
|
||||
innerRadius={48}
|
||||
outerRadius={82}
|
||||
stroke="none"
|
||||
labelLine={false}
|
||||
label={renderDonutPercentLabel}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
{(donutData ?? []).map((entry, index) => (
|
||||
<Cell key={`${entry.name}-${index}`} fill={DONUT_COLORS[index % DONUT_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="ml-[8px] flex-1 space-y-[16px] pr-[8px]">
|
||||
{(donutData ?? []).map((entry, index) => {
|
||||
const percent = Math.round((entry.value / donutTotal) * 100);
|
||||
return (
|
||||
<div key={`${entry.name}-legend-${index}`} className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full"
|
||||
style={{ backgroundColor: DONUT_COLORS[index % DONUT_COLORS.length] }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-bold text-[#767676]"
|
||||
style={{ color: "var(--background-text,#767676)" }}
|
||||
>
|
||||
{legendLabels?.[index] ?? entry.name}
|
||||
</p>
|
||||
</div>
|
||||
<p
|
||||
className="text-[18px] font-bold text-[#404040]"
|
||||
style={{ color: "var(--background-text,#404040)" }}
|
||||
>
|
||||
{percent}%
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeChartStyle === "grouped-bars" && (
|
||||
<div className="mt-[12px] flex h-[236px] items-center justify-between">
|
||||
<div className="h-[210px] w-[362px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={groupedBars ?? []}
|
||||
margin={{ top: 12, right: 6, left: -12, bottom: 0 }}
|
||||
barCategoryGap={20}
|
||||
>
|
||||
<CartesianGrid vertical={false} stroke="var(--stroke,#D7DCDA)" />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fill: "var(--background-text,#42484A)", fontSize: 10 }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
|
||||
tick={{ fill: "var(--background-text,#566061)", fontSize: 10 }}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="optionA"
|
||||
fill={MINI_BAR_DARK}
|
||||
radius={[4, 4, 0, 0]}
|
||||
maxBarSize={20}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
<LabelList
|
||||
dataKey="optionA"
|
||||
position="top"
|
||||
fill="var(--background-text,#5B6463)"
|
||||
fontSize={9}
|
||||
/>
|
||||
</Bar>
|
||||
<Bar
|
||||
dataKey="optionB"
|
||||
fill="var(--graph-2,#8A9A96)"
|
||||
radius={[4, 4, 0, 0]}
|
||||
maxBarSize={20}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
<LabelList
|
||||
dataKey="optionB"
|
||||
position="top"
|
||||
fill="var(--background-text,#5B6463)"
|
||||
fontSize={9}
|
||||
/>
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="ml-[24px] space-y-[24px]">
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full"
|
||||
style={{ backgroundColor: DONUT_COLORS[index % DONUT_COLORS.length] }}
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#0B4B40]"
|
||||
style={{ backgroundColor: "var(--graph-0,#0B4B40)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-bold text-[#767676]"
|
||||
style={{ color: "var(--background-text,#767676)" }}
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[index] ?? entry.name}
|
||||
{legendLabels?.[0] ?? "Option A"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#8A9A96]"
|
||||
style={{ backgroundColor: "var(--graph-2,#8A9A96)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[1] ?? "Option B"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeChartStyle === "dual-line" && (
|
||||
<div className="mt-[12px] flex h-[236px] items-center justify-between">
|
||||
<div className="h-[210px] w-[362px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={trendLines ?? []} margin={{ top: 12, right: 6, left: -6, bottom: 16 }}>
|
||||
<CartesianGrid vertical={false} stroke="var(--stroke,#D7DCDA)" />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fill: "var(--background-text,#42484A)", fontSize: 10 }}
|
||||
label={{
|
||||
value: xAxisName,
|
||||
position: "insideBottom",
|
||||
offset: -6,
|
||||
fill: "var(--background-text,#535B5C)",
|
||||
fontSize: 10,
|
||||
}}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
|
||||
tick={{ fill: "var(--background-text,#566061)", fontSize: 10 }}
|
||||
label={{
|
||||
value: yAxisName,
|
||||
angle: -90,
|
||||
position: "insideLeft",
|
||||
fill: "var(--background-text,#535B5C)",
|
||||
fontSize: 10,
|
||||
dx: -8,
|
||||
}}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="optionA"
|
||||
stroke={MINI_BAR_DARK}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="optionB"
|
||||
stroke="var(--graph-2,#8A9A96)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="ml-[18px] space-y-[24px]">
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#0B4B40]"
|
||||
style={{ backgroundColor: "var(--graph-0,#0B4B40)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[0] ?? "Option A"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#8A9A96]"
|
||||
style={{ backgroundColor: "var(--graph-2,#8A9A96)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[1] ?? "Option B"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={` w-[362px] ${activeChartStyle === "mini-bars" ? "top-[382px]" : "top-[320px]"
|
||||
}`}
|
||||
>
|
||||
<div className="flex flex-col justify-end items-end gap-[24px]">
|
||||
{visibleMetricCards.map((metric, index) => (
|
||||
<div
|
||||
key={`${metric.value}-${index}`}
|
||||
className="bg-[#F3F3F3] px-[33px] py-[24px]"
|
||||
style={{ backgroundColor: "var(--card-color,#F3F3F3)" }}
|
||||
>
|
||||
<div className="flex items-center gap-[14px]">
|
||||
<div
|
||||
className="flex h-[56px] w-[56px] items-center justify-center rounded-full"
|
||||
style={{ backgroundColor: metricIcon?.__icon_url__ ? "var(--primary-color,#113F37)" : KPI_ICON_BG }}
|
||||
>
|
||||
{usePulseFallback ? (
|
||||
<PulseIcon />
|
||||
) : (
|
||||
<RemoteSvgIcon
|
||||
url={metricIcon?.__icon_url__}
|
||||
strokeColor={"currentColor"}
|
||||
className="w-[24px] h-[24px] object-contain"
|
||||
color="var(--primary-text, #FEFEFF)"
|
||||
title={metricIcon?.__icon_query__}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p
|
||||
className="text-[48px] font-semibold leading-[1] text-[#113F37]"
|
||||
style={{ color: "var(--primary-color,#113F37)" }}
|
||||
>
|
||||
{metric.value}
|
||||
</p>
|
||||
</div>
|
||||
<p
|
||||
className="text-[18px] font-bold text-[#404040]"
|
||||
style={{ color: "var(--background-text,#404040)" }}
|
||||
className="mt-[18px] text-[28px] leading-[1.08] text-[#113F37]"
|
||||
style={{ color: "var(--primary-color,#113F37)" }}
|
||||
>
|
||||
{percent}%
|
||||
{metric.body}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeChartStyle === "grouped-bars" && (
|
||||
<div className="mt-[12px] flex h-[236px] items-center justify-between">
|
||||
<div className="h-[210px] w-[362px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={groupedBars ?? []}
|
||||
margin={{ top: 12, right: 6, left: -12, bottom: 0 }}
|
||||
barCategoryGap={20}
|
||||
>
|
||||
<CartesianGrid vertical={false} stroke="var(--stroke,#D7DCDA)" />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fill: "var(--background-text,#42484A)", fontSize: 10 }}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
|
||||
tick={{ fill: "var(--background-text,#566061)", fontSize: 10 }}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="optionA"
|
||||
fill={MINI_BAR_DARK}
|
||||
radius={[4, 4, 0, 0]}
|
||||
maxBarSize={20}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
<LabelList
|
||||
dataKey="optionA"
|
||||
position="top"
|
||||
fill="var(--background-text,#5B6463)"
|
||||
fontSize={9}
|
||||
/>
|
||||
</Bar>
|
||||
<Bar
|
||||
dataKey="optionB"
|
||||
fill="var(--graph-2,#8A9A96)"
|
||||
radius={[4, 4, 0, 0]}
|
||||
maxBarSize={20}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
<LabelList
|
||||
dataKey="optionB"
|
||||
position="top"
|
||||
fill="var(--background-text,#5B6463)"
|
||||
fontSize={9}
|
||||
/>
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="ml-[24px] space-y-[24px]">
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#0B4B40]"
|
||||
style={{ backgroundColor: "var(--graph-0,#0B4B40)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[0] ?? "Option A"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#8A9A96]"
|
||||
style={{ backgroundColor: "var(--graph-2,#8A9A96)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[1] ?? "Option B"}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeChartStyle === "dual-line" && (
|
||||
<div className="mt-[12px] flex h-[236px] items-center justify-between">
|
||||
<div className="h-[210px] w-[362px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={trendLines ?? []} margin={{ top: 12, right: 6, left: -6, bottom: 16 }}>
|
||||
<CartesianGrid vertical={false} stroke="var(--stroke,#D7DCDA)" />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fill: "var(--background-text,#42484A)", fontSize: 10 }}
|
||||
label={{
|
||||
value: xAxisName,
|
||||
position: "insideBottom",
|
||||
offset: -6,
|
||||
fill: "var(--background-text,#535B5C)",
|
||||
fontSize: 10,
|
||||
}}
|
||||
/>
|
||||
<YAxis
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
|
||||
tick={{ fill: "var(--background-text,#566061)", fontSize: 10 }}
|
||||
label={{
|
||||
value: yAxisName,
|
||||
angle: -90,
|
||||
position: "insideLeft",
|
||||
fill: "var(--background-text,#535B5C)",
|
||||
fontSize: 10,
|
||||
dx: -8,
|
||||
}}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="optionA"
|
||||
stroke={MINI_BAR_DARK}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="optionB"
|
||||
stroke="var(--graph-2,#8A9A96)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="ml-[18px] space-y-[24px]">
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#0B4B40]"
|
||||
style={{ backgroundColor: "var(--graph-0,#0B4B40)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[0] ?? "Option A"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span
|
||||
className="h-[14px] w-[14px] rounded-full bg-[#8A9A96]"
|
||||
style={{ backgroundColor: "var(--graph-2,#8A9A96)" }}
|
||||
/>
|
||||
<p
|
||||
className="text-[18px] font-medium leading-[1] text-[#6A6B6E]"
|
||||
style={{ color: "var(--background-text,#6A6B6E)" }}
|
||||
>
|
||||
{legendLabels?.[1] ?? "Option B"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`absolute right-[38px] bottom-[40px] w-[362px] ${activeChartStyle === "mini-bars" ? "top-[382px]" : "top-[320px]"
|
||||
}`}
|
||||
>
|
||||
<div className="flex flex-col justify-end items-end gap-[24px]">
|
||||
{visibleMetricCards.map((metric, index) => (
|
||||
<div
|
||||
key={`${metric.value}-${index}`}
|
||||
className="bg-[#F3F3F3] px-[33px] py-[24px]"
|
||||
style={{ backgroundColor: "var(--card-color,#F3F3F3)" }}
|
||||
>
|
||||
<div className="flex items-center gap-[14px]">
|
||||
<div
|
||||
className="flex h-[56px] w-[56px] items-center justify-center rounded-full"
|
||||
style={{ backgroundColor: KPI_ICON_BG }}
|
||||
>
|
||||
{usePulseFallback ? (
|
||||
<PulseIcon />
|
||||
) : (
|
||||
<img
|
||||
src={metricIcon?.__icon_url__}
|
||||
alt={metricIcon?.__icon_query__}
|
||||
className="h-[24px] w-[24px] object-contain"
|
||||
style={{ filter: "invert(1)" }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p
|
||||
className="text-[48px] font-semibold leading-[1] text-[#113F37]"
|
||||
style={{ color: "var(--primary-color,#113F37)" }}
|
||||
>
|
||||
{metric.value}
|
||||
</p>
|
||||
</div>
|
||||
<p
|
||||
className="mt-[18px] text-[28px] leading-[1.08] text-[#113F37]"
|
||||
style={{ color: "var(--primary-color,#113F37)" }}
|
||||
>
|
||||
{metric.body}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ const PRODUCT_BG = "var(--background-color,#d7dddd)";
|
|||
const PRODUCT_DARK = "var(--primary-color,#05463d)";
|
||||
|
||||
|
||||
export const slideLayoutId = "product-overview-table-of-content-slide";
|
||||
export const slideLayoutName = "Product Overview Table of Content Slide";
|
||||
export const slideLayoutId = "table-of-content-slide";
|
||||
export const slideLayoutName = "Table of Content Slide";
|
||||
export const slideLayoutDescription =
|
||||
"A two-column table-of-content slide with section titles and numbers on a dark left panel and a large title plus description paragraph on the right panel.";
|
||||
"A two-column table of contents slide with section titles and numbers on a left panel and a title plus description paragraph on the right panel.";
|
||||
|
||||
const SectionSchema = z.object({
|
||||
title: z.string().min(4).max(14).meta({
|
||||
title: z.string().min(4).max(25).meta({
|
||||
description: "Section label shown in the left navigation column.",
|
||||
}),
|
||||
number: z.string().min(2).max(3).meta({
|
||||
description: "Section number shown beside the section label.",
|
||||
}),
|
||||
description: z.string().min(4).max(22).optional().meta({
|
||||
description: z.string().min(4).max(60).optional().meta({
|
||||
description: "Section description shown in the right column.",
|
||||
}),
|
||||
});
|
||||
|
|
@ -25,22 +25,22 @@ export const Schema = z.object({
|
|||
title: z.string().min(6).max(18).default("Table Of Content").meta({
|
||||
description: "Heading in the right-side content area.",
|
||||
}),
|
||||
description: z.string().min(50).max(120).default(
|
||||
description: z.string().min(50).max(160).default(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore."
|
||||
).meta({
|
||||
description: "Supporting descriptive paragraph under the heading.",
|
||||
}),
|
||||
sections: z
|
||||
.array(SectionSchema)
|
||||
|
||||
.max(6)
|
||||
.default([
|
||||
{ title: "SECTION TITLE", number: "01", description: "Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE", number: "02", description: "Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE", number: "03", description: "Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE", number: "04", description: "Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE", number: "05", description: "Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE", number: "06", description: "Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE SECTION TITLE", number: "01", description: "Lorem ipsum dolor sit. Lorem ipsum dolor sit. Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE SECTION TITLE", number: "02", description: "Lorem ipsum dolor sit. Lorem ipsum dolor sit. Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE SECTION TITLE", number: "03", description: "Lorem ipsum dolor sit. Lorem ipsum dolor sit. Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE SECTION TITLE", number: "04", description: "Lorem ipsum dolor sit. Lorem ipsum dolor sit. Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE SECTION TITLE", number: "05", description: "Lorem ipsum dolor sit. Lorem ipsum dolor sit. Lorem ipsum dolor sit." },
|
||||
{ title: "SECTION TITLE SECTION TITLE", number: "06", description: "Lorem ipsum dolor sit. Lorem ipsum dolor sit. Lorem ipsum dolor sit." },
|
||||
|
||||
])
|
||||
.meta({
|
||||
description: "Six rows listed in the table of contents panel.",
|
||||
|
|
@ -56,17 +56,17 @@ const TableOfContentSlide = ({ data }: { data: Partial<SchemaType> }) => {
|
|||
<>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
||||
<div
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden rounded-[24px]"
|
||||
className="relative h-[720px] w-[1280px] overflow-hidden "
|
||||
style={{
|
||||
backgroundColor: PRODUCT_BG,
|
||||
fontFamily: "var(--body-font-family,'Bricolage Grotesque')",
|
||||
}}
|
||||
>
|
||||
<div className="grid h-full grid-cols-[1fr_1fr]">
|
||||
<div className="px-[128px] pt-[69px]" style={{ backgroundColor: PRODUCT_DARK }}>
|
||||
<div className="space-y-[40px]">
|
||||
<div className="px-[56px] pt-[69px]" style={{ backgroundColor: PRODUCT_DARK }}>
|
||||
<div className={`${sections && sections?.length > 3 ? 'space-y-[28px]' : 'space-y-[40px]'}`}>
|
||||
{sections?.map((section, index) => (
|
||||
<div key={index} className="flex items-center justify-between">
|
||||
<div key={index} className="flex items-center gap-4 justify-between">
|
||||
<div>
|
||||
|
||||
<p
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue