"use client" /** * Library **Folders** tree — shared outline primitives (`OutlineTree*`) so the rail * matches `HubTreePanelView` and shadcn sidebar file-tree rhythm. * * Indent model: flat `OutlineTreeSub` lists (full width) + `--outline-tree-depth-step` * (12px) on each row. Avoids compounding 24px sub-margins that crush deep labels. */ import * as React from "react" import { Link } from "react-router-dom" import { Collapsible, CollapsibleTrigger } from "@/components/ui/collapsible" import { Button } from "@/components/ui/button" import { SidebarNavLabel } from "@/components/ui/sidebar-nav-label" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Tip } from "@/components/ui/tip" import { cn } from "@/lib/utils" import { OutlineTreeCollapsibleContentRail, OutlineTreeMenuItem, OutlineTreeSub, outlineTreeBranchDepthStyle, } from "@/components/data-views/outline-tree-menu" import type { LibraryFolder } from "@/lib/mock/library-folders" import { LIBRARY_FOLDER_ICON_COLORS } from "@/lib/mock/library-folders" import { isLibraryNavActive, libraryHubScopeHref, type LibraryNavState, } from "@/lib/library-nav" /** Root rows align with All/My (`px-2` on the link only); nested rows add depth step. */ function libraryFolderRowIndentStyle(depth: number): React.CSSProperties | undefined { if (depth <= 0) return undefined return { "--outline-tree-depth": depth, paddingInlineStart: `calc(${depth} * var(--outline-tree-depth-step))`, } as React.CSSProperties } export interface LibraryFolderPickFolderProps { selectedFolderId: string onSelect: (folderId: string) => void /** When set, branches with no name/descendant match are hidden. */ searchQuery?: string } function libraryFolderMatchesSearch( folder: LibraryFolder, folders: LibraryFolder[], query: string, ): boolean { const needle = query.trim().toLowerCase() if (!needle) return true if (folder.name.toLowerCase().includes(needle)) return true return folders.some( f => f.parentId === folder.id && libraryFolderMatchesSearch(f, folders, query), ) } export interface LibraryFolderTreeBranchProps { folder: LibraryFolder folders: LibraryFolder[] pathname: string hubSearchParams: URLSearchParams nav: LibraryNavState canManageFolders: boolean canManageAccess: boolean onAddSubfolder: (parentId: string) => void onCustomizeFolder: (folder: LibraryFolder) => void onManageAccess: () => void onDeleteFolder: (folder: LibraryFolder) => void /** Nesting depth (0 = root folder under FOLDERS). */ depth?: number /** Selection mode for folder pickers (e.g. new-question inspector). */ pickFolder?: LibraryFolderPickFolderProps } function FolderRowActionsMenu({ folder, folderActive, canManageAccess, onAddSubfolder, onCustomizeFolder, onManageAccess, onDeleteFolder, overlay = false, className, }: { folder: LibraryFolder folderActive: boolean canManageAccess: boolean onAddSubfolder: (parentId: string) => void onCustomizeFolder: (folder: LibraryFolder) => void onManageAccess: () => void onDeleteFolder: (folder: LibraryFolder) => void overlay?: boolean className?: string }) { return (