HTML
1
CSS
1
JS
1
`; outputFrame.srcdoc = source; }; const debouncedRender = debounce(renderOutput, 300); const updateLineNumbers = (type) => { const codeEl = document.getElementById(`${type}-code`); const linesEl = document.getElementById(`${type}-lines`); const lineCount = codeEl.value.split('\n').length || 1; linesEl.innerHTML = Array.from({ length: lineCount }, (_, i) => i + 1).join('
'); debouncedRender(); }; ['html', 'css', 'js'].forEach(type => { const codeEl = document.getElementById(`${type}-code`); codeEl.addEventListener('scroll', () => { document.getElementById(`${type}-lines`).scrollTop = codeEl.scrollTop; }); updateLineNumbers(type); }); const fileConfigs = { html: { uploadBtn: document.getElementById('upload-html-btn'), downloadBtn: document.getElementById('download-html-btn'), uploadInput: document.getElementById('html-upload-input'), codeEl: htmlCodeEl, filename: 'index.html', mimeType: 'text/html' }, css: { uploadBtn: document.getElementById('upload-css-btn'), downloadBtn: document.getElementById('download-css-btn'), uploadInput: document.getElementById('css-upload-input'), codeEl: cssCodeEl, filename: 'style.css', mimeType: 'text/css' }, js: { uploadBtn: document.getElementById('upload-js-btn'), downloadBtn: document.getElementById('download-js-btn'), uploadInput: document.getElementById('js-upload-input'), codeEl: jsCodeEl, filename: 'script.js', mimeType: 'application/javascript' } }; const downloadFile = (content, filename, contentType) => { const a = document.createElement('a'); const file = new Blob([content], { type: contentType }); a.href = URL.createObjectURL(file); a.download = filename; a.click(); URL.revokeObjectURL(a.href); }; Object.keys(fileConfigs).forEach(type => { const config = fileConfigs[type]; config.downloadBtn.addEventListener('click', () => downloadFile(config.codeEl.value, config.filename, config.mimeType)); config.uploadBtn.addEventListener('click', () => config.uploadInput.click()); config.uploadInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { config.codeEl.value = e.target.result; updateLineNumbers(type); }; reader.readAsText(file); e.target.value = ''; }); }); const docElement = document.documentElement; const applyTheme = (theme) => { docElement.setAttribute('data-theme', theme); localStorage.setItem('editorTheme', theme); }; document.getElementById('theme-toggle-btn').addEventListener('click', () => { const newTheme = docElement.getAttribute('data-theme') === 'glass' ? 'dark' : 'glass'; applyTheme(newTheme); }); const appWrapper = document.querySelector('.app-wrapper'), previewToggleBtn = document.getElementById('preview-toggle-btn'); previewToggleBtn.addEventListener('click', () => { appWrapper.classList.toggle('full-preview-mode'); previewToggleBtn.title = appWrapper.classList.contains('full-preview-mode') ? 'Exit Full Preview' : 'Full Preview'; }); const editorTabs = document.querySelectorAll('.editor-tab'), editorPanels = document.querySelectorAll('.editor-panel'); editorTabs.forEach(tab => { tab.addEventListener('click', () => { const targetPanelId = tab.dataset.target; editorTabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); editorPanels.forEach(panel => { panel.classList.toggle('active', panel.id === targetPanelId); }); }); }); applyTheme(localStorage.getItem('editorTheme') || 'glass'); renderOutput();