const ThemeManager = { init() { const saved = localStorage.getItem('theme'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; this.setTheme(saved || (prefersDark ? 'dark' : 'light')); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { if (!localStorage.getItem('theme')) this.setTheme(e.matches ? 'dark' : 'light'); }); }, setTheme(t) { document.documentElement.setAttribute('data-theme', t); localStorage.setItem('theme', t); }, toggle() { this.setTheme(document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'); } }; const Toast = { container: null, init() { this.container = document.createElement('div'); this.container.className = 'toast-container'; document.body.appendChild(this.container); }, show(msg, type = 'success', dur = 2500) { const t = document.createElement('div'); t.className = `toast ${type}`; t.innerHTML = `${type === 'success' ? '' : ''}${msg}`; this.container.appendChild(t); setTimeout(() => { t.style.animation = 'slideIn 0.3s reverse'; setTimeout(() => t.remove(), 300); }, dur); } }; async function copyToClipboard(text, btn) { try { await navigator.clipboard.writeText(text); Toast.show('Copied!'); if (btn) { const o = btn.innerHTML; btn.innerHTML = '✓ Copied'; setTimeout(() => btn.innerHTML = o, 1500); } } catch { Toast.show('Copy failed', 'error'); } } function toggleWrap() { const body = document.querySelector('.code-body'); const btn = document.getElementById('wrap-toggle'); if (!body) return; body.classList.toggle('wrap-text'); const isWrapped = body.classList.contains('wrap-text'); localStorage.setItem('wrapText', isWrapped); if (btn) btn.classList.toggle('btn-primary', isWrapped); } const API = { async request(url, opts = {}) { const r = await fetch(url, { headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', ...opts }); const d = await r.json(); if (!r.ok) throw new Error(d.error || 'Error'); return d; }, createPaste: (d) => API.request('/api/paste', { method: 'POST', body: JSON.stringify(d) }), updatePaste: (id, d) => API.request(`/api/paste/${id}`, { method: 'PUT', body: JSON.stringify(d) }), deletePaste: (id) => API.request(`/api/paste/${id}`, { method: 'DELETE' }), forkPaste: (id) => API.request(`/api/paste/${id}/fork`, { method: 'POST' }), login: (u, p) => API.request('/api/auth/login', { method: 'POST', body: JSON.stringify({ username: u, password: p }) }), register: (u, p) => API.request('/api/auth/register', { method: 'POST', body: JSON.stringify({ username: u, password: p }) }), logout: () => API.request('/api/auth/logout', { method: 'POST' }) }; function setupPasteForm() { const f = document.getElementById('paste-form'); if (!f) return; f.addEventListener('submit', async e => { e.preventDefault(); const btn = f.querySelector('button[type="submit"]'); try { btn.disabled = true; btn.textContent = 'Creating...'; const paste = await API.createPaste({ title: f.title.value || 'Untitled', content: f.content.value, language: f.language.value, is_public: f.is_public.checked, expires_in: f.expires_in?.value || 'never', burn_after_read: f.burn_after_read?.checked || false }); window.location.href = `/${paste.id}`; } catch (err) { Toast.show(err.message, 'error'); btn.disabled = false; btn.textContent = 'Create Paste'; } }); } function setupEditForm() { const f = document.getElementById('edit-form'); if (!f) return; f.addEventListener('submit', async e => { e.preventDefault(); const btn = f.querySelector('button[type="submit"]'); try { btn.disabled = true; btn.textContent = 'Saving...'; await API.updatePaste(f.dataset.pasteId, { title: f.title.value, content: f.content.value, language: f.language.value, is_public: f.is_public.checked }); Toast.show('Saved!'); setTimeout(() => window.location.href = `/${f.dataset.pasteId}`, 800); } catch (err) { Toast.show(err.message, 'error'); btn.disabled = false; btn.textContent = 'Save'; } }); } function setupAuthForms() { const login = document.getElementById('login-form'); const reg = document.getElementById('register-form'); if (login) login.addEventListener('submit', async e => { e.preventDefault(); const btn = login.querySelector('button[type="submit"]'); try { btn.disabled = true; await API.login(login.username.value, login.password.value); window.location.href = '/dashboard'; } catch (err) { Toast.show(err.message, 'error'); btn.disabled = false; } }); if (reg) reg.addEventListener('submit', async e => { e.preventDefault(); const btn = reg.querySelector('button[type="submit"]'); try { btn.disabled = true; await API.register(reg.username.value, reg.password.value); window.location.href = '/dashboard'; } catch (err) { Toast.show(err.message, 'error'); btn.disabled = false; } }); } function setupDeleteButton() { const btn = document.getElementById('delete-paste'); if (!btn) return; btn.addEventListener('click', async () => { if (!confirm('Delete this paste?')) return; try { await API.deletePaste(btn.dataset.pasteId); Toast.show('Deleted!'); setTimeout(() => window.location.href = '/dashboard', 800); } catch (err) { Toast.show(err.message, 'error'); } }); } function setupForkButton() { const btn = document.getElementById('fork-paste'); if (!btn) return; btn.addEventListener('click', async () => { try { const f = await API.forkPaste(btn.dataset.pasteId); Toast.show('Forked!'); setTimeout(() => window.location.href = `/${f.id}`, 800); } catch (err) { Toast.show(err.message, 'error'); } }); } function setupLogout() { const btn = document.getElementById('logout-btn'); if (!btn) return; btn.addEventListener('click', async e => { e.preventDefault(); try { await API.logout(); window.location.href = '/'; } catch { } }); } function setupKeyboardShortcuts() { document.addEventListener('keydown', e => { if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { const f = document.querySelector('#paste-form, #edit-form'); if (f) { e.preventDefault(); f.dispatchEvent(new Event('submit')); } } if ((e.ctrlKey || e.metaKey) && e.key === 's') { const f = document.getElementById('edit-form'); if (f) { e.preventDefault(); f.dispatchEvent(new Event('submit')); } } }); } function restoreWrapState() { if (localStorage.getItem('wrapText') === 'true') { const body = document.querySelector('.code-body'); const btn = document.getElementById('wrap-toggle'); if (body) body.classList.add('wrap-text'); if (btn) btn.classList.add('btn-primary'); } } document.addEventListener('DOMContentLoaded', () => { ThemeManager.init(); Toast.init(); setupPasteForm(); setupEditForm(); setupAuthForms(); setupDeleteButton(); setupForkButton(); setupLogout(); setupKeyboardShortcuts(); restoreWrapState(); }); window.toggleTheme = () => ThemeManager.toggle(); window.copyToClipboard = copyToClipboard; window.toggleWrap = toggleWrap;