2026-11-02 15:56:33 +03:00
|
|
|
// Analytics load only after consent: Metrika, GTM and direct GA4.
|
|
|
|
|
// GA4 is configured here; do not configure the same GA4 tag/events again in GTM.
|
2026-10-30 21:59:08 +03:00
|
|
|
(function() {
|
2026-10-31 00:11:26 +03:00
|
|
|
const key = 'olyapka_analytics_v2';
|
2026-10-30 21:59:08 +03:00
|
|
|
const banner = document.getElementById('cookieBanner');
|
2026-10-31 00:11:26 +03:00
|
|
|
let choice = null;
|
|
|
|
|
try { choice = localStorage.getItem(key); } catch (err) { /* storage may be blocked */ }
|
|
|
|
|
window.analyticsAllowed = choice === 'accepted';
|
|
|
|
|
function loadAnalytics() {
|
|
|
|
|
if (!window.analyticsAllowed || window.analyticsLoaded) return;
|
|
|
|
|
window.analyticsLoaded = true;
|
|
|
|
|
window.ym = window.ym || function() { (window.ym.a = window.ym.a || []).push(arguments); };
|
|
|
|
|
window.ym.l = Date.now();
|
|
|
|
|
const metrika = document.createElement('script');
|
|
|
|
|
metrika.async = true; metrika.src = 'https://mc.yandex.ru/metrika/tag.js';
|
|
|
|
|
document.head.append(metrika);
|
|
|
|
|
window.ym(110606131, 'init', {clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true});
|
|
|
|
|
window.dataLayer = window.dataLayer || [];
|
2026-11-02 15:56:33 +03:00
|
|
|
window.gtag = window.gtag || function() { window.dataLayer.push(arguments); };
|
|
|
|
|
window.gtag('js', new Date());
|
|
|
|
|
window.gtag('config', 'G-T6084CKB81');
|
|
|
|
|
const ga = document.createElement('script');
|
|
|
|
|
ga.async = true; ga.src = 'https://www.googletagmanager.com/gtag/js?id=G-T6084CKB81';
|
|
|
|
|
document.head.append(ga);
|
2026-10-31 00:11:26 +03:00
|
|
|
window.dataLayer.push({'gtm.start': Date.now(), event: 'gtm.js'});
|
|
|
|
|
const gtm = document.createElement('script');
|
|
|
|
|
gtm.async = true; gtm.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-M5HGH586';
|
|
|
|
|
document.head.append(gtm);
|
2026-10-30 21:59:08 +03:00
|
|
|
}
|
2026-10-31 00:11:26 +03:00
|
|
|
function choose(value) {
|
|
|
|
|
const wasAllowed = window.analyticsAllowed;
|
|
|
|
|
try { localStorage.setItem(key, value); } catch (err) { /* session-only choice */ }
|
|
|
|
|
window.analyticsAllowed = value === 'accepted';
|
|
|
|
|
banner.hidden = true;
|
2026-10-30 21:59:08 +03:00
|
|
|
banner.classList.remove('show');
|
2026-10-31 00:11:26 +03:00
|
|
|
if (wasAllowed && !window.analyticsAllowed) { location.reload(); return; }
|
|
|
|
|
loadAnalytics();
|
|
|
|
|
}
|
|
|
|
|
if (banner) {
|
|
|
|
|
if (!choice) { banner.hidden = false; banner.classList.add('show'); }
|
|
|
|
|
document.getElementById('cookieAccept').addEventListener('click', () => choose('accepted'));
|
|
|
|
|
document.getElementById('cookieDecline').addEventListener('click', () => choose('declined'));
|
|
|
|
|
document.getElementById('cookieSettings').addEventListener('click', () => {
|
|
|
|
|
banner.hidden = false; banner.classList.add('show');
|
|
|
|
|
document.getElementById('cookieAccept').focus();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
loadAnalytics();
|
2026-10-30 21:59:08 +03:00
|
|
|
})();
|
|
|
|
|
|
2026-10-31 00:11:26 +03:00
|
|
|
// Accessible mobile navigation, including Escape and focus return.
|
2026-10-30 21:59:08 +03:00
|
|
|
(function() {
|
|
|
|
|
const burger = document.getElementById('burger');
|
|
|
|
|
const nav = document.getElementById('nav');
|
|
|
|
|
if (!burger || !nav) return;
|
2026-10-31 00:11:26 +03:00
|
|
|
document.documentElement.classList.add('js-menu');
|
|
|
|
|
function setOpen(open) {
|
|
|
|
|
burger.classList.toggle('open', open);
|
|
|
|
|
nav.classList.toggle('open', open);
|
|
|
|
|
burger.setAttribute('aria-expanded', String(open));
|
|
|
|
|
burger.setAttribute('aria-label', open ? 'Закрыть меню' : 'Открыть меню');
|
|
|
|
|
}
|
|
|
|
|
burger.addEventListener('click', () => setOpen(burger.getAttribute('aria-expanded') !== 'true'));
|
|
|
|
|
nav.addEventListener('click', e => { if (e.target.closest('a')) setOpen(false); });
|
|
|
|
|
document.addEventListener('keydown', e => {
|
|
|
|
|
if (e.key === 'Escape' && nav.classList.contains('open')) { setOpen(false); burger.focus(); }
|
2026-10-30 21:59:08 +03:00
|
|
|
});
|
2026-10-31 00:11:26 +03:00
|
|
|
document.addEventListener('click', e => { if (!nav.contains(e.target) && !burger.contains(e.target)) setOpen(false); });
|
|
|
|
|
matchMedia('(max-width: 768px)').addEventListener('change', () => setOpen(false));
|
2026-10-30 21:59:08 +03:00
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
// ===== Goal Tracking (Yandex.Metrika + GA) =====
|
|
|
|
|
(function() {
|
|
|
|
|
document.addEventListener('click', function(e) {
|
|
|
|
|
const target = e.target.closest('[data-goal]');
|
|
|
|
|
if (!target) return;
|
|
|
|
|
const goal = target.getAttribute('data-goal');
|
|
|
|
|
if (!goal) return;
|
|
|
|
|
|
|
|
|
|
// Yandex.Metrika
|
2026-10-31 00:11:26 +03:00
|
|
|
if (window.analyticsAllowed && typeof ym !== 'undefined') {
|
2026-10-30 21:59:08 +03:00
|
|
|
try { ym(110606131, 'reachGoal', goal); } catch(err) {}
|
|
|
|
|
}
|
2026-11-02 15:56:33 +03:00
|
|
|
// Send existing button goals directly to GA4.
|
|
|
|
|
if (window.analyticsAllowed && typeof window.gtag === 'function') {
|
|
|
|
|
window.gtag('event', goal, {send_to: 'G-T6084CKB81'});
|
|
|
|
|
}
|
|
|
|
|
// Keep custom events available to the existing GTM container.
|
2026-10-31 00:11:26 +03:00
|
|
|
if (window.analyticsAllowed && window.dataLayer) window.dataLayer.push({event: goal});
|
2026-10-30 21:59:08 +03:00
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
|
2026-10-31 00:11:26 +03:00
|
|
|
// Native anchor navigation preserves URL fragments and keyboard focus.
|
2026-10-30 22:31:58 +03:00
|
|
|
|
|
|
|
|
// ===== Portfolio Video Lightbox =====
|
|
|
|
|
(function() {
|
|
|
|
|
const modal = document.getElementById('videoModal');
|
|
|
|
|
const player = document.getElementById('videoModalPlayer');
|
|
|
|
|
const title = document.getElementById('videoModalTitle');
|
|
|
|
|
const fsBtn = document.getElementById('videoModalFullscreen');
|
|
|
|
|
const triggers = document.querySelectorAll('.work-video[data-video]');
|
|
|
|
|
if (!modal || !player || !triggers.length) return;
|
|
|
|
|
|
|
|
|
|
let lastFocus = null;
|
2026-10-31 00:11:26 +03:00
|
|
|
const background = Array.from(document.body.children).filter(el => el !== modal && el.tagName !== 'SCRIPT');
|
|
|
|
|
let inertStates = [];
|
|
|
|
|
modal.setAttribute('inert', '');
|
2026-10-30 22:31:58 +03:00
|
|
|
|
|
|
|
|
function open(src, label) {
|
|
|
|
|
lastFocus = document.activeElement;
|
2026-10-31 00:11:26 +03:00
|
|
|
modal.removeAttribute('inert');
|
|
|
|
|
inertStates = background.map(el => el.inert);
|
|
|
|
|
background.forEach(el => { el.inert = true; });
|
2026-10-30 22:31:58 +03:00
|
|
|
title.textContent = label || '';
|
|
|
|
|
player.src = src;
|
|
|
|
|
modal.classList.add('open');
|
|
|
|
|
modal.setAttribute('aria-hidden', 'false');
|
|
|
|
|
document.body.classList.add('video-modal-open');
|
|
|
|
|
const p = player.play();
|
|
|
|
|
if (p && typeof p.catch === 'function') p.catch(() => {});
|
|
|
|
|
player.focus({ preventScroll: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function close() {
|
|
|
|
|
if (document.fullscreenElement) {
|
|
|
|
|
document.exitFullscreen().catch(() => {});
|
|
|
|
|
}
|
|
|
|
|
player.pause();
|
|
|
|
|
modal.classList.remove('open');
|
|
|
|
|
modal.setAttribute('aria-hidden', 'true');
|
2026-10-31 00:11:26 +03:00
|
|
|
modal.setAttribute('inert', '');
|
|
|
|
|
background.forEach((el, i) => { el.inert = inertStates[i]; });
|
2026-10-30 22:31:58 +03:00
|
|
|
document.body.classList.remove('video-modal-open');
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
if (!modal.classList.contains('open')) {
|
|
|
|
|
player.removeAttribute('src');
|
|
|
|
|
player.load();
|
|
|
|
|
}
|
|
|
|
|
}, 300);
|
|
|
|
|
if (lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus({ preventScroll: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleFullscreen() {
|
|
|
|
|
if (document.fullscreenElement) {
|
|
|
|
|
document.exitFullscreen().catch(() => {});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (player.requestFullscreen) {
|
|
|
|
|
player.requestFullscreen().catch(() => {});
|
|
|
|
|
} else if (player.webkitEnterFullscreen) {
|
|
|
|
|
player.webkitEnterFullscreen(); // iOS Safari
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
triggers.forEach(btn => {
|
|
|
|
|
btn.addEventListener('click', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
open(btn.getAttribute('data-video'), btn.getAttribute('data-title'));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
modal.querySelectorAll('[data-video-close]').forEach(el => {
|
|
|
|
|
el.addEventListener('click', close);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Клик по тёмной области вокруг плеера тоже закрывает окно
|
|
|
|
|
modal.querySelectorAll('.video-modal-dialog, .video-modal-stage, .video-modal-bar').forEach(el => {
|
|
|
|
|
el.addEventListener('click', function(e) {
|
|
|
|
|
if (e.target === el) close();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (fsBtn) fsBtn.addEventListener('click', toggleFullscreen);
|
|
|
|
|
|
|
|
|
|
player.addEventListener('dblclick', toggleFullscreen);
|
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
|
|
|
if (!modal.classList.contains('open')) return;
|
|
|
|
|
if (e.key === 'Escape') { close(); return; }
|
2026-10-31 00:11:26 +03:00
|
|
|
if (e.key === 'Tab') {
|
|
|
|
|
const stops = Array.from(modal.querySelectorAll('button, video[controls]'));
|
|
|
|
|
const first = stops[0], last = stops[stops.length - 1];
|
|
|
|
|
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
|
|
|
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
|
|
|
}
|
2026-10-30 22:31:58 +03:00
|
|
|
if (e.key === ' ' && document.activeElement === player) return; // native handling
|
2026-10-31 00:11:26 +03:00
|
|
|
if ((e.key === 'f' || e.key === 'F') && document.activeElement === player) toggleFullscreen();
|
2026-10-30 22:31:58 +03:00
|
|
|
});
|
|
|
|
|
})();
|