/* Shared layout components: Nav, Footer, Marquee, Floating CTA, Tweaks panel */
const Logo = ({ size = 36, fg = 'var(--accent)' }) => (
);
const Marquee = ({ on = true }) => (
{[...Array(2)].map((_, k) => (
● МЕТОД БЕЗ ОТКАТОВ
● РАБОТАЕМ ТОЛЬКО С ТЕМИ, У КОГО ГОРИТ
● НЕ ЧИНИМ МУЖЕЙ
● ПРАВДА · ДЫХАНИЕ · ТЕЛО
● АВТОРСКАЯ ПРАКТИКА
● OSOZNANKA.COM
))}
);
const Nav = ({ current = 'home' }) => {
const [open, setOpen] = React.useState(false);
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 20);
window.addEventListener('scroll', onScroll); return () => window.removeEventListener('scroll', onScroll);
}, []);
return (
<>
>
);
};
const Footer = () => (
);
const FloatingCTA = () => {
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 400);
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
return () => window.removeEventListener('scroll', onScroll);
}, []);
const toTop = (e) => {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
};
return (
<>
↑
● Записаться
Записаться на сессию →
>
);
};
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"accent": "orange",
"posterScale": 1,
"marquee": true
}/*EDITMODE-END*/;
const TweaksPanel = ({ tweaks, setTweaks }) => {
const [editMode, setEditMode] = React.useState(false);
React.useEffect(() => {
const onMsg = (e) => {
const d = e.data || {};
if (d.type === '__activate_edit_mode') setEditMode(true);
if (d.type === '__deactivate_edit_mode') setEditMode(false);
};
window.addEventListener('message', onMsg);
window.parent.postMessage({type: '__edit_mode_available'}, '*');
return () => window.removeEventListener('message', onMsg);
}, []);
const persist = (edits) => {
const next = {...tweaks, ...edits};
setTweaks(next);
try { window.parent.postMessage({type:'__edit_mode_set_keys', edits}, '*'); } catch(e){}
};
if (!editMode) return null;
return (
Tweaks
Акцент
persist({accent: 'orange'})}>оранжевый
persist({accent: 'acid'})}>кислота
Размер постерных заголовков
persist({posterScale: Number(e.target.value)})}/>
×{Number(tweaks.posterScale).toFixed(2)}
Бегущая строка
persist({marquee: true})}>ВКЛ
persist({marquee: false})}>ВЫКЛ
);
};
const applyTweaks = (t) => {
const r = document.documentElement;
r.style.setProperty('--accent', t.accent === 'acid' ? 'var(--acid)' : 'var(--orange)');
r.style.setProperty('--poster-scale', String(t.posterScale));
};
// Универсальный блок «что дальше» — ставится внизу страниц, до футера.
// items: [{label, desc, href, primary?:bool}]
const NextSteps = ({ kicker = '§ дальше', title, items, note }) => (
{kicker}
{title}
{note ? (
{note}
) : null}
);
Object.assign(window, { Logo, Marquee, Nav, Footer, FloatingCTA, TweaksPanel, TWEAK_DEFAULTS, applyTweaks, NextSteps });