| 113 | } |
| 114 | |
| 115 | const FileTreeItem = ({ |
| 116 | item, |
| 117 | depth = 0, |
| 118 | }: { |
| 119 | item: FileItem |
| 120 | depth?: number |
| 121 | }) => { |
| 122 | const [isOpen, setIsOpen] = useState(item.type === 'folder') |
| 123 | |
| 124 | return ( |
| 125 | <div> |
| 126 | <div |
| 127 | className={cn( |
| 128 | 'flex items-center text-sm text-zinc-300 hover:bg-zinc-800/50 rounded px-2 py-1 cursor-pointer group transition-colors duration-150', |
| 129 | item.active && 'bg-zinc-800', |
| 130 | )} |
| 131 | style={{ paddingLeft: `${depth * 1.2 + 0.5}rem` }} |
| 132 | onClick={() => setIsOpen(!isOpen)} |
| 133 | > |
| 134 | {item.type === 'folder' && ( |
| 135 | <div |
| 136 | className="w-4 h-4 mr-1 transition-transform duration-200" |
| 137 | style={{ transform: isOpen ? 'rotate(90deg)' : 'none' }} |
| 138 | > |
| 139 | <ChevronRight size={16} /> |
| 140 | </div> |
| 141 | )} |
| 142 | <FileIcon extension={item.extension} /> |
| 143 | <span>{item.name}</span> |
| 144 | </div> |
| 145 | {isOpen && item.children && ( |
| 146 | <div className="animate-slideDown"> |
| 147 | {item.children.map((child, index) => ( |
| 148 | <FileTreeItem |
| 149 | key={child.name + index} |
| 150 | item={child} |
| 151 | depth={depth + 1} |
| 152 | /> |
| 153 | ))} |
| 154 | </div> |
| 155 | )} |
| 156 | </div> |
| 157 | ) |
| 158 | } |
| 159 | |
| 160 | interface IDEDemoProps { |
| 161 | className?: string |