// Mounts the Tweaks panel for ACLEAP site // Reads window.TWEAK_DEFAULTS and persists changes via host protocol. function ACLEAPTweaks() { const [t, setTweak] = useTweaks(window.TWEAK_DEFAULTS); // Apply tweaks to data attributes & CSS vars React.useEffect(() => { document.body.dataset.dark = String(!!t.dark); document.body.dataset.density = t.density || 'regular'; document.body.dataset.header = t.header || 'default'; // Apply primary color override const root = document.documentElement; if (t.primaryColor) { root.style.setProperty('--primary', t.primaryColor); // derive deeper shade by reducing lightness ~10% root.style.setProperty('--primary-deep', shade(t.primaryColor, -14)); root.style.setProperty('--primary-tint', tint(t.primaryColor, 0.85)); } }, [t]); return ( setTweak('primaryColor', v)} /> setTweak('dark', v)} /> setTweak('density', v)} /> setTweak('header', v)} /> ); } // Helpers: shade/tint a hex color function shade(hex, percent) { const c = hexToRgb(hex); if (!c) return hex; const f = 1 + percent / 100; const r = clamp(Math.round(c.r * f), 0, 255); const g = clamp(Math.round(c.g * f), 0, 255); const b = clamp(Math.round(c.b * f), 0, 255); return rgbToHex(r, g, b); } function tint(hex, amount) { const c = hexToRgb(hex); if (!c) return hex; const r = clamp(Math.round(c.r + (255 - c.r) * amount), 0, 255); const g = clamp(Math.round(c.g + (255 - c.g) * amount), 0, 255); const b = clamp(Math.round(c.b + (255 - c.b) * amount), 0, 255); return rgbToHex(r, g, b); } function hexToRgb(h) { if (!h) return null; const m = h.replace('#',''); if (m.length !== 6) return null; return { r: parseInt(m.slice(0,2),16), g: parseInt(m.slice(2,4),16), b: parseInt(m.slice(4,6),16) }; } function rgbToHex(r,g,b){return '#'+[r,g,b].map(x=>x.toString(16).padStart(2,'0')).join('')} function clamp(v,a,b){return Math.max(a,Math.min(b,v))} // Mount const __tweakMount = document.createElement('div'); document.body.appendChild(__tweakMount); ReactDOM.createRoot(__tweakMount).render();