TheBird

Product.jsx

3.1 kB · jsx · 74 lines

1import { useRef, useState } from "react";2import { SHOP } from "../config/shop.ts";3import { Breadcrumbs } from "../components/Breadcrumbs.jsx";4import { Carousel, FullGrid, Mockups, mockupSlides } from "../components/Gallery.jsx";5import { MoreVariations } from "../components/MoreVariations.jsx";6import { ProductDetails } from "../components/ProductDetails.jsx";7import { ProductGrid } from "../components/ProductGrid.jsx";8import { Strip } from "../components/Strip.jsx";9import { pickPrimary, useNow, usePrimary } from "../lib/hooks.ts";10import { left } from "../lib/life.ts";1112export function Product({ trail, product, family, matching = [], alike = [], printful, shop, tiles, buyPrefix, review, preview = false, now: built }) {13  const primary = usePrimary("light");14  const one = product[primary] ?? product.light;15  const now = useNow(built);16  const [index, setIndex] = useState(0);17  const [size, setSize] = useState("");18  const box = useRef(null);19  const hold = useRef(null);20  const slides = mockupSlides(one.images, product.title);21  const at = index < slides.length ? index : 0;22  const variant = one.variants.find((each) => each.size === size) ?? one.variants[0];23  const dead = Boolean(one.released) && left(one.released, now) <= 0;24  const jump = (i) => {25    setIndex(i);26    if (box.current?.open) box.current.close();27    else hold.current?.scrollIntoView({ block: "start", behavior: "smooth" });28  };29  return (30    <div className="wrap">31      <Breadcrumbs trail={trail} />32      <article className="product" data-primary={primary}>33        <div className="left">34          <Carousel slides={slides} index={at} onIndex={setIndex} keys full label="Image" hold={hold} onFull={() => box.current?.showModal()} />35          <Mockups images={one.images} title={product.title} onJump={jump} />36        </div>37        <div className="side">38          <ProductDetails39            product={product}40            one={one}41            primary={primary}42            onPrimary={pickPrimary}43            variant={variant}44            size={variant ? variant.size : ""}45            onSize={setSize}46            image={slides[at] ? slides[at].full : ""}47            buyPrefix={buyPrefix}48            printful={printful}49            shop={shop}50            tiles={tiles}51            now={built}52            review={review}53            preview={preview}54            dead={dead}55          />56          <MoreVariations family={family} current={product.design} title={product.title} shop={shop} />57        </div>58      </article>59      {matching.length ? (60        <section className="alike" aria-labelledby="matching">61          <Strip id="matching" title="Matching Products" href={`${SHOP}?design=${product.design}`} more={`All ${product.design}`} />62          <ProductGrid products={matching} now={built} />63        </section>64      ) : null}65      {alike.length ? (66        <section className="alike" aria-labelledby="alike">67          <Strip id="alike" title="You May Also Like" href={SHOP} more="All variations" />68          <ProductGrid products={alike} now={built} />69        </section>70      ) : null}71      <FullGrid images={one.images} title={product.title} box={box} onJump={jump} />72    </div>73  );74}