// Root Site component — composes sections, wires up Tweaks.
const { useState: useStateS, useEffect: useEffectS } = React;
function TweaksPanel({ state, setState, visible, onClose }) {
if (!visible) return null;
const upd = (k, v) => setState(s => ({ ...s, [k]: v }));
const swatchRow = (k, opts) => (
{opts.map(o => (
))}
);
return (
Firm size
Swaps proof points & highlights the pricing tier.
{swatchRow('firmTier', [
{ v: 'solo', label: 'Solo' },
{ v: 'boutique', label: 'Boutique' },
{ v: 'midsize', label: 'Mid-size' },
])}
Accent tint
{swatchRow('accent', [
{ v: 'blue', label: 'Blue', dot: T.blue },
{ v: 'green', label: 'Green', dot: T.green },
{ v: 'violet', label: 'Violet', dot: T.violet },
])}
Density
{swatchRow('density', [
{ v: 'comfortable', label: 'Comfortable' },
{ v: 'compact', label: 'Compact' },
])}
Hero product shot
{swatchRow('heroShot', [
{ v: 'dashboard', label: 'Dashboard' },
{ v: 'rfe', label: 'RFE' },
{ v: 'cases', label: 'Cases' },
])}
Changes persist across reloads. The firm-size tweak highlights the matching pricing tier and swaps the tone of the hero.
);
}
function Site() {
const defaults = window.__TWEAKS__ || { firmTier: 'boutique', accent: 'blue', density: 'comfortable', heroShot: 'dashboard' };
const [tweaks, setTweaks] = useStateS(() => {
try {
const saved = localStorage.getItem('immihub-atty-tweaks');
return saved ? { ...defaults, ...JSON.parse(saved) } : defaults;
} catch (e) { return defaults; }
});
const [tweakOpen, setTweakOpen] = useStateS(false);
// Persist
useEffectS(() => {
try { localStorage.setItem('immihub-atty-tweaks', JSON.stringify(tweaks)); } catch (e) {}
window.parent && window.parent.postMessage({ type: '__edit_mode_set_keys', edits: tweaks }, '*');
}, [tweaks]);
// Tweaks protocol — listener FIRST, then announce
useEffectS(() => {
const onMsg = (e) => {
if (!e.data || !e.data.type) return;
if (e.data.type === '__activate_edit_mode') setTweakOpen(true);
if (e.data.type === '__deactivate_edit_mode') setTweakOpen(false);
};
window.addEventListener('message', onMsg);
// announce
window.parent && window.parent.postMessage({ type: '__edit_mode_available' }, '*');
return () => window.removeEventListener('message', onMsg);
}, []);
const { accent, firmTier, heroShot } = tweaks;
return (
setTweaks(t => ({ ...t, firmTier: v }))} accent={accent} />
setTweakOpen(false)} />
);
}
Object.assign(window, { Site, TweaksPanel });