{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "search-results-page",
  "title": "Search Results Page",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-react/blocks/search-results-page/SearchResultsPage.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { BookOpen, FileText, GitBranch, MessageSquare, Search, Users, Video } from 'lucide-react'\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: React.ComponentType<{ className?: string }>\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\nexport interface SearchResultsPageProps extends React.HTMLAttributes<HTMLDivElement> {}\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 FACET_GROUPS: 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 TOTAL_PAGES = 3\n\nexport const SearchResultsPage = React.forwardRef<HTMLDivElement, SearchResultsPageProps>(\n  ({ className, ...props }, ref) => {\n    const [query, setQuery] = React.useState('onboarding flows')\n    const [chips, setChips] = React.useState([\n      { id: 'type-docs', label: 'Type: Docs' },\n      { id: 'team-product', label: 'Team: Product' },\n    ])\n    const [activeFacets, setActiveFacets] = React.useState<Set<string>>(() => new Set(['type-docs', 'team-product']))\n    const [page, setPage] = React.useState(1)\n\n    function removeChip(id: string) {\n      setChips((prev) => prev.filter((chip) => chip.id !== id))\n    }\n\n    function clearAll() {\n      setChips([])\n    }\n\n    function toggleFacet(id: string, checked: boolean | 'indeterminate') {\n      setActiveFacets((prev) => {\n        const next = new Set(prev)\n        if (checked === true) next.add(id)\n        else next.delete(id)\n        return next\n      })\n    }\n\n    const start = (page - 1) * RESULTS.length + 1\n    const resultRange = `${start}-${start + RESULTS.length - 1}`\n\n    return (\n      <div ref={ref} data-slot=\"search-results-page\" className={cn('w-full space-y-6', className)} {...props}>\n        <div className=\"space-y-3\">\n          <div className=\"relative max-w-xl\">\n            <Search\n              aria-hidden=\"true\"\n              className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n            />\n            <Input\n              type=\"search\"\n              value={query}\n              onChange={(e) => setQuery(e.target.value)}\n              placeholder=\"Search...\"\n              className=\"h-11 pl-9 text-base\"\n            />\n          </div>\n          <p className=\"text-muted-foreground text-sm\">\n            {resultRange} of 42 results for &ldquo;{query}&rdquo;\n          </p>\n        </div>\n\n        {chips.length > 0 && (\n          <div className=\"flex flex-wrap items-center gap-2\">\n            {chips.map((chip) => (\n              <Chip key={chip.id} variant=\"outline\" size=\"sm\" closable onClose={() => removeChip(chip.id)}>\n                {chip.label}\n              </Chip>\n            ))}\n            <Button variant=\"link\" size=\"sm\" className=\"text-muted-foreground h-auto min-h-6 px-2\" onClick={clearAll}>\n              Clear all\n            </Button>\n          </div>\n        )}\n\n        <div className=\"flex gap-8\">\n          <aside className=\"hidden w-48 shrink-0 space-y-6 lg:block\" aria-label=\"Filters\">\n            {FACET_GROUPS.map((group) => (\n              <div key={group.id}>\n                <h3 className=\"text-muted-foreground mb-3 text-xs font-medium tracking-wider uppercase\">\n                  {group.label}\n                </h3>\n                <ul className=\"space-y-2.5\">\n                  {group.options.map((option) => (\n                    <li key={option.id}>\n                      <label\n                        htmlFor={`${group.id}-${option.id}`}\n                        className=\"flex cursor-pointer items-center gap-2 text-sm\"\n                      >\n                        <Checkbox\n                          id={`${group.id}-${option.id}`}\n                          checked={activeFacets.has(option.id)}\n                          onCheckedChange={(checked) => toggleFacet(option.id, checked)}\n                        />\n                        <span>{option.label}</span>\n                        <span className=\"text-muted-foreground ml-auto text-xs tabular-nums\">{option.count}</span>\n                      </label>\n                    </li>\n                  ))}\n                </ul>\n              </div>\n            ))}\n          </aside>\n\n          <div className=\"min-w-0 flex-1\">\n            <ol className=\"divide-border divide-y\">\n              {RESULTS.map((result) => (\n                <li key={result.id}>\n                  <a\n                    href=\"#\"\n                    className=\"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 className=\"flex gap-4\">\n                      <div className=\"bg-muted/50 text-muted-foreground flex size-10 shrink-0 items-center justify-center rounded-md border\">\n                        <result.icon aria-hidden=\"true\" className=\"size-5\" />\n                      </div>\n                      <div className=\"min-w-0 space-y-1\">\n                        <p className=\"truncate font-medium\">{result.title}</p>\n                        <p className=\"text-muted-foreground truncate text-xs\">{result.path}</p>\n                        <p className=\"text-muted-foreground line-clamp-2 text-sm\">{result.snippet}</p>\n                        <div className=\"flex items-center gap-3 pt-1\">\n                          <Badge variant=\"secondary\">{result.type}</Badge>\n                          <span className=\"text-muted-foreground text-xs\">Updated {result.updated}</span>\n                        </div>\n                      </div>\n                    </div>\n                  </a>\n                </li>\n              ))}\n            </ol>\n\n            <nav className=\"flex items-center justify-between pt-4\" aria-label=\"Pagination\">\n              <Button variant=\"outline\" size=\"sm\" disabled={page === 1} onClick={() => setPage(page - 1)}>\n                Previous\n              </Button>\n              <div className=\"flex items-center gap-1\">\n                {Array.from({ length: TOTAL_PAGES }, (_, i) => i + 1).map((n) => (\n                  <Button\n                    key={n}\n                    variant={n === page ? 'outline' : 'ghost'}\n                    size=\"icon-sm\"\n                    aria-current={n === page ? 'page' : undefined}\n                    onClick={() => setPage(n)}\n                  >\n                    {n}\n                  </Button>\n                ))}\n              </div>\n              <Button variant=\"outline\" size=\"sm\" disabled={page === TOTAL_PAGES} onClick={() => setPage(page + 1)}>\n                Next\n              </Button>\n            </nav>\n          </div>\n        </div>\n      </div>\n    )\n  },\n)\n\nSearchResultsPage.displayName = 'SearchResultsPage'\n",
      "type": "registry:page",
      "target": "~/components/blocks/SearchResultsPage.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/checkbox.json",
    "https://uipkge.dev/r/react/chip.json",
    "https://uipkge.dev/r/react/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"
  ]
}