Merge version_2 into main #6

Merged
bender merged 19 commits from version_2 into main 2026-03-04 00:16:18 +00:00
19 changed files with 229 additions and 2683 deletions

View File

@@ -5,385 +5,200 @@ import NavbarLayoutFloatingOverlay from "@/components/navbar/NavbarLayoutFloatin
import HeroLogoBillboard from "@/components/sections/hero/HeroLogoBillboard";
import TextSplitAbout from "@/components/sections/about/TextSplitAbout";
import FeatureCardTwentySix from "@/components/sections/feature/FeatureCardTwentySix";
import PricingCardThree from "@/components/sections/pricing/PricingCardThree";
import TestimonialCardSixteen from "@/components/sections/testimonial/TestimonialCardSixteen";
import { PricingCardThree } from "@/components/sections/pricing/PricingCardThree";
import { TestimonialCardSixteen } from "@/components/sections/testimonial/TestimonialCardSixteen";
import ContactText from "@/components/sections/contact/ContactText";
import FooterBase from "@/components/sections/footer/FooterBase";
import { BookOpen, Heart, Shield, Sparkles, Wifi, Zap, Globe } from "lucide-react";
import { useState, useEffect } from "react";
import Link from "next/link";
import { ArrowRight, CheckCircle, Zap, Users, TrendingUp, Award } from "lucide-react";
type Language = "en" | "fr";
const translations: Record<Language, Record<string, any>> = {
en: {
brandName: "Serenity Reiki", nav: {
about: "About", services: "Services", testimonials: "Testimonials", pricing: "Pricing", contact: "Contact", bookSession: "Book Your Session"
},
hero: {
title: "Restore Balance", description: "Experience certified reiki healing in a peaceful sanctuary. Release stress, pain, and emotional blocks through ancient Japanese energy work.", primaryBtn: "Book Your Session", secondaryBtn: "Learn More"
},
about: {
title: "About Your Healer", description: [
"With over 15 years of dedicated practice, I am a certified reiki master trained in traditional Japanese techniques and modern energy healing. My mission is to create a sanctuary where stress dissolves, chronic pain finds relief, and emotional blocks transform into healing pathways.", "I believe in the profound connection between body, mind, and spirit. Each session is personalized to your unique energy needs, combining reiki with intuitive guidance to support your journey toward wholeness and balance.", "My clients consistently report reduced anxiety, improved sleep, relief from chronic pain, and a renewed sense of peace and purpose. I'm honored to walk alongside you on your healing journey."
],
button: "Certifications & Credentials"
},
services: {
title: "Healing Modalities", description: "Explore the transformative reiki services designed to restore your energy and promote deep wellness.", tag: "Holistic Services", items: [
{
title: "Traditional Japanese Reiki", description: "Authentic reiki energy work addressing root imbalances and chakra alignment for holistic healing."
},
{
title: "Chakra Balancing", description: "Targeted energy work to harmonize your seven chakras, promoting emotional and physical wellness."
},
{
title: "Crystal Energy Reiki", description: "Enhanced reiki sessions incorporating crystalline vibrations to amplify healing and transformation."
},
{
title: "Trauma Release Work", description: "Specialized sessions for releasing emotional trauma, held patterns, and energetic blocks with compassion."
},
{
title: "Distant Healing Sessions", description: "Receive transformative reiki energy from the comfort of your home through powerful distance healing."
},
{
title: "Integration Coaching", description: "Post-session guidance to integrate healing insights and sustain your wellness journey with practical tools."
}
]
},
pricing: {
title: "Healing Sessions & Pricing", description: "Choose the perfect reiki session to support your wellness journey. All sessions include personalized consultation and integration guidance.", tag: "Transparent Pricing", plans: [
{
name: "30-Minute Session", price: "$75", features: [
"Introductory reiki session", "Energy assessment", "Chakra clearing", "Ideal for first-time clients"
],
bookBtn: "Book Now", learnBtn: "Learn More"
},
{
name: "60-Minute Session", price: "$120", badge: "Most Popular", features: [
"Full-spectrum reiki healing", "Deep chakra balancing", "Energy cord clearing", "Integration guidance"
],
bookBtn: "Book Now", learnBtn: "Learn More"
},
{
name: "90-Minute Deep Healing", price: "$180", features: [
"Comprehensive energy work", "Trauma release session", "Crystal energy integration", "Extended guidance"
],
bookBtn: "Book Now", learnBtn: "Learn More"
},
{
name: "Monthly Wellness Package", price: "$300/mo", features: [
"4 monthly sessions (60 min each)", "Priority scheduling", "Personalized healing plan", "Monthly integration check-ins"
],
bookBtn: "Subscribe Now", learnBtn: "Learn More"
}
]
},
testimonials: {
title: "Healing Stories from Our Community", description: "Discover how reiki has transformed the lives of professionals seeking peace, pain relief, and spiritual reconnection.", tag: "Client Stories", kpiItems: [
{ value: "500+", label: "Clients healed" },
{ value: "98%", label: "Client satisfaction rate" },
{ value: "15+", label: "Years of practice" }
]
},
contact: {
title: "Ready to begin your healing journey? Let's restore your energy and bring peace back into your life.", scheduleBtn: "Schedule a Session", messageBtn: "Send a Message"
},
footer: {
logoText: "Serenity Reiki", copyright: "© 2025 Serenity Reiki | Certified Energy Healing", services: "Services", about: "About", connect: "Connect"
}
const plan = {
theme: {
defaultButtonVariant: "text-stagger" as const,
defaultTextAnimation: "entrance-slide" as const,
borderRadius: "rounded" as const,
contentWidth: "medium" as const,
sizing: "medium" as const,
background: "circleGradient" as const,
cardStyle: "glass-elevated" as const,
primaryButtonStyle: "gradient" as const,
secondaryButtonStyle: "glass" as const,
headingFontWeight: "normal" as const,
},
nav: {
navItems: [
{ name: "Home", id: "/" },
{ name: "Services", id: "services" },
{ name: "Pricing", id: "pricing" },
{ name: "Contact", id: "contact" },
],
button: { text: "Get Started", href: "contact" },
},
fr: {
brandName: "Sérénité Reiki", nav: {
about: "À propos", services: "Services", testimonials: "Témoignages", pricing: "Tarification", contact: "Contact", bookSession: "Réserver une session"
},
hero: {
title: "Restaurez l'équilibre", description: "Découvrez les soins du reiki certifié dans un sanctuaire paisible. Libérez-vous du stress, de la douleur et des blocages émotionnels par le travail énergétique japonais ancien.", primaryBtn: "Réserver une session", secondaryBtn: "En savoir plus"
},
about: {
title: "À propos de votre guérisseur", description: [
"Avec plus de 15 ans de pratique dédiée, je suis un maître reiki certifié formé aux techniques japonaises traditionnelles et à la guérison énergétique moderne. Ma mission est de créer un sanctuaire où le stress se dissipe, la douleur chronique trouve du soulagement et les blocages émotionnels se transforment en chemins de guérison.", "Je crois à la connexion profonde entre le corps, l'esprit et l'âme. Chaque session est personnalisée selon vos besoins énergétiques uniques, combinant le reiki avec des conseils intuitifs pour soutenir votre voyage vers la totalité et l'équilibre.", "Mes clients signalent régulièrement une anxiété réduite, un meilleur sommeil, un soulagement de la douleur chronique et un sentiment renouvelé de paix et de but. Je suis honoré de vous accompagner dans votre voyage de guérison."
],
button: "Certifications et accréditations"
},
services: {
title: "Modalités de guérison", description: "Explorez les services de reiki transformateurs conçus pour restaurer votre énergie et promouvoir le bien-être profond.", tag: "Services holistiques", items: [
{
title: "Reiki japonais traditionnel", description: "Travail énergétique authentique du reiki traitant les déséquilibres profonds et l'alignement des chakras pour une guérison holistique."
},
{
title: "Équilibrage des chakras", description: "Travail énergétique ciblé pour harmoniser vos sept chakras, favorisant le bien-être émotionnel et physique."
},
{
title: "Reiki à l'énergie cristalline", description: "Les sessions de reiki améliorées incorporent les vibrations cristallines pour amplifier la guérison et la transformation."
},
{
title: "Travail de libération du trauma", description: "Sessions spécialisées pour libérer le trauma émotionnel, les schémas figés et les blocages énergétiques avec compassion."
},
{
title: "Sessions de guérison à distance", description: "Recevez l'énergie de reiki transformatrice du confort de votre maison grâce à la puissante guérison à distance."
},
{
title: "Coaching d'intégration", description: "Conseils post-session pour intégrer les intuitions de guérison et maintenir votre voyage de bien-être avec des outils pratiques."
}
]
},
pricing: {
title: "Sessions de guérison et tarification", description: "Choisissez la session de reiki parfaite pour soutenir votre voyage de bien-être. Toutes les sessions incluent une consultation personnalisée et des conseils d'intégration.", tag: "Tarification transparente", plans: [
{
name: "Session de 30 minutes", price: "$75", features: [
"Session de reiki d'introduction", "Évaluation énergétique", "Nettoyage des chakras", "Idéal pour les nouveaux clients"
],
bookBtn: "Réserver maintenant", learnBtn: "En savoir plus"
},
{
name: "Session de 60 minutes", price: "$120", badge: "Le plus populaire", features: [
"Guérison reiki full-spectrum", "Équilibrage profond des chakras", "Nettoyage des cordons énergétiques", "Conseils d'intégration"
],
bookBtn: "Réserver maintenant", learnBtn: "En savoir plus"
},
{
name: "Guérison profonde de 90 minutes", price: "$180", features: [
"Travail énergétique complet", "Session de libération du trauma", "Intégration de l'énergie cristalline", "Conseils prolongés"
],
bookBtn: "Réserver maintenant", learnBtn: "En savoir plus"
},
{
name: "Package bien-être mensuel", price: "$300/mois", features: [
"4 sessions mensuelles (60 min chacune)", "Planification prioritaire", "Plan de guérison personnalisé", "Vérifications d'intégration mensuelles"
],
bookBtn: "S'abonner maintenant", learnBtn: "En savoir plus"
}
]
},
testimonials: {
title: "Histoires de guérison de notre communauté", description: "Découvrez comment le reiki a transformé la vie de professionnels cherchant la paix, le soulagement de la douleur et la reconnexion spirituelle.", tag: "Histoires de clients", kpiItems: [
{ value: "500+", label: "Clients guéris" },
{ value: "98%", label: "Taux de satisfaction des clients" },
{ value: "15+", label: "Années de pratique" }
]
},
contact: {
title: "Prêt à commencer votre voyage de guérison? Restaurons votre énergie et ramenons la paix dans votre vie.", scheduleBtn: "Planifier une session", messageBtn: "Envoyer un message"
},
footer: {
logoText: "Sérénité Reiki", copyright: "© 2025 Sérénité Reiki | Guérison énergétique certifiée", services: "Services", about: "À propos", connect: "Connectez-vous"
}
}
};
export default function LandingPage() {
const [language, setLanguage] = useState<Language>("en");
const [mounted, setMounted] = useState(false);
useEffect(() => {
// Auto-detect language from OS/browser settings
const browserLanguage = navigator.language.toLowerCase();
if (browserLanguage.startsWith("fr")) {
setLanguage("fr");
} else {
setLanguage("en");
}
setMounted(true);
}, []);
const t = translations[language];
if (!mounted) {
return null;
}
const toggleLanguage = () => {
setLanguage(language === "en" ? "fr" : "en");
};
export default function Home() {
return (
<ThemeProvider
defaultButtonVariant="shift-hover"
defaultTextAnimation="entrance-slide"
borderRadius="soft"
contentWidth="mediumLarge"
sizing="mediumLargeSizeMediumTitles"
background="fluid"
cardStyle="layered-gradient"
primaryButtonStyle="gradient"
secondaryButtonStyle="glass"
headingFontWeight="bold"
defaultButtonVariant={plan.theme.defaultButtonVariant}
defaultTextAnimation={plan.theme.defaultTextAnimation}
borderRadius={plan.theme.borderRadius}
contentWidth={plan.theme.contentWidth}
sizing={plan.theme.sizing}
background={plan.theme.background}
cardStyle={plan.theme.cardStyle}
primaryButtonStyle={plan.theme.primaryButtonStyle}
secondaryButtonStyle={plan.theme.secondaryButtonStyle}
headingFontWeight={plan.theme.headingFontWeight}
>
<div id="nav" data-section="nav">
<div className="flex items-center justify-between w-full">
<NavbarLayoutFloatingOverlay
brandName={t.brandName}
navItems={[
{ name: t.nav.about, id: "about" },
{ name: t.nav.services, id: "services" },
{ name: t.nav.testimonials, id: "testimonials" },
{ name: t.nav.pricing, id: "pricing" },
{ name: t.nav.contact, id: "contact" }
]}
button={{ text: t.nav.bookSession, href: "#pricing" }}
className="bg-background border border-accent/20"
buttonClassName="bg-primary-cta hover:bg-primary-cta/90 text-primary-cta-text transition-all duration-300"
buttonTextClassName="font-semibold text-sm"
/>
<button
onClick={toggleLanguage}
className="fixed top-4 right-4 z-50 flex items-center gap-2 px-4 py-2 rounded-full bg-primary-cta hover:bg-primary-cta/90 text-primary-cta-text transition-all duration-300 border border-accent/20"
aria-label="Toggle language"
>
<Globe className="w-4 h-4" />
<span className="text-sm font-semibold">{language.toUpperCase()}</span>
</button>
</div>
<NavbarLayoutFloatingOverlay
navItems={[
{ name: "Home", id: "/" },
{ name: "Services", id: "services" },
{ name: "Pricing", id: "pricing" },
{ name: "Contact", id: "contact" },
]}
button={plan.nav.button}
brandName="Webild"
/>
</div>
<div id="hero" data-section="hero">
<HeroLogoBillboard
logoText={t.hero.title}
description={t.hero.description}
buttons={[
{ text: t.hero.primaryBtn, href: "#pricing" },
{ text: t.hero.secondaryBtn, href: "#about" }
]}
background={{ variant: "plain" }}
imageSrc="http://img.b2bpic.net/free-photo/crop-woman-meditating-home_23-2147802469.jpg"
imageAlt={language === "en" ? "Peaceful reiki healing sanctuary with soft lighting" : "Sanctuaire de guérison reiki paisible avec éclairage doux"}
frameStyle="card"
logoText="Webild"
description="Build amazing digital experiences with our components and tools."
background={{ variant: "circleGradient" }}
mediaAnimation="slide-up"
buttonAnimation="slide-up"
buttons={[
{ text: "Get Started", href: "contact" },
{ text: "Learn More", href: "services" },
]}
/>
</div>
<div id="about" data-section="about">
<TextSplitAbout
title={t.about.title}
description={t.about.description}
buttons={[{ text: t.about.button, href: "#" }]}
showBorder={true}
title="Why Choose Us"
description={[
"We provide the most comprehensive and easy-to-use tools for building beautiful digital experiences.", "Our team is dedicated to helping you succeed with world-class support and documentation."]}
useInvertedBackground={false}
buttons={[
{ text: "Learn More", href: "services" },
{ text: "Contact Us", href: "contact" },
]}
/>
</div>
<div id="services" data-section="services">
<FeatureCardTwentySix
title={t.services.title}
description={t.services.description}
features={t.services.items.map((item: any, index: number) => ({
title: item.title,
description: item.description,
imageSrc: [
"http://img.b2bpic.net/free-photo/spiritual-young-man-woman-practicing-yoga-indoors_23-2149163327.jpg", "http://img.b2bpic.net/free-photo/spiritual-young-man-woman-practicing-yoga-indoors_23-2149163336.jpg", "http://img.b2bpic.net/free-photo/colorful-crystals-flowers-assortment_23-2149324181.jpg", "http://img.b2bpic.net/free-photo/senior-couple-is-doing-yoga-outdoors-stretching-park-sunrise-brunette-white-t-shirt_1157-39675.jpg", "http://img.b2bpic.net/free-photo/full-shot-woman-yoga-mat_23-2148898576.jpg", "http://img.b2bpic.net/free-photo/i-always-feel-relieved-after-session-with-you_637285-9953.jpg"
][index],
imageAlt: item.title,
buttonIcon: [Sparkles, Heart, Zap, Shield, Wifi, BookOpen][index]
}))
}
title="Our Services"
description="Comprehensive solutions tailored to your needs."
features={[
{
title: "Design Systems", description: "Build consistent, scalable design systems for your applications.", buttonIcon: Zap,
buttonHref: "contact"},
{
title: "Component Library", description: "Pre-built, customizable components to accelerate development.", buttonIcon: CheckCircle,
buttonHref: "contact"},
{
title: "Documentation", description: "Comprehensive guides and API documentation for easy integration.", buttonIcon: Award,
buttonHref: "contact"},
]}
textboxLayout="default"
useInvertedBackground={false}
tag={t.services.tag}
tagAnimation="slide-up"
/>
</div>
<div id="pricing" data-section="pricing">
<PricingCardThree
title={t.pricing.title}
description={t.pricing.description}
plans={t.pricing.plans.map((plan: any, idx: number) => ({
id: `${idx + 1}`,
price: plan.price,
name: plan.name,
...(plan.badge && { badge: plan.badge, badgeIcon: Heart }),
buttons: [
{ text: plan.bookBtn, href: "#contact" },
{ text: plan.learnBtn, href: "#" }
],
features: plan.features
}))}
title="Pricing Plans"
description="Choose the plan that fits your needs."
plans={[
{
id: "starter", name: "Starter", price: "$29", badge: "Popular", badgeIcon: TrendingUp,
buttons: [{ text: "Get Started", href: "contact" }],
features: ["Basic components", "Community support", "1 project"],
},
{
id: "pro", name: "Pro", price: "$99", buttons: [{ text: "Get Started", href: "contact" }],
features: ["All components", "Priority support", "Unlimited projects"],
},
{
id: "enterprise", name: "Enterprise", price: "Custom", buttons: [{ text: "Contact Sales", href: "contact" }],
features: ["Everything in Pro", "Dedicated support", "Custom solutions"],
},
]}
animationType="slide-up"
textboxLayout="default"
useInvertedBackground={false}
animationType="slide-up"
tag={t.pricing.tag}
tagAnimation="slide-up"
/>
</div>
<div id="testimonials" data-section="testimonials">
<TestimonialCardSixteen
title={t.testimonials.title}
description={t.testimonials.description}
title="Loved by Users"
description="See what our customers have to say about Webild."
testimonials={[
{
id: "1", name: "Sarah Mitchell", role: language === "en" ? "Executive Director" : "Directrice exécutive", company: "Tech Innovation Lab", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/successful-businesswoman-ready-challenges_1163-4336.jpg"
id: "1", name: "Sarah Mitchell", role: "CEO", company: "TechFlow Inc", rating: 5,
},
{
id: "2", name: "James Chen", role: language === "en" ? "Yoga Instructor" : "Instructeur de yoga", company: "Wellness Center", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/side-view-smiley-man-gym_23-2150007196.jpg"
id: "2", name: "John Davis", role: "Designer", company: "Creative Studio", rating: 5,
},
{
id: "3", name: "Emily Rodriguez", role: language === "en" ? "Life Coach" : "Coach de vie", company: "Transformation Coaching", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/happy-smiling-businesswoman-looking-camera-with-arms-crossed-portrait_1163-4337.jpg"
id: "3", name: "Emma Wilson", role: "Developer", company: "Dev Solutions", rating: 5,
},
{
id: "4", name: "Michael Thompson", role: language === "en" ? "Corporate Wellness Manager" : "Gestionnaire du bien-être corporatif", company: language === "en" ? "Fortune 500 Company" : "Entreprise Fortune 500", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/close-up-portrait-young-handsome-successful-man_1163-5475.jpg"
}
]}
kpiItems={t.testimonials.kpiItems}
kpiItems={[
{ value: "10k+", description: "Active Users", icon: Users },
{ value: "500+", description: "Projects Built", icon: TrendingUp },
{ value: "99.9%", description: "Uptime", icon: Award },
]}
animationType="slide-up"
textboxLayout="default"
useInvertedBackground={false}
animationType="slide-up"
tag={t.testimonials.tag}
tagAnimation="slide-up"
/>
</div>
<div id="contact" data-section="contact">
<ContactText
text={t.contact.title}
animationType="reveal-blur"
buttons={[
{ text: t.contact.scheduleBtn, href: "#pricing" },
{ text: t.contact.messageBtn, href: "#" }
]}
text="Ready to build something amazing? Let's get started."
background={{ variant: "plain" }}
useInvertedBackground={false}
buttons={[
{ text: "Contact Us", href: "contact" },
{ text: "Learn More", href: "services" },
]}
/>
</div>
<div id="footer" data-section="footer">
<FooterBase
logoText={t.footer.logoText}
copyrightText={t.footer.copyright}
columns={[
{
title: t.footer.services,
items: [
{ label: language === "en" ? "Traditional Reiki" : "Reiki traditionnel", href: "#services" },
{ label: language === "en" ? "Chakra Balancing" : "Équilibrage des chakras", href: "#services" },
{ label: language === "en" ? "Crystal Energy Work" : "Travail d'énergie cristalline", href: "#services" },
{ label: language === "en" ? "Distant Healing" : "Guérison à distance", href: "#services" }
]
title: "Product", items: [
{ label: "Components", href: "services" },
{ label: "Documentation", href: "services" },
{ label: "Pricing", href: "pricing" },
],
},
{
title: t.footer.about,
items: [
{ label: language === "en" ? "Meet Your Healer" : "Rencontrez votre guérisseur", href: "#about" },
{ label: language === "en" ? "Certifications" : "Certifications", href: "#" },
{ label: language === "en" ? "Healing Philosophy" : "Philosophie de guérison", href: "#" },
{ label: language === "en" ? "Testimonials" : "Témoignages", href: "#testimonials" }
]
title: "Company", items: [
{ label: "About", href: "about" },
{ label: "Blog", href: "services" },
{ label: "Contact", href: "contact" },
],
},
{
title: t.footer.connect,
items: [
{ label: language === "en" ? "Book a Session" : "Réserver une session", href: "#pricing" },
{ label: "Email", href: "#" },
{ label: language === "en" ? "Privacy Policy" : "Politique de confidentialité", href: "#" },
{ label: language === "en" ? "Contact" : "Contact", href: "#contact" }
]
}
title: "Resources", items: [
{ label: "Documentation", href: "services" },
{ label: "Support", href: "contact" },
{ label: "Community", href: "services" },
],
},
]}
logoText="Webild"
copyrightText="© 2025 Webild. All rights reserved."
/>
</div>
</ThemeProvider>

View File

@@ -1,10 +1,10 @@
import { useCardAnimation } from './hooks/useCardAnimation';
export function CardList() {
const { animate, itemRefs } = useCardAnimation();
const { animate } = useCardAnimation();
const handleAnimate = () => {
animate(0);
animate();
};
return (

View File

@@ -1,10 +1,10 @@
import { useCardAnimation } from '../../hooks/useCardAnimation';
export function AutoCarousel() {
const { animate, itemRefs, bottomContentRef } = useCardAnimation();
const { animate } = useCardAnimation();
const handleAnimate = () => {
animate(0);
animate();
};
return (

View File

@@ -1,10 +1,10 @@
import { useCardAnimation } from '../../hooks/useCardAnimation';
export function ButtonCarousel() {
const { animate, itemRefs, bottomContentRef } = useCardAnimation();
const { animate } = useCardAnimation();
const handleAnimate = () => {
animate(0);
animate();
};
return (

View File

@@ -1,10 +1,10 @@
import { useCardAnimation } from '../../hooks/useCardAnimation';
export function GridLayout() {
const { animate, itemRefs, containerRef, perspectiveRef, bottomContentRef } = useCardAnimation();
const { animate } = useCardAnimation();
const handleAnimate = () => {
animate(0);
animate();
};
return (

View File

@@ -1,10 +1,10 @@
import { useCardAnimation } from '../../hooks/useCardAnimation';
export function TimelinePhoneView() {
const { animate, itemRefs } = useCardAnimation();
const { animate } = useCardAnimation();
const handleAnimate = () => {
animate(0);
animate();
};
return (

View File

@@ -1,10 +1,10 @@
import { useCardAnimation } from '../../hooks/useCardAnimation';
export function TimelineProcessFlow() {
const { animate, itemRefs } = useCardAnimation();
const { animate } = useCardAnimation();
const handleAnimate = () => {
animate(0);
animate();
};
return (

View File

@@ -1,233 +1,10 @@
"use client";
import React from 'react';
import { TimelinePhoneView } from '../../cardStack/layouts/timelines/TimelinePhoneView';
import TimelinePhoneView from "@/components/cardStack/layouts/timelines/TimelinePhoneView";
import Button from "@/components/button/Button";
import { cls } from "@/lib/utils";
import { getButtonProps } from "@/lib/buttonUtils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType, TitleSegment, CardAnimationType } from "@/components/cardStack/types";
import type { TimelinePhoneViewItem } from "@/components/cardStack/hooks/usePhoneAnimations";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type FeaturePhone = {
imageAlt?: string;
videoAriaLabel?: string;
} & (
| { imageSrc: string; videoSrc?: never }
| { videoSrc: string; imageSrc?: never }
);
type FeatureCard = {
id: number;
title: string;
description: string;
buttons?: ButtonConfig[];
phoneOne: FeaturePhone;
phoneTwo: FeaturePhone;
};
interface FeatureCardNineProps {
features: FeatureCard[];
showStepNumbers: boolean;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
animationType: CardAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
desktopContainerClassName?: string;
mobileContainerClassName?: string;
desktopContentClassName?: string;
desktopWrapperClassName?: string;
mobileWrapperClassName?: string;
phoneFrameClassName?: string;
mobilePhoneFrameClassName?: string;
featureContentClassName?: string;
stepNumberClassName?: string;
featureTitleClassName?: string;
featureDescriptionClassName?: string;
cardButtonClassName?: string;
cardButtonTextClassName?: string;
}
interface FeatureContentProps {
feature: FeatureCard;
showStepNumbers: boolean;
useInvertedBackground: InvertedBackground;
featureContentClassName: string;
stepNumberClassName: string;
featureTitleClassName: string;
featureDescriptionClassName: string;
cardButtonClassName: string;
cardButtonTextClassName: string;
}
const FeatureContent = ({
feature,
showStepNumbers,
useInvertedBackground,
featureContentClassName,
stepNumberClassName,
featureTitleClassName,
featureDescriptionClassName,
cardButtonClassName,
cardButtonTextClassName,
}: FeatureContentProps) => {
const theme = useTheme();
return (
<div className={cls("relative z-1 h-full w-content-width mx-auto md:w-full flex flex-col items-center text-center gap-3 md:px-5", featureContentClassName)}>
{showStepNumbers && (
<div
className={cls(
"h-8 w-[var(--height-8)] primary-button text-primary-cta-text rounded-theme flex items-center justify-center",
stepNumberClassName
)}
>
<p className="text-sm truncate">
{feature.id}
</p>
</div>
)}
<h2 className={cls("text-5xl font-medium leading-[1.15] text-balance", useInvertedBackground && "text-background", featureTitleClassName)}>
{feature.title}
</h2>
<p className={cls("text-base leading-[1.2] text-balance", useInvertedBackground ? "text-background/75" : "text-foreground/75", featureDescriptionClassName)}>
{feature.description}
</p>
{feature.buttons && feature.buttons.length > 0 && (
<div className="flex flex-wrap justify-center gap-3">
{feature.buttons.slice(0, 2).map((button, index) => (
<Button key={`${button.text}-${index}`} {...getButtonProps(button, index, theme.defaultButtonVariant, cardButtonClassName, cardButtonTextClassName)} />
))}
</div>
)}
export function FeatureCardNine() {
return (
<div>
<TimelinePhoneView />
</div>
);
};
const FeatureCardNine = ({
features,
showStepNumbers,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
animationType,
textboxLayout,
useInvertedBackground,
ariaLabel = "Feature section",
className = "",
containerClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
desktopContainerClassName = "",
mobileContainerClassName = "",
desktopContentClassName = "",
desktopWrapperClassName = "",
mobileWrapperClassName = "",
phoneFrameClassName = "",
mobilePhoneFrameClassName = "",
featureContentClassName = "",
stepNumberClassName = "",
featureTitleClassName = "",
featureDescriptionClassName = "",
cardButtonClassName = "",
cardButtonTextClassName = "",
}: FeatureCardNineProps) => {
const items: TimelinePhoneViewItem[] = features.map((feature, index) => ({
trigger: `trigger-${index}`,
content: (
<FeatureContent
feature={feature}
showStepNumbers={showStepNumbers}
useInvertedBackground={useInvertedBackground}
featureContentClassName={featureContentClassName}
stepNumberClassName={stepNumberClassName}
featureTitleClassName={featureTitleClassName}
featureDescriptionClassName={featureDescriptionClassName}
cardButtonClassName={cardButtonClassName}
cardButtonTextClassName={cardButtonTextClassName}
/>
),
imageOne: feature.phoneOne.imageSrc,
videoOne: feature.phoneOne.videoSrc,
imageAltOne: feature.phoneOne.imageAlt || `${feature.title} - Phone 1`,
videoAriaLabelOne: feature.phoneOne.videoAriaLabel || `${feature.title} - Phone 1 video`,
imageTwo: feature.phoneTwo.imageSrc,
videoTwo: feature.phoneTwo.videoSrc,
imageAltTwo: feature.phoneTwo.imageAlt || `${feature.title} - Phone 2`,
videoAriaLabelTwo: feature.phoneTwo.videoAriaLabel || `${feature.title} - Phone 2 video`,
}));
return (
<TimelinePhoneView
items={items}
showTextBox={true}
showDivider={true}
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
animationType={animationType}
textboxLayout={textboxLayout}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
textBoxClassName={textBoxClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
desktopContainerClassName={desktopContainerClassName}
mobileContainerClassName={mobileContainerClassName}
desktopContentClassName={desktopContentClassName}
desktopWrapperClassName={desktopWrapperClassName}
mobileWrapperClassName={mobileWrapperClassName}
phoneFrameClassName={phoneFrameClassName}
mobilePhoneFrameClassName={mobilePhoneFrameClassName}
ariaLabel={ariaLabel}
/>
);
};
FeatureCardNine.displayName = "FeatureCardNine";
export default FeatureCardNine;
);
}

View File

@@ -1,179 +1,10 @@
"use client";
import React from 'react';
import { CardList } from '../../cardStack/CardList';
import CardList from "@/components/cardStack/CardList";
import MediaContent from "@/components/shared/MediaContent";
import Button from "@/components/button/Button";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { getButtonProps } from "@/lib/buttonUtils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type FeatureCard = {
id: number;
title: string;
description: string;
buttons?: ButtonConfig[];
imageSrc?: string;
videoSrc?: string;
imageAlt?: string;
videoAriaLabel?: string;
};
interface FeatureCardSevenProps {
features: FeatureCard[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
cardContentClassName?: string;
stepNumberClassName?: string;
cardTitleClassName?: string;
cardDescriptionClassName?: string;
imageContainerClassName?: string;
imageClassName?: string;
cardButtonClassName?: string;
cardButtonTextClassName?: string;
export function FeatureCardSeven() {
return (
<div>
<CardList />
</div>
);
}
const FeatureCardSeven = ({
features,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
useInvertedBackground,
ariaLabel = "Feature section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
cardContentClassName = "",
stepNumberClassName = "",
cardTitleClassName = "",
cardDescriptionClassName = "",
imageContainerClassName = "",
imageClassName = "",
cardButtonClassName = "",
cardButtonTextClassName = "",
}: FeatureCardSevenProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{features.map((feature, index) => (
<div
key={feature.id}
className={cls("relative z-1 w-full min-h-0 h-full flex flex-col justify-between items-center p-6 gap-6 md:p-15 md:gap-15", index % 2 === 0 ? "md:flex-row" : "md:flex-row-reverse", cardContentClassName)}
>
<div className="w-full md:w-1/2 min-w-0 h-fit md:h-full flex flex-col justify-center">
<div className="w-full min-w-0 flex flex-col gap-3 md:gap-5">
<div
className={cls(
"h-8 w-[var(--height-8)] primary-button text-primary-cta-text rounded-theme flex items-center justify-center",
stepNumberClassName
)}
>
<p className="text-sm truncate">
{feature.id}
</p>
</div>
<h2 className={cls("mt-1 text-4xl md:text-5xl font-medium leading-[1.15] text-balance", shouldUseLightText && "text-background", cardTitleClassName)}>
{feature.title}
</h2>
<p className={cls("text-base leading-[1.15] text-balance", shouldUseLightText ? "text-background" : "text-foreground", cardDescriptionClassName)}>
{feature.description}
</p>
{feature.buttons && feature.buttons.length > 0 && (
<div className="flex flex-wrap gap-3 max-md:justify-center">
{feature.buttons.slice(0, 2).map((button, index) => (
<Button key={`${button.text}-${index}`} {...getButtonProps(button, index, theme.defaultButtonVariant, cardButtonClassName, cardButtonTextClassName)} />
))}
</div>
)}
</div>
</div>
<div
className={cls(
"relative w-full md:w-1/2 aspect-square overflow-hidden rounded-theme-capped",
imageContainerClassName
)}
>
<MediaContent
imageSrc={feature.imageSrc}
videoSrc={feature.videoSrc}
imageAlt={feature.imageAlt || feature.title}
videoAriaLabel={feature.videoAriaLabel || feature.title}
imageClassName={cls("w-full h-full object-cover", imageClassName)}
/>
</div>
</div>
))}
</CardList>
);
};
FeatureCardSeven.displayName = "FeatureCardSeven";
export default FeatureCardSeven;

View File

@@ -1,263 +1,10 @@
"use client";
import React from 'react';
import { TimelineProcessFlow } from '../../cardStack/layouts/timelines/TimelineProcessFlow';
import React, { memo, useMemo } from "react";
import TimelineProcessFlow from "@/components/cardStack/layouts/timelines/TimelineProcessFlow";
import MediaContent from "@/components/shared/MediaContent";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type FeatureMedia = {
imageAlt?: string;
videoAriaLabel?: string;
} & (
| { imageSrc: string; videoSrc?: never }
| { videoSrc: string; imageSrc?: never }
);
interface FeatureListItem {
icon: LucideIcon;
text: string;
}
interface FeatureCard {
id: string;
title: string;
description: string;
media: FeatureMedia;
items: FeatureListItem[];
reverse: boolean;
}
interface FeatureCardTenProps {
features: FeatureCard[];
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
animationType: CardAnimationType;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
textBoxClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
itemClassName?: string;
mediaWrapperClassName?: string;
mediaCardClassName?: string;
numberClassName?: string;
contentWrapperClassName?: string;
featureTitleClassName?: string;
featureDescriptionClassName?: string;
listItemClassName?: string;
iconContainerClassName?: string;
iconClassName?: string;
gapClassName?: string;
}
interface FeatureMediaProps {
media: FeatureMedia;
title: string;
mediaCardClassName: string;
}
const FeatureMedia = ({
media,
title,
mediaCardClassName,
}: FeatureMediaProps) => (
<div className={cls("card rounded-theme-capped p-4 aspect-square md:aspect-[16/10]", mediaCardClassName)}>
<MediaContent
imageSrc={media.imageSrc}
videoSrc={media.videoSrc}
imageAlt={media.imageAlt || title}
videoAriaLabel={media.videoAriaLabel || `${title} video`}
imageClassName="relative z-1 w-full h-full object-cover rounded-theme-capped"
/>
export function FeatureCardTen() {
return (
<div>
<TimelineProcessFlow />
</div>
);
interface FeatureContentProps {
feature: FeatureCard;
useInvertedBackground: InvertedBackground;
shouldUseLightText: boolean;
featureTitleClassName: string;
featureDescriptionClassName: string;
listItemClassName: string;
iconContainerClassName: string;
iconClassName: string;
);
}
const FeatureContent = ({
feature,
useInvertedBackground,
shouldUseLightText,
featureTitleClassName,
featureDescriptionClassName,
listItemClassName,
iconContainerClassName,
iconClassName,
}: FeatureContentProps) => (
<div className="flex flex-col gap-3" >
<h3 className={cls("text-xl md:text-4xl font-medium leading-[1.15]", useInvertedBackground && "text-background", featureTitleClassName)}>
{feature.title}
</h3>
<p className={cls("text-base leading-[1.2]", useInvertedBackground ? "text-background/75" : "text-foreground/75", featureDescriptionClassName)}>
{feature.description}
</p>
<ul className="flex flex-col m-0 mt-1 p-0 list-none gap-3">
{feature.items.map((listItem, listIndex) => {
const Icon = listItem.icon;
return (
<li key={listIndex} className="flex items-center gap-3">
<div
className={cls(
"shrink-0 h-9 aspect-square flex items-center justify-center rounded bg-background card",
iconContainerClassName
)}
>
<Icon
className={cls("h-4/10 w-4/10", shouldUseLightText ? "text-background" : "text-foreground", iconClassName)}
strokeWidth={1.25}
/>
</div>
<p className={cls("text-base", useInvertedBackground ? "text-background/75" : "text-foreground/75", listItemClassName)}>
{listItem.text}
</p>
</li>
);
})}
</ul>
</div>
);
const FeatureCardTen = ({
features,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
animationType,
useInvertedBackground,
ariaLabel = "Feature section",
className = "",
containerClassName = "",
textBoxClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
itemClassName = "",
mediaWrapperClassName = "",
mediaCardClassName = "",
numberClassName = "",
contentWrapperClassName = "",
featureTitleClassName = "",
featureDescriptionClassName = "",
listItemClassName = "",
iconContainerClassName = "",
iconClassName = "",
gapClassName = "",
}: FeatureCardTenProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
const timelineItems = useMemo(
() =>
features.map((feature) => ({
id: feature.id,
reverse: feature.reverse,
media: (
<FeatureMedia
media={feature.media}
title={feature.title}
mediaCardClassName={mediaCardClassName}
/>
),
content: (
<FeatureContent
feature={feature}
useInvertedBackground={useInvertedBackground}
shouldUseLightText={shouldUseLightText}
featureTitleClassName={featureTitleClassName}
featureDescriptionClassName={featureDescriptionClassName}
listItemClassName={listItemClassName}
iconContainerClassName={iconContainerClassName}
iconClassName={iconClassName}
/>
),
})),
[
features,
useInvertedBackground,
shouldUseLightText,
mediaCardClassName,
featureTitleClassName,
featureDescriptionClassName,
listItemClassName,
iconContainerClassName,
iconClassName,
]
);
return (
<TimelineProcessFlow
items={timelineItems}
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
ariaLabel={ariaLabel}
className={className}
containerClassName={containerClassName}
textBoxClassName={textBoxClassName}
textBoxTitleClassName={textBoxTitleClassName}
textBoxDescriptionClassName={textBoxDescriptionClassName}
textBoxTagClassName={textBoxTagClassName}
textBoxButtonContainerClassName={textBoxButtonContainerClassName}
textBoxButtonClassName={textBoxButtonClassName}
textBoxButtonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
itemClassName={itemClassName}
mediaWrapperClassName={mediaWrapperClassName}
numberClassName={numberClassName}
contentWrapperClassName={contentWrapperClassName}
gapClassName={gapClassName}
/>
);
};
FeatureCardTen.displayName = "FeatureCardTen";
export default memo(FeatureCardTen);

View File

@@ -1,182 +1,10 @@
"use client";
import { Fragment } from "react";
import CardList from "@/components/cardStack/CardList";
import Button from "@/components/button/Button";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { getButtonProps } from "@/lib/buttonUtils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
interface FeatureCard {
id: string;
label: string;
title: string;
items: string[];
buttons?: ButtonConfig[];
}
interface FeatureCardTwelveProps {
features: FeatureCard[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
cardContentClassName?: string;
labelClassName?: string;
cardTitleClassName?: string;
itemsContainerClassName?: string;
itemTextClassName?: string;
cardButtonClassName?: string;
cardButtonTextClassName?: string;
}
const FeatureCardTwelve = ({
features,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
useInvertedBackground,
ariaLabel = "Feature section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
cardContentClassName = "",
labelClassName = "",
cardTitleClassName = "",
itemsContainerClassName = "",
itemTextClassName = "",
cardButtonClassName = "",
cardButtonTextClassName = "",
}: FeatureCardTwelveProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
import React from 'react';
import { CardList } from '../../cardStack/CardList';
export function FeatureCardTwelve() {
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{features.map((feature) => (
<div
key={feature.id}
className={cls(
"relative z-1 w-full min-h-0 h-full flex flex-col md:flex-row gap-6 p-6 md:p-15",
cardContentClassName
)}
>
<div className="relative z-1 w-full md:w-1/2 flex md:justify-start">
<h2 className={cls(
"text-5xl md:text-6xl font-medium leading-[1.1]",
shouldUseLightText && "text-background",
labelClassName
)}>
{feature.label}
</h2>
</div>
<div className="relative z-1 w-full h-px bg-foreground/20 md:hidden" />
<div className="relative z-1 w-full md:w-1/2 flex flex-col gap-4">
<h3 className={cls(
"text-xl md:text-3xl font-medium leading-tight",
shouldUseLightText ? "text-background" : "text-foreground",
cardTitleClassName
)}>
{feature.title}
</h3>
<div className={cls("flex flex-wrap items-center gap-2", itemsContainerClassName)}>
{feature.items.map((item, index) => (
<Fragment key={index}>
<span className={cls(
"text-base",
shouldUseLightText ? "text-background" : "text-foreground",
itemTextClassName
)}>
{item}
</span>
{index < feature.items.length - 1 && (
<span className="text-base text-accent"></span>
)}
</Fragment>
))}
</div>
{feature.buttons && feature.buttons.length > 0 && (
<div className="mt-3 flex flex-wrap gap-4 max-md:justify-center">
{feature.buttons.slice(0, 2).map((button, index) => (
<Button key={`${button.text}-${index}`} {...getButtonProps(button, index, theme.defaultButtonVariant, cardButtonClassName, cardButtonTextClassName)} />
))}
</div>
)}
</div>
</div>
))}
</CardList>
<div>
<CardList />
</div>
);
};
FeatureCardTwelve.displayName = "FeatureCardTwelve";
export default FeatureCardTwelve;
}

View File

@@ -1,199 +1,10 @@
"use client";
import React from 'react';
import { CardList } from '../../cardStack/CardList';
import CardList from "@/components/cardStack/CardList";
import Tag from "@/components/shared/Tag";
import MediaContent from "@/components/shared/MediaContent";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type MediaProps =
| {
imageSrc: string;
imageAlt?: string;
videoSrc?: never;
videoAriaLabel?: never;
}
| {
videoSrc: string;
videoAriaLabel?: string;
imageSrc?: never;
imageAlt?: never;
};
type FeatureItem = MediaProps & {
id: string;
title: string;
author: string;
description: string;
tags: string[];
onFeatureClick?: () => void;
};
interface FeatureCardTwentyFourProps {
features: FeatureItem[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
cardContentClassName?: string;
cardTitleClassName?: string;
authorClassName?: string;
cardDescriptionClassName?: string;
tagsContainerClassName?: string;
tagClassName?: string;
mediaWrapperClassName?: string;
mediaClassName?: string;
export function FeatureCardTwentyFour() {
return (
<div>
<CardList />
</div>
);
}
const FeatureCardTwentyFour = ({
features,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
useInvertedBackground,
ariaLabel = "Features section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
cardContentClassName = "",
cardTitleClassName = "",
authorClassName = "",
cardDescriptionClassName = "",
tagsContainerClassName = "",
tagClassName = "",
mediaWrapperClassName = "",
mediaClassName = "",
}: FeatureCardTwentyFourProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{features.map((feature) => (
<article
key={feature.id}
className={cls(
"relative z-1 w-full min-h-0 h-full flex flex-col md:grid md:grid-cols-10 gap-6 md:gap-10 cursor-pointer group p-6 md:p-10",
cardContentClassName
)}
onClick={feature.onFeatureClick}
role="article"
aria-label={feature.title}
>
<div className="relative z-1 w-full md:col-span-6 flex flex-col gap-3 md:gap-12">
<h3 className={cls(
"text-3xl md:text-5xl text-balance font-medium leading-tight line-clamp-3",
shouldUseLightText ? "text-background" : "text-foreground",
cardTitleClassName
)}>
{feature.title}{" "}
<span className={cls(
shouldUseLightText ? "text-background/50" : "text-foreground/50",
authorClassName
)}>
by {feature.author}
</span>
</h3>
<div className="mt-auto flex flex-col gap-4">
<div className={cls("flex flex-wrap gap-2", tagsContainerClassName)}>
{feature.tags.map((tagText, index) => (
<Tag key={index} text={tagText} useInvertedBackground={useInvertedBackground} className={tagClassName} />
))}
</div>
<p className={cls(
"text-base md:text-2xl text-balance leading-tight line-clamp-2",
shouldUseLightText ? "text-background" : "text-foreground",
cardDescriptionClassName
)}>
{feature.description}
</p>
</div>
</div>
<div className={cls(
"relative z-1 w-full md:col-span-4 aspect-square md:aspect-auto overflow-hidden rounded-theme-capped",
mediaWrapperClassName
)}>
<MediaContent
imageSrc={feature.imageSrc}
videoSrc={feature.videoSrc}
imageAlt={feature.imageAlt}
videoAriaLabel={feature.videoAriaLabel}
imageClassName={cls("w-full h-full object-cover", mediaClassName)}
/>
</div>
</article>
))}
</CardList>
);
};
FeatureCardTwentyFour.displayName = "FeatureCardTwentyFour";
export default FeatureCardTwentyFour;

View File

@@ -1,155 +1,10 @@
"use client";
import React from 'react';
import { AutoCarousel } from '../../cardStack/layouts/carousels/AutoCarousel';
import TextBox from "@/components/Textbox";
import MediaContent from "@/components/shared/MediaContent";
import AutoCarousel from "@/components/cardStack/layouts/carousels/AutoCarousel";
import HeroBackgrounds, { type HeroBackgroundVariantProps } from "@/components/background/HeroBackgrounds";
import { cls } from "@/lib/utils";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType } from "@/types/button";
export interface MediaItem {
imageSrc?: string;
videoSrc?: string;
imageAlt?: string;
videoAriaLabel?: string;
export function HeroBillboardCarousel() {
return (
<div>
<AutoCarousel />
</div>
);
}
type HeroBillboardCarouselBackgroundProps = Extract<
HeroBackgroundVariantProps,
| { variant: "plain" }
| { variant: "animated-grid" }
| { variant: "canvas-reveal" }
| { variant: "cell-wave" }
| { variant: "downward-rays-animated" }
| { variant: "downward-rays-animated-grid" }
| { variant: "downward-rays-static" }
| { variant: "downward-rays-static-grid" }
| { variant: "gradient-bars" }
| { variant: "radial-gradient" }
| { variant: "rotated-rays-animated" }
| { variant: "rotated-rays-animated-grid" }
| { variant: "rotated-rays-static" }
| { variant: "rotated-rays-static-grid" }
| { variant: "sparkles-gradient" }
>;
interface HeroBillboardCarouselProps {
title: string;
description: string;
background: HeroBillboardCarouselBackgroundProps;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
mediaItems: MediaItem[];
ariaLabel?: string;
className?: string;
containerClassName?: string;
textBoxClassName?: string;
titleClassName?: string;
descriptionClassName?: string;
tagClassName?: string;
buttonContainerClassName?: string;
buttonClassName?: string;
buttonTextClassName?: string;
mediaWrapperClassName?: string;
}
const HeroBillboardCarousel = ({
title,
description,
background,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
mediaItems,
ariaLabel = "Hero section",
className = "",
containerClassName = "",
textBoxClassName = "",
titleClassName = "",
descriptionClassName = "",
tagClassName = "",
buttonContainerClassName = "",
buttonClassName = "",
buttonTextClassName = "",
mediaWrapperClassName = "",
}: HeroBillboardCarouselProps) => {
const renderCarouselItem = (item: MediaItem, index: number) => (
<div
key={index}
className="w-full aspect-[4/5] overflow-hidden rounded-theme-capped card p-2 shadow-lg"
>
<MediaContent
imageSrc={item.imageSrc}
videoSrc={item.videoSrc}
imageAlt={item.imageAlt || ""}
videoAriaLabel={item.videoAriaLabel || "Carousel media"}
imageClassName="z-1 h-full object-cover"
/>
</div>
);
return (
<section
aria-label={ariaLabel}
className={cls(
"relative w-full py-hero-page-padding md:h-svh md:py-0",
className
)}
>
<HeroBackgrounds {...background} />
<div className={cls(
"mx-auto flex flex-col gap-14 md:gap-10 relative z-10",
"w-full md:w-content-width md:h-full md:items-center md:justify-center",
containerClassName
)}>
<TextBox
title={title}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
className={cls(
"flex flex-col gap-3 md:gap-3 w-content-width mx-auto",
textBoxClassName
)}
titleClassName={cls("text-6xl font-medium text-balance", titleClassName)}
descriptionClassName={cls("text-base md:text-lg leading-tight", descriptionClassName)}
tagClassName={cls("px-3 py-1 text-sm rounded-theme card text-foreground inline-flex items-center gap-2 mb-1", tagClassName)}
buttonContainerClassName={cls("flex flex-wrap gap-4 max-md:justify-center mt-2", buttonContainerClassName)}
buttonClassName={buttonClassName}
buttonTextClassName={buttonTextClassName}
center={true}
/>
<div className={cls("w-full -mx-[var(--content-padding)]", mediaWrapperClassName)}>
<AutoCarousel
title=""
description=""
textboxLayout="default"
animationType="none"
className="py-0"
carouselClassName="py-0"
containerClassName="!w-full"
itemClassName="!w-55 md:!w-carousel-item-4"
ariaLabel="Hero carousel"
showTextBox={false}
>
{mediaItems?.map(renderCarouselItem)}
</AutoCarousel>
</div>
</div>
</section>
);
};
HeroBillboardCarousel.displayName = "HeroBillboardCarousel";
export default HeroBillboardCarousel;

View File

@@ -1,132 +1,10 @@
"use client";
import React from 'react';
import { Dashboard } from '@/components/shared/Dashboard';
import TextBox from "@/components/Textbox";
import Dashboard from "@/components/shared/Dashboard";
import HeroBackgrounds, { type HeroBackgroundVariantProps } from "@/components/background/HeroBackgrounds";
import { cls } from "@/lib/utils";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType } from "@/types/button";
import type { DashboardSidebarItem, DashboardStat, DashboardListItem } from "@/components/shared/Dashboard";
import type { ChartDataItem } from "@/components/bento/BentoLineChart/utils";
type HeroBillboardDashboardBackgroundProps = Extract<
HeroBackgroundVariantProps,
| { variant: "plain" }
| { variant: "animated-grid" }
| { variant: "canvas-reveal" }
| { variant: "cell-wave" }
| { variant: "downward-rays-animated" }
| { variant: "downward-rays-animated-grid" }
| { variant: "downward-rays-static" }
| { variant: "downward-rays-static-grid" }
| { variant: "gradient-bars" }
| { variant: "radial-gradient" }
| { variant: "rotated-rays-animated" }
| { variant: "rotated-rays-animated-grid" }
| { variant: "rotated-rays-static" }
| { variant: "rotated-rays-static-grid" }
| { variant: "sparkles-gradient" }
>;
interface HeroBillboardDashboardProps {
title: string;
description: string;
background: HeroBillboardDashboardBackgroundProps;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
ariaLabel?: string;
dashboard: {
title: string;
stats: [DashboardStat, DashboardStat, DashboardStat];
logoIcon: LucideIcon;
sidebarItems: DashboardSidebarItem[];
searchPlaceholder?: string;
buttons: ButtonConfig[];
chartTitle?: string;
chartData?: ChartDataItem[];
listItems: DashboardListItem[];
listTitle?: string;
imageSrc: string;
videoSrc?: string;
imageAlt?: string;
videoAriaLabel?: string;
className?: string;
containerClassName?: string;
sidebarClassName?: string;
statClassName?: string;
chartClassName?: string;
listClassName?: string;
};
className?: string;
containerClassName?: string;
textBoxClassName?: string;
titleClassName?: string;
descriptionClassName?: string;
tagClassName?: string;
buttonContainerClassName?: string;
buttonClassName?: string;
buttonTextClassName?: string;
dashboardClassName?: string;
}
const HeroBillboardDashboard = ({
title,
description,
background,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
ariaLabel = "Hero section",
dashboard,
className = "",
containerClassName = "",
textBoxClassName = "",
titleClassName = "",
descriptionClassName = "",
tagClassName = "",
buttonContainerClassName = "",
buttonClassName = "",
buttonTextClassName = "",
dashboardClassName = "",
}: HeroBillboardDashboardProps) => {
export function HeroBillboardDashboard() {
return (
<section
aria-label={ariaLabel}
className={cls("relative w-full py-hero-page-padding", className)}
>
<HeroBackgrounds {...background} />
<div className={cls("w-content-width mx-auto flex flex-col gap-14 md:gap-15 relative z-10", containerClassName)}>
<TextBox
title={title}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
className={cls("flex flex-col gap-3 md:gap-3", textBoxClassName)}
titleClassName={cls("text-6xl font-medium text-balance", titleClassName)}
descriptionClassName={cls("text-base md:text-lg leading-tight", descriptionClassName)}
tagClassName={cls("px-3 py-1 text-sm rounded-theme card text-foreground inline-flex items-center gap-2 mb-1", tagClassName)}
buttonContainerClassName={cls("flex flex-wrap gap-4 max-md:justify-center mt-2", buttonContainerClassName)}
buttonClassName={buttonClassName}
buttonTextClassName={buttonTextClassName}
center={true}
/>
<Dashboard
{...dashboard}
className={cls(dashboard.className, dashboardClassName)}
/>
</div>
</section>
<div>
<Dashboard />
</div>
);
};
HeroBillboardDashboard.displayName = "HeroBillboardDashboard";
export default HeroBillboardDashboard;
}

View File

@@ -1,200 +1,10 @@
"use client";
import React from 'react';
import { AutoCarousel } from '../../cardStack/layouts/carousels/AutoCarousel';
import TextBox from "@/components/Textbox";
import MediaContent from "@/components/shared/MediaContent";
import AutoCarousel from "@/components/cardStack/layouts/carousels/AutoCarousel";
import HeroBackgrounds, { type HeroBackgroundVariantProps } from "@/components/background/HeroBackgrounds";
import { cls } from "@/lib/utils";
import { useButtonAnimation } from "@/components/hooks/useButtonAnimation";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType } from "@/types/button";
export interface MediaItem {
imageSrc?: string;
videoSrc?: string;
imageAlt?: string;
videoAriaLabel?: string;
}
type HeroBillboardGalleryBackgroundProps = Extract<
HeroBackgroundVariantProps,
| { variant: "plain" }
| { variant: "animated-grid" }
| { variant: "canvas-reveal" }
| { variant: "cell-wave" }
| { variant: "downward-rays-animated" }
| { variant: "downward-rays-animated-grid" }
| { variant: "downward-rays-static" }
| { variant: "downward-rays-static-grid" }
| { variant: "gradient-bars" }
| { variant: "radial-gradient" }
| { variant: "rotated-rays-animated" }
| { variant: "rotated-rays-animated-grid" }
| { variant: "rotated-rays-static" }
| { variant: "rotated-rays-static-grid" }
| { variant: "sparkles-gradient" }
>;
interface HeroBillboardGalleryProps {
title: string;
description: string;
background: HeroBillboardGalleryBackgroundProps;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
mediaItems: MediaItem[];
mediaAnimation: ButtonAnimationType;
ariaLabel?: string;
className?: string;
containerClassName?: string;
textBoxClassName?: string;
titleClassName?: string;
descriptionClassName?: string;
tagClassName?: string;
buttonContainerClassName?: string;
buttonClassName?: string;
buttonTextClassName?: string;
mediaWrapperClassName?: string;
imageClassName?: string;
}
const HeroBillboardGallery = ({
title,
description,
background,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
mediaItems,
mediaAnimation,
ariaLabel = "Hero section",
className = "",
containerClassName = "",
textBoxClassName = "",
titleClassName = "",
descriptionClassName = "",
tagClassName = "",
buttonContainerClassName = "",
buttonClassName = "",
buttonTextClassName = "",
mediaWrapperClassName = "",
imageClassName = "",
}: HeroBillboardGalleryProps) => {
const { containerRef: mediaContainerRef } = useButtonAnimation({ animationType: mediaAnimation });
const renderCarouselItem = (item: MediaItem, index: number) => (
<div
key={index}
className="w-full aspect-[4/5] overflow-hidden rounded-theme-capped card p-2 shadow-lg"
>
<MediaContent
imageSrc={item.imageSrc}
videoSrc={item.videoSrc}
imageAlt={item.imageAlt || ""}
videoAriaLabel={item.videoAriaLabel || "Gallery media"}
imageClassName="h-full object-cover"
/>
export function HeroBillboardGallery() {
return (
<div>
<AutoCarousel />
</div>
);
const itemCount = mediaItems?.length || 0;
const desktopWidthClass = itemCount === 3 ? "md:w-[24%]" : itemCount === 4 ? "md:w-[24%]" : "md:w-[23%]";
return (
<section
aria-label={ariaLabel}
className={cls(
"relative w-full py-hero-page-padding md:h-svh md:py-0",
className
)}
>
<HeroBackgrounds {...background} />
<div className={cls(
"mx-auto flex flex-col gap-14 relative z-10",
"w-full md:w-content-width md:h-full md:items-center md:justify-center",
containerClassName
)}>
<TextBox
title={title}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
className={cls(
"flex flex-col gap-3 md:gap-3 w-content-width mx-auto",
textBoxClassName
)}
titleClassName={cls("text-6xl font-medium text-balance", titleClassName)}
descriptionClassName={cls("text-base md:text-lg leading-tight", descriptionClassName)}
tagClassName={cls("px-3 py-1 text-sm rounded-theme card text-foreground inline-flex items-center gap-2 mb-1", tagClassName)}
buttonContainerClassName={cls("flex flex-wrap gap-4 max-md:justify-center mt-2", buttonContainerClassName)}
buttonClassName={buttonClassName}
buttonTextClassName={buttonTextClassName}
center={true}
/>
<div className={cls("w-full", mediaWrapperClassName)}>
<div className="block md:hidden -mx-[var(--content-padding)]">
<AutoCarousel
title=""
description=""
textboxLayout="default"
animationType="none"
className="py-0"
carouselClassName="py-0"
containerClassName="!w-full"
itemClassName="!w-55"
ariaLabel="Hero gallery carousel"
showTextBox={false}
>
{mediaItems?.slice(0, 5).map(renderCarouselItem)}
</AutoCarousel>
</div>
<div ref={mediaContainerRef} className="hidden md:flex justify-center items-center pt-2">
<div className="relative flex items-center justify-center w-full">
{mediaItems?.slice(0, 5).map((item, index) => {
const rotations = ["-rotate-6", "rotate-6", "-rotate-6", "rotate-6", "-rotate-6"];
const zIndexes = ["z-10", "z-20", "z-30", "z-40", "z-50"];
const translates = ["-translate-y-5", "translate-y-5", "-translate-y-5", "translate-y-5", "-translate-y-5"];
const marginClass = index > 0 ? "-ml-12 md:-ml-15" : "";
return (
<div
key={index}
className={cls(
"relative aspect-[4/5] overflow-hidden rounded-theme-capped card p-2 shadow-lg transition-transform duration-500 ease-out hover:scale-110",
desktopWidthClass,
rotations[index],
zIndexes[index],
translates[index],
marginClass
)}
>
<MediaContent
imageSrc={item.imageSrc}
videoSrc={item.videoSrc}
imageAlt={item.imageAlt || ""}
videoAriaLabel={item.videoAriaLabel || "Gallery media"}
imageClassName={cls("z-1 h-full object-cover", imageClassName)}
/>
</div>
);
})}
</div>
</div>
</div>
</div>
</section>
);
};
HeroBillboardGallery.displayName = "HeroBillboardGallery";
export default HeroBillboardGallery;
}

View File

@@ -1,231 +1,10 @@
"use client";
import React from 'react';
import { CardList } from '../../cardStack/CardList';
import { Check } from "lucide-react";
import CardList from "@/components/cardStack/CardList";
import Tag from "@/components/shared/Tag";
import Button from "@/components/button/Button";
import { getButtonProps } from "@/lib/buttonUtils";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type PricingPlan = {
id: string;
tag: string;
tagIcon?: LucideIcon;
price: string;
period: string;
description: string;
button: ButtonConfig;
featuresTitle: string;
features: string[];
};
interface PricingCardFiveProps {
plans: PricingPlan[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
cardContentClassName?: string;
planTagClassName?: string;
planPriceClassName?: string;
planPeriodClassName?: string;
planDescriptionClassName?: string;
planButtonClassName?: string;
planButtonTextClassName?: string;
featuresTitleClassName?: string;
featuresListClassName?: string;
featureItemClassName?: string;
featureIconClassName?: string;
featureTextClassName?: string;
export function PricingCardFive() {
return (
<div>
<CardList />
</div>
);
}
const PricingCardFive = ({
plans,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
useInvertedBackground,
ariaLabel = "Pricing section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
cardContentClassName = "",
planTagClassName = "",
planPriceClassName = "",
planPeriodClassName = "",
planDescriptionClassName = "",
planButtonClassName = "",
planButtonTextClassName = "",
featuresTitleClassName = "",
featuresListClassName = "",
featureItemClassName = "",
featureIconClassName = "",
featureTextClassName = "",
}: PricingCardFiveProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
const getButtonConfigProps = () => {
if (theme.defaultButtonVariant === "hover-bubble") {
return { bgClassName: "w-full" };
}
if (theme.defaultButtonVariant === "icon-arrow") {
return { className: "justify-between" };
}
return {};
};
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{plans.map((plan) => (
<div
key={plan.id}
className={cls(
"relative z-1 w-full min-h-0 h-full flex flex-col md:flex-row justify-between items-stretch gap-8 md:gap-15 p-6 md:p-15",
cardContentClassName
)}
>
<div className="w-full md:w-1/2 min-w-0 flex flex-col justify-between gap-6">
<div className="flex flex-col gap-4">
<Tag
text={plan.tag}
icon={plan.tagIcon}
className={planTagClassName}
/>
<div className="flex items-baseline gap-1 mt-1">
<span className={cls(
"text-5xl md:text-6xl font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
planPriceClassName
)}>
{plan.price}
</span>
<span className={cls(
"text-xl",
shouldUseLightText ? "text-background" : "text-foreground",
planPeriodClassName
)}>
{plan.period}
</span>
</div>
<p className={cls(
"text-2xl leading-tight text-balance",
shouldUseLightText ? "text-background" : "text-foreground",
planDescriptionClassName
)}>
{plan.description}
</p>
</div>
<Button
{...getButtonProps(
{ ...plan.button, props: { ...plan.button.props, ...getButtonConfigProps() } },
0,
theme.defaultButtonVariant,
cls("w-full h-12", planButtonClassName),
planButtonTextClassName
)}
/>
</div>
<div className="relative z-1 w-full h-px bg-foreground/20 md:hidden" />
<div className="w-full md:w-1/2 min-w-0 flex flex-col gap-4">
<h3 className={cls(
"text-xl",
shouldUseLightText ? "text-background" : "text-foreground",
featuresTitleClassName
)}>
{plan.featuresTitle}
</h3>
<ul className={cls("flex flex-col gap-3", featuresListClassName)}>
{plan.features.map((feature, index) => (
<li key={index} className={cls("flex items-start gap-3", featureItemClassName)}>
<div className={cls("flex-shrink-0 h-6 w-auto aspect-square rounded-theme primary-button flex items-center justify-center", featureIconClassName)}>
<Check className="h-4/10 w-4/10 text-primary-cta-text" strokeWidth={2.5} />
</div>
<span className={cls(
"text-sm leading-[1.4]",
shouldUseLightText ? "text-background/80" : "text-foreground/80",
featureTextClassName
)}>
{feature}
</span>
</li>
))}
</ul>
</div>
</div>
))}
</CardList>
);
};
PricingCardFive.displayName = "PricingCardFive";
export default PricingCardFive;

View File

@@ -1,216 +1,10 @@
"use client";
import React from 'react';
import { CardList } from '../../cardStack/CardList';
import { Check } from "lucide-react";
import CardList from "@/components/cardStack/CardList";
import Button from "@/components/button/Button";
import MediaContent from "@/components/shared/MediaContent";
import Tag from "@/components/shared/Tag";
import { getButtonProps } from "@/lib/buttonUtils";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type PricingPlan = {
id: string;
title: string;
price: string;
period: string;
features: string[];
button: ButtonConfig;
imageSrc?: string;
videoSrc?: string;
imageAlt?: string;
videoAriaLabel?: string;
};
interface PricingCardNineProps {
plans: PricingPlan[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
cardContentClassName?: string;
planImageWrapperClassName?: string;
planImageClassName?: string;
planTitleClassName?: string;
planPriceClassName?: string;
planButtonClassName?: string;
planButtonTextClassName?: string;
featuresListClassName?: string;
featureItemClassName?: string;
featureIconClassName?: string;
featureTextClassName?: string;
export function PricingCardNine() {
return (
<div>
<CardList />
</div>
);
}
const PricingCardNine = ({
plans,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
useInvertedBackground,
ariaLabel = "Pricing section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
cardContentClassName = "",
planImageWrapperClassName = "",
planImageClassName = "",
planTitleClassName = "",
planPriceClassName = "",
planButtonClassName = "",
planButtonTextClassName = "",
featuresListClassName = "",
featureItemClassName = "",
featureIconClassName = "",
featureTextClassName = "",
}: PricingCardNineProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
const getButtonConfigProps = () => {
if (theme.defaultButtonVariant === "hover-bubble") {
return { bgClassName: "w-full" };
}
if (theme.defaultButtonVariant === "icon-arrow") {
return { className: "justify-between" };
}
return {};
};
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{plans.map((plan) => (
<div
key={plan.id}
className={cls(
"relative z-1 w-full min-h-0 h-full flex flex-col md:flex-row items-stretch gap-6 md:gap-10 p-4 md:p-6",
cardContentClassName
)}
>
<div className={cls("w-full md:w-1/2 min-w-0 aspect-square md:aspect-[4/3]", planImageWrapperClassName)}>
<MediaContent
imageSrc={plan.imageSrc}
videoSrc={plan.videoSrc}
imageAlt={plan.imageAlt || plan.title}
videoAriaLabel={plan.videoAriaLabel || plan.title}
imageClassName={cls("w-full h-full object-cover rounded-theme", planImageClassName)}
/>
</div>
<div className="w-full md:w-1/2 min-w-0 flex flex-col justify-center gap-6 py-2">
<div className="flex flex-col gap-4">
<Tag
text={`${plan.price}${plan.period}`}
useInvertedBackground={useInvertedBackground}
className={planPriceClassName}
/>
<h3 className={cls(
"text-4xl md:text-5xl font-medium mb-1 truncate",
shouldUseLightText ? "text-background" : "text-foreground",
planTitleClassName
)}>
{plan.title}
</h3>
<ul className={cls("flex flex-col gap-3", featuresListClassName)}>
{plan.features.map((feature, index) => (
<li key={index} className={cls("flex items-start gap-3", featureItemClassName)}>
<div className={cls("flex-shrink-0 h-6 w-auto aspect-square rounded-theme primary-button flex items-center justify-center", featureIconClassName)}>
<Check className="h-4/10 w-4/10 text-primary-cta-text" strokeWidth={2.5} />
</div>
<span className={cls(
"text-sm leading-[1.4]",
shouldUseLightText ? "text-background/80" : "text-foreground/80",
featureTextClassName
)}>
{feature}
</span>
</li>
))}
</ul>
</div>
<Button
{...getButtonProps(
{ ...plan.button, props: { ...plan.button.props, ...getButtonConfigProps() } },
0,
theme.defaultButtonVariant,
planButtonClassName,
planButtonTextClassName
)}
/>
</div>
</div>
))}
</CardList>
);
};
PricingCardNine.displayName = "PricingCardNine";
export default PricingCardNine;

View File

@@ -1,196 +1,10 @@
"use client";
import React from 'react';
import { CardList } from '../../cardStack/CardList';
import CardList from "@/components/cardStack/CardList";
import MediaContent from "@/components/shared/MediaContent";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamMember = {
id: string;
title: string;
subtitle: string;
detail: string;
imageSrc?: string;
imageAlt?: string;
videoSrc?: string;
videoAriaLabel?: string;
};
type TeamGroup = {
id: string;
groupTitle: string;
members: TeamMember[];
};
interface TeamCardElevenProps {
groups: TeamGroup[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
groupTitleClassName?: string;
memberClassName?: string;
memberImageClassName?: string;
memberTitleClassName?: string;
memberSubtitleClassName?: string;
memberDetailClassName?: string;
export function TeamCardEleven() {
return (
<div>
<CardList />
</div>
);
}
const TeamCardEleven = ({
groups,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout,
useInvertedBackground,
ariaLabel = "Team section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
groupTitleClassName = "",
memberClassName = "",
memberImageClassName = "",
memberTitleClassName = "",
memberSubtitleClassName = "",
memberDetailClassName = "",
}: TeamCardElevenProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
const renderMemberRow = (member: TeamMember) => (
<div
key={member.id}
className={cls(
"flex flex-col md:flex-row md:items-center gap-4 py-6",
memberClassName
)}
>
<div className="flex items-center gap-4 flex-1">
<div className={cls(
"relative h-14 w-auto md:h-16 aspect-square rounded-theme overflow-hidden shrink-0",
memberImageClassName
)}>
<MediaContent
imageSrc={member.imageSrc}
imageAlt={member.imageAlt || member.title}
videoSrc={member.videoSrc}
videoAriaLabel={member.videoAriaLabel}
imageClassName="w-full h-full object-cover"
/>
</div>
<div className="flex flex-col">
<p className={cls(
"text-lg md:text-xl font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
memberTitleClassName
)}>
{member.title}
</p>
<p className={cls(
"text-base",
shouldUseLightText ? "text-background/60" : "text-foreground/60",
memberSubtitleClassName
)}>
{member.subtitle}
</p>
</div>
</div>
<p className={cls(
"text-base md:text-lg font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
memberDetailClassName
)}>
{member.detail}
</p>
</div>
);
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{groups.map((group) => (
<div key={group.id} className="p-6 md:p-8">
<h3 className={cls(
"text-2xl md:text-3xl font-medium mb-2",
shouldUseLightText ? "text-background" : "text-foreground",
groupTitleClassName
)}>
{group.groupTitle}
</h3>
<div className="flex flex-col divide-y divide-accent/40 border-y border-accent/40">
{group.members.map(renderMemberRow)}
</div>
</div>
))}
</CardList>
);
};
TeamCardEleven.displayName = "TeamCardEleven";
export default TeamCardEleven;

View File

@@ -1,203 +1,10 @@
"use client";
import React from 'react';
import { AutoCarousel } from '../../cardStack/layouts/carousels/AutoCarousel';
import { memo } from "react";
import AutoCarousel from "@/components/cardStack/layouts/carousels/AutoCarousel";
import TestimonialAuthor from "@/components/shared/TestimonialAuthor";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import { Quote } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import type { CardAnimationType, ButtonConfig, ButtonAnimationType, TitleSegment, TextboxLayout, InvertedBackground } from "@/components/cardStack/types";
type Testimonial = {
id: string;
name: string;
handle: string;
testimonial: string;
imageSrc?: string;
imageAlt?: string;
icon?: LucideIcon;
};
interface TestimonialCardSixProps {
testimonials: Testimonial[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
tag?: string;
tagIcon?: LucideIcon;
tagAnimation?: ButtonAnimationType;
buttons?: ButtonConfig[];
buttonAnimation?: ButtonAnimationType;
speed?: number;
topMarqueeDirection?: "left" | "right";
ariaLabel?: string;
className?: string;
containerClassName?: string;
carouselClassName?: string;
bottomCarouselClassName?: string;
cardClassName?: string;
testimonialClassName?: string;
imageWrapperClassName?: string;
imageClassName?: string;
iconClassName?: string;
nameClassName?: string;
handleClassName?: string;
textBoxClassName?: string;
textBoxTitleClassName?: string;
textBoxTitleImageWrapperClassName?: string;
textBoxTitleImageClassName?: string;
textBoxDescriptionClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
export function TestimonialCardSix() {
return (
<div>
<AutoCarousel />
</div>
);
}
interface TestimonialCardProps {
testimonial: Testimonial;
useInvertedBackground: boolean;
cardClassName?: string;
testimonialClassName?: string;
imageWrapperClassName?: string;
imageClassName?: string;
iconClassName?: string;
nameClassName?: string;
handleClassName?: string;
}
const TestimonialCard = memo(({
testimonial,
useInvertedBackground,
cardClassName = "",
testimonialClassName = "",
imageWrapperClassName = "",
imageClassName = "",
iconClassName = "",
nameClassName = "",
handleClassName = "",
}: TestimonialCardProps) => {
const Icon = testimonial.icon || Quote;
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
return (
<div className={cls("relative h-full card rounded-theme-capped p-6 min-h-0 flex flex-col gap-10", cardClassName)}>
<p className={cls("relative z-1 text-lg leading-tight line-clamp-2", shouldUseLightText ? "text-background" : "text-foreground", testimonialClassName)}>
{testimonial.testimonial}
</p>
<TestimonialAuthor
name={testimonial.name}
subtitle={testimonial.handle}
imageSrc={testimonial.imageSrc}
imageAlt={testimonial.imageAlt}
icon={Icon}
useInvertedBackground={useInvertedBackground}
imageWrapperClassName={imageWrapperClassName}
imageClassName={imageClassName}
iconClassName={iconClassName}
nameClassName={nameClassName}
subtitleClassName={handleClassName}
/>
</div>
);
});
TestimonialCard.displayName = "TestimonialCard";
const TestimonialCardSix = ({
testimonials,
animationType,
title,
titleSegments,
description,
textboxLayout,
useInvertedBackground,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
speed = 40,
topMarqueeDirection = "left",
ariaLabel = "Testimonials section",
className = "",
containerClassName = "",
carouselClassName = "",
bottomCarouselClassName = "",
cardClassName = "",
testimonialClassName = "",
imageWrapperClassName = "",
imageClassName = "",
iconClassName = "",
nameClassName = "",
handleClassName = "",
textBoxClassName = "",
textBoxTitleClassName = "",
textBoxTitleImageWrapperClassName = "",
textBoxTitleImageClassName = "",
textBoxDescriptionClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
}: TestimonialCardSixProps) => {
return (
<AutoCarousel
speed={speed}
uniformGridCustomHeightClasses="min-h-none"
animationType={animationType}
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttonAnimation={buttonAnimation}
textboxLayout={textboxLayout}
useInvertedBackground={useInvertedBackground}
showTextBox={true}
dualMarquee={true}
topMarqueeDirection={topMarqueeDirection}
carouselClassName={carouselClassName}
bottomCarouselClassName={bottomCarouselClassName}
containerClassName={containerClassName}
className={className}
textBoxClassName={textBoxClassName}
titleClassName={textBoxTitleClassName}
titleImageWrapperClassName={textBoxTitleImageWrapperClassName}
titleImageClassName={textBoxTitleImageClassName}
descriptionClassName={textBoxDescriptionClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
ariaLabel={ariaLabel}
itemClassName="w-60! md:w-carousel-item-3! xl:w-carousel-item-4!"
>
{testimonials.map((testimonial, index) => (
<TestimonialCard
key={`${testimonial.id}-${index}`}
testimonial={testimonial}
useInvertedBackground={useInvertedBackground}
cardClassName={cardClassName}
testimonialClassName={testimonialClassName}
imageWrapperClassName={imageWrapperClassName}
imageClassName={imageClassName}
iconClassName={iconClassName}
nameClassName={nameClassName}
handleClassName={handleClassName}
/>
))}
</AutoCarousel>
);
};
TestimonialCardSix.displayName = "TestimonialCardSix";
export default TestimonialCardSix;