Vector Motion
E-Commerce

Product Categories Card - Category Performance

Monitor product category performance and sales distribution. Track top-performing categories and trends.

Product Categories Card

The Product Categories Card Monitor category performance and sales distribution.

Preview

Installation

ash npx shadcn@latest add https://vectormotion.vercel.app/registry/product-categories-card.json

Product Categories Card
'use client';import React from "react";import { Grid, TrendingUp } from "lucide-react";import { motion } from "motion/react";import { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge";function cn(...inputs: ClassValue[]) {  return twMerge(clsx(inputs));}interface Category {  name: string;  revenue: number;  growth: number;  color: string;  [key: string]: any;}interface ProductCategoriesCardProps {  className?: string;  title?: string;  description?: string;  categories?: Category[];}const DEFAULT_TITLE = "Product Categories";const DEFAULT_DESCRIPTION = "Category Performance";const DEFAULT_CATEGORIES: Category[] = [  { name: "Electronics", revenue: 125000, growth: 15, color: "bg-blue-500" },  { name: "Apparel", revenue: 89000, growth: 8, color: "bg-purple-500" },  {    name: "Home & Garden",    revenue: 67000,    growth: 22,    color: "bg-emerald-500",  },  { name: "Sports", revenue: 45000, growth: -3, color: "bg-orange-500" },];export const ProductCategoriesCard: React.FC<ProductCategoriesCardProps> = ({  className = "",  title = DEFAULT_TITLE,  description = DEFAULT_DESCRIPTION,  categories = DEFAULT_CATEGORIES,}) => {  const isInteractive = true;  const index = 19;  const totalRevenue = categories.reduce((sum, cat) => sum + cat.revenue, 0);  return (    <motion.div      layoutId={isInteractive ? `card-${index}-${title}` : undefined}      transition={{ duration: 0.4, ease: "easeOut" }}      className={cn(        "relative overflow-hidden rounded-xl border border-border bg-card text-card-foreground p-6 shadow-sm transition-all flex flex-col group",        isInteractive          ? "cursor-pointer hover:border-zinc-300 dark:hover:border-zinc-700"          : "",        className,      )}    >      <div className="mb-4 flex items-start justify-between relative z-10">        <div>          <h3 className="font-semibold text-lg tracking-tight text-foreground">            {title}          </h3>          {description && (            <p className="text-sm text-muted-foreground mt-1">{description}</p>          )}        </div>        <div className="rounded-full bg-zinc-100 dark:bg-zinc-800 p-2 text-foreground flex items-center justify-center">          <Grid className="h-5 w-5 text-purple-500" />        </div>      </div>      <div className="relative z-10 flex-1">        <div className="text-2xl font-bold text-foreground mb-1">          ${(totalRevenue / 1000).toFixed(0)}K        </div>        <p className="text-sm text-muted-foreground mb-4">          Total category revenue        </p>        <div className="space-y-3">          {categories.map((category, idx) => {            const percentage = Math.round(              (category.revenue / totalRevenue) * 100,            );            return (              <div key={idx}>                <div className="flex justify-between items-center mb-1">                  <span className="text-sm text-foreground">                    {category.name}                  </span>                  <div className="flex items-center gap-2">                    <span                      className={`text-xs font-medium ${category.growth >= 0                          ? "text-emerald-500"                          : "text-red-500"                        }`}                    >                      {category.growth >= 0 ? "+" : ""}                      {category.growth}%                    </span>                    <span className="text-sm font-bold text-foreground">                      ${(category.revenue / 1000).toFixed(0)}K                    </span>                  </div>                </div>                <div className="flex items-center gap-2">                  <div className="flex-1 bg-zinc-100 dark:bg-zinc-800 rounded-full h-2 overflow-hidden">                    <motion.div                      initial={{ width: 0 }}                      animate={{ width: `${percentage}%` }}                      transition={{ duration: 1, delay: idx * 0.1 }}                      className={`h-full ${category.color} rounded-full`}                    />                  </div>                  <span className="text-xs text-muted-foreground w-8 text-right">                    {percentage}%                  </span>                </div>              </div>            );          })}        </div>      </div>    </motion.div>  );};

Usage

This component is a data-rich dashboard card displaying e-commerce metrics with animated visualizations and dark mode support. Perfect for dashboards, landing pages, and analytics interfaces.

Prop

Type