import React, { useState } from 'react';
import { ChevronLeft, ChevronRight, Download } from 'lucide-react';
const BannerGeneratorPreview = () => {
const [currentStep, setCurrentStep] = useState(0);
const [bannerData, setBannerData] = useState({
mainTitle: 'Welcome to Our Site',
subTitle: 'Discover Amazing Features',
logo: null,
legalText: '© 2025 All rights reserved',
ctaText: 'Get Started',
style: 'static',
ctaLink: '',
selectedSizes: [],
});
const [previewSize, setPreviewSize] = useState({ width: 300, height: 250 });
const bannerSizes = [
{ width: 300, height: 250, name: '300x250 Medium Rectangle' },
{ width: 728, height: 90, name: '728x90 Leaderboard' },
{ width: 160, height: 600, name: '160x600 Wide Skyscraper' },
{ width: 320, height: 50, name: '320x50 Mobile Banner' }
];
const handleLogoUpload = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
setBannerData({ ...bannerData, logo: e.target.result });
};
reader.readAsDataURL(file);
}
};
const updateBannerData = (field, value) => {
setBannerData({ ...bannerData, [field]: value });
};
const handleSizeToggle = (size) => {
const sizes = [...bannerData.selectedSizes];
const index = sizes.findIndex(s => s.width === size.width && s.height === size.height);
if (index === -1) {
sizes.push(size);
} else {
sizes.splice(index, 1);
}
setBannerData({ ...bannerData, selectedSizes: sizes });
};
const getAnimationClass = (style) => {
switch (style) {
case 'dynamic':
return 'animate-pulse';
case 'moving':
return 'animate-bounce';
case 'calm':
return 'transition-all duration-700';
default:
return '';
}
};
const renderBannerPreview = () => {
const animation = getAnimationClass(bannerData.style);
const scale = Math.min(
400 / previewSize.width,
400 / previewSize.height
);
return (
<div className="relative bg-gray-100 p-4 rounded-lg">
<div
className="relative border border-gray-300 bg-white mx-auto overflow-hidden"
style={{
width: previewSize.width,
height: previewSize.height,
transform: `scale(${scale})`,
transformOrigin: 'top left'
}}
>
<div className={`p-4 h-full flex flex-col justify-between ${animation}`}>
{bannerData.logo && (
<img
src={bannerData.logo}
alt="Logo"
className="max-h-12 object-contain mb-2"
/>
)}
<div className="flex-grow flex flex-col justify-center">
<h1 className="text-xl font-bold mb-2">{bannerData.mainTitle}</h1>
<h2 className="text-sm mb-4">{bannerData.subTitle}</h2>
<button
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition-colors"
>
{bannerData.ctaText}
</button>
</div>
<p className="text-xs text-gray-500 mt-2">{bannerData.legalText}</p>
</div>
</div>
</div>
);
};
const steps = [
{
title: 'Banner Content',
content: (
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-1">Logo</label>
<input
type="file"
accept="image/*"
onChange={handleLogoUpload}
className="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Main Title</label>
<input
type="text"
value={bannerData.mainTitle}
onChange={(e) => updateBannerData('mainTitle', e.target.value)}
className="w-full p-2 border rounded"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Subtitle</label>
<input
type="text"
value={bannerData.subTitle}
onChange={(e) => updateBannerData('subTitle', e.target.value)}
className="w-full p-2 border rounded"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">CTA Text</label>
<input
type="text"
value={bannerData.ctaText}
onChange={(e) => updateBannerData('ctaText', e.target.value)}
className="w-full p-2 border rounded"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Legal Text</label>
<textarea
value={bannerData.legalText}
onChange={(e) => updateBannerData('legalText', e.target.value)}
className="w-full p-2 border rounded"
rows="2"
/>
</div>
</div>
)
},
{
title: 'Banner Style',
content: (
<div className="space-y-4">
<label className="block text-sm font-medium mb-2">Select Style</label>
<div className="grid grid-cols-2 gap-4">
{['static', 'dynamic', 'moving', 'calm'].map((style) => (
<div
key={style}
className={`p-4 border rounded cursor-pointer transition-all ${
bannerData.style === style
? 'border-blue-500 bg-blue-50'
: 'border-gray-200 hover:border-blue-300'
}`}
onClick={() => updateBannerData('style', style)}
>
<div className="flex items-center space-x-2">
<div className={`w-4 h-4 rounded-full border-2 ${
bannerData.style === style
? 'border-blue-500 bg-blue-500'
: 'border-gray-300'
}`} />
<span className="capitalize">{style}</span>
</div>
</div>
))}
</div>
</div>
)
},
{
title: 'CTA Link',
content: (
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-1">Enter CTA Link</label>
<input
type="url"
value={bannerData.ctaLink}
onChange={(e) => updateBannerData('ctaLink', e.target.value)}
placeholder="https://"
className="w-full p-2 border rounded"
/>
</div>
<div className="bg-blue-50 p-4 rounded">
<p className="text-sm text-blue-800">
This link will be added to the banner's call-to-action button.
</p>
</div>
</div>
)
},
{
title: 'Banner Sizes',
content: (
<div className="space-y-4">
<label className="block text-sm font-medium mb-2">Select Sizes for Export</label>
<div className="space-y-2">
{bannerSizes.map((size) => (
<label key={size.name} className="flex items-center p-3 border rounded hover:bg-gray-50">
<input
type="checkbox"
checked={bannerData.selectedSizes.some(
s => s.width === size.width && s.height === size.height
)}
onChange={() => handleSizeToggle(size)}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="ml-2">{size.name}</span>
</label>
))}
</div>
<div className="bg-yellow-50 p-4 rounded mt-4">
<p className="text-sm text-yellow-800">
Select all sizes you want to generate. Each size will be optimized automatically.
</p>
</div>
</div>
)
},
{
title: 'Export',
content: (
<div className="space-y-4">
<div className="bg-gray-50 p-4 rounded mb-6">
<p className="text-sm text-gray-600 mb-2">Selected sizes:</p>
<div className="flex flex-wrap gap-2">
{bannerData.selectedSizes.map((size) => (
<span key={`${size.width}x${size.height}`} className="px-2 py-1 bg-blue-100 text-blue-700 rounded text-sm">
{size.width}x{size.height}
</span>
))}
</div>
</div>
<button className="w-full p-3 bg-blue-500 text-white rounded flex items-center justify-center space-x-2 hover:bg-blue-600">
<Download className="w-4 h-4" />
<span>Download as ZIP</span>
</button>
<button className="w-full p-3 bg-green-500 text-white rounded flex items-center justify-center space-x-2 hover:bg-green-600">
<Download className="w-4 h-4" />
<span>Save as PNG</span>
</button>
</div>
)
}
];
return (
<div className="max-w-4xl mx-auto p-4">
<div className="mb-8">
<h1 className="text-2xl font-bold mb-2">Banner Generator</h1>
<div className="flex items-center space-x-2">
{steps.map((step, index) => (
<React.Fragment key={step.title}>
<div
className={`h-2 flex-grow rounded ${
index <= currentStep ? 'bg-blue-500' : 'bg-gray-200'
}`}
/>
{index < steps.length - 1 && (
<div className="w-4 h-4 rounded-full bg-blue-500 text-white flex items-center justify-center text-xs">
{index + 1}
</div>
)}
</React.Fragment>
))}
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div className="space-y-6">
<h2 className="text-xl font-semibold mb-4">{steps[currentStep].title}</h2>
{steps[currentStep].content}
<div className="flex justify-between pt-4">
<button
onClick={() => setCurrentStep(Math.max(0, currentStep - 1))}
disabled={currentStep === 0}
className="flex items-center space-x-2 px-4 py-2 border rounded text-gray-600 disabled:opacity-50"
>
<ChevronLeft className="w-4 h-4" />
<span>Previous</span>
</button>
<button
onClick={() => setCurrentStep(Math.min(steps.length - 1, currentStep + 1))}
disabled={currentStep === steps.length - 1}
className="flex items-center space-x-2 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-50"
>
<span>Next</span>
<ChevronRight className="w-4 h-4" />
</button>
</div>
</div>
<div className="bg-gray-50 p-6 rounded-lg">
<h3 className="text-lg font-semibold mb-4">Live Preview</h3>
{renderBannerPreview()}
<div className="mt-4">
<label className="block text-sm font-medium mb-2">Preview Size</label>
<select
value={`${previewSize.width}x${previewSize.height}`}
onChange={(e) => {
const [width, height] = e.target.value.split('x').map(Number);
setPreviewSize({ width, height });
}}
className="w-full p-2 border rounded"
>
{bannerSizes.map((size) => (
<option key={size.name} value={`${size.width}x${size.height}`}>
{size.name}
</option>
))}
</select>
</div>
</div>
</div>
</div>
);
};
export default BannerGeneratorPreview;