/* ============================================================
Shared components · Надёжные люди
============================================================ */
const { useState, useEffect, useRef, useContext, createContext } = React;
/* ---------- navigation context ---------- */
const NavCtx = createContext({ page: 'home', go: () => {} });
const useNav = () => useContext(NavCtx);
/* ---------- icons (rounded stroke set) ---------- */
function Icon({ name, size = 24, stroke = 2.1, style, className }) {
const p = { fill: 'none', stroke: 'currentColor', strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round' };
const paths = {
heart: ,
hands: ,
chat: ,
calendar: ,
shield: ,
star: ,
arrow: ,
arrowUpRight: ,
check: ,
phone: ,
mail: ,
pin: ,
users: ,
sprout: ,
gift: ,
handHeart: ,
play: ,
quote: ,
menu: ,
close: ,
repeat: ,
doc: ,
download: ,
};
return (
);
}
/* ---------- squiggle underline ---------- */
function Squiggle({ color = 'var(--orange)', children }) {
return (
{children}
);
}
/* ---------- logo ---------- */
function Logo({ size = 46, onClick, showText = true }) {
return (
);
}
/* ---------- button (router-aware) ---------- */
function Btn({ to, href, variant = 'orange', size = '', children, icon, iconLeft, onClick, ...rest }) {
const { go } = useNav();
const cls = `btn btn-${variant} ${size === 'lg' ? 'btn-lg' : size === 'sm' ? 'btn-sm' : ''}`;
const handle = (e) => {
if (onClick) onClick(e);
if (to) { e.preventDefault(); go(to); }
};
const inner = (
<>
{iconLeft && }
{children}
{icon && }
>
);
if (href) return {inner};
return ;
}
/* ---------- scroll reveal ---------- */
function Reveal({ children, delay = 0, as = 'div', className = '', style, ...rest }) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver((entries) => {
entries.forEach((e) => { if (e.isIntersecting) { setTimeout(() => el.classList.add('in'), delay); io.unobserve(el); } });
}, { threshold: 0.12 });
io.observe(el);
return () => io.disconnect();
}, [delay]);
const Tag = as;
return {children};
}
/* ---------- stat ---------- */
function Stat({ value, label, color = 'var(--green)' }) {
return (
);
}
/* ============================================================
HEADER
============================================================ */
const NAV_LINKS = [
{ id: 'about', label: 'О фонде' },
{ id: 'mentorship', label: 'Наставничество' },
{ id: 'business', label: 'Бизнесу' },
{ id: 'team', label: 'Команда' },
{ id: 'contacts', label: 'Контакты' },
];
function Header() {
const { page, go } = useNav();
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 16);
onScroll();
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
useEffect(() => { setOpen(false); }, [page]);
return (
go('home')} />
Помочь
{open && (
setOpen(false)}>
e.stopPropagation()}>
go('home')} />
{NAV_LINKS.map((l) => (
))}
Помочь фонду
)}
);
}
/* ============================================================
FOOTER
============================================================ */
function Footer() {
const { go } = useNav();
return (
);
}
Object.assign(window, { NavCtx, useNav, Icon, Squiggle, Logo, Btn, Reveal, Stat, Header, Footer, NAV_LINKS });
/* ============================================================
COOKIE BANNER
============================================================ */
function CookieBanner() {
const { go } = useNav();
const [show, setShow] = useState(false);
useEffect(() => {
let ok = false;
try { ok = localStorage.getItem('nl-cookie-consent') === 'yes'; } catch (e) {}
if (!ok) { const t = setTimeout(() => setShow(true), 900); return () => clearTimeout(t); }
}, []);
const accept = () => {
try { localStorage.setItem('nl-cookie-consent', 'yes'); } catch (e) {}
setShow(false);
};
if (!show) return null;
return (
);
}
Object.assign(window, { CookieBanner });