ruslanmv's picture
feat: complete AutoApp Builder - AI-powered HF Space generator
2c304fc verified
/**
* AutoApp Builder - Frontend JavaScript
*/
// ─── Character Counter ──────────────────────────────────────────────
const promptInput = document.getElementById('promptInput');
const charCount = document.getElementById('charCount');
if (promptInput && charCount) {
promptInput.addEventListener('input', () => {
const len = promptInput.value.length;
charCount.textContent = `${len} / 2000`;
if (len > 1800) {
charCount.classList.add('text-yellow-500');
} else {
charCount.classList.remove('text-yellow-500');
}
});
}
// ─── Example Buttons ────────────────────────────────────────────────
document.querySelectorAll('.example-btn').forEach(btn => {
btn.addEventListener('click', () => {
const prompt = btn.getAttribute('data-prompt');
if (promptInput && prompt) {
promptInput.value = prompt;
promptInput.dispatchEvent(new Event('input'));
promptInput.focus();
// Scroll to textarea
promptInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
});
});
// ─── SDK Preference Toggle ──────────────────────────────────────────
document.querySelectorAll('.sdk-option').forEach(label => {
label.addEventListener('click', () => {
// Remove active styles from all
document.querySelectorAll('.sdk-option').forEach(l => {
l.classList.remove('bg-cyan-500/20', 'text-cyan-400');
l.classList.add('text-dark-400');
});
// Add active style to clicked
label.classList.add('bg-cyan-500/20', 'text-cyan-400');
label.classList.remove('text-dark-400');
});
});
// ─── Advanced Options Toggle ────────────────────────────────────────
const toggleAdvanced = document.getElementById('toggleAdvanced');
const advancedPanel = document.getElementById('advancedPanel');
const advancedArrow = document.getElementById('advancedArrow');
if (toggleAdvanced && advancedPanel) {
toggleAdvanced.addEventListener('click', () => {
advancedPanel.classList.toggle('hidden');
if (advancedArrow) {
advancedArrow.style.transform = advancedPanel.classList.contains('hidden')
? 'rotate(0deg)'
: 'rotate(90deg)';
}
});
}
// ─── Form Submission Loading State ──────────────────────────────────
const generateForm = document.getElementById('generateForm');
if (generateForm) {
generateForm.addEventListener('submit', () => {
const btn = document.getElementById('submitBtn');
const text = document.getElementById('submitText');
const spinner = document.getElementById('submitSpinner');
if (btn) btn.disabled = true;
if (text) text.textContent = 'Generating...';
if (spinner) spinner.classList.remove('hidden');
btn.classList.add('opacity-75', 'cursor-not-allowed');
});
}
const editForm = document.getElementById('editForm');
if (editForm) {
editForm.addEventListener('submit', () => {
const btn = document.getElementById('editBtn');
const text = document.getElementById('editText');
const spinner = document.getElementById('editSpinner');
if (btn) btn.disabled = true;
if (text) text.textContent = 'Editing...';
if (spinner) spinner.classList.remove('hidden');
btn.classList.add('opacity-75', 'cursor-not-allowed');
});
}
// ─── File Selection & Code Preview (Result Page) ────────────────────
function selectFile(filepath) {
if (typeof fileData === 'undefined') return;
const content = fileData[filepath];
if (content === undefined) return;
// Update active state in tree
document.querySelectorAll('.file-tree-item').forEach(item => {
item.classList.remove('active');
});
const activeItem = document.querySelector(`[data-filepath="${filepath}"]`);
if (activeItem) activeItem.classList.add('active');
// Update filename display
const fileNameEl = document.getElementById('currentFileName');
if (fileNameEl) fileNameEl.textContent = filepath;
// Determine language for syntax highlighting
const lang = getLanguage(filepath);
// Show code block, hide placeholder
const placeholder = document.getElementById('codePlaceholder');
const codeBlock = document.getElementById('codeBlock');
const codeContent = document.getElementById('codeContent');
if (placeholder) placeholder.classList.add('hidden');
if (codeBlock) codeBlock.classList.remove('hidden');
if (codeContent) {
// Escape HTML entities
codeContent.textContent = content;
codeContent.className = `language-${lang}`;
// Re-highlight
if (window.Prism) {
Prism.highlightElement(codeContent);
}
}
}
function getLanguage(filepath) {
const ext = filepath.split('.').pop().toLowerCase();
const langMap = {
'py': 'python',
'js': 'javascript',
'ts': 'javascript',
'html': 'markup',
'htm': 'markup',
'css': 'css',
'md': 'markdown',
'yaml': 'yaml',
'yml': 'yaml',
'json': 'javascript',
'sh': 'bash',
'bash': 'bash',
'dockerfile': 'docker',
'txt': 'text',
'toml': 'text',
'cfg': 'text',
'ini': 'text',
'gitignore': 'text',
};
// Handle Dockerfile specifically
if (filepath.toLowerCase() === 'dockerfile') return 'docker';
return langMap[ext] || 'text';
}
// ─── Copy Code ──────────────────────────────────────────────────────
function copyCode() {
const codeContent = document.getElementById('codeContent');
if (!codeContent) return;
const text = codeContent.textContent;
navigator.clipboard.writeText(text).then(() => {
const btn = document.getElementById('copyBtn');
if (btn) {
const originalHTML = btn.innerHTML;
btn.innerHTML = '<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> Copied!';
btn.classList.add('text-emerald-400');
setTimeout(() => {
btn.innerHTML = originalHTML;
btn.classList.remove('text-emerald-400');
}, 2000);
}
}).catch(() => {
// Fallback: select text
const range = document.createRange();
range.selectNodeContents(codeContent);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
});
}
// ─── Architecture Diagram Toggle ────────────────────────────────────
function toggleDiagram() {
const panel = document.getElementById('diagramPanel');
const toggle = document.getElementById('diagramToggle');
if (panel) {
panel.classList.toggle('hidden');
if (toggle) {
toggle.textContent = panel.classList.contains('hidden') ? 'Show' : 'Hide';
}
}
}
// ─── Keyboard Shortcuts ─────────────────────────────────────────────
document.addEventListener('keydown', (e) => {
// Ctrl/Cmd + Enter to submit form
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
const form = document.getElementById('generateForm') || document.getElementById('editForm');
if (form) {
form.dispatchEvent(new Event('submit', { bubbles: true }));
form.submit();
}
}
});