mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-05-03 10:14:52 +00:00
96 lines
2.4 KiB
TypeScript
96 lines
2.4 KiB
TypeScript
import { useState, useCallback } from 'react'
|
|
import { toast } from 'sonner'
|
|
|
|
export interface FileNode {
|
|
id: string
|
|
name: string
|
|
type: 'file' | 'folder'
|
|
content?: string
|
|
language?: string
|
|
children?: FileNode[]
|
|
expanded?: boolean
|
|
}
|
|
|
|
/**
|
|
* Hook to manage file tree operations
|
|
* Handles tree traversal, node creation, deletion, and updates
|
|
*/
|
|
export function useFileTree(initialFiles: FileNode[] = []) {
|
|
const [files, setFiles] = useState<FileNode[]>(initialFiles)
|
|
|
|
const findNodeById = useCallback((id: string, nodes = files): FileNode | null => {
|
|
for (const node of nodes) {
|
|
if (node.id === id) return node
|
|
if (node.children) {
|
|
const found = findNodeById(id, node.children)
|
|
if (found) return found
|
|
}
|
|
}
|
|
return null
|
|
}, [files])
|
|
|
|
const updateNode = useCallback((id: string, updates: Partial<FileNode>) => {
|
|
const update = (nodes: FileNode[]): FileNode[] =>
|
|
nodes.map(node => {
|
|
if (node.id === id) {
|
|
return { ...node, ...updates }
|
|
}
|
|
if (node.children) {
|
|
return { ...node, children: update(node.children) }
|
|
}
|
|
return node
|
|
})
|
|
|
|
setFiles(update)
|
|
}, [])
|
|
|
|
const deleteNode = useCallback((id: string) => {
|
|
const remove = (nodes: FileNode[]): FileNode[] =>
|
|
nodes.filter(node => node.id !== id).map(node => ({
|
|
...node,
|
|
children: node.children ? remove(node.children) : undefined,
|
|
}))
|
|
|
|
setFiles(remove)
|
|
toast.success('Deleted')
|
|
}, [])
|
|
|
|
const toggleFolder = useCallback((id: string) => {
|
|
updateNode(id, { expanded: (node => !node.expanded)(findNodeById(id)!) })
|
|
}, [updateNode, findNodeById])
|
|
|
|
const addChild = useCallback((parentId: string, child: FileNode) => {
|
|
const parent = findNodeById(parentId)
|
|
if (!parent || parent.type !== 'folder') return
|
|
|
|
setFiles(files =>
|
|
files.map(node => {
|
|
if (node.id === parentId) {
|
|
return {
|
|
...node,
|
|
children: [...(node.children || []), child],
|
|
}
|
|
}
|
|
if (node.children) {
|
|
return {
|
|
...node,
|
|
children: files.map(n => (n.id === parentId ? { ...n, children: [...(n.children || []), child] } : n))[0]?.children || node.children,
|
|
}
|
|
}
|
|
return node
|
|
})
|
|
)
|
|
toast.success('Created')
|
|
}, [findNodeById, files])
|
|
|
|
return {
|
|
files,
|
|
setFiles,
|
|
findNodeById,
|
|
updateNode,
|
|
deleteNode,
|
|
toggleFolder,
|
|
addChild,
|
|
}
|
|
}
|