Initial commit: Craft2Prints with Stages 1-3

This commit is contained in:
Andymick
2026-07-15 18:09:59 +01:00
commit 41937ffc15
158 changed files with 16054 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
import Link from 'next/link';
import ProductMockup from './ProductMockup';
import Price from './Price';
import type { ProductDTO } from '@/lib/types';
const NEW_WINDOW_MS = 1000 * 60 * 60 * 24 * 30; // 30 days
export default function ProductCard({
product,
hrefBase = '/made-to-order',
}: {
product: ProductDTO;
hrefBase?: string;
}) {
const thumbnail = product.colorPhotos[product.colors[0]] ?? product.imageUrl;
const isNew = Date.now() - new Date(product.createdAt).getTime() < NEW_WINDOW_MS;
return (
<Link href={`${hrefBase}/${product.slug}`} className="group block">
<div className="relative border border-line bg-surface p-6 shadow-sm transition-all duration-300 group-hover:-translate-y-1 group-hover:border-ink group-hover:shadow-lg">
{isNew && (
<span className="tag-label absolute left-3 top-3 rounded-full bg-splash-blue/10 px-2.5 py-1 text-splash-blue">
New
</span>
)}
{product.onSale && (
<span className="tag-label absolute right-3 top-3 rounded-full bg-splash-pink/10 px-2.5 py-1 text-splash-pink">
Sale
</span>
)}
<div className="mx-auto aspect-square w-full max-w-[280px] overflow-hidden">
{thumbnail ? (
<img
src={thumbnail}
alt={product.name}
className="h-full w-full object-contain transition-transform duration-300 group-hover:scale-105"
/>
) : (
<div className="transition-transform duration-300 group-hover:scale-105">
<ProductMockup mockup={product.mockup} color={product.colors[0]} />
</div>
)}
</div>
</div>
<div className="mt-3 flex justify-end gap-2 text-right">
{product.onSale && product.originalPrice != null && (
<Price cents={product.originalPrice} className="font-mono text-sm text-muted line-through" />
)}
<Price
cents={product.effectivePrice}
className={`font-mono text-sm ${product.onSale ? 'text-splash-pink' : 'text-muted'}`}
/>
</div>
</Link>
);
}