/* ============ ШАБЛОН СТАТЬИ — 115-ФЗ простыми словами ============ */ const { useState: useArtS, useEffect: useArtE } = React; const TOC = [ ["t1", "Что такое 115-ФЗ"], ["t2", "Кого закон касается"], ["t3", "Почему блокируют счёт"], ["t4", "Что такое ЗСК и «светофор»"], ["t5", "Что делать при блокировке"], ["t6", "Как снизить риск"], ]; function ReadingProgress() { const [w, setW] = useArtS(0); useArtE(() => { const f = () => { const h = document.documentElement; const max = h.scrollHeight - h.clientHeight; setW(max > 0 ? (h.scrollTop / max) * 100 : 0); }; f(); window.addEventListener("scroll", f, { passive: true }); return () => window.removeEventListener("scroll", f); }, []); return
; } function ArticleToc() { const [active, setActive] = useArtS("t1"); useArtE(() => { const io = new IntersectionObserver((es) => { es.forEach(e => { if (e.isIntersecting) setActive(e.target.id); }); }, { rootMargin: "-30% 0px -60% 0px" }); TOC.forEach(([id]) => { const el = document.getElementById(id); if (el) io.observe(el); }); return () => io.disconnect(); }, []); return (
Содержание
{TOC.map(([id, t]) => ( {t} ))}
); } function Article() { useReveal(); return (