Todos os componentes

Product Quickviews 01

Product Quickviews 01 é um componente para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.

Bund UI MIT other

O que é

Product Quickviews 01 é um componente para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.

Como usar

Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.

Abrir no catálogo

Cinco cópias grátis por mês. Sem cartão.

Precisa de

npm i lucide-react

Licença

Este componente vem de Bund UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.

Product Quickviews 01

examples/blocks/ecommerce/product-quickviews/01/components/product-quickview-modal.tsx
"use client";

import { useState } from "react";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { HeartIcon, Star, X } from "lucide-react";
import { cn } from "@/lib/utils";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

interface ProductQuickviewProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  product: {
    id: string;
    title: string;
    price: number;
    rating: number;
    reviewCount: number;
    image: string;
    colors: Array<{ name: string; value: string }>;
    sizes: Array<{ name: string; available: boolean }>;
  };
}

export function ProductQuickviewDialog({ open, onOpenChange, product }: ProductQuickviewProps) {
  const [selectedColor, setSelectedColor] = useState(product.colors[0]?.name);
  const [selectedSize, setSelectedSize] = useState("S");

  const renderStars = (rating: number) => {
    return Array(5)
      .fill("")
      .map((_, i) =>
        i < rating ? (
          <Star key={i} className="size-4 fill-amber-500 text-amber-500 lg:size-5" />
        ) : (
          <Star key={i} className="text-muted-foreground size-4 lg:size-5" />
        )
      );
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="gap-0 overflow-hidden p-0 sm:max-w-4xl">
        <div className="flex grid-cols-1 flex-col gap-0 md:grid md:grid-cols-2">
          {/* Product Image */}
          <figure className="flex items-center justify-center">
            <img
              src={product.image}
              alt={product.title}
              className="aspect-square h-full w-full object-cover"
            />
          </figure>

          {/* Product Details */}
          <div className="flex flex-col p-4 md:p-8">
            <div className="flex-1">
              <h2 className="font-heading mb-4 text-2xl text-balance lg:text-3xl">
                {product.title}
              </h2>

              <p className="mb-4 text-2xl font-medium lg:mb-6">${product.price}</p>

              {/* Rating */}
              <div className="mb-6 flex items-center gap-3 lg:mb-8">
                <div className="flex gap-1">{renderStars(product.rating)}</div>
                <a href="#" className="text-sm font-medium text-indigo-600 hover:text-indigo-700">
                  {product.reviewCount} reviews
                </a>
              </div>

              {/* Color Selection */}
              <fieldset className="mb-4 space-y-4 lg:mb-8">
                <legend className="text-foreground text-sm leading-none font-medium">Color</legend>
                <RadioGroup
                  className="flex gap-1.5"
                  onValueChange={(value) => setSelectedColor(value)}
                  defaultValue="blue">
                  {product.colors.map((color) => (
                    <RadioGroupItem
                      value={color.name}
                      style={{ backgroundColor: color.value }}
                      aria-label={`Select ${color.name} color`}
                      className={cn(
                        "size-6 rounded-full border-1 transition-all",
                        selectedColor === color.name
                          ? "border-foreground ring-foreground ring ring-offset-2"
                          : "border-border hover:border-foreground/50"
                      )}
                    />
                  ))}
                </RadioGroup>
              </fieldset>

              {/* Size Selection */}
              <fieldset className="mb-4 space-y-4 lg:mb-8">
                <legend className="text-foreground flex w-full items-center justify-between text-sm leading-none font-medium">
                  <span>Size</span>
                  <a
                    href="#size-guide"
                    className="text-sm font-medium text-indigo-600 hover:text-indigo-700">
                    Size guide
                  </a>
                </legend>
                <RadioGroup
                  className="grid grid-cols-4 gap-2"
                  onValueChange={(value) => setSelectedSize(value)}
                  defaultValue="1">
                  {product.sizes.map((size) => (
                    <label
                      key={`${size.name}`}
                      className="border-input has-focus-visible:border-ring has-focus-visible:ring-ring/50 has-data-[state=checked]:border-primary/50 relative flex cursor-pointer flex-col items-center gap-3 rounded-md border px-2 py-3 text-center shadow-xs transition-[color,box-shadow] outline-none has-focus-visible:ring-[3px] has-data-disabled:cursor-not-allowed has-data-disabled:opacity-50">
                      <RadioGroupItem
                        id={`${size.name}`}
                        value={size.name}
                        className="sr-only after:absolute after:inset-0"
                      />
                      <p className="text-foreground text-sm leading-none font-medium">
                        {size.name}
                      </p>
                    </label>
                  ))}
                </RadioGroup>
              </fieldset>
            </div>

            {/* Add to Bag Button */}
            <div className="flex gap-2">
              <Button size="lg" className="grow">
                Add to Cart
              </Button>
              <Button variant="outline" size="lg">
                <HeartIcon />
              </Button>
            </div>
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}
examples/blocks/ecommerce/product-quickviews/01/page.tsx
"use client";

import { ProductQuickviewDialog } from "./components/product-quickview-modal";
import Link from "next/link";
import Image from "next/image";
import { useState } from "react";
import { Button } from "@/components/ui/button";

const productData = {
  id: "1",
  title: "Skater Jeans",
  price: 49,
  rating: 4,
  reviewCount: 117,
  image: "/images/products/list2.png",
  colors: [
    { name: "White", value: "#FFFFFF" },
    { name: "Gray", value: "#9CA3AF" },
    { name: "Crimson", value: "crimson" },
    { name: "Navy", value: "#1E293B" }
  ],
  sizes: [
    { name: "XXS", available: true },
    { name: "XS", available: true },
    { name: "S", available: true },
    { name: "M", available: true },
    { name: "L", available: true },
    { name: "XL", available: true },
    { name: "XXL", available: true },
    { name: "XXXL", available: false }
  ]
};

export default function Page() {
  const [open, setOpen] = useState(true);

  return (
    <>
      <div className="mx-auto max-w-80 py-60 md:py-24">
        <Link href="#" className="group">
          <figure className="relative aspect-square w-full overflow-hidden rounded-md object-cover">
            <Image
              fill
              className="object-cover transition-transform duration-300 group-hover:scale-105 group-hover:rotate-2"
              src={productData.image}
              alt={productData.title}
            />
          </figure>
          <div className="mt-3 space-y-2">
            <div className="flex items-center justify-between gap-1">
              <p className="font-medium">{productData.title}</p>
              <p className="text-muted-foreground">{productData.price}</p>
            </div>
          </div>
          <Button onClick={() => setOpen(true)} variant="secondary" className="mt-4 w-full">
            Quick View
          </Button>
        </Link>
      </div>
      <ProductQuickviewDialog open={open} onOpenChange={setOpen} product={productData} />
    </>
  );
}

Componentes parecidos