141 lines
No EOL
6.2 KiB
TypeScript
141 lines
No EOL
6.2 KiB
TypeScript
import React from 'react'
|
|
import * as z from "zod";
|
|
import { ImageSchema, IconSchema } from '@/presentation-layouts/defaultSchemes';
|
|
|
|
export const layoutId = 'card-slide'
|
|
export const layoutName = 'Card Slide'
|
|
export const layoutDescription = 'A professional slide featuring feature cards with icons, titles, and descriptions.'
|
|
|
|
const cardSlideSchema = z.object({
|
|
title: z.string().min(3).max(100).default('Our Features').meta({
|
|
description: "Main title of the slide",
|
|
}),
|
|
subtitle: z.string().min(10).max(200).optional().meta({
|
|
description: "Optional subtitle or description",
|
|
}),
|
|
cards: z.array(z.object({
|
|
icon: IconSchema.default({
|
|
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
|
|
__icon_query__: 'Default card icon'
|
|
}).meta({
|
|
description: "Icon for the card",
|
|
}),
|
|
title: z.string().min(2).max(50).meta({
|
|
description: "Title for the card",
|
|
}),
|
|
description: z.string().min(10).max(150).meta({
|
|
description: "Description of the feature",
|
|
})
|
|
})).min(2).max(6).default([
|
|
{
|
|
icon: {
|
|
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
|
|
__icon_query__: 'Lightning fast icon'
|
|
},
|
|
title: 'Lightning Fast',
|
|
description: 'Optimized performance for quick results and seamless user experience'
|
|
},
|
|
{
|
|
icon: {
|
|
__icon_url__: 'https://cdn.pixabay.com/photo/2016/02/19/11/19/office-1209640_1280.jpg',
|
|
__icon_query__: 'Secure and safe icon'
|
|
},
|
|
title: 'Secure & Safe',
|
|
description: 'Enterprise-grade security with advanced encryption and protection'
|
|
},
|
|
{
|
|
icon: {
|
|
__icon_url__: 'https://cdn.pixabay.com/photo/2017/08/10/08/47/laptop-2619235_1280.jpg',
|
|
__icon_query__: 'Precise targeting icon'
|
|
},
|
|
title: 'Precise Targeting',
|
|
description: 'Advanced analytics to reach your exact audience with precision'
|
|
}
|
|
]).meta({
|
|
description: "List of feature cards (2-6 items)",
|
|
}),
|
|
backgroundImage: ImageSchema.optional().meta({
|
|
description: "Background image for the slide",
|
|
})
|
|
})
|
|
|
|
export const Schema = cardSlideSchema
|
|
|
|
export type CardSlideData = z.infer<typeof cardSlideSchema>
|
|
|
|
interface CardSlideLayoutProps {
|
|
data?: Partial<CardSlideData>
|
|
}
|
|
|
|
const CardSlideLayout: React.FC<CardSlideLayoutProps> = ({ data: slideData }) => {
|
|
|
|
return (
|
|
<div
|
|
className="relative w-full aspect-[16/9] flex flex-col bg-white overflow-hidden shadow-2xl border border-slate-200 print:shadow-none print:border-gray-300"
|
|
style={slideData?.backgroundImage ? {
|
|
backgroundImage: `linear-gradient(135deg, rgba(0,0,0,0.5), rgba(0,0,0,0.7)), url(${slideData.backgroundImage.__image_url__})`,
|
|
backgroundSize: 'cover',
|
|
backgroundPosition: 'center'
|
|
} : {}}
|
|
>
|
|
|
|
|
|
{/* Header section */}
|
|
<div className="text-center px-12 py-8 print:px-8 print:py-6 relative z-10">
|
|
<h1 className="text-4xl font-bold text-blue-600 mb-4 leading-tight print:text-3xl">
|
|
{slideData?.title || 'Our Features'}
|
|
</h1>
|
|
{slideData?.subtitle && (
|
|
<p className="text-lg text-gray-600 max-w-2xl mx-auto leading-relaxed print:text-base">
|
|
{slideData.subtitle}
|
|
</p>
|
|
)}
|
|
<div className="mt-4 w-24 h-1 bg-gradient-to-r from-blue-600 to-blue-800 mx-auto rounded-full"></div>
|
|
</div>
|
|
|
|
{/* Cards section */}
|
|
<div className="flex-1 px-12 pb-8 print:px-8 print:pb-6 relative z-10">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 h-full items-center">
|
|
{slideData?.cards?.map((card, index) => (
|
|
<div
|
|
key={index}
|
|
className="relative bg-white/95 backdrop-blur-sm rounded-2xl p-6 shadow-2xl border border-white/50 text-center group hover:transform hover:scale-105 transition-all duration-300 print:shadow-md print:p-4"
|
|
>
|
|
{/* Card accent */}
|
|
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-blue-600 to-blue-800" />
|
|
|
|
{/* Icon */}
|
|
<div className="mb-4 group-hover:scale-110 transition-transform duration-300">
|
|
<div className="w-16 h-16 mx-auto bg-blue-100 rounded-xl flex items-center justify-center overflow-hidden print:w-12 print:h-12">
|
|
<img
|
|
src={card.icon?.__icon_url__ || ''}
|
|
alt={card.icon?.__icon_query__ || card.title}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Title */}
|
|
<h3 className="text-xl font-bold text-blue-600 mb-3 leading-tight print:text-lg">
|
|
{card.title}
|
|
</h3>
|
|
|
|
{/* Description */}
|
|
<p className="text-gray-700 leading-relaxed text-sm print:text-xs">
|
|
{card.description}
|
|
</p>
|
|
|
|
{/* Background decoration */}
|
|
<div className="absolute bottom-0 right-0 w-16 h-16 bg-gradient-to-tl from-blue-600 to-blue-800 opacity-5 rounded-tl-full" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom decorative accent */}
|
|
<div className="absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-blue-600 to-blue-800"></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default CardSlideLayout
|