import React, { useState } from 'react' import { clsx } from 'clsx' import type { DocFile } from '@/lib/types' import { getDisplayName } from '@/lib/parser' interface DocTreeProps { files: DocFile[] selectedPath?: string onSelect: (file: DocFile) => void onFolderClick?: (folderPath: string) => void } interface TreeNodeProps { file: DocFile level: number isLast: boolean ancestorsLast: boolean[] selectedPath?: string onSelect: (file: DocFile) => void onFolderClick?: (folderPath: string) => void expandedSet: Set onToggle: (path: string) => void } const TreeNode = React.memo(({ file, level, isLast, ancestorsLast, selectedPath, onSelect, onFolderClick, expandedSet, onToggle, }: TreeNodeProps) => { const isDir = file.isDir const isExpanded = expandedSet.has(file.relativePath) const isSelected = selectedPath === file.relativePath const handleClick = () => { if (isDir) { onFolderClick?.(file.relativePath) onToggle(file.relativePath) } else { onSelect(file) } } const getIndent = (): string => { let result = '' for (let i = 0; i < level; i++) { result += ancestorsLast[i] ? ' ' : '│ ' } result += isLast ? '└─ ' : '├─ ' return result } const getIndentWidth = (): number => { return level * 3 + 3 } const showChildren = isDir && isExpanded && file.children return ( <>
{getIndent()} {getDisplayName(file.name)}
{showChildren && file.children!.map((child, idx) => ( ))} ) }) TreeNode.displayName = 'TreeNode' export const DocTree = ({ files, selectedPath, onSelect, onFolderClick }: DocTreeProps) => { const [expandedSet, setExpandedSet] = useState>(() => { const set = new Set() files.forEach(f => { if (f.isDir) set.add(f.relativePath) }) return set }) const handleToggle = (path: string) => { setExpandedSet(prev => { const next = new Set(prev) if (next.has(path)) { next.delete(path) } else { next.add(path) } return next }) } return (
{files.map((file, idx) => ( ))}
) }