import { showToast } from '../components/toast.js'; const API = (url, opts = {}) => fetch('/api' + url, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('token')}`, ...opts.headers }, ...opts }).then(r => r.json()); const WIDGET_TYPES = [ { id: 'clock', name: 'Clock', icon: '🕓', desc: 'Digital clock with date' }, { id: 'weather', name: 'Weather', icon: '⛅', desc: 'Current weather conditions' }, { id: 'rss', name: 'News Ticker', icon: '📰', desc: 'Scrolling RSS feed' }, { id: 'text', name: 'Text/HTML', icon: '📝', desc: 'Custom text or HTML content' }, { id: 'webpage', name: 'Webpage', icon: '🌐', desc: 'Embed a webpage' }, { id: 'social', name: 'Social Feed', icon: '💬', desc: 'Social media feed' }, ]; export async function render(container) { container.innerHTML = `
`; let editingWidget = null; let creatingType = null; document.getElementById('newWidgetBtn').onclick = () => { const grid = document.getElementById('widgetTypeGrid'); grid.style.display = grid.style.display === 'none' ? 'grid' : 'none'; }; container.querySelectorAll('[data-create-type]').forEach(el => { el.onclick = () => { creatingType = el.dataset.createType; editingWidget = null; document.getElementById('widgetTypeGrid').style.display = 'none'; showConfigForm(creatingType, {}); }; }); function showConfigForm(type, config) { const typeName = WIDGET_TYPES.find(t => t.id === type)?.name || type; document.getElementById('widgetModalTitle').textContent = editingWidget ? `Edit ${typeName}` : `New ${typeName}`; let html = '
'; switch (type) { case 'clock': html += `
`; break; case 'weather': html += `
`; break; case 'rss': html += `
`; break; case 'text': html += `
`; break; case 'webpage': html += `
`; break; case 'social': html += `
`; break; } document.getElementById('widgetConfigForm').innerHTML = html; document.getElementById('widgetModal').style.display = 'flex'; } function getConfigFromForm(type) { const config = {}; const val = id => document.getElementById(id)?.value; switch (type) { case 'clock': Object.assign(config, { format: val('wFormat'), timezone: val('wTimezone'), font_size: parseInt(val('wFontSize')) || 64, color: val('wColor'), background: val('wBg'), show_date: true }); break; case 'weather': Object.assign(config, { location: val('wLocation'), units: val('wUnits'), font_size: parseInt(val('wFontSize')) || 48, color: val('wColor') }); break; case 'rss': Object.assign(config, { feed_url: val('wFeedUrl'), scroll_speed: parseInt(val('wScrollSpeed')) || 30, max_items: parseInt(val('wMaxItems')) || 10, font_size: parseInt(val('wFontSize')) || 24, color: val('wColor'), background: val('wBg') }); break; case 'text': Object.assign(config, { html: val('wHtml'), css: val('wCss'), background: val('wBg') }); break; case 'webpage': Object.assign(config, { url: val('wUrl'), zoom: parseInt(val('wZoom')) || 100, refresh_interval: parseInt(val('wRefresh')) || 0 }); break; case 'social': Object.assign(config, { platform: val('wPlatform'), query: val('wQuery') }); break; } return config; } document.getElementById('saveWidgetBtn').onclick = async () => { const type = editingWidget?.widget_type || creatingType; const name = document.getElementById('wName').value; const config = getConfigFromForm(type); try { if (editingWidget) { await API(`/widgets/${editingWidget.id}`, { method: 'PUT', body: JSON.stringify({ name, config }) }); } else { await API('/widgets', { method: 'POST', body: JSON.stringify({ widget_type: type, name, config }) }); } document.getElementById('widgetModal').style.display = 'none'; showToast('Widget saved', 'success'); loadWidgets(); } catch (err) { showToast(err.message, 'error'); } }; document.getElementById('previewWidgetBtn').onclick = () => { if (editingWidget) { window.open(`/api/widgets/${editingWidget.id}/render`, '_blank', 'width=600,height=400'); } else { showToast('Save the widget first to preview', 'info'); } }; async function loadWidgets() { const widgets = await API('/widgets'); const grid = document.getElementById('widgetGrid'); if (!widgets.length) { grid.innerHTML = '

No widgets yet

Create a widget to add dynamic content to your layouts.

'; return; } grid.innerHTML = widgets.map(w => { const typeMeta = WIDGET_TYPES.find(t => t.id === w.widget_type) || {}; return `
${typeMeta.icon || '?'}
${w.name}
${typeMeta.name || w.widget_type}
`; }).join(''); grid.onclick = async (e) => { const editBtn = e.target.closest('[data-edit-widget]'); if (editBtn) { const w = widgets.find(x => x.id === editBtn.dataset.editWidget); if (w) { editingWidget = w; creatingType = w.widget_type; const config = JSON.parse(w.config || '{}'); config._name = w.name; showConfigForm(w.widget_type, config); } return; } const deleteBtn = e.target.closest('[data-delete-widget]'); if (deleteBtn) { try { await API(`/widgets/${deleteBtn.dataset.deleteWidget}`, { method: 'DELETE' }); showToast('Widget deleted', 'success'); loadWidgets(); } catch (err) { showToast(err.message, 'error'); } } }; } loadWidgets(); } export function cleanup() {}