import { useState } from 'react' import { useEditorStore } from '../../store/editorStore' import type { FileNode } from '../../types/editor' interface DndPayload { name: string dirPath: string } interface Props { node: FileNode depth: number dirPath: string siblings: FileNode[] } export function FileTreeNode({ node, depth, dirPath, siblings }: Props): JSX.Element { const [expanded, setExpanded] = useState(true) const { activeFilePath, setActiveFile, moveNode } = useEditorStore() const openFile = async (): Promise => { if (node.type === 'file') { const content = await window.api.readFile(node.path) setActiveFile(node.path, content) } } function handleDragStart(e: React.DragEvent): void { e.dataTransfer.effectAllowed = 'move' e.dataTransfer.setData('dnd', JSON.stringify({ name: node.name, dirPath } satisfies DndPayload)) e.currentTarget.classList.add('dragging') } function handleDragEnd(e: React.DragEvent): void { e.currentTarget.classList.remove('dragging') } function handleDragOver(e: React.DragEvent): void { e.preventDefault() e.dataTransfer.dropEffect = 'move' e.currentTarget.classList.add('drag-over') } function handleDragLeave(e: React.DragEvent): void { e.currentTarget.classList.remove('drag-over') } function handleDrop(e: React.DragEvent): void { e.preventDefault() e.currentTarget.classList.remove('drag-over') const raw = e.dataTransfer.getData('dnd') if (!raw) return const payload: DndPayload = JSON.parse(raw) if (payload.dirPath !== dirPath) return const fromIdx = siblings.findIndex((n) => n.name === payload.name) const toIdx = siblings.findIndex((n) => n.name === node.name) if (fromIdx !== -1 && toIdx !== -1 && fromIdx !== toIdx) { moveNode(dirPath, fromIdx, toIdx) } } if (node.type === 'directory') { return (
{expanded && node.children?.map((child) => ( ))}
) } const isActive = activeFilePath === node.path return ( ) }