Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import Link from 'next/link'
|
|
import Image from 'next/image'
|
|
import { Card, CardContent } from '@/components/ui/card'
|
|
import type { Product } from '@/lib/products/types'
|
|
|
|
interface ProductCardProps {
|
|
product: Product
|
|
}
|
|
|
|
export function ProductCard({ product }: ProductCardProps) {
|
|
const imageUrl = product.images?.[0] || '/placeholder.svg'
|
|
const description = product.description
|
|
? product.description.length > 120
|
|
? `${product.description.substring(0, 120)}...`
|
|
: product.description
|
|
: ''
|
|
|
|
return (
|
|
<Link href={`/products/${product.id}`}>
|
|
<Card className="border-border/50 overflow-hidden hover:border-secondary/50 hover:shadow-lg transition-shadow transition-colors h-full flex flex-col">
|
|
<div className="aspect-square relative overflow-hidden bg-muted">
|
|
<Image
|
|
src={imageUrl}
|
|
alt={product.name}
|
|
fill
|
|
className="object-cover hover:scale-105 transition-transform duration-300"
|
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
/>
|
|
</div>
|
|
<CardContent className="p-6 flex flex-col flex-1">
|
|
<h3 className="text-xl font-semibold mb-2">{product.name}</h3>
|
|
{description && (
|
|
<p className="text-sm text-muted-foreground leading-relaxed mb-4 flex-1">
|
|
{description}
|
|
</p>
|
|
)}
|
|
<div className="mt-auto">
|
|
<p className="text-2xl font-bold text-secondary">
|
|
${product.price.toFixed(2)} {product.currency.toUpperCase()}
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</Link>
|
|
)
|
|
}
|
|
|
|
|