90 lines
2.9 KiB
TypeScript
90 lines
2.9 KiB
TypeScript
"use client";
|
|
|
|
import React from 'react';
|
|
import { ChevronRight, ChevronDown, FileIcon, FolderIcon, Plus, FolderPlus } from 'lucide-react';
|
|
import { useEditorStore, FileNode } from '@/store/editor-store';
|
|
import { cn, getFileIcon, getPlatformIcon } from '@/lib/utils';
|
|
|
|
export function FileTree() {
|
|
const { files, openFile } = useEditorStore();
|
|
const [expandedFolders, setExpandedFolders] = React.useState<Set<string>>(
|
|
new Set(['roblox', 'web', 'mobile', 'desktop', 'shared'])
|
|
);
|
|
|
|
const toggleFolder = (folderId: string) => {
|
|
setExpandedFolders(prev => {
|
|
const next = new Set(prev);
|
|
if (next.has(folderId)) {
|
|
next.delete(folderId);
|
|
} else {
|
|
next.add(folderId);
|
|
}
|
|
return next;
|
|
});
|
|
};
|
|
|
|
const renderNode = (node: FileNode, depth: number = 0) => {
|
|
const isExpanded = expandedFolders.has(node.id);
|
|
const isFolder = node.type === 'folder';
|
|
|
|
return (
|
|
<div key={node.id}>
|
|
<div
|
|
className={cn(
|
|
"flex items-center gap-2 px-2 py-1 cursor-pointer hover:bg-surface/50 transition-colors",
|
|
"text-sm"
|
|
)}
|
|
style={{ paddingLeft: `${depth * 12 + 8}px` }}
|
|
onClick={() => isFolder ? toggleFolder(node.id) : openFile(node)}
|
|
>
|
|
{isFolder && (
|
|
<span className="text-gray-400">
|
|
{isExpanded ? <ChevronDown className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />}
|
|
</span>
|
|
)}
|
|
{!isFolder && <span className="w-4" />}
|
|
|
|
<span className="text-lg">
|
|
{isFolder ? (isExpanded ? '📂' : '📁') : getFileIcon(node.name)}
|
|
</span>
|
|
|
|
<span className="flex-1 truncate text-gray-200">{node.name}</span>
|
|
|
|
{node.platform && (
|
|
<span className="text-xs opacity-50">
|
|
{getPlatformIcon(node.platform)}
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{isFolder && isExpanded && node.children && (
|
|
<div>
|
|
{node.children.map(child => renderNode(child, depth + 1))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="h-full flex flex-col bg-gray-900 text-white">
|
|
<div className="flex items-center justify-between px-3 py-2 border-b border-gray-800">
|
|
<span className="text-xs font-semibold uppercase tracking-wider text-gray-400">
|
|
Explorer
|
|
</span>
|
|
<div className="flex gap-1">
|
|
<button className="p-1 hover:bg-surface rounded transition-colors" title="New File">
|
|
<Plus className="w-4 h-4 text-gray-400" />
|
|
</button>
|
|
<button className="p-1 hover:bg-surface rounded transition-colors" title="New Folder">
|
|
<FolderPlus className="w-4 h-4 text-gray-400" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex-1 overflow-y-auto">
|
|
{files.map((node: any) => renderNode(node))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|