setDevMode(on) already exists. It's the floating Dev icon (44ร44, dark with green </>). When OFF: only the icon is visible, sitting above any app UI. When ON: chips appear on sections, dock pills on the edges, panels open, inspector slides in. One toggle, the whole layer.
Bring nature into the classroom with beautifully illustrated, curriculum-aligned resources.
Books ยท News ยท Team ยท Resources
Ready to bring trees to your classroom?
ยฉ 2026 Tree Academy
Bring nature into the classroom with beautifully illustrated, curriculum-aligned resources.
Books ยท News ยท Team ยท Resources
Ready to bring trees to your classroom?
ยฉ 2026 Tree Academy
safe-area-inset-* respected (iOS notch)Ctrl+Shift+D?dev=1fvcms.dev=1// freshvibe-cms/cms/devToggle.js โ the floating Dev icon export function mountDevToggle({ setDevMode, // required: the existing setDevMode from install-editor getDevMode, // required: isDevMode() persist = true, }) { // Create the toggle element const btn = document.createElement('button'); btn.className = 'fvcms-dev-toggle'; btn.setAttribute('aria-label', 'Toggle Dev mode'); btn.innerHTML = '</>'; // Restore position from localStorage const pos = JSON.parse(localStorage.getItem('fvcms.devTogglePos') || 'null'); if (pos) { btn.style.left = pos.x + 'px'; btn.style.top = pos.y + 'px'; } else { btn.style.right = '12px'; btn.style.bottom = '70px'; // above app bar } // Sync visual state with dev mode const sync = () => { const on = getDevMode(); btn.classList.toggle('on', on); document.body.classList.toggle('fvcms-dev-on', on); }; // Click toggles dev mode (uses existing setDevMode) btn.addEventListener('click', () => { setDevMode(!getDevMode()); sync(); }); // Drag to reposition let drag = null; btn.addEventListener('pointerdown', (e) => { const r = btn.getBoundingClientRect(); drag = { x: e.clientX - r.left, y: e.clientY - r.top }; btn.setPointerCapture(e.pointerId); }); btn.addEventListener('pointermove', (e) => { if (!drag) return; const x = e.clientX - drag.x, y = e.clientY - drag.y; btn.style.left = clamp(x, 0, innerWidth - 44) + 'px'; btn.style.top = clamp(y, 0, innerHeight - 44) + 'px'; btn.style.right = btn.style.bottom = 'auto'; }); btn.addEventListener('pointerup', (e) => { if (!drag) return; if (persist) { const r = btn.getBoundingClientRect(); localStorage.setItem('fvcms.devTogglePos', JSON.stringify({ x: r.left, y: r.top })); } drag = null; }); sync(); document.body.appendChild(btn); return btn; }
installEditor() exposes setDevMode and isDevMode. Adding a parallel toggle creates two ways to do the same thing, which is a bug sourceisDevMode()+ Widget we just designed)fvcms.dev=1 or fvcms.dev=0fvcms.devTogglePos?dev=0 forces OFF (for sharing clean pages)?dev=1 forces ON (for demos, recordings)