capcutsync-pro / components /upload-zone.js
eubottura's picture
Deve respeitar esses criterios, === PROJETO ESTRUTURADO PARA ANÁLISE ===
d789176 verified
class UploadZone extends HTMLElement {
constructor() {
super();
this.dragCounter = 0;
}
connectedCallback() {
this.innerHTML = `
<div id="drop-zone" class="relative group">
<div class="border-2 border-dashed border-slate-700 rounded-2xl p-8 text-center transition-all duration-300 bg-slate-900/50 hover:border-primary-500/50 hover:bg-primary-500/5">
<!-- Icon -->
<div class="w-16 h-16 mx-auto mb-4 rounded-full bg-slate-800 flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
<i data-feather="upload-cloud" class="w-8 h-8 text-slate-400 group-hover:text-primary-400 transition-colors"></i>
</div>
<h3 class="text-lg font-semibold text-slate-300 mb-2 group-hover:text-slate-200">
Arraste arquivos de áudio
</h3>
<p class="text-sm text-slate-500 mb-4">
ou <span class="text-primary-400 cursor-pointer hover:underline">clique para selecionar</span>
</p>
<div class="flex items-center justify-center gap-2 text-xs text-slate-600">
<span class="px-2 py-1 rounded bg-slate-800">MP3</span>
<span class="px-2 py-1 rounded bg-slate-800">WAV</span>
<span class="px-2 py-1 rounded bg-slate-800">M4A</span>
<span class="px-2 py-1 rounded bg-slate-800">FLAC</span>
</div>
<!-- Hidden Input -->
<input type="file" id="file-input" multiple accept="audio/*" class="hidden">
</div>
<!-- Processing Overlay -->
<div id="upload-overlay" class="absolute inset-0 bg-slate-900/90 backdrop-blur-sm rounded-2xl flex items-center justify-center hidden">
<div class="text-center">
<div class="w-12 h-12 border-4 border-primary-500/30 border-t-primary-500 rounded-full animate-spin mx-auto mb-3"></div>
<p class="text-sm text-slate-300">Analisando áudio...</p>
</div>
</div>
</div>
`;
this.setupEventListeners();
}
setupEventListeners() {
const dropZone = this.querySelector('#drop-zone');
const fileInput = this.querySelector('#file-input');
const overlay = this.querySelector('#upload-overlay');
// Click to select
dropZone.addEventListener('click', (e) => {
if (e.target !== fileInput) {
fileInput.click();
}
});
fileInput.addEventListener('change', (e) => {
this.handleFiles(e.target.files);
});
// Drag and Drop
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, (e) => {
e.preventDefault();
e.stopPropagation();
}, false);
});
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
this.dragCounter++;
dropZone.classList.add('drag-over');
}, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
this.dragCounter--;
if (this.dragCounter === 0) {
dropZone.classList.remove('drag-over');
}
}, false);
});
dropZone.addEventListener('drop', (e) => {
this.dragCounter = 0;
dropZone.classList.remove('drag-over');
const files = e.dataTransfer.files;
if (files.length > 0) {
// Show overlay briefly for effect
overlay.classList.remove('hidden');
setTimeout(() => {
overlay.classList.add('hidden');
this.handleFiles(files);
}, 500);
}
});
}
handleFiles(files) {
// Dispatch custom event to main app
document.dispatchEvent(new CustomEvent('files-uploaded', {
detail: { files: Array.from(files) }
}));
}
}
customElements.define('upload-zone', UploadZone);