Newer
Older
cortex-hub / frontend / src / features / skills / components / SkillFileTree.js
import React, { useState } from 'react';

export default function SkillFileTree({ files, activeFile, onSelectFile, onAddFile, onDeleteFile, Icon }) {
    const [newFileName, setNewFileName] = useState('');
    const [isAdding, setIsAdding] = useState(false);

    const handleAdd = () => {
        if (newFileName.trim()) {
            onAddFile(newFileName.trim());
            setNewFileName('');
            setIsAdding(false);
        }
    };

    return (
        <div className="w-64 bg-gray-50 dark:bg-gray-900/50 border-r border-gray-200 dark:border-gray-700 flex flex-col h-full overflow-hidden">
            <div className="p-4 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center bg-gray-100/50 dark:bg-gray-800/50">
                <span className="text-[10px] uppercase font-black tracking-widest text-gray-400">Environment Files</span>
                <button onClick={() => setIsAdding(!isAdding)} className="text-gray-400 hover:text-indigo-500 transition-colors" title="Add File">
                    <Icon path="M12 4v16m8-8H4" className="w-4 h-4" />
                </button>
            </div>
            
            <div className="flex-grow overflow-y-auto custom-scrollbar p-2">
                {isAdding && (
                    <div className="mb-2 p-2 relative">
                        <input 
                            autoFocus
                            type="text" 
                            className="w-full bg-white dark:bg-gray-800 border border-indigo-300 dark:border-indigo-700 rounded-lg px-2 py-1 text-xs outline-none focus:border-indigo-500 text-gray-800 dark:text-gray-200"
                            placeholder="scripts/new.py"
                            value={newFileName}
                            onChange={(e) => setNewFileName(e.target.value)}
                            onKeyDown={(e) => {
                                if (e.key === 'Enter') handleAdd();
                                if (e.key === 'Escape') setIsAdding(false);
                            }}
                            onBlur={() => setIsAdding(false)}
                        />
                    </div>
                )}
                
                {files.map((file) => (
                    <div 
                        key={file.path} 
                        className={`group flex items-center justify-between px-3 py-2 rounded-lg cursor-pointer transition-colors mb-1 ${activeFile === file.path ? 'bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 font-bold' : 'text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-800'}`}
                        onClick={() => onSelectFile(file.path)}
                    >
                        <div className="flex items-center gap-2 truncate">
                            <Icon path="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" className="w-4 h-4 flex-none opacity-50" />
                            <span className="text-xs truncate">{file.path}</span>
                        </div>
                        {file.path !== 'SKILL.md' && onDeleteFile && (
                            <button 
                                onClick={(e) => { e.stopPropagation(); onDeleteFile(file.path); }}
                                className="opacity-0 group-hover:opacity-100 text-gray-400 hover:text-red-500 transition-opacity"
                                title="Delete File"
                            >
                                <Icon path="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" className="w-3 h-3" />
                            </button>
                        )}
                    </div>
                ))}
                
                {files.length === 0 && !isAdding && (
                    <div className="py-6 text-center text-gray-400 dark:text-gray-500">
                        <Icon path="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" className="w-6 h-6 mx-auto mb-2 opacity-30" />
                        <p className="text-[10px] uppercase font-bold tracking-widest">No Files Found</p>
                    </div>
                )}
            </div>
        </div>
    );
}