import { useState, useRef, useEffect } from 'react'; import type { FileNode } from '../../lib/types/api'; interface FileTreeProps { files: FileNode[]; selectedFile: string | null; onSelectFile: (path: string) => void; owner: string; repo: string; onCreateFile?: (parentPath: string) => void; onCreateFolder?: (parentPath: string) => void; onRename?: (oldPath: string, newName: string) => void; } export function FileTree({ files, selectedFile, onSelectFile, owner, repo, onCreateFile, onCreateFolder, onRename, }: FileTreeProps) { return (
{files.length === 0 ? (
No markdown files found in this repository
) : ( files.map((file) => ( )) )}
); } interface FileTreeNodeProps { node: FileNode; selectedFile: string | null; onSelectFile: (path: string) => void; level: number; owner: string; repo: string; onCreateFile?: (parentPath: string) => void; onCreateFolder?: (parentPath: string) => void; onRename?: (oldPath: string, newName: string) => void; } function FileTreeNode({ node, selectedFile, onSelectFile, level, owner, repo, onCreateFile, onCreateFolder, onRename, }: FileTreeNodeProps) { const [isExpanded, setIsExpanded] = useState(true); const [showActions, setShowActions] = useState(false); const [isRenaming, setIsRenaming] = useState(false); const [renameValue, setRenameValue] = useState(node.name); const renameInputRef = useRef(null); const isSelected = selectedFile === node.path; useEffect(() => { if (isRenaming && renameInputRef.current) { renameInputRef.current.focus(); renameInputRef.current.select(); } }, [isRenaming]); const handleRenameSubmit = () => { if (renameValue.trim() && renameValue !== node.name && onRename) { // Replace spaces with hyphens let sanitizedName = renameValue.trim().replace(/\s+/g, '-'); // For files, ensure .md extension if not present if (node.type === 'file' && !sanitizedName.endsWith('.md') && !sanitizedName.endsWith('.mdx')) { sanitizedName += '.md'; } onRename(node.path, sanitizedName); } setIsRenaming(false); setRenameValue(node.name); }; const handleRenameCancel = () => { setIsRenaming(false); setRenameValue(node.name); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { handleRenameSubmit(); } else if (e.key === 'Escape') { handleRenameCancel(); } }; if (node.type === 'file') { return (
setShowActions(true)} onMouseLeave={() => setShowActions(false)} > {isRenaming ? (
setRenameValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleRenameSubmit} className="flex-1 px-2 py-1 text-sm border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-gray-900" />
) : ( )} {/* Actions menu for files */} {showActions && !isRenaming && (
)}
); } return (
setShowActions(true)} onMouseLeave={() => setShowActions(false)} > {isRenaming ? (
setRenameValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleRenameSubmit} className="flex-1 px-2 py-1 text-sm border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-gray-900" />
) : ( )} {/* Actions menu for folders */} {showActions && !isRenaming && (
)}
{isExpanded && node.children && (
{node.children.map((child) => ( ))}
)}
); }