Files
XCSDD/src/components/DocTree.tsx

98 lines
2.5 KiB
TypeScript
Raw Normal View History

import React, { useState } from 'react'
import { ChevronRight, ChevronDown, Folder, FileText } from 'lucide-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
}
interface DocTreeNodeProps {
file: DocFile
level: number
selectedPath?: string
onSelect: (file: DocFile) => void
}
const DocTreeNode = React.memo(({ file, level, selectedPath, onSelect }: DocTreeNodeProps) => {
const [expanded, setExpanded] = useState(level === 0)
const isSelected = selectedPath === file.relativePath
const isDir = file.isDir
const handleClick = (e: React.MouseEvent) => {
e.stopPropagation()
if (isDir) {
setExpanded(!expanded)
} else {
onSelect(file)
}
}
return (
<div>
<div
className={clsx(
'flex items-center gap-2 py-1 px-2 rounded-md cursor-pointer transition-colors text-sm',
isSelected
? 'bg-gray-600 text-white'
: 'hover:bg-gray-700 text-gray-300'
)}
onClick={handleClick}
style={{ paddingLeft: `${level * 16 + 8}px` }}
>
<span className="text-gray-400 shrink-0">
{isDir ? (
expanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />
) : (
<span className="w-4" />
)}
</span>
<span className="text-gray-400 shrink-0">
{isDir ? <Folder size={16} /> : <FileText size={16} />}
</span>
<span className="truncate">{getDisplayName(file.name)}</span>
</div>
{isDir && expanded && file.children && (
<div>
{file.children.map((child) => (
<DocTreeNode
key={child.relativePath}
file={child}
level={level + 1}
selectedPath={selectedPath}
onSelect={onSelect}
/>
))}
</div>
)}
</div>
)
})
DocTreeNode.displayName = 'DocTreeNode'
export const DocTree = ({ files, selectedPath, onSelect }: DocTreeProps) => {
return (
<div className="select-none w-full h-full overflow-auto py-2">
<div className="space-y-1">
{files.map((file) => (
<DocTreeNode
key={file.relativePath}
file={file}
level={0}
selectedPath={selectedPath}
onSelect={onSelect}
/>
))}
</div>
</div>
)
}