{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-explorer-block",
  "type": "registry:block",
  "title": "File explorer",
  "description": "Finder-inspired file browser with locations, search, resizable columns, breadcrumbs, and an item preview.",
  "dependencies": [
    "lucide-react@^1.27.0"
  ],
  "registryDependencies": [
    "http://127.0.0.1:3000/r/button.json",
    "http://127.0.0.1:3000/r/core.json",
    "http://127.0.0.1:3000/r/empty.json",
    "http://127.0.0.1:3000/r/input-group.json",
    "http://127.0.0.1:3000/r/resizable.json",
    "http://127.0.0.1:3000/r/scroll-area.json",
    "http://127.0.0.1:3000/r/sidebar.json"
  ],
  "files": [
    {
      "path": "src/registry/blocks/control-ui/file-explorer-data.ts",
      "target": "@components/control-ui/blocks/file-explorer-data.ts",
      "type": "registry:block",
      "content": "import type { ReactNode } from \"react\";\n\nexport type FileExplorerEntryDetail = {\n  label: string;\n  value: ReactNode;\n};\n\nexport type FileExplorerEntry = {\n  id: string;\n  name: string;\n  kind: \"file\" | \"folder\";\n  group?: string;\n  icon?: ReactNode;\n  description?: ReactNode;\n  details?: readonly FileExplorerEntryDetail[];\n  preview?: ReactNode;\n  children?: readonly FileExplorerEntry[];\n};\n\nexport type FileExplorerLocation = {\n  id: string;\n  label: string;\n  group?: string;\n  icon?: ReactNode;\n  entries: readonly FileExplorerEntry[];\n};\n\nexport type FileExplorerColumn = {\n  id: string;\n  label: string;\n  entries: readonly FileExplorerEntry[];\n  selectedId?: string;\n};\n\nexport type FileExplorerBreadcrumb = {\n  id: string;\n  label: string;\n  path: readonly string[];\n  entry?: FileExplorerEntry;\n};\n\nexport type FileExplorerResolution = {\n  columns: readonly FileExplorerColumn[];\n  breadcrumbs: readonly FileExplorerBreadcrumb[];\n  selectedEntry?: FileExplorerEntry;\n  validPath: readonly string[];\n};\n\nexport type FileExplorerSearchResult = {\n  entry: FileExplorerEntry;\n  path: readonly string[];\n  parents: readonly string[];\n};\n\nexport function resolveFileExplorer(location: FileExplorerLocation, selectedPath: readonly string[]): FileExplorerResolution {\n  const columns: FileExplorerColumn[] = [];\n  const breadcrumbs: FileExplorerBreadcrumb[] = [{ id: location.id, label: location.label, path: [] }];\n  const validPath: string[] = [];\n  let entries = location.entries;\n  let selectedEntry: FileExplorerEntry | undefined;\n  let columnLabel = location.label;\n\n  for (let depth = 0; ; depth += 1) {\n    const selectedId = selectedPath[depth];\n    const selected = selectedId ? entries.find((entry) => entry.id === selectedId) : undefined;\n\n    columns.push({\n      id: depth === 0 ? `location:${location.id}` : `folder:${validPath[depth - 1]}`,\n      label: columnLabel,\n      entries,\n      selectedId: selected?.id,\n    });\n\n    if (!selected) break;\n\n    selectedEntry = selected;\n    validPath.push(selected.id);\n    breadcrumbs.push({ id: selected.id, label: selected.name, path: [...validPath], entry: selected });\n\n    if (selected.kind !== \"folder\") break;\n    entries = selected.children ?? [];\n    columnLabel = selected.name;\n  }\n\n  return { columns, breadcrumbs, selectedEntry, validPath };\n}\n\nexport function groupFileExplorerItems<T extends { group?: string }>(items: readonly T[]) {\n  const groups = new Map<string, T[]>();\n\n  for (const item of items) {\n    const label = item.group ?? \"\";\n    const group = groups.get(label) ?? [];\n    group.push(item);\n    groups.set(label, group);\n  }\n\n  return [...groups].map(([label, groupedItems]) => ({ label, items: groupedItems }));\n}\n\nexport function searchFileExplorer(location: FileExplorerLocation, query: string): readonly FileExplorerSearchResult[] {\n  const normalizedQuery = query.trim().toLocaleLowerCase();\n  if (!normalizedQuery) return [];\n\n  const results: FileExplorerSearchResult[] = [];\n\n  function visit(entries: readonly FileExplorerEntry[], path: readonly string[], parents: readonly string[]) {\n    for (const entry of entries) {\n      const entryPath = [...path, entry.id];\n      if (entry.name.toLocaleLowerCase().includes(normalizedQuery)) results.push({ entry, path: entryPath, parents });\n      if (entry.kind === \"folder\" && entry.children) visit(entry.children, entryPath, [...parents, entry.name]);\n    }\n  }\n\n  visit(location.entries, [], []);\n  return results;\n}\n"
    },
    {
      "path": "src/registry/blocks/control-ui/file-explorer.tsx",
      "target": "@components/control-ui/blocks/file-explorer.tsx",
      "type": "registry:block",
      "content": "\"use client\";\n\nimport { ChevronRightIcon, FileIcon, FolderIcon, SearchIcon, XIcon } from \"lucide-react\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { Button } from \"@/components/control-ui/ui/button\";\nimport { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from \"@/components/control-ui/ui/empty\";\nimport { InputGroup, InputGroupAddon, InputGroupInput } from \"@/components/control-ui/ui/input-group\";\nimport { ResizableHandle, ResizablePanel, ResizablePanelGroup } from \"@/components/control-ui/ui/resizable\";\nimport { ScrollArea } from \"@/components/control-ui/ui/scroll-area\";\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarGroup,\n  SidebarGroupLabel,\n  SidebarHeader,\n  SidebarInset,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarProvider,\n  SidebarRail,\n  type SidebarStyle,\n  SidebarTrigger,\n  useSidebar,\n} from \"@/components/control-ui/ui/sidebar\";\nimport {\n  type FileExplorerBreadcrumb,\n  type FileExplorerColumn,\n  type FileExplorerEntry,\n  type FileExplorerLocation,\n  type FileExplorerSearchResult,\n  groupFileExplorerItems,\n  resolveFileExplorer,\n  searchFileExplorer,\n} from \"./file-explorer-data\";\n\nexport type {\n  FileExplorerBreadcrumb,\n  FileExplorerColumn,\n  FileExplorerEntry,\n  FileExplorerEntryDetail,\n  FileExplorerLocation,\n  FileExplorerResolution,\n  FileExplorerSearchResult,\n} from \"./file-explorer-data\";\n\nexport type FileExplorerBlockProps = Omit<ComponentProps<\"div\">, \"children\" | \"defaultValue\" | \"onChange\"> & {\n  locations: readonly FileExplorerLocation[];\n  activeLocationId?: string;\n  defaultActiveLocationId?: string;\n  selectedPath?: readonly string[];\n  defaultSelectedPath?: readonly string[];\n  searchValue?: string;\n  defaultSearchValue?: string;\n  onActiveLocationChange?: (location: FileExplorerLocation) => void;\n  onSelectedPathChange?: (path: readonly string[], entry: FileExplorerEntry | undefined) => void;\n  onSearchValueChange?: (value: string) => void;\n  onOpenEntry?: (entry: FileExplorerEntry, path: readonly string[]) => void;\n  sidebarTop?: ReactNode;\n  sidebarFooter?: ReactNode;\n  headerActions?: ReactNode;\n  searchPlaceholder?: string | false;\n  layout?: \"viewport\" | \"contained\";\n};\n\nexport function FileExplorerBlock({\n  locations,\n  activeLocationId,\n  defaultActiveLocationId,\n  selectedPath,\n  defaultSelectedPath = [],\n  searchValue,\n  defaultSearchValue = \"\",\n  onActiveLocationChange,\n  onSelectedPathChange,\n  onSearchValueChange,\n  onOpenEntry,\n  sidebarTop,\n  sidebarFooter,\n  headerActions,\n  searchPlaceholder = \"Search files\",\n  layout = \"viewport\",\n  className,\n  style,\n  ...props\n}: FileExplorerBlockProps) {\n  const [internalLocationId, setInternalLocationId] = useState(defaultActiveLocationId ?? locations[0]?.id);\n  const [internalSelectedPath, setInternalSelectedPath] = useState<readonly string[]>(defaultSelectedPath);\n  const [internalSearchValue, setInternalSearchValue] = useState(defaultSearchValue);\n  const currentLocationId = activeLocationId ?? internalLocationId;\n  const currentPath = selectedPath ?? internalSelectedPath;\n  const query = searchValue ?? internalSearchValue;\n  const activeLocation = locations.find((location) => location.id === currentLocationId) ?? locations[0];\n  const contained = layout === \"contained\";\n\n  function changePath(path: readonly string[], entry: FileExplorerEntry | undefined) {\n    if (selectedPath === undefined) setInternalSelectedPath(path);\n    onSelectedPathChange?.(path, entry);\n  }\n\n  function changeQuery(value: string) {\n    if (searchValue === undefined) setInternalSearchValue(value);\n    onSearchValueChange?.(value);\n  }\n\n  function changeLocation(location: FileExplorerLocation) {\n    if (activeLocationId === undefined) setInternalLocationId(location.id);\n    changePath([], undefined);\n    changeQuery(\"\");\n    onActiveLocationChange?.(location);\n  }\n\n  if (!activeLocation) {\n    return <FileExplorerUnavailable className={className} style={style} {...props} />;\n  }\n\n  const resolution = resolveFileExplorer(activeLocation, currentPath);\n  const searchResults = searchFileExplorer(activeLocation, query);\n\n  function selectEntry(entry: FileExplorerEntry, columnIndex: number) {\n    changePath([...resolution.validPath.slice(0, columnIndex), entry.id], entry);\n  }\n\n  function selectSearchResult(result: FileExplorerSearchResult) {\n    changePath(result.path, result.entry);\n    changeQuery(\"\");\n  }\n\n  function openEntry(entry: FileExplorerEntry, path: readonly string[]) {\n    onOpenEntry?.(entry, path);\n  }\n\n  const providerStyle: SidebarStyle = { \"--sidebar-width\": \"14.5rem\", ...style };\n\n  return (\n    <SidebarProvider\n      className={cn(\"overflow-hidden bg-background text-foreground\", contained ? \"relative h-full min-h-0\" : \"h-svh min-h-svh\", className)}\n      style={providerStyle}\n      {...props}\n    >\n      <FileExplorerSidebar\n        locations={locations}\n        activeLocationId={activeLocation.id}\n        contained={contained}\n        sidebarTop={sidebarTop}\n        sidebarFooter={sidebarFooter}\n        onLocationSelect={changeLocation}\n      />\n\n      <SidebarInset className=\"h-full min-h-0 min-w-0 overflow-hidden\">\n        <FileExplorerHeader\n          location={activeLocation}\n          breadcrumbs={resolution.breadcrumbs}\n          query={query}\n          searchPlaceholder={searchPlaceholder}\n          canGoBack={resolution.validPath.length > 0}\n          headerActions={headerActions}\n          onBack={() => changePath(resolution.validPath.slice(0, -1), resolution.breadcrumbs.at(-2)?.entry)}\n          onBreadcrumbSelect={(breadcrumb) => changePath(breadcrumb.path, breadcrumb.entry)}\n          onQueryChange={changeQuery}\n        />\n\n        <div className=\"min-h-0 flex-1 overflow-hidden\">\n          {query.trim() ? (\n            <FileExplorerSearchResults query={query} results={searchResults} onSelect={selectSearchResult} onOpen={openEntry} />\n          ) : (\n            <FileExplorerColumns\n              columns={resolution.columns}\n              selectedEntry={resolution.selectedEntry}\n              selectedPath={resolution.validPath}\n              onSelect={selectEntry}\n              onOpen={openEntry}\n            />\n          )}\n        </div>\n\n        <FileExplorerStatusBar\n          breadcrumbs={resolution.breadcrumbs}\n          selectedEntry={resolution.selectedEntry}\n          onBreadcrumbSelect={(breadcrumb) => changePath(breadcrumb.path, breadcrumb.entry)}\n        />\n      </SidebarInset>\n    </SidebarProvider>\n  );\n}\n\nfunction FileExplorerUnavailable({ className, ...props }: ComponentProps<\"div\">) {\n  return (\n    <div className={cn(\"flex min-h-96 items-center justify-center border bg-background\", className)} {...props}>\n      <Empty>\n        <EmptyHeader>\n          <EmptyMedia>\n            <FolderIcon />\n          </EmptyMedia>\n          <EmptyTitle>No locations</EmptyTitle>\n          <EmptyDescription>Add at least one location to populate the file explorer.</EmptyDescription>\n        </EmptyHeader>\n      </Empty>\n    </div>\n  );\n}\n\nfunction FileExplorerSidebar({\n  locations,\n  activeLocationId,\n  contained,\n  sidebarTop,\n  sidebarFooter,\n  onLocationSelect,\n}: {\n  locations: readonly FileExplorerLocation[];\n  activeLocationId: string;\n  contained: boolean;\n  sidebarTop?: ReactNode;\n  sidebarFooter?: ReactNode;\n  onLocationSelect: (location: FileExplorerLocation) => void;\n}) {\n  const { setOpenMobile } = useSidebar();\n  const groups = groupFileExplorerItems(locations);\n\n  return (\n    <Sidebar collapsible=\"offcanvas\" className={contained ? \"absolute! inset-y-0! h-full border-r border-sidebar-border\" : undefined}>\n      {sidebarTop ? (\n        <SidebarHeader className=\"min-h-11 justify-center border-b border-sidebar-border px-3\">{sidebarTop}</SidebarHeader>\n      ) : null}\n      <SidebarContent>\n        {groups.map((group) => (\n          <SidebarGroup key={group.label || \"locations\"}>\n            {group.label ? <SidebarGroupLabel>{group.label}</SidebarGroupLabel> : null}\n            <SidebarMenu>\n              {group.items.map((location) => {\n                const isActive = location.id === activeLocationId;\n                return (\n                  <SidebarMenuItem key={location.id}>\n                    <SidebarMenuButton\n                      size=\"sm\"\n                      isActive={isActive}\n                      aria-current={isActive ? \"location\" : undefined}\n                      onClick={() => {\n                        onLocationSelect(location);\n                        setOpenMobile(false);\n                      }}\n                    >\n                      {location.icon ?? <FolderIcon />}\n                      <span>{location.label}</span>\n                    </SidebarMenuButton>\n                  </SidebarMenuItem>\n                );\n              })}\n            </SidebarMenu>\n          </SidebarGroup>\n        ))}\n      </SidebarContent>\n      {sidebarFooter ? <SidebarFooter className=\"border-t border-sidebar-border\">{sidebarFooter}</SidebarFooter> : null}\n      <SidebarRail />\n    </Sidebar>\n  );\n}\n\nfunction FileExplorerHeader({\n  location,\n  breadcrumbs,\n  query,\n  searchPlaceholder,\n  canGoBack,\n  headerActions,\n  onBack,\n  onBreadcrumbSelect,\n  onQueryChange,\n}: {\n  location: FileExplorerLocation;\n  breadcrumbs: readonly FileExplorerBreadcrumb[];\n  query: string;\n  searchPlaceholder: string | false;\n  canGoBack: boolean;\n  headerActions?: ReactNode;\n  onBack: () => void;\n  onBreadcrumbSelect: (breadcrumb: FileExplorerBreadcrumb) => void;\n  onQueryChange: (value: string) => void;\n}) {\n  return (\n    <header className=\"shrink-0 border-b border-border/70 bg-card/35\">\n      <div className=\"flex h-12 items-center gap-2 px-3\">\n        <SidebarTrigger size=\"xs\" />\n        <Button variant=\"ghost\" size=\"xs\" disabled={!canGoBack} aria-label=\"Go back\" onClick={onBack}>\n          <ChevronRightIcon className=\"size-4 rotate-180\" />\n        </Button>\n        <h1 className=\"min-w-0 flex-1 truncate text-label font-semibold\">{location.label}</h1>\n        {headerActions ? <div className=\"hidden shrink-0 items-center gap-1 sm:flex\">{headerActions}</div> : null}\n        {searchPlaceholder ? (\n          <InputGroup size=\"sm\" className=\"w-36 bg-background/60 md:w-48\">\n            <InputGroupAddon className=\"pl-2\">\n              <SearchIcon className=\"size-3.5\" aria-hidden=\"true\" />\n            </InputGroupAddon>\n            <InputGroupInput\n              type=\"search\"\n              aria-label={searchPlaceholder}\n              placeholder={searchPlaceholder}\n              value={query}\n              onChange={(event) => onQueryChange(event.currentTarget.value)}\n            />\n            {query ? (\n              <Button variant=\"ghost\" size=\"xs\" iconOnly className=\"mr-1\" aria-label=\"Clear search\" onClick={() => onQueryChange(\"\")}>\n                <XIcon className=\"size-3.5\" />\n              </Button>\n            ) : null}\n          </InputGroup>\n        ) : null}\n      </div>\n      <div className=\"px-3 pb-2\">\n        <FileExplorerBreadcrumbs breadcrumbs={breadcrumbs} onSelect={onBreadcrumbSelect} variant=\"address\" />\n      </div>\n    </header>\n  );\n}\n\nfunction FileExplorerColumns({\n  columns,\n  selectedEntry,\n  selectedPath,\n  onSelect,\n  onOpen,\n}: {\n  columns: readonly FileExplorerColumn[];\n  selectedEntry?: FileExplorerEntry;\n  selectedPath: readonly string[];\n  onSelect: (entry: FileExplorerEntry, columnIndex: number) => void;\n  onOpen: (entry: FileExplorerEntry, path: readonly string[]) => void;\n}) {\n  const paneCount = columns.length + 1;\n  const columnSize = `${Math.max(18, Math.floor(68 / paneCount))}%`;\n\n  return (\n    <ResizablePanelGroup orientation=\"horizontal\" className=\"rounded-none border-0 bg-card shadow-none\">\n      {columns.map((column, columnIndex) => (\n        <FileExplorerPanel key={column.id} defaultSize={columnSize} minSize=\"16%\">\n          <FileExplorerColumnView\n            column={column}\n            columnIndex={columnIndex}\n            onSelect={onSelect}\n            onOpen={(entry) => onOpen(entry, [...selectedPath.slice(0, columnIndex), entry.id])}\n          />\n        </FileExplorerPanel>\n      ))}\n      <ResizablePanel defaultSize=\"32%\" minSize=\"20%\">\n        <FileExplorerPreview entry={selectedEntry} />\n      </ResizablePanel>\n    </ResizablePanelGroup>\n  );\n}\n\nfunction FileExplorerPanel({ children, ...props }: ComponentProps<typeof ResizablePanel>) {\n  return (\n    <>\n      <ResizablePanel {...props}>{children}</ResizablePanel>\n      <ResizableHandle />\n    </>\n  );\n}\n\nfunction FileExplorerColumnView({\n  column,\n  columnIndex,\n  onSelect,\n  onOpen,\n}: {\n  column: FileExplorerColumn;\n  columnIndex: number;\n  onSelect: (entry: FileExplorerEntry, columnIndex: number) => void;\n  onOpen: (entry: FileExplorerEntry) => void;\n}) {\n  const groups = groupFileExplorerItems(column.entries);\n\n  if (column.entries.length === 0) {\n    return (\n      <Empty className=\"h-full rounded-none\">\n        <EmptyHeader>\n          <EmptyMedia>\n            <FolderIcon />\n          </EmptyMedia>\n          <EmptyTitle>Empty folder</EmptyTitle>\n          <EmptyDescription>{column.label} has no files yet.</EmptyDescription>\n        </EmptyHeader>\n      </Empty>\n    );\n  }\n\n  return (\n    <ScrollArea className=\"h-full\" lockAxis=\"x\">\n      <div className=\"grid gap-4 p-2\">\n        {groups.map((group) => (\n          <section key={group.label || \"files\"} className=\"min-w-0\">\n            {group.label ? <h2 className=\"mb-1 px-2 text-caption font-semibold text-muted-foreground\">{group.label}</h2> : null}\n            <div className=\"grid gap-0.5\">\n              {group.items.map((entry) => {\n                const isSelected = entry.id === column.selectedId;\n                return (\n                  <Button\n                    key={entry.id}\n                    variant=\"quiet\"\n                    size=\"sm\"\n                    active={isSelected}\n                    aria-current={isSelected ? \"page\" : undefined}\n                    className=\"w-full justify-start gap-2 px-2 text-left\"\n                    title={entry.name}\n                    onClick={() => onSelect(entry, columnIndex)}\n                    onDoubleClick={() => onOpen(entry)}\n                  >\n                    <span className=\"flex size-4 shrink-0 items-center justify-center text-[oklch(0.72_0.14_235)] [&>svg]:size-4\">\n                      {entry.icon ?? (entry.kind === \"folder\" ? <FolderIcon /> : <FileIcon className=\"text-muted-foreground\" />)}\n                    </span>\n                    <span className=\"min-w-0 flex-1 truncate\">{entry.name}</span>\n                    {entry.kind === \"folder\" ? <ChevronRightIcon className=\"size-3.5 shrink-0 text-muted-foreground\" /> : null}\n                  </Button>\n                );\n              })}\n            </div>\n          </section>\n        ))}\n      </div>\n    </ScrollArea>\n  );\n}\n\nfunction FileExplorerPreview({ entry }: { entry?: FileExplorerEntry }) {\n  if (!entry) {\n    return (\n      <Empty className=\"h-full rounded-none bg-background/45\">\n        <EmptyHeader>\n          <EmptyMedia>\n            <FileIcon />\n          </EmptyMedia>\n          <EmptyTitle>Select an item</EmptyTitle>\n          <EmptyDescription>Choose a file or folder to inspect its details.</EmptyDescription>\n        </EmptyHeader>\n      </Empty>\n    );\n  }\n\n  return (\n    <ScrollArea className=\"h-full bg-background/45\" lockAxis=\"x\">\n      <div className=\"mx-auto flex w-full max-w-lg flex-col items-center px-6 py-10 text-center\">\n        <div className=\"flex size-16 items-center justify-center rounded-[var(--radius-panel)] bg-foreground/6 text-[oklch(0.72_0.14_235)] shadow-sm ring-1 ring-foreground/8 [&>svg]:size-8\">\n          {entry.icon ?? (entry.kind === \"folder\" ? <FolderIcon /> : <FileIcon className=\"text-muted-foreground\" />)}\n        </div>\n        <h2 className=\"mt-4 max-w-full truncate text-base font-semibold\">{entry.name}</h2>\n        {entry.description ? <div className=\"mt-1 text-caption leading-5 text-muted-foreground\">{entry.description}</div> : null}\n        {entry.details && entry.details.length > 0 ? (\n          <dl className=\"mt-6 grid w-full grid-cols-[auto_1fr] gap-x-4 gap-y-2 border-t border-border/70 pt-4 text-left text-caption\">\n            {entry.details.map((detail) => (\n              <div key={detail.label} className=\"contents\">\n                <dt className=\"text-muted-foreground\">{detail.label}</dt>\n                <dd className=\"min-w-0 truncate text-right text-foreground\">{detail.value}</dd>\n              </div>\n            ))}\n          </dl>\n        ) : null}\n        {entry.preview ? <div className=\"mt-6 w-full text-left\">{entry.preview}</div> : null}\n      </div>\n    </ScrollArea>\n  );\n}\n\nfunction FileExplorerSearchResults({\n  query,\n  results,\n  onSelect,\n  onOpen,\n}: {\n  query: string;\n  results: readonly FileExplorerSearchResult[];\n  onSelect: (result: FileExplorerSearchResult) => void;\n  onOpen: (entry: FileExplorerEntry, path: readonly string[]) => void;\n}) {\n  if (results.length === 0) {\n    return (\n      <Empty className=\"h-full rounded-none\">\n        <EmptyHeader>\n          <EmptyMedia>\n            <SearchIcon />\n          </EmptyMedia>\n          <EmptyTitle>No results for “{query}”</EmptyTitle>\n          <EmptyDescription>Try a shorter file or folder name.</EmptyDescription>\n        </EmptyHeader>\n      </Empty>\n    );\n  }\n\n  return (\n    <ScrollArea className=\"h-full\" lockAxis=\"x\">\n      <div className=\"mx-auto grid w-full max-w-3xl gap-1 p-4\">\n        <div className=\"mb-2 flex items-center justify-between px-2 text-caption text-muted-foreground\">\n          <span>\n            {results.length} {results.length === 1 ? \"result\" : \"results\"}\n          </span>\n          <span>Search: {query}</span>\n        </div>\n        {results.map((result) => (\n          <Button\n            key={result.path.join(\"/\")}\n            variant=\"quiet\"\n            size=\"lg\"\n            className=\"h-auto w-full justify-start gap-3 px-3 py-2 text-left\"\n            onClick={() => onSelect(result)}\n            onDoubleClick={() => onOpen(result.entry, result.path)}\n          >\n            <span className=\"flex size-8 shrink-0 items-center justify-center rounded-[var(--radius-control)] bg-foreground/6 text-[oklch(0.72_0.14_235)] [&>svg]:size-4\">\n              {result.entry.icon ?? (result.entry.kind === \"folder\" ? <FolderIcon /> : <FileIcon className=\"text-muted-foreground\" />)}\n            </span>\n            <span className=\"min-w-0 flex-1\">\n              <span className=\"block truncate text-label text-foreground\">{result.entry.name}</span>\n              <span className=\"block truncate text-caption text-muted-foreground\">{result.parents.join(\" / \") || \"Top level\"}</span>\n            </span>\n          </Button>\n        ))}\n      </div>\n    </ScrollArea>\n  );\n}\n\nfunction FileExplorerStatusBar({\n  breadcrumbs,\n  selectedEntry,\n  onBreadcrumbSelect,\n}: {\n  breadcrumbs: readonly FileExplorerBreadcrumb[];\n  selectedEntry?: FileExplorerEntry;\n  onBreadcrumbSelect: (breadcrumb: FileExplorerBreadcrumb) => void;\n}) {\n  return (\n    <footer className=\"flex h-8 shrink-0 items-center gap-3 border-t border-border/70 bg-card/45 px-3\">\n      <FileExplorerBreadcrumbs breadcrumbs={breadcrumbs} onSelect={onBreadcrumbSelect} variant=\"status\" />\n      <span className=\"ml-auto shrink-0 text-micro text-muted-foreground\">\n        {selectedEntry?.kind === \"folder\" ? `${selectedEntry.children?.length ?? 0} items` : (selectedEntry?.name ?? \"No selection\")}\n      </span>\n    </footer>\n  );\n}\n\nfunction FileExplorerBreadcrumbs({\n  breadcrumbs,\n  onSelect,\n  variant,\n}: {\n  breadcrumbs: readonly FileExplorerBreadcrumb[];\n  onSelect: (breadcrumb: FileExplorerBreadcrumb) => void;\n  variant: \"address\" | \"status\";\n}) {\n  return (\n    <nav\n      aria-label={variant === \"address\" ? \"Current folder\" : \"Selected path\"}\n      className={cn(\n        \"min-w-0 flex-1 overflow-hidden\",\n        variant === \"address\" && \"rounded-[var(--radius-control)] border bg-background/55 px-2 py-1 shadow-inner\",\n      )}\n    >\n      <ol\n        className={cn(\n          \"flex min-w-0 flex-nowrap items-center gap-1 overflow-hidden text-caption text-muted-foreground\",\n          variant === \"status\" && \"text-micro\",\n        )}\n      >\n        {breadcrumbs.map((breadcrumb, index) => {\n          const isCurrent = index === breadcrumbs.length - 1;\n          return (\n            <li key={`${breadcrumb.id}:${breadcrumb.path.join(\"/\")}`} className=\"flex min-w-0 items-center gap-1\">\n              {index > 0 ? <ChevronRightIcon className=\"size-3 shrink-0\" aria-hidden=\"true\" /> : null}\n              <button\n                type=\"button\"\n                aria-current={isCurrent ? \"page\" : undefined}\n                className={cn(\n                  \"min-w-0 truncate rounded-[var(--radius-popup-item)] px-1 py-0.5 text-muted-foreground outline-none transition hover:bg-foreground/6 hover:text-foreground focus-visible:ring-2 focus-visible:ring-foreground/20\",\n                  isCurrent && \"text-foreground\",\n                )}\n                onClick={() => onSelect(breadcrumb)}\n              >\n                {breadcrumb.label}\n              </button>\n            </li>\n          );\n        })}\n      </ol>\n    </nav>\n  );\n}\n"
    }
  ],
  "meta": {}
}
