ai-ops-templates/snippets/vendor-card.tsx
DMleadgen 3cb8d3cb3f Initial commit: AI Ops Templates repository
- Schema.org JSON-LD templates (product, event, local-business, faq)
- Brand, UI, SEO, and decision guide rules
- Working code snippets (vendor-card, schema-inject, deploy-webhook)
- JSON schemas for project config validation
- Client presets (slc-bride, default)
- Self-update protocol with changelog tracking

Made-with: Cursor
2026-03-06 16:03:31 -07:00

92 lines
2.7 KiB
TypeScript

import Image from 'next/image'
import Link from 'next/link'
import { Card, CardContent } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Star, MapPin } from 'lucide-react'
interface Vendor {
id: string
name: string
slug: string
category: string
description: string
image_url: string
rating: number
review_count: number
location: string
price_range?: string
}
interface VendorCardProps {
vendor: Vendor
className?: string
}
export function VendorCard({ vendor, className }: VendorCardProps) {
return (
<Link href={`/vendors/${vendor.slug}`}>
<Card className={cn(
'group overflow-hidden transition-all duration-300 hover:shadow-lg',
className
)}>
{/* Image Container */}
<div className="relative aspect-[4/3] overflow-hidden">
<Image
src={vendor.image_url}
alt={`${vendor.name} - ${vendor.category} in ${vendor.location}`}
fill
className="object-cover transition-transform duration-300 group-hover:scale-105"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
{vendor.price_range && (
<Badge className="absolute top-3 right-3" variant="secondary">
{vendor.price_range}
</Badge>
)}
</div>
{/* Content */}
<CardContent className="p-4">
{/* Category Badge */}
<Badge variant="outline" className="mb-2">
{vendor.category}
</Badge>
{/* Name */}
<h3 className="font-semibold text-lg mb-1 group-hover:text-primary transition-colors">
{vendor.name}
</h3>
{/* Rating */}
<div className="flex items-center gap-1 mb-2">
<Star className="h-4 w-4 fill-yellow-400 text-yellow-400" />
<span className="font-medium">{vendor.rating.toFixed(1)}</span>
<span className="text-muted-foreground text-sm">
({vendor.review_count} reviews)
</span>
</div>
{/* Location */}
<div className="flex items-center gap-1 text-muted-foreground text-sm">
<MapPin className="h-3 w-3" />
<span>{vendor.location}</span>
</div>
{/* Description - truncated */}
<p className="mt-2 text-sm text-muted-foreground line-clamp-2">
{vendor.description}
</p>
</CardContent>
</Card>
</Link>
)
}
// Usage:
// import { VendorCard } from '@/components/vendor-card'
//
// <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
// {vendors.map((vendor) => (
// <VendorCard key={vendor.id} vendor={vendor} />
// ))}
// </div>