const STORAGE_KEY = "bratskih-hub-preferences"; const defaultPreferences = { theme: window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark", view: "cards", accent: "violet", }; const preferences = { ...defaultPreferences, ...readPreferences(), }; const services = document.querySelector(".services"); const themeButtons = document.querySelectorAll("[data-theme]"); const viewButtons = document.querySelectorAll("[data-view]"); const accentButtons = document.querySelectorAll("[data-accent]"); const cards = document.querySelectorAll(".service-card"); applyPreferences(preferences); themeButtons.forEach((button) => { button.addEventListener("click", () => { preferences.theme = button.dataset.theme; applyPreferences(preferences); savePreferences(preferences); }); }); viewButtons.forEach((button) => { button.addEventListener("click", () => { preferences.view = button.dataset.view; applyPreferences(preferences); savePreferences(preferences); }); }); accentButtons.forEach((button) => { button.addEventListener("click", () => { preferences.accent = button.dataset.accent; applyPreferences(preferences); savePreferences(preferences); }); }); cards.forEach((card) => { let leaveTimer; card.addEventListener("pointerenter", () => { window.clearTimeout(leaveTimer); card.classList.add("is-hovered"); }); card.addEventListener("pointermove", (event) => { window.clearTimeout(leaveTimer); card.classList.add("is-hovered"); const rect = card.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const xPercent = clamp((x / rect.width) * 100, 8, 92); const yPercent = clamp((y / rect.height) * 100, 8, 92); const rotateY = ((xPercent - 50) / 50) * 2.6; const rotateX = ((50 - yPercent) / 50) * 2.6; card.style.setProperty("--card-x", `${xPercent}%`); card.style.setProperty("--card-y", `${yPercent}%`); card.style.setProperty("--tilt-x", `${rotateX}deg`); card.style.setProperty("--tilt-y", `${rotateY}deg`); }); card.addEventListener("pointerleave", () => { leaveTimer = window.setTimeout(() => { card.classList.remove("is-hovered"); card.style.setProperty("--card-x", "50%"); card.style.setProperty("--card-y", "50%"); card.style.setProperty("--tilt-x", "0deg"); card.style.setProperty("--tilt-y", "0deg"); }, 80); }); }); function applyPreferences(nextPreferences) { document.documentElement.dataset.theme = nextPreferences.theme; document.documentElement.dataset.accent = nextPreferences.accent; services.classList.toggle("cards-view", nextPreferences.view === "cards"); services.classList.toggle("list-view", nextPreferences.view === "list"); setActiveButton(themeButtons, "theme", nextPreferences.theme); setActiveButton(viewButtons, "view", nextPreferences.view); setActiveButton(accentButtons, "accent", nextPreferences.accent); } function setActiveButton(buttons, key, value) { buttons.forEach((button) => { const isActive = button.dataset[key] === value; button.classList.toggle("is-active", isActive); button.setAttribute("aria-pressed", String(isActive)); }); } function readPreferences() { try { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || {}; } catch { return {}; } } function savePreferences(nextPreferences) { localStorage.setItem(STORAGE_KEY, JSON.stringify(nextPreferences)); } function clamp(value, min, max) { return Math.min(Math.max(value, min), max); }