Create card components to refactor
This commit is contained in:
parent
c529273c0f
commit
8bd5968f77
116
components/ui/FormationCard.tsx
Normal file
116
components/ui/FormationCard.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
129
components/ui/PricingCard.tsx
Normal file
129
components/ui/PricingCard.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
41
components/ui/ProductCard.tsx
Normal file
41
components/ui/ProductCard.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user