// tweaks.jsx — AAGU design tweaks panel // Exposes brand palette, type, radius, block-meta visibility, page focus, hero variant. const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "primary": "#F18E00", "primaryDark": "#C57400", "primaryTint": "#FFF1DE", "darkSurface": "#111827", "bg": "#FFFFFF", "displayFont": "Corporate S Pro", "bodyFont": "Corporate S Pro", "radiusScale": 1.0, "showBlockMeta": true, "heroVariant": "dark", "focus": "all", "stopsGeometry": "angled", "stopsColor": "brand", "stopsDecoration": "ghost" }/*EDITMODE-END*/; // Lighten/darken helpers — for derived shades function shiftHex(hex, amt) { const h = hex.replace('#', ''); const n = parseInt(h.length === 3 ? h.split('').map(c => c + c).join('') : h, 16); let r = (n >> 16) & 0xff, g = (n >> 8) & 0xff, b = n & 0xff; r = Math.max(0, Math.min(255, r + amt)); g = Math.max(0, Math.min(255, g + amt)); b = Math.max(0, Math.min(255, b + amt)); return '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1); } function withAlpha(hex, a) { const h = hex.replace('#', ''); const n = parseInt(h.length === 3 ? h.split('').map(c => c + c).join('') : h, 16); const r = (n >> 16) & 0xff, g = (n >> 8) & 0xff, b = n & 0xff; return `rgba(${r}, ${g}, ${b}, ${a})`; } // Preload Google Fonts available for swap const DISPLAY_FONTS = { "Corporate S Pro": "", "Source Sans 3": "Source+Sans+3:wght@300;500;600;700", "DM Sans": "DM+Sans:opsz,wght@9..40,500;9..40,600;9..40,700;9..40,800", "Manrope": "Manrope:wght@500;600;700;800", "Space Grotesk": "Space+Grotesk:wght@500;600;700", "Plus Jakarta Sans": "Plus+Jakarta+Sans:wght@500;600;700;800", "Bricolage Grotesque": "Bricolage+Grotesque:opsz,wght@12..96,500;12..96,600;12..96,700;12..96,800", }; const BODY_FONTS = { "Corporate S Pro": "", "Source Sans 3": "Source+Sans+3:wght@300;400;500;600;700", "Inter": "Inter:wght@300;400;500;600;700", "IBM Plex Sans": "IBM+Plex+Sans:wght@300;400;500;600;700", "Figtree": "Figtree:wght@300;400;500;600;700", "Geist": "Geist:wght@400;500;600;700", }; function ensureFontLoaded(family, kind) { const id = `font-${kind}-${family.replace(/\s+/g, '-')}`; if (document.getElementById(id)) return; const map = kind === 'display' ? DISPLAY_FONTS : BODY_FONTS; const spec = map[family]; if (!spec) return; const link = document.createElement('link'); link.id = id; link.rel = 'stylesheet'; link.href = `https://fonts.googleapis.com/css2?family=${spec}&display=swap`; document.head.appendChild(link); } function applyTweaks(t) { const r = document.documentElement; // Brand r.style.setProperty('--brand-orange', t.primary); r.style.setProperty('--brand-orange-dark', t.primaryDark || shiftHex(t.primary, -25)); r.style.setProperty('--brand-orange-tint', t.primaryTint || withAlpha(t.primary, 0.14)); r.style.setProperty('--gray-900', t.darkSurface); r.style.setProperty('--gray-800', shiftHex(t.darkSurface, 14)); r.style.setProperty('--bg', t.bg); // Type ensureFontLoaded(t.displayFont, 'display'); ensureFontLoaded(t.bodyFont, 'body'); r.style.setProperty('--font-display', `"${t.displayFont}", system-ui, sans-serif`); r.style.setProperty('--font-body', `"${t.bodyFont}", system-ui, sans-serif`); // Radius scale (multiplier) const s = t.radiusScale ?? 1; r.style.setProperty('--r-xs', `${Math.round(6 * s)}px`); r.style.setProperty('--r-sm', `${Math.round(10 * s)}px`); r.style.setProperty('--r-md', `${Math.round(14 * s)}px`); r.style.setProperty('--r-lg', `${Math.round(20 * s)}px`); r.style.setProperty('--r-xl', `${Math.round(28 * s)}px`); // Block-meta visibility document.body.dataset.metaVisible = t.showBlockMeta ? '1' : '0'; // Focus mode document.body.dataset.focus = t.focus || 'all'; // Hero variant document.body.dataset.heroVariant = t.heroVariant || 'dark'; // Stops block tweaks document.body.dataset.stopsGeometry = t.stopsGeometry || 'angled'; document.body.dataset.stopsColor = t.stopsColor || 'brand'; document.body.dataset.stopsDecoration = t.stopsDecoration || 'ghost'; // Notify blocks that read body.dataset.* — they re-render on this event. window.dispatchEvent(new Event('aagu:tweaks-changed')); } function TweaksUI() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); React.useEffect(() => { applyTweaks(t); }, [t]); return ( { setTweak({ primary: v, primaryDark: shiftHex(v, -25), primaryTint: withAlpha(v, 0.14), }); }} /> setTweak('darkSurface', v)} /> setTweak('bg', v)} /> setTweak('displayFont', v)} /> setTweak('bodyFont', v)} /> setTweak('radiusScale', v)} /> setTweak('stopsGeometry', v)} /> setTweak('stopsColor', v)} /> setTweak('stopsDecoration', v)} /> setTweak('heroVariant', v)} /> setTweak('showBlockMeta', v)} /> setTweak('focus', v)} /> setTweak({ primary: '#F18E00', primaryDark: '#C57400', primaryTint: '#FFF1DE', darkSurface: '#111827', bg: '#FFFFFF', displayFont: 'Corporate S Pro', bodyFont: 'Corporate S Pro', radiusScale: 1.0, showBlockMeta: true, heroVariant: 'dark', focus: 'all', stopsGeometry: 'angled', stopsColor: 'brand', stopsDecoration: 'ghost', })} /> ); } Object.assign(window, { TweaksUI, TWEAK_DEFAULTS, applyTweaks, shiftHex });