{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cart-empty",
  "type": "registry:component",
  "title": "Empty cart",
  "description": "Token-drawn bag illustration, a human line of copy, a bestsellers action and a two-item rail.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "cart",
    "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/price.json",
    "https://storekit-eight.vercel.app/r/product-image.json",
    "https://storekit-eight.vercel.app/r/sk-analytics.json"
  ],
  "files": [
    {
      "path": "cart/cart-empty.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { useState } from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { Check, Plus } from \"lucide-react\"\nimport { cn } from \"@/components/storekit/lib/cn\"\nimport { Button } from \"@/components/storekit/ui/button\"\nimport { Price } from \"@/components/storekit/ui/price\"\nimport { ProductImage } from \"@/components/storekit/ui/product-image\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Empty cart: a quiet token-drawn illustration, a human line of copy, one\n   clear action and a two-item rail so the next step is one tap away. */\n\nconst EASE: [number, number, number, number] = [0.16, 1, 0.3, 1]\n\ntype Suggestion = { id: string; title: string; price: number; compareAt?: number; image: string }\n\nconst SAMPLE: Suggestion[] = [\n  { id: \"daily-greens\", title: \"Daily Greens\", price: 4900, image: \"/brands/morrow/greens.webp\" },\n  { id: \"electrolytes\", title: \"Electrolytes\", price: 3200, image: \"/brands/morrow/electrolytes.webp\" },\n]\n\nfunction BagIllustration() {\n  return (\n    <svg viewBox=\"0 0 120 120\" className=\"h-28 w-28\" aria-hidden>\n      <circle cx=\"60\" cy=\"60\" r=\"54\" className=\"fill-sk-surface stroke-sk-accent/40\" strokeWidth=\"1.5\" strokeDasharray=\"4 6\" />\n      <path d=\"M38 46h44l-3 40a6 6 0 0 1-6 5.5H47a6 6 0 0 1-6-5.5L38 46z\" className=\"fill-sk-card stroke-sk-ink/50\" strokeWidth=\"2\" strokeLinejoin=\"round\" />\n      <path d=\"M49 52v-9a11 11 0 0 1 22 0v9\" className=\"fill-none stroke-sk-ink/50\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n      <path d=\"M52 70h16\" className=\"stroke-sk-line\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n    </svg>\n  )\n}\n\nexport function CartEmpty({\n  suggestions = SAMPLE,\n  onShop,\n  onAdd,\n  className,\n}: {\n  suggestions?: Suggestion[]\n  onShop?: () => void\n  onAdd?: (id: string) => void\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"cart\", \"cart-empty\")\n  const [added, setAdded] = useState<string | null>(null)\n  const add = (id: string) => {\n    setAdded(id)\n    sk.emit(\"interact\", \"suggestion_add\")\n    onAdd?.(id)\n    window.setTimeout(() => setAdded((a) => (a === id ? null : a)), 1200)\n  }\n  const rise = (i: number) => ({\n    initial: reduce ? false : { opacity: 0, y: 8 },\n    animate: { opacity: 1, y: 0 },\n    transition: { duration: 0.5, delay: i * 0.05, ease: EASE },\n  })\n  return (\n    <div ref={sk.ref as React.Ref<HTMLDivElement>} {...sk.attrs} className={cn(\"mx-auto flex w-full max-w-sm flex-col items-center text-center\", className)}>\n      <motion.div {...rise(0)}>\n        <BagIllustration />\n      </motion.div>\n      <motion.h3 {...rise(1)} className=\"mt-5 font-sk-display text-xl font-semibold leading-[1.1] tracking-[-0.02em]\">\n        Your cart is empty.\n      </motion.h3>\n      <motion.p {...rise(2)} className=\"mt-2 text-sm text-sk-muted\">\n        The best sellers are a good place to start.\n      </motion.p>\n      <motion.div {...rise(3)} className=\"mt-5\">\n        <Button\n          onClick={() => {\n            sk.emit(\"convert\", \"shop_cta\")\n            onShop?.()\n          }}\n        >\n          Shop bestsellers\n        </Button>\n      </motion.div>\n\n      {suggestions.length ? (\n        <motion.div {...rise(4)} className=\"mt-10 w-full text-left\">\n          <p className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">Most reordered</p>\n          <ul className=\"mt-3 grid grid-cols-2 gap-3\">\n            {suggestions.slice(0, 2).map((s) => {\n              const done = added === s.id\n              return (\n                <li key={s.id} className=\"flex flex-col overflow-hidden rounded-sk-card border border-sk-line bg-sk-card\">\n                  <ProductImage src={s.image} alt={s.title} fit=\"cover\" />\n                  <div className=\"flex flex-1 flex-col gap-2 p-3\">\n                    <p className=\"line-clamp-2 hyphens-auto break-words text-sm font-medium leading-snug\">{s.title}</p>\n                    <div className=\"mt-auto flex items-end justify-between gap-2\">\n                      <Price amount={s.price} compareAt={s.compareAt} size=\"sm\" className=\"min-w-0\" />\n                      <button\n                        type=\"button\"\n                        aria-label={done ? `${s.title} added` : `Add ${s.title}`}\n                        onClick={() => add(s.id)}\n                        className={cn(\n                          \"grid h-11 w-11 shrink-0 place-items-center rounded-sk-btn border transition-[transform,background-color,color] duration-200 active:scale-[0.97]\",\n                          \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper\",\n                          done ? \"border-sk-savings/40 text-sk-savings\" : \"border-sk-line text-sk-ink hover:bg-sk-ink/[0.05]\"\n                        )}\n                      >\n                        {done ? <Check size={16} /> : <Plus size={16} />}\n                      </button>\n                    </div>\n                  </div>\n                </li>\n              )\n            })}\n          </ul>\n        </motion.div>\n      ) : null}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/storekit/cart/cart-empty.tsx"
    }
  ],
  "meta": {
    "section": "cart",
    "variant": "empty",
    "niche": [
      "any"
    ],
    "commerce": [
      "cart",
      "atc",
      "recommendations"
    ],
    "previewHeight": 640
  }
}