{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "search-results-page",
  "title": "Search Results Page",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-vue/blocks/search-results-page/SearchResultsPage.vue",
      "content": "<script setup lang=\"ts\">\nimport type { Component, HTMLAttributes } from 'vue'\nimport { computed, ref } from 'vue'\nimport { BookOpen, FileText, GitBranch, MessageSquare, Search, Users, Video } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport { Chip } from '@/components/ui/chip'\nimport { Input } from '@/components/ui/input'\n\ninterface SearchResult {\n  id: string\n  icon: Component\n  title: string\n  path: string\n  snippet: string\n  type: string\n  updated: string\n}\n\ninterface FacetOption {\n  id: string\n  label: string\n  count: number\n}\n\ninterface FacetGroup {\n  id: string\n  label: string\n  options: FacetOption[]\n}\n\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n}>()\n\nconst query = ref('onboarding flows')\n\nconst chips = ref([\n  { id: 'type-docs', label: 'Type: Docs' },\n  { id: 'team-product', label: 'Team: Product' },\n])\n\nfunction removeChip(id: string) {\n  chips.value = chips.value.filter((chip) => chip.id !== id)\n}\n\nfunction clearAll() {\n  chips.value = []\n}\n\nconst facetGroups: FacetGroup[] = [\n  {\n    id: 'type',\n    label: 'Type',\n    options: [\n      { id: 'type-docs', label: 'Docs', count: 18 },\n      { id: 'type-guides', label: 'Guides', count: 11 },\n      { id: 'type-video', label: 'Video', count: 7 },\n      { id: 'type-discussion', label: 'Discussion', count: 6 },\n    ],\n  },\n  {\n    id: 'team',\n    label: 'Team',\n    options: [\n      { id: 'team-product', label: 'Product', count: 14 },\n      { id: 'team-engineering', label: 'Engineering', count: 16 },\n      { id: 'team-design', label: 'Design', count: 8 },\n      { id: 'team-support', label: 'Support', count: 4 },\n    ],\n  },\n]\n\nconst activeFacets = ref(new Set(['type-docs', 'team-product']))\n\nfunction toggleFacet(id: string, checked: boolean) {\n  const next = new Set(activeFacets.value)\n  if (checked) next.add(id)\n  else next.delete(id)\n  activeFacets.value = next\n}\n\nconst results: SearchResult[] = [\n  {\n    id: 'r1',\n    icon: BookOpen,\n    title: 'Onboarding flows: design your first-run experience',\n    path: 'docs.acme.dev / guides / onboarding-flows',\n    snippet:\n      'Learn how to compose onboarding flows from checklists, tours, and progressive disclosure so new users reach their first aha moment faster.',\n    type: 'Docs',\n    updated: '2 days ago',\n  },\n  {\n    id: 'r2',\n    icon: FileText,\n    title: 'Checklist API reference for onboarding flows',\n    path: 'docs.acme.dev / api / checklist',\n    snippet:\n      'Full reference for the Checklist primitive used to drive onboarding flows, including step completion events, persistence, and theming.',\n    type: 'Reference',\n    updated: '5 hours ago',\n  },\n  {\n    id: 'r3',\n    icon: Video,\n    title: 'Video walkthrough: building onboarding flows in 20 minutes',\n    path: 'learn.acme.dev / videos / onboarding-flows-walkthrough',\n    snippet:\n      'A hands-on screencast that builds a complete onboarding flow with branching steps, skippable tours, and analytics instrumentation.',\n    type: 'Video',\n    updated: '1 week ago',\n  },\n  {\n    id: 'r4',\n    icon: MessageSquare,\n    title: 'How do you measure completion of onboarding flows?',\n    path: 'community.acme.dev / discussions / 4821',\n    snippet:\n      'Community thread comparing activation-rate funnels, step-drop-off charts, and qualitative surveys for measuring onboarding flow success.',\n    type: 'Discussion',\n    updated: '3 days ago',\n  },\n  {\n    id: 'r5',\n    icon: GitBranch,\n    title: 'Example repo: onboarding flows with A/B-tested variants',\n    path: 'github.com / acme / examples / onboarding-ab-test',\n    snippet:\n      'Runnable example that splits new signups into two onboarding flow variants and reports which one converts better to first project creation.',\n    type: 'Example',\n    updated: '2 weeks ago',\n  },\n  {\n    id: 'r6',\n    icon: Users,\n    title: 'Playbook: personalizing onboarding flows by team role',\n    path: 'docs.acme.dev / playbooks / role-based-onboarding',\n    snippet:\n      'Patterns for tailoring onboarding flows to admins, editors, and viewers, with sample copy, suggested defaults, and rollout checklists.',\n    type: 'Guide',\n    updated: '4 days ago',\n  },\n]\n\nconst page = ref(1)\nconst totalPages = 3\n\nconst resultRange = computed(() => {\n  const start = (page.value - 1) * 6 + 1\n  return `${start}-${start + results.length - 1}`\n})\n</script>\n\n<template>\n  <div data-slot=\"search-results-page\" :class=\"cn('w-full space-y-6', props.class)\">\n    <div class=\"space-y-3\">\n      <div class=\"relative max-w-xl\">\n        <Search\n          aria-hidden=\"true\"\n          class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n        />\n        <Input v-model=\"query\" type=\"search\" placeholder=\"Search...\" class=\"h-11 pl-9 text-base\" />\n      </div>\n      <p class=\"text-muted-foreground text-sm\">{{ resultRange }} of 42 results for &ldquo;{{ query }}&rdquo;</p>\n    </div>\n\n    <div v-if=\"chips.length > 0\" class=\"flex flex-wrap items-center gap-2\">\n      <Chip v-for=\"chip in chips\" :key=\"chip.id\" variant=\"outline\" size=\"sm\" closable @close=\"removeChip(chip.id)\">\n        {{ chip.label }}\n      </Chip>\n      <Button variant=\"link\" size=\"sm\" class=\"text-muted-foreground h-auto min-h-6 px-2\" @click=\"clearAll\">\n        Clear all\n      </Button>\n    </div>\n\n    <div class=\"flex gap-8\">\n      <aside class=\"hidden w-48 shrink-0 space-y-6 lg:block\" aria-label=\"Filters\">\n        <div v-for=\"group in facetGroups\" :key=\"group.id\">\n          <h3 class=\"text-muted-foreground mb-3 text-xs font-medium tracking-wider uppercase\">\n            {{ group.label }}\n          </h3>\n          <ul class=\"space-y-2.5\">\n            <li v-for=\"option in group.options\" :key=\"option.id\">\n              <label :for=\"`${group.id}-${option.id}`\" class=\"flex cursor-pointer items-center gap-2 text-sm\">\n                <Checkbox\n                  :id=\"`${group.id}-${option.id}`\"\n                  :model-value=\"activeFacets.has(option.id)\"\n                  @update:model-value=\"toggleFacet(option.id, $event === true)\"\n                />\n                <span>{{ option.label }}</span>\n                <span class=\"text-muted-foreground ml-auto text-xs tabular-nums\">{{ option.count }}</span>\n              </label>\n            </li>\n          </ul>\n        </div>\n      </aside>\n\n      <div class=\"min-w-0 flex-1\">\n        <ol class=\"divide-border divide-y\">\n          <li v-for=\"result in results\" :key=\"result.id\">\n            <a\n              href=\"#\"\n              class=\"hover:bg-muted/50 focus-visible:ring-ring block rounded-lg p-4 transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n            >\n              <div class=\"flex gap-4\">\n                <div\n                  class=\"bg-muted/50 text-muted-foreground flex size-10 shrink-0 items-center justify-center rounded-md border\"\n                >\n                  <component :is=\"result.icon\" aria-hidden=\"true\" class=\"size-5\" />\n                </div>\n                <div class=\"min-w-0 space-y-1\">\n                  <p class=\"truncate font-medium\">{{ result.title }}</p>\n                  <p class=\"text-muted-foreground truncate text-xs\">{{ result.path }}</p>\n                  <p class=\"text-muted-foreground line-clamp-2 text-sm\">{{ result.snippet }}</p>\n                  <div class=\"flex items-center gap-3 pt-1\">\n                    <Badge variant=\"secondary\">{{ result.type }}</Badge>\n                    <span class=\"text-muted-foreground text-xs\">Updated {{ result.updated }}</span>\n                  </div>\n                </div>\n              </div>\n            </a>\n          </li>\n        </ol>\n\n        <nav class=\"flex items-center justify-between pt-4\" aria-label=\"Pagination\">\n          <Button variant=\"outline\" size=\"sm\" :disabled=\"page === 1\" @click=\"page--\">Previous</Button>\n          <div class=\"flex items-center gap-1\">\n            <Button\n              v-for=\"n in totalPages\"\n              :key=\"n\"\n              :variant=\"n === page ? 'outline' : 'ghost'\"\n              size=\"icon-sm\"\n              :aria-current=\"n === page ? 'page' : undefined\"\n              @click=\"page = n\"\n            >\n              {{ n }}\n            </Button>\n          </div>\n          <Button variant=\"outline\" size=\"sm\" :disabled=\"page === totalPages\" @click=\"page++\">Next</Button>\n        </nav>\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:page",
      "target": "~/app/components/blocks/SearchResultsPage.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/checkbox.json",
    "https://uipkge.dev/r/vue/chip.json",
    "https://uipkge.dev/r/vue/input.json"
  ],
  "description": "Full search results page: large pre-filled search input with result count, removable filter chips with clear-all, a left facet sidebar with Type and Team checkbox groups (hidden below lg), six result rows with icon tiles, titles, paths, snippets, and type/updated meta, plus a Previous/Next pagination footer. Chips and facets are interactive; swap the stub rows for your search source.",
  "categories": [
    "layout",
    "app"
  ]
}