presenton/servers/nextjs/presentation-templates/professional/TableOfContentsSlide.tsx

197 lines
6.1 KiB
TypeScript

import * as z from "zod";
import { ImageSchema, IconSchema } from "../defaultSchemes";
export const layoutName = "Table of Contents Slide";
export const layoutId = "table-of-contents-slide";
export const layoutDescription = "A slide with a table of contents";
// Schema definition
export const Schema = z.object({
sectionTitle: z.string().min(3).max(30).default("TABLE OF CONTENTS").meta({
description:
"Main heading for the content overview - can be 'Agenda', 'Overview', 'Contents', or similar",
}),
sectionSubtitle: z
.string()
.min(10)
.max(60)
.default("PRESENTATION OVERVIEW AND AGENDA")
.meta({
description:
"Supporting subtitle that explains what the audience will learn or see",
}),
contentItems: z
.array(
z.object({
itemNumber: z.string().min(1).max(3),
contentTitle: z.string().min(3).max(40),
contentDescription: z.string().min(10).max(100).optional(),
})
)
.min(3)
.max(8)
.default([
{
itemNumber: "01",
contentTitle: "Introduction & Welcome",
contentDescription: "Brief overview and objectives",
},
{
itemNumber: "02",
contentTitle: "About Our Organization",
contentDescription: "Background and mission",
},
{
itemNumber: "03",
contentTitle: "Key Challenges",
contentDescription: "Current issues and opportunities",
},
{
itemNumber: "04",
contentTitle: "Our Solutions",
contentDescription: "Proposed approaches and methods",
},
{
itemNumber: "05",
contentTitle: "Implementation Plan",
contentDescription: "Timeline and next steps",
},
{
itemNumber: "06",
contentTitle: "Questions & Discussion",
contentDescription: "Interactive engagement",
},
])
.meta({
description:
"List of presentation sections with numbered sequence and brief descriptions",
}),
brandingVisual: ImageSchema.default({
__image_url__:
"https://via.placeholder.com/200x100/22C55E/FFFFFF?text=BRAND",
__image_prompt__: "Organization logo or brand visual element",
}).meta({
description:
"Logo or branding element displayed prominently for visual identity",
}),
showDecorations: z.boolean().default(true).meta({
description:
"Whether to display decorative visual elements like underlines and accents",
}),
useColumnLayout: z.boolean().default(true).meta({
description:
"Whether to arrange content items in two columns for better space utilization",
}),
});
// Type inference
type SchemaType = z.infer<typeof Schema>;
// Component definition
const TableOfContentsSlide = ({ data }: { data: Partial<SchemaType> }) => {
const {
sectionTitle,
sectionSubtitle,
contentItems,
brandingVisual,
showDecorations,
useColumnLayout,
} = data;
return (
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
{/* Main Content Area */}
<div className="h-full flex">
{/* Left Side - Content */}
<div className="w-3/5 px-16 py-12 flex flex-col justify-start">
{/* Title Section */}
<div className="mb-12">
{sectionTitle && (
<h1 className="text-3xl lg:text-4xl font-black text-teal-700 leading-tight mb-4">
{sectionTitle}
</h1>
)}
{/* Decorative underline */}
{showDecorations && (
<div className="w-32 h-1 bg-yellow-300 mb-6"></div>
)}
{sectionSubtitle && (
<p className="text-base font-medium text-gray-700 tracking-wide">
{sectionSubtitle}
</p>
)}
</div>
{/* Content Items */}
{contentItems && contentItems.length > 0 && (
<div
className={`grid ${
useColumnLayout ? "grid-cols-2" : "grid-cols-1"
} gap-x-16 gap-y-8`}
>
{contentItems.map((item, index) => (
<div key={index} className="flex items-start space-x-4">
{/* Number Circle */}
<div className="w-10 h-10 bg-yellow-200 rounded-full flex items-center justify-center flex-shrink-0">
<span className="text-teal-700 font-bold text-sm">
{item.itemNumber}
</span>
</div>
{/* Content */}
<div className="flex-1">
<h3 className="text-lg font-bold text-gray-900 mb-1">
{item.contentTitle}
</h3>
{item.contentDescription && (
<p className="text-sm text-gray-600 leading-relaxed">
{item.contentDescription}
</p>
)}
</div>
</div>
))}
</div>
)}
</div>
{/* Right Side - Branding and Visual Elements */}
<div className="w-2/5 relative bg-gray-50 flex items-center justify-center">
{/* Branding Visual */}
{brandingVisual?.__image_url__ && (
<div className="text-center">
<img
src={brandingVisual.__image_url__}
alt={brandingVisual.__image_prompt__}
className="max-w-64 max-h-32 object-contain mx-auto"
/>
</div>
)}
{/* Decorative Elements */}
{showDecorations && (
<>
{/* Decorative circles */}
<div className="absolute top-8 right-8 w-6 h-6 bg-teal-600 rounded-full opacity-60"></div>
<div className="absolute bottom-12 left-8 w-4 h-4 bg-yellow-300 rounded-full"></div>
<div className="absolute top-32 left-12 w-3 h-3 bg-teal-400 rounded-full"></div>
</>
)}
</div>
</div>
{/* Bottom accent strip */}
<div className="absolute bottom-0 left-0 right-0 h-2 bg-teal-600"></div>
</div>
);
};
export default TableOfContentsSlide;