markemacht/_markemacht.de/assets/js/app.js
Kevin Adametz 00796a35d5
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
Markenwissen-Wissensbasis: Konsistenz-Korrekturen + Copyright-Hygiene
Konsolidierter, bereinigter Stand der Wissensbasis (docs/). Frischer
Wurzel-Commit, um urheberrechtlich problematische Volltexte aus der
Historie zu entfernen (die bisherige Historie bestand aus einem einzigen
Initial-Commit).

Enthaltene Änderungen (vgl. docs/_Steuerung/CHANGELOG.md, 2026-05-29):
- Copyright-Hygiene: 25 Volltext-/Übersetzungsdateien (Sharp 14 Kap.,
  Wala 11 Kap.) entfernt; je Quelle _Fundstellen-Index.md als
  Provenienzbeleg; Quellnachweise + Steuerungsdateien angepasst.
- Konsistenz-Korrekturen: Reichweite 000-013 (Scorecard-Regeln),
  Rule-ID MW-WK-DIFF-101, Quellnachweis-Dateiverweis, Dok.000 v2.0.2.
- Dateinamen-Normalisierung: Startdatei ohne Leerzeichen.

Originale (Wala/Sharp E-Books) privat außerhalb des Repos archiviert.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 08:23:03 +00:00

131 lines
3.8 KiB
JavaScript

/* markemacht.de — Interaktionen
* - Wirkung-Switch (monolithisch | editorial) + localStorage
* - Mobile Drawer
* - Scroll-Reveal (IntersectionObserver, max 400ms, ease-out)
* - Keyboard: ESC schließt Drawer
*/
(function () {
'use strict';
/* ---------- Wirkung ---------------------------------------------------- */
const STORAGE_KEY = 'mm-wirkung';
const VALID = ['monolith', 'editorial'];
const DEFAULT = 'monolith';
function getStored() {
try {
const v = localStorage.getItem(STORAGE_KEY);
return VALID.includes(v) ? v : null;
} catch (_) { return null; }
}
function applyMode(mode) {
if (!VALID.includes(mode)) mode = DEFAULT;
document.documentElement.setAttribute('data-theme', mode);
try { localStorage.setItem(STORAGE_KEY, mode); } catch (_) {}
syncButtons(mode);
}
function syncButtons(mode) {
document.querySelectorAll('[data-wirkung]').forEach((btn) => {
const pressed = btn.getAttribute('data-wirkung') === mode;
btn.setAttribute('aria-pressed', pressed ? 'true' : 'false');
});
}
function initWirkung() {
const initial = getStored() || DEFAULT;
applyMode(initial);
document.querySelectorAll('[data-wirkung]').forEach((btn) => {
btn.addEventListener('click', () => {
const mode = btn.getAttribute('data-wirkung');
applyMode(mode);
});
});
}
/* ---------- Mobile Drawer --------------------------------------------- */
function initDrawer() {
const drawer = document.querySelector('[data-mobile-drawer]');
if (!drawer) return;
const openBtns = document.querySelectorAll('[data-drawer-open]');
const closeBtns = document.querySelectorAll('[data-drawer-close]');
function open() {
drawer.classList.add('is-open');
document.body.classList.add('drawer-open');
drawer.setAttribute('aria-hidden', 'false');
const firstLink = drawer.querySelector('a, button');
if (firstLink) firstLink.focus();
}
function close() {
drawer.classList.remove('is-open');
document.body.classList.remove('drawer-open');
drawer.setAttribute('aria-hidden', 'true');
}
openBtns.forEach((b) => b.addEventListener('click', open));
closeBtns.forEach((b) => b.addEventListener('click', close));
drawer.querySelectorAll('a[href]').forEach((a) => {
a.addEventListener('click', close);
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && drawer.classList.contains('is-open')) {
close();
}
});
}
/* ---------- Scroll Reveal --------------------------------------------- */
function initReveal() {
const items = document.querySelectorAll('[data-reveal]');
if (!items.length) return;
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReduced || !('IntersectionObserver' in window)) {
items.forEach((el) => el.classList.add('is-revealed'));
return;
}
const io = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const el = entry.target;
const delay = parseInt(el.getAttribute('data-reveal-delay') || '0', 10);
if (delay > 0) {
setTimeout(() => el.classList.add('is-revealed'), delay);
} else {
el.classList.add('is-revealed');
}
io.unobserve(el);
}
});
}, {
threshold: 0.08,
rootMargin: '0px 0px -5% 0px'
});
items.forEach((el) => io.observe(el));
}
/* ---------- Boot ------------------------------------------------------- */
function boot() {
initWirkung();
initDrawer();
initReveal();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}
})();