/* ============== Top Nav + Sticky Side Form ============== */
/* ---- Хлебные крошки ----
Данные приходят из PHP (FormulaTheme.crumbs) — той же иерархии страниц,
из которой собирается разметка BreadcrumbList. Блок живёт внутри TopNav,
потому что React затирает весь #root вместе с серверным слоем .seo-pre. */
function Crumbs() {
const items = (window.FormulaTheme || {}).crumbs || [];
if (items.length < 2) return null;
return (
);
}
function TopNav({ page = 'home' }) {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 8);
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
return () => window.removeEventListener('scroll', onScroll);
}, []);
// Per-page nav config. Items use either { id } for in-page scroll, or { href } for cross-page link.
const ft = window.FormulaTheme || {};
const navHome = [
{ id: 'services', label: 'Услуги', href: ft.urls?.services || '#' },
{ id: 'tariffs', label: 'Тарифы' },
{ id: 'founder', label: 'О нас' },
{ id: 'cases', label: 'Кейсы' },
{ id: 'footer', label: 'Контакты' },
];
const navServices = [
{ id: 'directions', label: 'Услуги', active: true },
{ id: 'tariffs', label: 'Тарифы' },
{ id: 'founder', label: 'О нас', href: ft.homeUrl ? ft.homeUrl + '#founder' : '#founder' },
{ id: 'cases', label: 'Кейсы' },
{ id: 'footer', label: 'Контакты' },
];
const navPromo = [
{ id: 'directions', label: 'Услуги', href: ft.urls?.services || '#', active: true },
{ id: 'tariffs', label: 'Тарифы' },
{ id: 'founder', label: 'О нас', href: ft.homeUrl ? ft.homeUrl + '#founder' : '#founder' },
{ id: 'cases', label: 'Кейсы' },
{ id: 'footer', label: 'Контакты' },
];
const navPercent = [
{ id: 'directions', label: 'Услуги', href: ft.urls?.services || '#', active: true },
{ id: 'how', label: 'Как работает' },
{ id: 'founder', label: 'О нас', href: ft.homeUrl ? ft.homeUrl + '#founder' : '#founder' },
{ id: 'cases', label: 'Кейсы' },
{ id: 'footer', label: 'Контакты' },
];
const navSubservice = [
{ id: 'directions', label: 'Услуги', href: ft.urls?.services || '#', active: true },
{ id: 'tariffs', label: 'Тарифы', href: ft.homeUrl ? ft.homeUrl + '#tariffs' : '#' },
{ id: 'founder', label: 'О нас', href: ft.homeUrl ? ft.homeUrl + '#founder' : '#' },
{ id: 'cases', label: 'Кейсы', href: ft.homeUrl ? ft.homeUrl + '#cases' : '#' },
{ id: 'footer', label: 'Контакты' },
];
const nav = page === 'services' ? navServices
: page === 'promo' ? navPromo
: page === 'percent' ? navPercent
: page === 'subservice' ? navSubservice
: navHome;
const uslugi = ft.urls?.services || '/uslugi/';
const SERVICES = [
['avitolog', 'Услуги авитолога'],
['prodvizhenie-obyavleniy', 'Продвижение объявлений'],
['vedenie-avito', 'Ведение Авито'],
['seo-prodvizhenie', 'SEO продвижение'],
['vedenie-magazinov', 'Ведение магазинов'],
['otzyvy-i-reputaciya', 'Отзывы и репутация'],
['avitolog-za-procent', 'Авитолог за процент'],
['reklama-profilya', 'Реклама профиля'],
['yandex-direct', 'Яндекс.Директ'],
['konsultaciya', 'Консультация'],
];
const handleNav = (e, item) => {
if (item.href) {
// Cross-page navigation: allow native click
return;
}
e.preventDefault();
scrollToId(item.id);
};
return (
<>
>
);
}
/* ---- Sticky side form ---- */
function StickySideForm() {
const [open, setOpen] = useState(false);
const [visible, setVisible] = useState(false);
useEffect(() => {
const onScroll = () => setVisible(window.scrollY > 600);
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
return () => window.removeEventListener('scroll', onScroll);
}, []);
if (!visible) return null;
return (
{!open && (
)}
{open && (
Нужна консультация?
Перезвоним в течение 30 минут и ответим на ваши вопросы
)}
);
}
/* ---- Inline styles for nav/sticky (component-scoped) ---- */
const navStyles = document.createElement('style');
navStyles.textContent = `
.topnav {
position: sticky;
top: 0;
z-index: 50;
background: rgba(250, 249, 249, 0.85);
backdrop-filter: saturate(180%) blur(14px);
-webkit-backdrop-filter: saturate(180%) blur(14px);
border-bottom: 1px solid transparent;
transition: border-color .2s ease, background .2s ease;
}
.topnav.scrolled { border-bottom-color: var(--border); }
.crumbs { background: transparent; padding: 12px 0 0; }
.crumbs__in {
display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
font-size: 13px; line-height: 1.5; color: var(--ink-55, rgba(10,10,10,.55));
}
.crumbs a { color: rgba(10,10,10,.55); text-decoration: none; }
.crumbs a:hover { color: #0A0A0A; text-decoration: underline; }
.crumbs__sep { color: rgba(10,10,10,.3); }
.crumbs__cur { color: rgba(10,10,10,.85); }
@media (max-width: 600px) {
.crumbs__in { font-size: 12px; gap: 6px; flex-wrap: nowrap; }
.crumbs__in > a { white-space: nowrap; }
.crumbs__cur { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
.topnav__inner {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 32px;
align-items: center;
padding-top: 14px;
padding-bottom: 14px;
}
.topnav__brand {
display: flex; align-items: center; gap: 14px;
}
.topnav__brand img { height: 40px; width: auto; }
.topnav__brand-desc {
font-size: 11px;
line-height: 1.25;
color: var(--ink-60);
font-weight: 600;
letter-spacing: 0.01em;
border-left: 1px solid var(--border);
padding-left: 14px;
max-width: 200px;
}
.topnav__nav {
display: flex;
gap: 4px;
justify-content: center;
}
.topnav__nav a {
padding: 10px 14px;
font-size: 15px;
font-weight: 600;
color: var(--ink-80);
border-radius: 999px;
white-space: nowrap;
transition: background .15s ease, color .15s ease;
}
.topnav__nav a:hover { background: var(--ink-08); color: var(--ink); }
.topnav__nav a.active { background: var(--ink); color: #fff; }
.topnav__nav a.active:hover { background: var(--ink); color: #fff; }
.topnav__contact {
display: flex; align-items: center; gap: 18px;
}
.topnav__phone { text-align: right; line-height: 1.15; }
.topnav__phone a { font-size: 17px; font-weight: 800; white-space: nowrap; }
.topnav__phone span { font-size: 11px; color: var(--ink-60); display: block; margin-top: 2px; }
.topnav__burger {
display: none;
background: transparent; border: 1px solid var(--border);
width: 44px; height: 44px;
border-radius: 12px;
align-items: center; justify-content: center;
color: var(--ink);
}
@media (max-width: 1100px) {
.topnav__nav, .topnav__brand-desc { display: none; }
.topnav__inner { grid-template-columns: 1fr auto; }
}
@media (max-width: 720px) {
.topnav {
background: #FAF9F9;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border-bottom: 1px solid var(--border);
}
.topnav__inner { padding-top: 9px; padding-bottom: 9px; grid-template-columns: 1fr auto; }
.topnav__brand img { height: 30px; }
.topnav__contact { display: none; }
.topnav__burger { display: inline-flex; width: 38px; height: 38px; border-radius: 10px; }
}
/* Mobile menu */
.mobile-menu {
position: fixed; inset: 0; z-index: 100;
background: rgba(10,10,10,0.5);
animation: fadeIn .2s ease;
}
.mobile-menu__sheet {
position: absolute; top: 0; right: 0; bottom: 0;
width: min(420px, 100%);
background: #FAF9F9;
box-shadow: -20px 0 60px rgba(10,10,10,0.25);
padding: 22px;
display: flex; flex-direction: column;
gap: 24px;
animation: slideInR .25s ease;
}
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes slideInR { from { transform: translateX(100%) } to { transform: translateX(0) } }
.mobile-menu__head { display: flex; justify-content: space-between; align-items: center; }
.mobile-menu__close { background: transparent; border: 1px solid var(--border); width: 44px; height: 44px; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center; }
.mobile-menu__nav { display: flex; flex-direction: column; }
.mobile-menu__nav a {
display: flex; justify-content: space-between; align-items: center;
padding: 18px 4px;
font-size: 22px; font-weight: 700;
border-bottom: 1px solid var(--border);
}
.mobile-menu__contact { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--border); }
.mobile-menu__cta { width: 100%; margin-top: 16px; }
/* Sticky side form */
.sticky-side {
position: fixed;
right: 24px;
bottom: 24px;
z-index: 40;
animation: slideInUp .3s ease;
}
@keyframes slideInUp { from { transform: translateY(20px); opacity: 0 } to { transform: translateY(0); opacity: 1 } }
.sticky-side__pill {
display: inline-flex; align-items: center; gap: 10px;
background: var(--ink); color: #fff;
padding: 14px 22px;
border-radius: 999px;
border: none;
font-weight: 700;
font-size: 15px;
box-shadow: var(--shadow-lg);
position: relative;
}
.sticky-side__pill:hover { background: var(--brand-red); }
.sticky-side__pulse {
width: 10px; height: 10px;
background: var(--brand-red);
border-radius: 50%;
display: inline-block;
position: relative;
margin-right: 2px;
}
.sticky-side__pulse::after {
content: ''; position: absolute; inset: -3px;
border-radius: 50%;
border: 2px solid var(--brand-red);
animation: pulseRing 1.6s ease-out infinite;
}
@keyframes pulseRing {
0% { transform: scale(0.8); opacity: 0.7 }
100% { transform: scale(2.2); opacity: 0 }
}
.sticky-side__panel {
width: 360px;
background: var(--surface);
border-radius: 22px;
box-shadow: var(--shadow-lg);
padding: 24px;
border: 1px solid var(--border);
position: relative;
}
.sticky-side__close {
position: absolute; top: 12px; right: 12px;
width: 36px; height: 36px;
background: var(--surface-2); border: none;
border-radius: 50%;
display: inline-flex; align-items: center; justify-content: center;
}
.sticky-side__title { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; }
.sticky-side__sub { font-size: 14px; color: var(--ink-60); margin: 6px 0 18px; }
@media (max-width: 600px) {
.sticky-side { right: 12px; bottom: 12px; left: 12px; }
.sticky-side__panel { width: 100%; }
}
/* Lead form layout */
.lead-form__grid {
display: grid;
grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
gap: 12px;
margin-bottom: 14px;
}
.lead-form.small .lead-form__grid { grid-template-columns: 1fr; }
@media (max-width: 900px) {
.lead-form__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
.lead-form__grid { grid-template-columns: 1fr; }
}
.form-submit { width: 100%; }
.form-success {
display: flex; align-items: center; gap: 14px;
padding: 22px;
border-radius: 16px;
background: rgba(255, 47, 0, 0.08);
border: 1px solid rgba(255, 47, 0, 0.16);
}
.form-success.dark { background: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.1); }
.form-success__icon {
width: 44px; height: 44px;
border-radius: 50%;
background: var(--brand-red); color: #fff;
display: inline-flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
`;
document.head.appendChild(navStyles);
Object.assign(window, { TopNav, StickySideForm });