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>
131 lines
3.8 KiB
JavaScript
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();
|
|
}
|
|
})();
|