{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "reviews-summary",
  "type": "registry:block",
  "title": "Review summary",
  "description": "Big average, star histogram that grows into view, write a review and most mentioned chips.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "reviews",
    "any"
  ],
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://storekit-eight.vercel.app/r/cn.json",
    "https://storekit-eight.vercel.app/r/button.json",
    "https://storekit-eight.vercel.app/r/stars.json",
    "https://storekit-eight.vercel.app/r/sk-analytics.json"
  ],
  "files": [
    {
      "path": "reviews/reviews-summary.tsx",
      "content": "\"use client\"\n\nimport { motion, useInView, useReducedMotion } from \"motion/react\"\nimport { PenLine } from \"lucide-react\"\nimport { cn } from \"@/components/storekit/lib/cn\"\nimport { Button } from \"@/components/storekit/ui/button\"\nimport { Stars } from \"@/components/storekit/ui/stars\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Review summary: the average as a big numeral, a five row histogram whose\n   bars grow from the left when scrolled into view, and the most mentioned\n   topics as chips. */\n\nconst EASE = [0.23, 1, 0.32, 1] as const\nconst RING = \"outline-none focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper\"\n\nexport function ReviewsSummary({\n  average = 4.6,\n  /** Counts for 5, 4, 3, 2, 1 stars. */\n  distribution = [962, 214, 61, 25, 22],\n  mentions = [\n    { label: \"Taste\", count: 418 },\n    { label: \"Shipping\", count: 296 },\n    { label: \"Packaging\", count: 187 },\n  ],\n  onWrite,\n  onMention,\n  className,\n}: {\n  average?: number\n  distribution?: number[]\n  mentions?: { label: string; count: number }[]\n  onWrite?: () => void\n  onMention?: (label: string) => void\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"reviews\", \"reviews-summary\")\n  // One observer for the whole block so every bar grows together.\n  const inView = useInView(sk.ref, { once: true, amount: 0.2 })\n  const total = distribution.reduce((a, b) => a + b, 0)\n  const max = Math.max(1, ...distribution)\n\n  return (\n    <section {...sk.attrs} ref={sk.ref as React.RefObject<HTMLElement>} className={cn(\"grid w-full gap-8 rounded-sk-card border border-sk-line bg-sk-card p-5 sm:p-6 md:grid-cols-[auto_1fr] md:gap-12\", className)} aria-label=\"Review summary\">\n      <div className=\"flex flex-col gap-3\">\n        <span className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">Customer reviews</span>\n        <span className=\"font-sk-display text-6xl font-semibold leading-[1.1] tracking-[-0.02em] tabular-nums text-sk-ink\">{average.toFixed(1)}</span>\n        <Stars value={average} size={16} />\n        <span className=\"text-sm text-sk-muted\">\n          Based on <span className=\"tabular-nums\">{total.toLocaleString()}</span> reviews\n        </span>\n        <Button variant=\"outline\" className=\"mt-2 w-full sm:w-auto\" onClick={() => {\n            sk.emit(\"interact\", \"write_review\", undefined)\n            onWrite?.()\n          }}>\n          <PenLine size={15} aria-hidden /> Write a review\n        </Button>\n      </div>\n\n      <div className=\"flex flex-col justify-center gap-6\">\n        <ul className=\"flex flex-col gap-2\">\n          {distribution.map((n, i) => {\n            const stars = 5 - i\n            const pct = total ? Math.round((n / total) * 100) : 0\n            return (\n              <li key={stars} className=\"grid grid-cols-[3.5rem_1fr_3rem] items-center gap-3 text-sm\" aria-label={`${stars} star: ${pct}%`}>\n                <span className=\"tabular-nums text-sk-muted\">{stars} star</span>\n                <span className=\"relative h-2 overflow-hidden rounded-full bg-sk-surface\" aria-hidden>\n                  <motion.span\n                    className=\"absolute inset-y-0 left-0 origin-left rounded-full bg-sk-accent\"\n                    style={{ width: `${(n / max) * 100}%` }}\n                    initial={{ scaleX: reduce ? 1 : 0 }}\n                    animate={{ scaleX: inView || reduce ? 1 : 0 }}\n                    transition={{ duration: reduce ? 0 : 0.6, ease: EASE, delay: reduce ? 0 : 0.1 + i * 0.05 }}\n                  />\n                </span>\n                <span className=\"text-right font-sk-mono text-[12px] tabular-nums text-sk-muted\">{pct}%</span>\n              </li>\n            )\n          })}\n        </ul>\n\n        <div className=\"flex flex-col gap-2.5\">\n          <span className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">Most mentioned</span>\n          <div className=\"flex flex-wrap gap-2\">\n            {mentions.map((m) => (\n              <button\n                key={m.label}\n                type=\"button\"\n                onClick={() => onMention?.(m.label)}\n                className={cn(\"inline-flex h-11 items-center gap-2 rounded-sk-chip border border-sk-line px-4 text-sm text-sk-ink transition-[background-color,transform] duration-200 hover:bg-sk-ink/[0.04] active:scale-[0.97]\", RING)}\n              >\n                {m.label}\n                <span className=\"font-sk-mono text-[11px] tabular-nums text-sk-muted\">{m.count}</span>\n              </button>\n            ))}\n          </div>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "components/storekit/reviews/reviews-summary.tsx"
    }
  ],
  "meta": {
    "section": "reviews",
    "variant": "summary",
    "niche": [
      "any"
    ],
    "commerce": [
      "reviews"
    ],
    "previewHeight": 380
  }
}