Erfasst den vollständigen Projektstand mit drei Hauptbereichen:
1. Laravel 11 Application-Skelett
- Standard-Setup (app/, bootstrap/, config/, database/, public/, resources/, routes/, storage/, tests/)
- Composer + npm Konfiguration
- Devcontainer für Laravel Sail (PHP/MySQL/Redis)
- GitHub Actions Workflows (lint + tests)
- Tailwind/Vite Build-Pipeline
2. docs/ – Wissensbasis "Marke macht." (Methodik-Verfassung)
Stand nach Pflegerunde 2026-05-28:
- 00_Methodik-Verfassung: Dok. 000 (v2.0.2) bis Dok. 013 (NEU) + Anhänge
- 10_Quellen-Original: Wala, Sharp, Simon (read-only Quellen)
- 20_Markenwissen: 25 abgeleitete MW-Dokumente (Wala_MW-WAL, Sharp_MW-HBG, Simon_MW-SIM)
- 30_Synthese: Markenwissen_I_Synthese_Gesamt + Scorecard-Regeln
- 40_Implementierung: 011b-Erweiterung
- _Steuerung: 00_START_HIER, Serienübersicht, CHANGELOG.md
Letzte methodische Eingriffe:
- Methodik-Update v2.0 (Ownership Autorenschaft/Anwendung, Geltungsbereich Kernthese,
Score-Ebenen DNA-Reifegrad, Preislogik Governance-Scope)
- Dok. 013 NEU: Akquise- & Conversion-Logik (Auffahrten statt Funnel)
- Rebranding brandwork.io → Brand Rules (brand-rules.com)
- Schichtverletzungen behoben, Ordner-Symmetrie hergestellt, Verweise konsolidiert
3. _markemacht.de/ – Web-Frontend Design-Sandbox
- Statische HTML-Entwürfe (Startseite, Methode, Manifest, Denken, Blog)
- Design-System (warm_intellectualism, based_web_design)
- Assets (CSS, JS, Favicon)
Konfiguration:
- .gitignore um .DS_Store und Thumbs.db erweitert
- Lokale Git-Identity gesetzt: Kevin Adametz <kevin.adametz@me.com>
- .env wird ignoriert (nur .env.example versioniert)
Konfliktregel: Bei Spannung zwischen Code und Methodik gilt die Methodik (Dok. 000).
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();
|
|
}
|
|
})();
|