feat: mockup page with template library and generator UI

This commit is contained in:
2026-06-22 12:27:35 +02:00
parent 921d9d6a77
commit 4811b73c69
3 changed files with 245 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
'use client'
import { useState } from 'react'
import { Header } from '@/components/layout/Header'
import { TemplateLibrary } from '@/components/mockup/TemplateLibrary'
import { MockupGenerator } from '@/components/mockup/MockupGenerator'
type Tab = 'generate' | 'library'
export default function MockupPage() {
const [tab, setTab] = useState<Tab>('generate')
const [shopifyId, setShopifyId] = useState('')
const [productName, setProductName] = useState('')
const [family, setFamily] = useState('Menuiserie')
const [dimensions, setDimensions] = useState('')
const [cutoutB64, setCutoutB64] = useState<string | null>(null)
const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (!file) return
const reader = new FileReader()
reader.onload = ev => {
const result = ev.target?.result as string
setCutoutB64(result.split(',')[1])
}
reader.readAsDataURL(file)
}
return (
<>
<Header title="🖼️ Mockups" actions={
<div className="flex gap-2">
{(['generate', 'library'] as Tab[]).map(t => (
<button
key={t}
type="button"
onClick={() => setTab(t)}
className={`px-3 py-1 text-xs rounded-lg transition-colors ${tab === t ? 'bg-indigo-600 text-white' : 'text-gray-400 hover:text-white'}`}
>
{t === 'generate' ? 'Générer' : 'Bibliothèque templates'}
</button>
))}
</div>
} />
<div className="p-6 max-w-2xl mx-auto">
{tab === 'library' ? (
<TemplateLibrary />
) : (
<div className="space-y-4">
<div className="bg-slate-800 rounded-xl p-4 border border-slate-700 space-y-3">
<h2 className="text-sm font-semibold text-white">Produit</h2>
<div className="grid grid-cols-2 gap-3">
<div>
<label className="block text-xs text-gray-400 mb-1">Nom produit</label>
<input value={productName} onChange={e => setProductName(e.target.value)}
className="w-full bg-slate-700 border border-slate-600 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:ring-1 focus:ring-indigo-500" />
</div>
<div>
<label className="block text-xs text-gray-400 mb-1">ID Shopify</label>
<input value={shopifyId} onChange={e => setShopifyId(e.target.value)}
className="w-full bg-slate-700 border border-slate-600 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:ring-1 focus:ring-indigo-500" />
</div>
<div>
<label className="block text-xs text-gray-400 mb-1">Famille</label>
<select value={family} onChange={e => setFamily(e.target.value)}
className="w-full bg-slate-700 border border-slate-600 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
{['Menuiserie', 'Baies vitrées', 'Carrelage', 'Tous'].map(f => <option key={f}>{f}</option>)}
</select>
</div>
<div>
<label className="block text-xs text-gray-400 mb-1">Dimensions (ex: 90x215cm)</label>
<input value={dimensions} onChange={e => setDimensions(e.target.value)}
placeholder="optionnel"
className="w-full bg-slate-700 border border-slate-600 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:ring-1 focus:ring-indigo-500" />
</div>
</div>
<div>
<label className="block text-xs text-gray-400 mb-1">Image découpée (PNG)</label>
<input type="file" accept="image/png" onChange={handleFile} className="text-sm text-gray-300" />
</div>
</div>
{cutoutB64 ? (
<MockupGenerator
productCutoutBase64={cutoutB64}
productName={productName}
shopifyId={shopifyId || undefined}
family={family}
dimensions={dimensions || undefined}
/>
) : (
<p className="text-sm text-gray-500 text-center py-8">Sélectionnez une image découpée pour commencer.</p>
)}
</div>
)}
</div>
</>
)
}