Fazekit

Code

import * as React from "react";
import { ArrowDownRight, ArrowUpRight } from "lucide-react";
import { cn } from "@/lib/utils";

export type Kpi = { label: string; value: string; delta: number; series: number[] };
export type TopProduct = { name: string; units: number; revenue: string };

function Bars({ series, positive }: { series: number[]; positive: boolean }) {
  const max = Math.max(...series, 1);
  return (
    <div className="flex h-10 items-end gap-[3px]" aria-hidden>
      {series.map((v, i) => (
        <span
          key={i}
          className={cn("w-full rounded-sm", positive ? "bg-emerald-500/70" : "bg-rose-500/70", i === series.length - 1 && "opacity-100", i < series.length - 1 && "opacity-50")}
          style={{ height: `${Math.max(8, (v / max) * 100)}%` }}
        />
      ))}
    </div>
  );
}

export function SalesOverview({ kpis, products, period = "Last 7 days", className }: { kpis: Kpi[]; products: TopProduct[]; period?: string; className?: string }) {
  const maxUnits = Math.max(...products.map((p) => p.units), 1);
  return (
    <div className={cn("w-full space-y-4", className)}>
      <div className="flex items-baseline justify-between">
        <h2 className="text-lg font-semibold">Overview</h2>
        <span className="text-sm text-muted-foreground">{period}</span>
      </div>
      <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
        {kpis.map((k) => {
          const up = k.delta >= 0;
          return (
            <div key={k.label} className="rounded-xl border bg-card p-4 text-card-foreground">
              <p className="text-sm text-muted-foreground">{k.label}</p>
              <div className="mt-1 flex items-baseline gap-2">
                <p className="text-2xl font-semibold tracking-tight tabular-nums">{k.value}</p>
                <span className={cn("flex items-center text-xs font-medium", up ? "text-emerald-600 dark:text-emerald-400" : "text-rose-600 dark:text-rose-400")}>
                  {up ? <ArrowUpRight className="size-3.5" /> : <ArrowDownRight className="size-3.5" />}
                  {Math.abs(k.delta).toFixed(1)}%
                </span>
              </div>
              <div className="mt-3">
                <Bars series={k.series} positive={up} />
              </div>
            </div>
          );
        })}
      </div>
      <div className="rounded-xl border bg-card p-4 text-card-foreground">
        <p className="mb-3 text-sm font-medium">Top products</p>
        <ul className="space-y-3">
          {products.map((p, i) => (
            <li key={p.name} className="grid grid-cols-[1.5rem_1fr_auto] items-center gap-3 text-sm">
              <span className="text-muted-foreground tabular-nums">{i + 1}</span>
              <div className="min-w-0">
                <p className="truncate">{p.name}</p>
                <div className="mt-1 h-1.5 rounded-full bg-muted">
                  <div className="h-full rounded-full bg-primary" style={{ width: `${(p.units / maxUnits) * 100}%` }} />
                </div>
              </div>
              <span className="text-right tabular-nums">
                <span className="font-medium">{p.revenue}</span>
                <span className="block text-xs text-muted-foreground">{p.units} units</span>
              </span>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}