{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "frequently-bought-together",
  "title": "Frequently Bought Together",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/frequently-bought-together/FrequentlyBoughtTogether.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Plus, ShoppingBag, Truck } from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card } from '@/components/ui/card'\nimport { Checkbox } from '@/components/ui/checkbox'\n\ninterface BundleItem {\n  id: string\n  name: string\n  subtitle: string\n  price: number\n  image: string\n  isMain?: boolean\n}\n\nconst items: BundleItem[] = [\n  {\n    id: 'headphones',\n    name: 'Pro Studio Headphones',\n    subtitle: 'Space Black · Over-Ear Wireless ANC',\n    price: 299.0,\n    image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=500&auto=format&fit=crop&q=80',\n    isMain: true,\n  },\n  {\n    id: 'case',\n    name: 'Premium Hard Shell Case',\n    subtitle: 'Weather-resistant EVA shell with plush velvet lining',\n    price: 45.0,\n    image: 'https://images.unsplash.com/photo-1583394838336-acd977736f90?w=500&auto=format&fit=crop&q=80',\n  },\n  {\n    id: 'cable',\n    name: 'Braided 3.5mm Audiophile Cable',\n    subtitle: '1.5m Silver-plated OFC copper with gold-plated jacks',\n    price: 25.0,\n    image: 'https://images.unsplash.com/photo-1546435770-a3e426bf472b?w=500&auto=format&fit=crop&q=80',\n  },\n]\n\nconst selectedIds = ref<string[]>(['headphones', 'case', 'cable'])\n\nfunction toggleItem(id: string) {\n  if (selectedIds.value.includes(id)) {\n    selectedIds.value = selectedIds.value.filter((itemId) => itemId !== id)\n  } else {\n    selectedIds.value = [...selectedIds.value, id]\n  }\n}\n\nconst selectedItems = computed(() => items.filter((item) => selectedIds.value.includes(item.id)))\nconst selectedCount = computed(() => selectedItems.value.length)\n\nconst originalTotal = computed(() => selectedItems.value.reduce((sum, item) => sum + item.price, 0))\n\nconst discountRate = computed(() => (selectedCount.value >= 2 ? 0.15 : 0))\nconst discountAmount = computed(() => originalTotal.value * discountRate.value)\nconst finalPrice = computed(() => originalTotal.value - discountAmount.value)\nconst hasDiscount = computed(() => discountRate.value > 0)\n\nconst buttonText = computed(() => {\n  if (selectedCount.value === items.length) return `Add all ${items.length} to Cart`\n  if (selectedCount.value > 1) return `Add ${selectedCount.value} selected to Cart`\n  if (selectedCount.value === 1) return 'Add 1 selected to Cart'\n  return 'Select items to add'\n})\n\nconst deliveryNote = computed(() => {\n  if (selectedCount.value >= 2) return 'Free express delivery included with this bundle'\n  if (selectedCount.value === 1) return 'Standard delivery included'\n  return 'Select items to view delivery options'\n})\n\nfunction formatCurrency(val: number) {\n  return '$' + val.toFixed(2)\n}\n</script>\n\n<template>\n  <Card data-slot=\"frequently-bought-together\" class=\"mx-auto w-full max-w-4xl space-y-6 p-6 shadow-xs\">\n    <!-- Header -->\n    <div class=\"space-y-1.5\">\n      <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">Frequently Bought Together</h2>\n      <p class=\"text-muted-foreground text-sm\">\n        Pair with these recommended essentials for maximum performance and save 15% on the bundle\n      </p>\n    </div>\n\n    <!-- Product Visual Row -->\n    <div class=\"grid grid-cols-1 items-center gap-3 sm:grid-cols-[1fr_auto_1fr_auto_1fr] sm:gap-4\">\n      <template v-for=\"(item, index) in items\" :key=\"item.id\">\n        <div\n          class=\"border-border bg-muted/20 relative flex flex-col rounded-xl border p-3 text-left transition-colors duration-200 sm:p-4\"\n          :class=\"selectedIds.includes(item.id) ? 'opacity-100' : 'opacity-40 grayscale'\"\n        >\n          <div class=\"border-border bg-background relative mb-3 aspect-square w-full overflow-hidden rounded-lg border\">\n            <img :src=\"item.image\" :alt=\"item.name\" class=\"size-full object-cover\" />\n            <Badge\n              v-if=\"item.isMain\"\n              variant=\"secondary\"\n              class=\"bg-background/90 text-foreground absolute top-2 left-2 text-xs font-medium backdrop-blur-xs\"\n            >\n              This item\n            </Badge>\n          </div>\n          <span class=\"text-foreground line-clamp-1 text-xs leading-tight font-semibold sm:text-sm\">\n            {{ item.name }}\n          </span>\n          <span class=\"text-foreground mt-1 text-xs font-semibold tabular-nums sm:text-sm\">\n            {{ formatCurrency(item.price) }}\n          </span>\n        </div>\n\n        <div\n          v-if=\"index < items.length - 1\"\n          class=\"border-border/50 text-muted-foreground bg-muted mx-auto flex size-8 shrink-0 items-center justify-center rounded-full border\"\n          aria-hidden=\"true\"\n        >\n          <Plus class=\"size-4\" />\n        </div>\n      </template>\n    </div>\n\n    <!-- Item Selection Checkbox List -->\n    <div class=\"space-y-2.5\">\n      <div\n        v-for=\"item in items\"\n        :key=\"item.id\"\n        role=\"button\"\n        tabindex=\"0\"\n        class=\"border-border focus-visible:ring-ring flex cursor-pointer items-start justify-between gap-3 rounded-lg border p-3.5 transition-colors select-none focus-visible:ring-2 focus-visible:outline-none sm:items-center\"\n        :class=\"\n          selectedIds.includes(item.id)\n            ? 'bg-card hover:border-primary/40'\n            : 'border-border/60 bg-muted/10 opacity-60 hover:opacity-80'\n        \"\n        @click=\"toggleItem(item.id)\"\n        @keydown.space.prevent=\"toggleItem(item.id)\"\n        @keydown.enter.prevent=\"toggleItem(item.id)\"\n      >\n        <div class=\"flex items-start gap-3 sm:items-center\">\n          <Checkbox\n            :id=\"item.id\"\n            :model-value=\"selectedIds.includes(item.id)\"\n            class=\"pointer-events-none mt-0.5 sm:mt-0\"\n            tabindex=\"-1\"\n          />\n          <div class=\"space-y-0.5\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <span class=\"text-foreground text-sm font-medium\">\n                <span v-if=\"item.isMain\" class=\"font-semibold\">This item: </span>\n                {{ item.name }}\n              </span>\n              <Badge v-if=\"item.isMain\" variant=\"secondary\" class=\"text-xs\"> Main Item </Badge>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">{{ item.subtitle }}</p>\n          </div>\n        </div>\n        <span class=\"text-foreground shrink-0 text-sm font-semibold tabular-nums\">\n          {{ formatCurrency(item.price) }}\n        </span>\n      </div>\n    </div>\n\n    <!-- Price & Bundle Checkout Summary Box -->\n    <div\n      class=\"border-border bg-muted/30 flex flex-col gap-4 rounded-xl border p-4 sm:p-5 md:flex-row md:items-center md:justify-between\"\n    >\n      <div class=\"space-y-1.5\">\n        <div class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n          {{ selectedCount >= 2 ? 'Bundle Price' : 'Total Price' }}\n        </div>\n        <div class=\"flex flex-wrap items-baseline gap-2.5\">\n          <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">\n            {{ formatCurrency(finalPrice) }}\n          </span>\n          <span\n            v-if=\"hasDiscount\"\n            class=\"text-muted-foreground text-sm font-medium tabular-nums line-through sm:text-base\"\n          >\n            {{ formatCurrency(originalTotal) }}\n          </span>\n          <Badge\n            v-if=\"hasDiscount\"\n            variant=\"outline\"\n            class=\"border-success/30 bg-success/10 text-success text-xs font-medium\"\n          >\n            Save {{ formatCurrency(discountAmount) }} (15% Bundle Discount)\n          </Badge>\n        </div>\n        <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n          <Truck class=\"text-success size-3.5 shrink-0\" />\n          <span>{{ deliveryNote }}</span>\n        </div>\n      </div>\n\n      <Button size=\"lg\" :disabled=\"selectedCount === 0\" class=\"w-full gap-2 font-semibold shadow-xs md:w-auto\">\n        <ShoppingBag class=\"size-4\" />\n        <span>{{ buttonText }}</span>\n      </Button>\n    </div>\n  </Card>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/FrequentlyBoughtTogether.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/checkbox.json"
  ],
  "description": "E-commerce frequently bought together bundle builder with interactive product preview cards, checkbox selection, dynamic bundle discount calculation, and one-click cart checkout.",
  "categories": [
    "commerce",
    "ecommerce"
  ]
}