const FilesUI = { currentPath: '', async load() { await FilesUI.navigate(''); }, async navigate(path) { try { const data = await API.files.list(path); FilesUI.currentPath = data.path || ''; FilesUI.render(data); } catch (err) { Toast.error(`Erro ao carregar arquivos: ${err.message}`); } }, render(data) { const container = document.getElementById('files-container'); if (!container) return; const breadcrumb = FilesUI._renderBreadcrumb(data.path); const entries = data.entries || []; if (entries.length === 0) { container.innerHTML = ` ${breadcrumb}

Nenhum arquivo encontrado neste diretório

`; Utils.refreshIcons(container); return; } const rows = entries.map(entry => FilesUI._renderRow(entry, data.path)).join(''); container.innerHTML = ` ${breadcrumb}
${entries.length} ${entries.length === 1 ? 'item' : 'itens'}
${rows}
Nome Tamanho Modificado
`; Utils.refreshIcons(container); }, _renderBreadcrumb(currentPath) { const parts = currentPath ? currentPath.split('/').filter(Boolean) : []; let html = `'; return html; }, _renderRow(entry, currentPath) { const fullPath = currentPath ? `${currentPath}/${entry.name}` : entry.name; const icon = entry.type === 'directory' ? 'folder' : FilesUI._fileIcon(entry.extension); const iconColor = entry.type === 'directory' ? 'var(--warning)' : 'var(--text-muted)'; const size = entry.type === 'directory' ? '—' : FilesUI._formatSize(entry.size); const date = FilesUI._formatDate(entry.modified); const nameCell = entry.type === 'directory' ? ` ${Utils.escapeHtml(entry.name)}` : ` ${Utils.escapeHtml(entry.name)}`; const downloadBtn = entry.type === 'directory' ? `` : ``; const deleteBtn = ``; const actions = `${downloadBtn}${deleteBtn}`; return ` ${nameCell} ${size} ${date} ${actions} `; }, _fileIcon(ext) { const map = { js: 'file-code-2', ts: 'file-code-2', jsx: 'file-code-2', tsx: 'file-code-2', py: 'file-code-2', rb: 'file-code-2', go: 'file-code-2', rs: 'file-code-2', java: 'file-code-2', c: 'file-code-2', cpp: 'file-code-2', h: 'file-code-2', html: 'file-code-2', css: 'file-code-2', scss: 'file-code-2', vue: 'file-code-2', json: 'file-json', xml: 'file-json', yaml: 'file-json', yml: 'file-json', md: 'file-text', txt: 'file-text', log: 'file-text', csv: 'file-text', pdf: 'file-text', png: 'file-image', jpg: 'file-image', jpeg: 'file-image', gif: 'file-image', svg: 'file-image', webp: 'file-image', ico: 'file-image', zip: 'file-archive', tar: 'file-archive', gz: 'file-archive', rar: 'file-archive', sh: 'file-terminal', bash: 'file-terminal', sql: 'database', env: 'file-lock', }; return map[ext] || 'file'; }, _formatSize(bytes) { if (bytes == null) return '—'; if (bytes === 0) return '0 B'; const units = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return (bytes / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0) + ' ' + units[i]; }, _formatDate(isoString) { if (!isoString) return '—'; const d = new Date(isoString); return d.toLocaleDateString('pt-BR') + ' ' + d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }); }, downloadFile(path) { const a = document.createElement('a'); a.href = `/api/files/download?path=${encodeURIComponent(path)}`; a.download = ''; a.click(); }, downloadFolder(path) { const a = document.createElement('a'); a.href = `/api/files/download-folder?path=${encodeURIComponent(path)}`; a.download = ''; a.click(); }, async deleteEntry(path, entryType) { const label = entryType === 'directory' ? 'pasta' : 'arquivo'; const name = path.split('/').pop(); const confirmed = await Modal.confirm( `Excluir ${label}`, `Tem certeza que deseja excluir "${name}"? Esta ação não pode ser desfeita.` ); if (!confirmed) return; try { await API.files.delete(path); Toast.success(`${label.charAt(0).toUpperCase() + label.slice(1)} excluído`); await FilesUI.navigate(FilesUI.currentPath); } catch (err) { Toast.error(`Erro ao excluir: ${err.message}`); } }, }; window.FilesUI = FilesUI;