Seed: ecommerce template (24 files)

This commit is contained in:
2026-07-23 22:55:39 +00:00
parent 4da53449db
commit 5e6250b2a4
+18 -18
View File
@@ -92,8 +92,8 @@ export default function CheckoutPage() {
<div className="flex items-center justify-center gap-4 mb-12">
{steps.map((s, i) => (
<div key={s.num} className="flex items-center gap-2">
<div className={`flex items-center gap-2 cursor-pointer \${step >= s.num ? "text-stone-900" : "text-stone-400"}`} onClick={() => s.num < step && setStep(s.num)}>
<div className={`h-9 w-9 rounded-full flex items-center justify-center text-sm font-semibold backdrop-blur-xl border-white/20 \${
<div className={`flex items-center gap-2 cursor-pointer ${step >= s.num ? "text-stone-900" : "text-stone-400"}`} onClick={() => s.num < step && setStep(s.num)}>
<div className={`h-9 w-9 rounded-full flex items-center justify-center text-sm font-semibold backdrop-blur-xl border-white/20 ${
step > s.num ? "bg-green-500/80 text-white" : step === s.num ? "bg-stone-900/80 text-white" : "bg-white/80 dark:bg-slate-900/80 text-stone-500"
}`}>
{step > s.num ? <Check className="h-4 w-4" /> : s.num}
@@ -101,7 +101,7 @@ export default function CheckoutPage() {
<span className="hidden sm:inline text-sm font-medium">{s.label}</span>
</div>
{i < steps.length - 1 && (
<div className={`w-12 sm:w-20 h-px \${step > s.num ? "bg-green-500" : "bg-stone-200"}`} />
<div className={`w-12 sm:w-20 h-px ${step > s.num ? "bg-green-500" : "bg-stone-200"}`} />
)}
</div>
))}
@@ -122,7 +122,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">First Name</label>
<div className="relative">
<Input value={shipping.firstName} onChange={(e) => updateShipping("firstName", e.target.value)} placeholder="John" className={`\${errors.firstName ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={shipping.firstName} onChange={(e) => updateShipping("firstName", e.target.value)} placeholder="John" className={`${errors.firstName ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.firstName && shipping.firstName.trim() && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.firstName && <p className="text-xs text-red-500 mt-1">{errors.firstName}</p>}
@@ -130,7 +130,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">Last Name</label>
<div className="relative">
<Input value={shipping.lastName} onChange={(e) => updateShipping("lastName", e.target.value)} placeholder="Doe" className={`\${errors.lastName ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={shipping.lastName} onChange={(e) => updateShipping("lastName", e.target.value)} placeholder="Doe" className={`${errors.lastName ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.lastName && shipping.lastName.trim() && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.lastName && <p className="text-xs text-red-500 mt-1">{errors.lastName}</p>}
@@ -138,7 +138,7 @@ export default function CheckoutPage() {
<div className="sm:col-span-2">
<label className="text-sm font-medium text-stone-700 mb-1.5 block">Email</label>
<div className="relative">
<Input type="email" value={shipping.email} onChange={(e) => updateShipping("email", e.target.value)} placeholder="john@example.com" className={`\${errors.email ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input type="email" value={shipping.email} onChange={(e) => updateShipping("email", e.target.value)} placeholder="john@example.com" className={`${errors.email ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.email && shipping.email?.includes("@") && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.email && <p className="text-xs text-red-500 mt-1">{errors.email}</p>}
@@ -146,7 +146,7 @@ export default function CheckoutPage() {
<div className="sm:col-span-2">
<label className="text-sm font-medium text-stone-700 mb-1.5 block">Address</label>
<div className="relative">
<Input value={shipping.address} onChange={(e) => updateShipping("address", e.target.value)} placeholder="123 Main Street" className={`\${errors.address ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={shipping.address} onChange={(e) => updateShipping("address", e.target.value)} placeholder="123 Main Street" className={`${errors.address ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.address && shipping.address.trim() && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.address && <p className="text-xs text-red-500 mt-1">{errors.address}</p>}
@@ -154,7 +154,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">City</label>
<div className="relative">
<Input value={shipping.city} onChange={(e) => updateShipping("city", e.target.value)} placeholder="New York" className={`\${errors.city ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={shipping.city} onChange={(e) => updateShipping("city", e.target.value)} placeholder="New York" className={`${errors.city ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.city && shipping.city.trim() && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.city && <p className="text-xs text-red-500 mt-1">{errors.city}</p>}
@@ -167,7 +167,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">ZIP</label>
<div className="relative">
<Input value={shipping.zip} onChange={(e) => updateShipping("zip", e.target.value)} placeholder="10001" className={`\${errors.zip ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={shipping.zip} onChange={(e) => updateShipping("zip", e.target.value)} placeholder="10001" className={`${errors.zip ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.zip && shipping.zip.trim() && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.zip && <p className="text-xs text-red-500 mt-1">{errors.zip}</p>}
@@ -203,7 +203,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">Card Number</label>
<div className="relative">
<Input value={payment.cardNumber} onChange={(e) => updatePayment("cardNumber", e.target.value)} placeholder="4242 4242 4242 4242" className={`\${errors.cardNumber ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={payment.cardNumber} onChange={(e) => updatePayment("cardNumber", e.target.value)} placeholder="4242 4242 4242 4242" className={`${errors.cardNumber ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.cardNumber && payment.cardNumber.replace(/\s/g, "").length >= 16 && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.cardNumber && <p className="text-xs text-red-500 mt-1">{errors.cardNumber}</p>}
@@ -212,7 +212,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">Expiry Date</label>
<div className="relative">
<Input value={payment.expiry} onChange={(e) => updatePayment("expiry", e.target.value)} placeholder="MM/YY" className={`\${errors.expiry ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={payment.expiry} onChange={(e) => updatePayment("expiry", e.target.value)} placeholder="MM/YY" className={`${errors.expiry ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.expiry && payment.expiry.trim() && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.expiry && <p className="text-xs text-red-500 mt-1">{errors.expiry}</p>}
@@ -220,7 +220,7 @@ export default function CheckoutPage() {
<div>
<label className="text-sm font-medium text-stone-700 mb-1.5 block">CVV</label>
<div className="relative">
<Input value={payment.cvv} onChange={(e) => updatePayment("cvv", e.target.value)} placeholder="123" className={`\${errors.cvv ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
<Input value={payment.cvv} onChange={(e) => updatePayment("cvv", e.target.value)} placeholder="123" className={`${errors.cvv ? "border-red-500 focus-visible:ring-red-500" : ""}`} />
{!errors.cvv && payment.cvv.length >= 3 && <Check className="h-4 w-4 text-emerald-500 absolute right-3 top-1/2 -translate-y-1/2" />}
</div>
{errors.cvv && <p className="text-xs text-red-500 mt-1">{errors.cvv}</p>}
@@ -260,7 +260,7 @@ export default function CheckoutPage() {
<p className="text-sm font-medium truncate">{item.name}</p>
<p className="text-xs text-stone-500">Qty: {item.quantity} | {item.size} | {item.color}</p>
</div>
<span className="text-sm font-semibold">\${(item.price * item.quantity).toFixed(2)}</span>
<span className="text-sm font-semibold">${(item.price * item.quantity).toFixed(2)}</span>
</div>
))}
</div>
@@ -308,7 +308,7 @@ export default function CheckoutPage() {
{items.map((item) => (
<div key={item.id} className="flex justify-between text-sm">
<span className="text-stone-600 truncate mr-2">{item.name} x{item.quantity}</span>
<span className="font-medium shrink-0">\${(item.price * item.quantity).toFixed(2)}</span>
<span className="font-medium shrink-0">${(item.price * item.quantity).toFixed(2)}</span>
</div>
))}
</div>
@@ -316,23 +316,23 @@ export default function CheckoutPage() {
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-stone-500">Subtotal</span>
<span>\${total.toFixed(2)}</span>
<span>${total.toFixed(2)}</span>
</div>
<div className="flex justify-between">
<span className="text-stone-500">Shipping</span>
<span className={shippingCost === 0 ? "text-green-600" : ""}>
{shippingCost === 0 ? "Free" : `\$\${shippingCost.toFixed(2)}`}
{shippingCost === 0 ? "Free" : `$${shippingCost.toFixed(2)}`}
</span>
</div>
<div className="flex justify-between">
<span className="text-stone-500">Tax</span>
<span>\${tax.toFixed(2)}</span>
<span>${tax.toFixed(2)}</span>
</div>
</div>
<Separator className="my-4" />
<div className="flex justify-between text-lg font-bold">
<span>Total</span>
<span>\${grandTotal.toFixed(2)}</span>
<span>${grandTotal.toFixed(2)}</span>
</div>
</CardContent>
</Card>