From b076bd66e6862334a1b36c9cb476d31b8287964d Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Fri, 20 Mar 2026 22:57:37 -0700 Subject: [PATCH] Refactor: Move DOM/UI helpers --- src/app/dom.js | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/app/dom.js diff --git a/src/app/dom.js b/src/app/dom.js new file mode 100644 index 0000000..e74d7c3 --- /dev/null +++ b/src/app/dom.js @@ -0,0 +1,83 @@ +export const ELEMENT_IDS = [ + 'setup-screen', 'main-screen', 'setup-key', 'setup-save', + 'btn-settings', 'modal-settings', 'modal-key', 'modal-save', 'btn-close-modal', + 'sel-model', 'inp-prompt', 'inp-frames', 'inp-fps', 'sel-size', 'sel-ratio', + 'btn-generate', 'progress-area', 'progress-bar', 'progress-text', 'frames-preview', + 'result-area', 'result-gif', 'btn-download' +]; + +const camelize = (id) => id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + +export function grabElements(ids = ELEMENT_IDS) { + const el = {}; + for (const id of ids) { + const key = camelize(id); + el[key] = document.getElementById(id); + if (!el[key]) console.warn(`vibegif: missing element #${id}`); + } + return el; +} + +export function show(node) { + if (!node) return; + node.classList.remove('hidden'); + node.style.display = ''; +} + +export function hide(node) { + if (!node) return; + node.classList.add('hidden'); + node.style.display = ''; +} + +export function setProgress(el, pct, text) { + show(el.progressArea); + if (el.progressBar) el.progressBar.style.width = `${Math.max(0, Math.min(100, pct))}%`; + if (el.progressText) el.progressText.textContent = text || ''; +} + +export function resetProgress(el) { + hide(el.progressArea); + if (el.progressBar) el.progressBar.style.width = '0%'; + if (el.progressText) el.progressText.textContent = ''; + if (el.framesPreview) el.framesPreview.innerHTML = ''; +} + +export function addFramePreview(el, src, index) { + if (!el.framesPreview) return; + const img = document.createElement('img'); + img.src = src; + img.className = 'w-16 h-16 rounded-lg border border-neutral-200 object-cover'; + img.title = `frame ${index + 1}`; + el.framesPreview.appendChild(img); +} + +export function showResult(el, blobUrl) { + if (el.resultArea) { + el.resultArea.classList.remove('hidden'); + el.resultArea.style.display = 'flex'; + } + if (el.resultGif) el.resultGif.src = blobUrl; + if (el.btnDownload) el.btnDownload.href = blobUrl; +} + +export function hideResult(el) { + if (!el.resultArea) return; + el.resultArea.classList.add('hidden'); + el.resultArea.style.display = ''; +} + +export function setGenerating(el, active) { + if (!el.btnGenerate) return; + el.btnGenerate.disabled = !!active; + el.btnGenerate.style.opacity = active ? '0.5' : '1'; + el.btnGenerate.style.cursor = active ? 'not-allowed' : 'pointer'; +} + +export function syncSizeByModel(el) { + if (!el.selModel || !el.selSize) return; + const isGemini = el.selModel.value.startsWith('google/'); + const opt05 = el.selSize.querySelector('option[value="0.5K"]'); + if (opt05) opt05.disabled = !isGemini; + if (!isGemini && el.selSize.value === '0.5K') el.selSize.value = '1K'; +}