Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | 1x 6x 6x 6x 6x 6x 6x 18x 12x 18x | import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Mail, Calendar, Bell, ArrowRight, Zap, CheckCircle2, Code, LayoutGrid } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import CodeBlock from './CodeBlock';
const PluginShowcase: React.FC = () => {
const { t } = useTranslation();
const [activeTab, setActiveTab] = useState(0);
const [viewMode, setViewMode] = useState<'marketplace' | 'code'>('marketplace');
const examples = [
{
id: 'winback',
icon: Mail,
title: t('marketing.plugins.examples.winback.title'),
description: t('marketing.plugins.examples.winback.description'),
stats: [t('marketing.plugins.examples.winback.stats.retention'), t('marketing.plugins.examples.winback.stats.revenue')],
marketplaceImage: 'bg-gradient-to-br from-pink-500 to-rose-500',
code: t('marketing.plugins.examples.winback.code'),
},
{
id: 'noshow',
icon: Bell,
title: t('marketing.plugins.examples.noshow.title'),
description: t('marketing.plugins.examples.noshow.description'),
stats: [t('marketing.plugins.examples.noshow.stats.reduction'), t('marketing.plugins.examples.noshow.stats.utilization')],
marketplaceImage: 'bg-gradient-to-br from-blue-500 to-cyan-500',
code: t('marketing.plugins.examples.noshow.code'),
},
{
id: 'report',
icon: Calendar,
title: t('marketing.plugins.examples.report.title'),
description: t('marketing.plugins.examples.report.description'),
stats: [t('marketing.plugins.examples.report.stats.timeSaved'), t('marketing.plugins.examples.report.stats.visibility')],
marketplaceImage: 'bg-gradient-to-br from-purple-500 to-indigo-500',
code: t('marketing.plugins.examples.report.code'),
},
];
const CurrentIcon = examples[activeTab].icon;
return (
<section className="py-24 bg-gray-50 dark:bg-gray-900 overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid lg:grid-cols-2 gap-16 items-center">
{/* Left Column: Content */}
<div>
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-100 dark:bg-brand-900/30 text-brand-600 dark:text-brand-400 text-sm font-medium mb-6">
<Zap className="w-4 h-4" />
<span>{t('marketing.plugins.badge')}</span>
</div>
<h2 className="text-4xl font-bold text-gray-900 dark:text-white mb-6">
{t('marketing.plugins.headline')}
</h2>
<p className="text-lg text-gray-600 dark:text-gray-400 mb-10">
{t('marketing.plugins.subheadline')}
</p>
<div className="space-y-4">
{examples.map((example, index) => (
<button
key={example.id}
onClick={() => setActiveTab(index)}
className={`w-full text-left p-4 rounded-xl transition-all duration-200 border ${activeTab === index
? 'bg-white dark:bg-gray-800 border-brand-500 shadow-lg scale-[1.02]'
: 'bg-transparent border-transparent hover:bg-white/50 dark:hover:bg-gray-800/50'
}`}
>
<div className="flex items-start gap-4">
<div className={`p-2 rounded-lg ${activeTab === index
? 'bg-brand-100 text-brand-600 dark:bg-brand-900/50 dark:text-brand-400'
: 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'
}`}>
<example.icon className="w-6 h-6" />
</div>
<div>
<h3 className={`font-semibold mb-1 ${activeTab === index ? 'text-gray-900 dark:text-white' : 'text-gray-600 dark:text-gray-400'
}`}>
{example.title}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-500">
{example.description}
</p>
</div>
</div>
</button>
))}
</div>
</div>
{/* Right Column: Visuals */}
<div className="relative">
{/* Background Decor */}
<div className="absolute -inset-4 bg-gradient-to-r from-brand-500/20 to-purple-500/20 rounded-3xl blur-2xl opacity-50" />
{/* View Toggle */}
<div className="absolute -top-12 right-0 flex bg-gray-100 dark:bg-gray-800 p-1 rounded-lg border border-gray-200 dark:border-gray-700">
<button
onClick={() => setViewMode('marketplace')}
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all ${viewMode === 'marketplace'
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm'
: 'text-gray-500 hover:text-gray-700 dark:hover:text-gray-300'
}`}
>
<LayoutGrid className="w-4 h-4" />
{t('marketing.plugins.viewToggle.marketplace')}
</button>
<button
onClick={() => setViewMode('code')}
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all ${viewMode === 'code'
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm'
: 'text-gray-500 hover:text-gray-700 dark:hover:text-gray-300'
}`}
>
<Code className="w-4 h-4" />
{t('marketing.plugins.viewToggle.developer')}
</button>
</div>
<AnimatePresence mode="wait">
<motion.div
key={`${activeTab}-${viewMode}`}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
className="relative mt-8" // Added margin top for toggle
>
{/* Stats Cards */}
<div className="flex gap-4 mb-6">
{examples[activeTab].stats.map((stat, i) => (
<div key={i} className="flex items-center gap-2 px-4 py-2 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<CheckCircle2 className="w-4 h-4 text-green-500" />
<span className="text-sm font-medium text-gray-900 dark:text-white">{stat}</span>
</div>
))}
</div>
{viewMode === 'marketplace' ? (
// Marketplace Card View
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-xl overflow-hidden">
<div className={`h-32 ${examples[activeTab].marketplaceImage} flex items-center justify-center`}>
<CurrentIcon className="w-16 h-16 text-white opacity-90" />
</div>
<div className="p-6">
<div className="flex justify-between items-start mb-4">
<div>
<h3 className="text-xl font-bold text-gray-900 dark:text-white">{examples[activeTab].title}</h3>
<div className="text-sm text-gray-500">{t('marketing.plugins.marketplaceCard.author')}</div>
</div>
<button className="px-4 py-2 bg-brand-600 text-white rounded-lg font-medium text-sm hover:bg-brand-700 transition-colors">
{t('marketing.plugins.marketplaceCard.installButton')}
</button>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-6">
{examples[activeTab].description}
</p>
<div className="flex items-center gap-2 text-sm text-gray-500">
<div className="flex -space-x-2">
{[1, 2, 3].map(i => (
<div key={i} className="w-6 h-6 rounded-full bg-gray-300 border-2 border-white dark:border-gray-800" />
))}
</div>
<span>{t('marketing.plugins.marketplaceCard.usedBy')}</span>
</div>
</div>
</div>
) : (
// Code View
<CodeBlock
code={examples[activeTab].code}
filename={`${examples[activeTab].id}_plugin.py`}
/>
)}
{/* CTA */}
<div className="mt-6 text-right">
<a href="/features" className="inline-flex items-center gap-2 text-brand-600 dark:text-brand-400 font-medium hover:underline">
{t('marketing.plugins.cta')} <ArrowRight className="w-4 h-4" />
</a>
</div>
</motion.div>
</AnimatePresence>
</div>
</div>
</div>
</section>
);
};
export default PluginShowcase;
|