iWeb / src /pages /Store.jsx
ronylu's picture
Upload 4 files
851da48 verified
Raw
History Blame Contribute Delete
2.54 kB
import React, { useMemo, useState } from "react";
import { Link } from "react-router-dom";
import { products } from "../data/products.js";
export default function Store() {
const [q, setQ] = useState("");
const filtered = useMemo(() => {
const term = q.trim().toLowerCase();
if (!term) return products;
return products.filter((p) =>
[p.name, p.category, p.tagline].some((x) => x.toLowerCase().includes(term))
);
}, [q]);
return (
<div className="space-y-6">
<div className="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div>
<h2 className="text-3xl font-semibold tracking-tight">Store</h2>
<p className="text-neutral-600">Browse products (demo data).</p>
</div>
<div className="w-full md:w-80">
<label className="text-xs font-semibold uppercase tracking-wider text-neutral-500">Search</label>
<input
value={q}
onChange={(e) => setQ(e.target.value)}
placeholder="Search products..."
className="mt-2 w-full rounded-xl border border-neutral-300 bg-white px-4 py-2.5 text-sm outline-none focus:border-neutral-900"
/>
</div>
</div>
<div className="grid gap-4 md:grid-cols-3">
{filtered.map((p) => (
<Link
key={p.slug}
to={`/product/${p.slug}`}
className="group rounded-3xl border border-neutral-200 bg-white p-5 hover:shadow-sm"
>
<div className="overflow-hidden rounded-2xl border border-neutral-200">
<img
src={p.heroImage}
alt={p.name}
className="h-44 w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]"
loading="lazy"
/>
</div>
<div className="pt-4">
<p className="text-xs font-semibold uppercase tracking-wider text-neutral-500">{p.category}</p>
<h3 className="pt-1 text-lg font-semibold tracking-tight">{p.name}</h3>
<p className="pt-1 text-sm text-neutral-600">{p.tagline}</p>
<p className="pt-3 text-sm font-semibold text-neutral-900">From ${p.priceFrom}</p>
</div>
</Link>
))}
</div>
{filtered.length === 0 ? (
<div className="rounded-2xl border border-neutral-200 bg-neutral-50 p-6 text-neutral-700">
No results. Try a different search term.
</div>
) : null}
</div>
);
}