Create card components to refactor

This commit is contained in:
Omar Oughriss 2025-10-20 11:38:33 +02:00
parent c529273c0f
commit 8bd5968f77
3 changed files with 286 additions and 0 deletions

View File

@ -0,0 +1,116 @@
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Clock, Users, LucideIcon } from "lucide-react"
interface FormationCardProps {
icon: LucideIcon
title: string
description: string
program: string[]
specialization: {
title: string
items: string[]
}
duration: string
maxParticipants: string
color: 'red' | 'green' | 'blue'
href?: string
}
export default function FormationCard({
icon: Icon,
title,
description,
program,
specialization,
duration,
maxParticipants,
color,
href = "/formation/devis"
}: FormationCardProps) {
const getColorClasses = () => {
switch (color) {
case 'red':
return {
card: "border-2 border-gray-700 hover:border-red-600 bg-gray-800 hover:shadow-xl transition-all duration-300",
icon: "h-16 w-16 text-red-400 mx-auto mb-4",
title: "text-2xl text-red-300",
specialization: "bg-red-900",
specializationTitle: "font-semibold text-red-200 mb-2",
specializationItems: "text-sm text-red-300 space-y-1",
button: "w-full bg-red-600 hover:bg-red-700 text-white"
}
case 'green':
return {
card: "border-2 border-gray-700 hover:border-green-600 bg-gray-800 hover:shadow-xl transition-all duration-300",
icon: "h-16 w-16 text-green-400 mx-auto mb-4",
title: "text-2xl text-green-300",
specialization: "bg-green-900",
specializationTitle: "font-semibold text-green-200 mb-2",
specializationItems: "text-sm text-green-300 space-y-1",
button: "w-full bg-green-600 hover:bg-green-700 text-white"
}
case 'blue':
return {
card: "border-2 border-gray-700 hover:border-blue-600 bg-gray-800 hover:shadow-xl transition-all duration-300",
icon: "h-16 w-16 text-blue-400 mx-auto mb-4",
title: "text-2xl text-blue-300",
specialization: "bg-blue-900",
specializationTitle: "font-semibold text-blue-200 mb-2",
specializationItems: "text-sm text-blue-300 space-y-1",
button: "w-full bg-blue-600 hover:bg-blue-700 text-white"
}
}
}
const colorClasses = getColorClasses()
return (
<Card className={colorClasses.card}>
<CardHeader className="text-center">
<Icon className={colorClasses.icon} />
<CardTitle className={colorClasses.title}>{title}</CardTitle>
<CardDescription className="text-lg text-gray-300">
{description}
</CardDescription>
</CardHeader>
<CardContent className="space-y-6 text-gray-300">
<div>
<h4 className="font-semibold mb-3">Programme de formation :</h4>
<ul className="space-y-2">
{program.map((item, index) => (
<li key={index}> {item}</li>
))}
</ul>
</div>
<div className={`${colorClasses.specialization} p-4 rounded-lg`}>
<h5 className={colorClasses.specializationTitle}>{specialization.title}</h5>
<ul className={colorClasses.specializationItems}>
{specialization.items.map((item, index) => (
<li key={index}> {item}</li>
))}
</ul>
</div>
<div className="flex items-center justify-between text-sm text-gray-400">
<div className="flex items-center">
<Clock className="h-4 w-4 mr-1" />
{duration}
</div>
<div className="flex items-center">
<Users className="h-4 w-4 mr-1" />
{maxParticipants}
</div>
</div>
<Link href={href}>
<Button className={colorClasses.button}>
S'inscrire à la formation
</Button>
</Link>
</CardContent>
</Card>
)
}

View File

@ -0,0 +1,129 @@
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { CheckCircle, Database, Zap, Users, LucideIcon } from "lucide-react"
interface TokenBreakdown {
icon: LucideIcon
title: string
value: string
description: string
color: 'blue' | 'green' | 'purple'
}
interface PricingFeature {
text: string
}
interface PricingCardProps {
title: string
price: string
tokensIncluded: string
tokenBreakdown: TokenBreakdown[]
features: PricingFeature[]
ctaText: string
ctaHref: string
variant?: 'default' | 'featured'
}
export default function PricingCard({
title,
price,
tokensIncluded,
tokenBreakdown,
features,
ctaText,
ctaHref,
variant = 'default'
}: PricingCardProps) {
const getColorClasses = (color: 'blue' | 'green' | 'purple') => {
switch (color) {
case 'blue':
return {
bg: "bg-blue-50 dark:bg-blue-800",
icon: "text-blue-600 dark:text-blue-300",
title: "text-blue-800 dark:text-blue-200",
value: "text-blue-600 dark:text-blue-300",
description: "text-blue-700 dark:text-blue-200"
}
case 'green':
return {
bg: "bg-green-50 dark:bg-green-800",
icon: "text-green-600 dark:text-green-300",
title: "text-green-800 dark:text-green-200",
value: "text-green-600 dark:text-green-300",
description: "text-green-700 dark:text-green-200"
}
case 'purple':
return {
bg: "bg-purple-50 dark:bg-purple-800",
icon: "text-purple-600 dark:text-purple-300",
title: "text-purple-800 dark:text-purple-200",
value: "text-purple-600 dark:text-purple-300",
description: "text-purple-700 dark:text-purple-200"
}
}
}
return (
<Card className="border-2 border-blue-200 bg-blue-50 dark:bg-blue-900 dark:border-blue-700 transition-colors">
<CardHeader className="text-center">
<CardTitle className="text-3xl font-bold text-blue-700 dark:text-blue-400">
{title}
</CardTitle>
<CardDescription className="text-2xl font-semibold text-blue-600 dark:text-blue-300">
{price}
</CardDescription>
<Badge className="bg-green-600 text-white text-lg px-4 py-2 mt-2 dark:bg-green-500">
{tokensIncluded}
</Badge>
</CardHeader>
<CardContent>
{/* Token Breakdown */}
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg mb-6 transition-colors">
<h3 className="text-xl font-bold text-gray-900 dark:text-white mb-4 text-center">
🎯 Que comprennent {tokensIncluded} ?
</h3>
<div className="grid md:grid-cols-3 gap-6">
{tokenBreakdown.map((item, index) => {
const colorClasses = getColorClasses(item.color)
const Icon = item.icon
return (
<div key={index} className={`text-center p-4 ${colorClasses.bg} rounded-lg transition-colors`}>
<Icon className={`h-8 w-8 mx-auto ${colorClasses.icon} mb-2`} />
<h4 className={`font-semibold ${colorClasses.title}`}>{item.title}</h4>
<p className={`text-2xl font-bold ${colorClasses.value}`}>{item.value}</p>
<p className={`text-sm ${colorClasses.description}`}>{item.description}</p>
</div>
)
})}
</div>
</div>
{/* Features */}
<div className="space-y-3 mb-6 text-gray-900 dark:text-gray-200">
{features.map((feature, index) => (
<div key={index} className="flex items-center">
<CheckCircle className="h-5 w-5 text-green-600 dark:text-green-300 mr-3" />
<span>{feature.text}</span>
</div>
))}
</div>
{/* CTA */}
<div className="text-center">
<p className="text-lg font-semibold text-blue-700 dark:text-blue-400 mb-4">
Tarification à la consommation + setup personnalisé
</p>
<Link href={ctaHref}>
<Button size="lg" className="w-full">
{ctaText}
</Button>
</Link>
</div>
</CardContent>
</Card>
)
}

View File

@ -0,0 +1,41 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { LucideIcon } from "lucide-react"
interface ProductCardProps {
icon: LucideIcon
title: string
description: string[]
variant?: 'default' | 'gradient'
}
export default function ProductCard({
icon: Icon,
title,
description,
variant = 'default'
}: ProductCardProps) {
const getCardStyles = () => {
switch (variant) {
case 'gradient':
return "border-2 border-gray-200 dark:border-gray-700 hover:border-blue-200 dark:hover:border-blue-400 transition-colors duration-300 bg-gradient-to-br from-white to-blue-50 dark:from-gray-800 dark:to-blue-900"
default:
return "border-2 border-gray-200 dark:border-gray-700 hover:border-blue-200 dark:hover:border-blue-400 transition-colors duration-300"
}
}
return (
<Card className={getCardStyles()}>
<CardHeader>
<Icon className="h-12 w-12 text-blue-600 dark:text-blue-400 mb-4" />
<CardTitle className="dark:text-gray-100">{title}</CardTitle>
</CardHeader>
<CardContent>
{description.map((text, index) => (
<p key={index} className="text-gray-600 dark:text-gray-300 mb-4 last:mb-0">
{text}
</p>
))}
</CardContent>
</Card>
)
}