| import React from "react"; |
| import { Link, useParams } from "react-router-dom"; |
| import { getProduct } from "../data/products.js"; |
|
|
| function SpecRow({ label, value }) { |
| return ( |
| <div className="flex items-center justify-between gap-6 border-b border-neutral-200 py-3 text-sm"> |
| <span className="text-neutral-600">{label}</span> |
| <span className="font-medium text-neutral-900">{value}</span> |
| </div> |
| ); |
| } |
|
|
| export default function Product() { |
| const { slug } = useParams(); |
| const p = getProduct(slug); |
|
|
| if (!p) { |
| return ( |
| <div className="rounded-3xl border border-neutral-200 bg-white p-8"> |
| <h2 className="text-2xl font-semibold">Product not found</h2> |
| <p className="pt-2 text-neutral-600">The product you’re looking for doesn’t exist.</p> |
| <Link to="/store" className="mt-6 inline-block rounded-full bg-neutral-900 px-5 py-2.5 text-sm font-semibold text-white"> |
| Back to Store |
| </Link> |
| </div> |
| ); |
| } |
|
|
| return ( |
| <div className="space-y-10"> |
| <div className="flex items-center justify-between"> |
| <Link to="/store" className="text-sm font-semibold text-neutral-700 hover:text-neutral-900"> |
| ← Back to Store |
| </Link> |
| <p className="text-sm text-neutral-500">From ${p.priceFrom}</p> |
| </div> |
| |
| <section className="grid gap-8 md:grid-cols-2 md:items-start"> |
| <div className="space-y-4"> |
| <p className="text-xs font-semibold uppercase tracking-wider text-neutral-500">{p.category}</p> |
| <h1 className="text-4xl font-semibold tracking-tight">{p.name}</h1> |
| <p className="text-lg text-neutral-600">{p.tagline}</p> |
| |
| <div className="flex flex-wrap gap-3 pt-2"> |
| <button className="rounded-full bg-neutral-900 px-5 py-2.5 text-sm font-semibold text-white hover:bg-neutral-800"> |
| Buy (demo) |
| </button> |
| <a |
| className="rounded-full border border-neutral-300 bg-white px-5 py-2.5 text-sm font-semibold text-neutral-900 hover:bg-neutral-50" |
| href="https://www.apple.com/" |
| target="_blank" |
| rel="noreferrer" |
| > |
| Compare on official site |
| </a> |
| </div> |
| |
| <div className="pt-6"> |
| <h3 className="text-base font-semibold">Highlights</h3> |
| <ul className="mt-3 list-disc space-y-2 pl-5 text-sm text-neutral-700"> |
| {p.highlights.map((h, idx) => ( |
| <li key={idx}>{h}</li> |
| ))} |
| </ul> |
| </div> |
| </div> |
| |
| <div className="space-y-4"> |
| <div className="overflow-hidden rounded-3xl border border-neutral-200"> |
| <img src={p.heroImage} alt={p.name} className="w-full object-cover" loading="lazy" /> |
| </div> |
| |
| <div className="grid grid-cols-2 gap-3"> |
| {p.gallery.map((src, idx) => ( |
| <div key={idx} className="overflow-hidden rounded-2xl border border-neutral-200"> |
| <img src={src} alt={`${p.name} ${idx + 1}`} className="h-32 w-full object-cover" loading="lazy" /> |
| </div> |
| ))} |
| </div> |
| </div> |
| </section> |
| |
| <section className="grid gap-6 md:grid-cols-2"> |
| <div className="rounded-3xl border border-neutral-200 bg-white p-6"> |
| <h3 className="text-base font-semibold">Specifications</h3> |
| <div className="mt-3"> |
| {Object.entries(p.specs).map(([k, v]) => ( |
| <SpecRow key={k} label={k.toUpperCase()} value={v} /> |
| ))} |
| </div> |
| <p className="pt-4 text-xs text-neutral-500"> |
| Replace these sample specs with your own data or data you’re licensed to publish. |
| </p> |
| </div> |
| |
| <div className="rounded-3xl border border-neutral-200 bg-white p-6"> |
| <h3 className="text-base font-semibold">Video</h3> |
| <p className="pt-2 text-sm text-neutral-600"> |
| Embedded video (YouTube). Use official videos or content you have rights to. |
| </p> |
| <div className="mt-4 aspect-video overflow-hidden rounded-2xl border border-neutral-200"> |
| <iframe |
| className="h-full w-full" |
| src={`https://www.youtube.com/embed/${p.youtubeId}`} |
| title="Product video" |
| allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" |
| allowFullScreen |
| /> |
| </div> |
| </div> |
| </section> |
| |
| <section className="rounded-3xl border border-neutral-200 bg-neutral-50 p-6 text-sm text-neutral-700"> |
| <b>Note:</b> This is an original demo UI inspired by modern ecommerce layouts. |
| Do not copy Apple’s site design or use Apple’s copyrighted assets without permission. |
| </section> |
| </div> |
| ); |
| } |
|
|