From 098a7ad99adde14cb2c352cf0f2e3b5f6f894118 Mon Sep 17 00:00:00 2001 From: mAi Date: Sun, 26 Apr 2026 01:36:21 +0200 Subject: [PATCH] mAi: #4 - Impressum als Klick-Overlay statt inline (full variant) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - variant=full: kleiner Footer-Trigger ("Impressum"), Klick öffnet Overlay mit § 5 TMG-Block. Schließen via × / ESC / Backdrop-Klick. Fade-in. - variant=minimal: bleibt unveränderter Inline-Einzeiler. - API unverändert: data-owner / data-variant am Script-Tag. - Alles inline (kein neues Stylesheet, keine Abhängigkeiten). --- shared/impressum.js | 192 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 175 insertions(+), 17 deletions(-) diff --git a/shared/impressum.js b/shared/impressum.js index cfbed9d..b9db8d1 100644 --- a/shared/impressum.js +++ b/shared/impressum.js @@ -10,8 +10,8 @@ * data-owner="msbls" (default) — Kurzverweis auf msbls.de * data-owner="flexsiebels" — Kurzverweis auf flexsiebels.de * data-owner="martinsiebels" — volles Impressum Martin Siebels (separate Person, Osnabrück) - * data-variant="minimal" (default) — Einzeiler im Footer - * data-variant="full" — vollständige Angaben nach § 5 TMG + * data-variant="minimal" (default) — Einzeiler im Footer (inline) + * data-variant="full" — kleiner Trigger im Footer, voller § 5 TMG-Block im Overlay * * Legacy-Alias: data-style (gleiche Werte wie data-variant). * @@ -54,24 +54,182 @@ }; const config = owners[owner] || owners.msbls; - const html = config[variant] || config.minimal; - - const el = document.createElement('div'); - el.className = 'onepager-impressum'; - el.innerHTML = html; - - // Dezent, erbt Farben vom Container. - el.style.cssText = 'text-align:center;font-size:0.75rem;opacity:0.6;padding:12px 0;margin-top:4px;line-height:1.7;'; - el.querySelectorAll('a').forEach(a => { - a.style.color = 'inherit'; - a.style.textDecoration = 'underline'; - a.style.textDecorationThickness = '1px'; - a.style.textUnderlineOffset = '2px'; - }); const target = document.getElementById('impressum') || document.querySelector('footer .container') || document.querySelector('footer') || document.body; - target.appendChild(el); + + if (variant === 'full') { + renderOverlay(config.full, target); + } else { + renderInline(config.minimal, target); + } + + function renderInline(html, target) { + const el = document.createElement('div'); + el.className = 'onepager-impressum'; + el.innerHTML = html; + el.style.cssText = 'text-align:center;font-size:0.75rem;opacity:0.6;padding:12px 0;margin-top:4px;line-height:1.7;'; + el.querySelectorAll('a').forEach(a => { + a.style.color = 'inherit'; + a.style.textDecoration = 'underline'; + a.style.textDecorationThickness = '1px'; + a.style.textUnderlineOffset = '2px'; + }); + target.appendChild(el); + } + + function renderOverlay(html, target) { + // Trigger im Footer — klein, dezent, erbt Farben. + const trigger = document.createElement('button'); + trigger.type = 'button'; + trigger.className = 'onepager-impressum-trigger'; + trigger.textContent = 'Impressum'; + trigger.style.cssText = [ + 'display:inline-block', + 'background:none', + 'border:none', + 'padding:12px 8px', + 'margin-top:4px', + 'font:inherit', + 'font-size:0.75rem', + 'color:inherit', + 'opacity:0.6', + 'cursor:pointer', + 'text-decoration:underline', + 'text-decoration-thickness:1px', + 'text-underline-offset:2px', + 'transition:opacity 0.2s ease', + ].join(';'); + trigger.addEventListener('mouseenter', () => { trigger.style.opacity = '1'; }); + trigger.addEventListener('mouseleave', () => { trigger.style.opacity = '0.6'; }); + trigger.addEventListener('focus', () => { trigger.style.opacity = '1'; }); + trigger.addEventListener('blur', () => { trigger.style.opacity = '0.6'; }); + + const wrap = document.createElement('div'); + wrap.className = 'onepager-impressum'; + wrap.style.cssText = 'text-align:center;padding:8px 0;margin-top:4px;'; + wrap.appendChild(trigger); + target.appendChild(wrap); + + let backdrop = null; + let lastFocus = null; + + trigger.addEventListener('click', open); + + function open() { + if (backdrop) return; + lastFocus = document.activeElement; + + backdrop = document.createElement('div'); + backdrop.className = 'onepager-impressum-backdrop'; + backdrop.style.cssText = [ + 'position:fixed', + 'inset:0', + 'background:rgba(0,0,0,0.55)', + 'display:flex', + 'align-items:center', + 'justify-content:center', + 'padding:24px', + 'z-index:99999', + 'opacity:0', + 'transition:opacity 0.18s ease', + ].join(';'); + + const card = document.createElement('div'); + card.className = 'onepager-impressum-card'; + card.setAttribute('role', 'dialog'); + card.setAttribute('aria-modal', 'true'); + card.setAttribute('aria-label', 'Impressum'); + card.style.cssText = [ + 'position:relative', + 'max-width:420px', + 'width:100%', + 'background:#fff', + 'color:#111', + 'padding:32px 28px 28px', + 'border-radius:8px', + 'box-shadow:0 20px 60px rgba(0,0,0,0.35)', + 'font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif', + 'font-size:0.9rem', + 'line-height:1.55', + 'transform:translateY(8px)', + 'transition:transform 0.18s ease', + 'box-sizing:border-box', + ].join(';'); + + const close = document.createElement('button'); + close.type = 'button'; + close.setAttribute('aria-label', 'Schließen'); + close.innerHTML = '×'; + close.style.cssText = [ + 'position:absolute', + 'top:6px', + 'right:10px', + 'background:none', + 'border:none', + 'font-size:1.6rem', + 'line-height:1', + 'color:#666', + 'cursor:pointer', + 'padding:6px 10px', + 'border-radius:4px', + 'transition:color 0.15s ease', + ].join(';'); + close.addEventListener('mouseenter', () => { close.style.color = '#000'; }); + close.addEventListener('mouseleave', () => { close.style.color = '#666'; }); + close.addEventListener('click', dismiss); + + const content = document.createElement('div'); + content.innerHTML = html; + content.style.cssText = 'margin-top:4px;'; + content.querySelectorAll('a').forEach(a => { + a.style.color = '#0057b8'; + a.style.textDecoration = 'underline'; + }); + content.querySelectorAll('strong').forEach(s => { + s.style.display = 'block'; + s.style.marginBottom = '8px'; + }); + + card.appendChild(close); + card.appendChild(content); + backdrop.appendChild(card); + document.body.appendChild(backdrop); + + // Trigger fade-in nach dem Mounten. + requestAnimationFrame(() => { + backdrop.style.opacity = '1'; + card.style.transform = 'translateY(0)'; + }); + + backdrop.addEventListener('click', (e) => { + if (e.target === backdrop) dismiss(); + }); + document.addEventListener('keydown', onKey); + close.focus(); + } + + function dismiss() { + if (!backdrop) return; + document.removeEventListener('keydown', onKey); + const node = backdrop; + backdrop = null; + node.style.opacity = '0'; + setTimeout(() => { + if (node.parentNode) node.parentNode.removeChild(node); + if (lastFocus && typeof lastFocus.focus === 'function') { + lastFocus.focus(); + } + }, 180); + } + + function onKey(e) { + if (e.key === 'Escape') { + e.preventDefault(); + dismiss(); + } + } + } })();