Update from Git Manager GUI

This commit is contained in:
2026-03-29 22:27:20 +02:00
parent 7684cae147
commit 2882231550
6 changed files with 326 additions and 86 deletions

View File

@@ -0,0 +1 @@

View File

@@ -1,4 +1,4 @@
// header-scroll.js ergänzt um Header-Suche Toggle // header-scroll.js kompakter Header beim Scrollen + Suche Toggle
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
// ── Customizer Guard ────────────────────────────────────────────────── // ── Customizer Guard ──────────────────────────────────────────────────
@@ -9,12 +9,79 @@ document.addEventListener('DOMContentLoaded', function () {
return; return;
} }
// ── Scroll-Effekt ───────────────────────────────────────────────────── // ── Scroll-Effekt + kompakter Header ─────────────────────────────────
const header = document.querySelector('.site-header'); const header = document.querySelector('.site-header');
const brandingRow = header ? header.querySelector('.header-row-branding') : null;
if (header) { if (header) {
window.addEventListener('scroll', function () { let lastScrollY = Math.max(window.scrollY, 0);
header.classList.toggle('scrolled', window.scrollY > 50); let directionAnchorY = lastScrollY;
}, { passive: true }); let isCompact = header.classList.contains('header-compact');
let lastStateChangeAt = 0;
let ticking = false;
const compactEnterThreshold = 110;
const compactExitThreshold = 24;
const directionThreshold = 10;
const expandDelta = 120;
const stateChangeCooldown = 260;
const setCompactState = function (nextCompact, now) {
if (isCompact === nextCompact) {
return;
}
isCompact = nextCompact;
lastStateChangeAt = now;
directionAnchorY = Math.max(window.scrollY, 0);
header.classList.toggle('header-compact', nextCompact);
if (brandingRow) {
brandingRow.classList.toggle('branding-hidden', nextCompact);
}
};
const updateHeaderState = function () {
ticking = false;
const now = window.performance && typeof window.performance.now === 'function'
? window.performance.now()
: Date.now();
const currentScrollY = Math.max(window.scrollY, 0);
const delta = currentScrollY - lastScrollY;
const canChangeState = now - lastStateChangeAt >= stateChangeCooldown;
header.classList.toggle('scrolled', currentScrollY > 50);
if (currentScrollY <= compactExitThreshold) {
setCompactState(false, now);
} else if (canChangeState && delta > directionThreshold) {
directionAnchorY = currentScrollY;
if (currentScrollY > compactEnterThreshold) {
setCompactState(true, now);
}
} else if (canChangeState && delta < -directionThreshold) {
if (directionAnchorY - currentScrollY >= expandDelta) {
setCompactState(false, now);
}
}
lastScrollY = currentScrollY;
};
const onScroll = function () {
if (ticking) {
return;
}
ticking = true;
window.requestAnimationFrame(updateHeaderState);
};
updateHeaderState();
window.addEventListener('scroll', onScroll, { passive: true });
} }
// ── Suche Toggle ────────────────────────────────────────────────────── // ── Suche Toggle ──────────────────────────────────────────────────────

View File

@@ -0,0 +1,63 @@
// Lädt skinview3d von CDN
(function(){
if(document.getElementById('skinview3d-cdn')) return;
var s = document.createElement('script');
s.id = 'skinview3d-cdn';
s.src = 'https://unpkg.com/skinview3d@4.1.1/bundles/skinview3d.min.js';
s.onload = function() {
window.skinview3dReady = true;
};
document.head.appendChild(s);
})();
window.showMinecraftSkinModal = function(uuid) {
if(document.getElementById('minecraft-skin-modal')) return;
var modal = document.createElement('div');
modal.id = 'minecraft-skin-modal';
modal.innerHTML = `
<div class="sv3d-modal-bg"></div>
<div class="sv3d-modal-content">
<button class="sv3d-modal-close" aria-label="Schließen">&times;</button>
<div id="sv3d-canvas-wrap" style="width:320px;height:320px;"></div>
</div>
`;
document.body.appendChild(modal);
document.querySelector('.sv3d-modal-close').onclick = function(){ modal.remove(); };
document.querySelector('.sv3d-modal-bg').onclick = function(){ modal.remove(); };
function renderSkin() {
var skinUrl = `https://crafatar.com/skins/${uuid}`;
var canvas = document.createElement('canvas');
canvas.width = 320; canvas.height = 320;
document.getElementById('sv3d-canvas-wrap').appendChild(canvas);
var viewer = new skinview3d.SkinViewer({
canvas: canvas,
width: 320,
height: 320,
skin: skinUrl
});
viewer.controls.enableZoom = false;
viewer.animation = new skinview3d.WalkingAnimation();
viewer.animation.speed = 1.2;
viewer.animation.play();
}
if(window.skinview3dReady) renderSkin();
else {
var check = setInterval(function(){
if(window.skinview3dReady) { clearInterval(check); renderSkin(); }
}, 100);
}
};
// Avatar-Widget-Click-Handler
window.addEventListener('DOMContentLoaded', function(){
var widget = document.getElementById('minecraft-avatar-widget');
if(widget) {
widget.style.cursor = 'pointer';
widget.title = 'Klicke für 3D Skin-Ansicht';
widget.onclick = function(){
var uuid = widget.getAttribute('data-uuid');
if(uuid) window.showMinecraftSkinModal(uuid);
};
}
});

View File

@@ -1,61 +1,174 @@
( function() { ( function () {
// FIX: Null-Check Script bricht auf Login-Seite & Seiten ohne Nav nicht mehr ab 'use strict';
const siteNavigation = document.getElementById( 'site-navigation' );
if ( ! siteNavigation ) { var isSidebarLayout = document.querySelector( '.site-header--sidebar' ) !== null;
return;
if ( isSidebarLayout ) {
// --- Panel öffnen / schließen ---
var panel = document.getElementById( 'header-sidebar' );
var overlay = document.getElementById( 'sidebar-overlay' );
var openBtn = document.querySelector( '.sidebar-menu-toggle' );
var closeBtn = document.querySelector( '.sidebar-menu-close' );
function openPanel() {
if ( ! panel ) return;
panel.classList.add( 'is-open' );
panel.setAttribute( 'aria-hidden', 'false' );
if ( openBtn ) openBtn.setAttribute( 'aria-expanded', 'true' );
if ( overlay ) overlay.classList.add( 'is-visible' );
document.body.classList.add( 'sidebar-nav-open' );
} }
const menuToggle = siteNavigation.querySelector( '.menu-toggle' ); function closePanel() {
if ( ! menuToggle ) { if ( ! panel ) return;
return; panel.classList.remove( 'is-open' );
panel.setAttribute( 'aria-hidden', 'true' );
if ( openBtn ) openBtn.setAttribute( 'aria-expanded', 'false' );
if ( overlay ) overlay.classList.remove( 'is-visible' );
document.body.classList.remove( 'sidebar-nav-open' );
} }
// Toggle Klassen hinzufügen (Menü öffnen/schließen) if ( openBtn ) openBtn.addEventListener( 'click', openPanel );
menuToggle.addEventListener( 'click', function() { if ( closeBtn ) closeBtn.addEventListener( 'click', closePanel );
siteNavigation.classList.toggle( 'toggled' ); if ( overlay ) overlay.addEventListener( 'click', closePanel );
document.addEventListener( 'keydown', function ( e ) {
if ( menuToggle.getAttribute( 'aria-expanded' ) === 'true' ) { if ( e.key === 'Escape' ) closePanel();
menuToggle.setAttribute( 'aria-expanded', 'false' );
menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
} else {
menuToggle.setAttribute( 'aria-expanded', 'true' );
menuToggle.innerHTML = '<i class="fas fa-times"></i>';
}
} ); } );
// FIX: Menü bei Klick außerhalb schließen // --- Submenu Flyout ---
document.addEventListener( 'click', function( e ) { var sidebarNav = document.getElementById( 'site-navigation' );
if ( sidebarNav ) {
sidebarNav.querySelectorAll( '.menu-item-has-children' ).forEach( function ( item ) {
var subMenu = item.querySelector( ':scope > .sub-menu' );
if ( ! subMenu ) return;
var isOpen = false;
var moveHdlr = null;
function showFlyout() {
if ( isOpen ) return;
isOpen = true;
subMenu.style.top = item.getBoundingClientRect().top + 'px';
item.classList.add( 'flyout-open' );
// Erkennungszone berechnen:
// - vertikal: Höhe des li-Elements
// - horizontal: von linkem Rand der Sidebar (0) bis
// rechtem Rand des Flyout-Panels
// → voller horizontaler Streifen für diesen Menüpunkt
moveHdlr = function ( e ) {
var ir = item.getBoundingClientRect();
var sr = subMenu.getBoundingClientRect();
var zoneLeft = 0; // Bildschirmrand links
var zoneRight = Math.max( ir.right, sr.right ); // bis Ende Flyout
var zoneTop = ir.top; // oberer Rand des li
var zoneBottom = ir.bottom; // unterer Rand des li
var inZone = e.clientX >= zoneLeft &&
e.clientX <= zoneRight &&
e.clientY >= zoneTop &&
e.clientY <= zoneBottom;
if ( ! inZone ) hideFlyout();
};
document.addEventListener( 'mousemove', moveHdlr );
}
function hideFlyout() {
if ( ! isOpen ) return;
isOpen = false;
item.classList.remove( 'flyout-open' );
if ( moveHdlr ) {
document.removeEventListener( 'mousemove', moveHdlr );
moveHdlr = null;
}
}
item.addEventListener( 'mouseenter', showFlyout );
// Klick-Toggle für Touch / Tastatur
var btn = document.createElement( 'button' );
btn.className = 'submenu-toggle';
btn.setAttribute( 'aria-expanded', 'false' );
btn.innerHTML = '<i class="fas fa-chevron-down"></i>';
var link = item.querySelector( ':scope > a' );
if ( link ) link.insertAdjacentElement( 'afterend', btn );
btn.addEventListener( 'click', function ( e ) {
e.stopPropagation();
var open = item.classList.toggle( 'active' );
btn.setAttribute( 'aria-expanded', open ? 'true' : 'false' );
if ( open ) {
subMenu.style.top = item.getBoundingClientRect().top + 'px';
item.classList.add( 'flyout-open' );
isOpen = true;
} else {
hideFlyout();
}
} );
} );
}
return;
}
// =========================================================================
// CLASSIC / CENTERED / MEGA
// =========================================================================
var siteNavigation = document.getElementById( 'site-navigation' );
if ( ! siteNavigation ) return;
var menuToggle = siteNavigation.querySelector( '.menu-toggle' );
var subMenuParents = siteNavigation.querySelectorAll( '.menu-item-has-children' );
if ( menuToggle ) {
menuToggle.addEventListener( 'click', function () {
var expanded = siteNavigation.classList.toggle( 'toggled' );
this.setAttribute( 'aria-expanded', String( expanded ) );
this.innerHTML = expanded ? '<i class="fas fa-times"></i>' : '<i class="fas fa-bars"></i>';
} );
document.addEventListener( 'click', function ( e ) {
if ( siteNavigation.classList.contains( 'toggled' ) && ! siteNavigation.contains( e.target ) ) { if ( siteNavigation.classList.contains( 'toggled' ) && ! siteNavigation.contains( e.target ) ) {
siteNavigation.classList.remove( 'toggled' ); siteNavigation.classList.remove( 'toggled' );
menuToggle.setAttribute( 'aria-expanded', 'false' ); menuToggle.setAttribute( 'aria-expanded', 'false' );
menuToggle.innerHTML = '<i class="fas fa-bars"></i>'; menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
} }
} ); } );
window.addEventListener( 'resize', function () {
// Mobile Submenu Toggle if ( window.innerWidth > 992 ) {
const subMenuParents = siteNavigation.querySelectorAll( '.menu-item-has-children' ); siteNavigation.classList.remove( 'toggled' );
menuToggle.setAttribute( 'aria-expanded', 'false' );
subMenuParents.forEach( function( subMenuParent ) { menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
// FIX: Eigenen Toggle-Button erzeugen statt gesamtes <li> klickbar zu machen subMenuParents.forEach( function ( i ) { i.classList.remove( 'active' ); } );
const toggleBtn = document.createElement( 'button' );
toggleBtn.classList.add( 'submenu-toggle' );
toggleBtn.setAttribute( 'aria-expanded', 'false' );
toggleBtn.innerHTML = '<i class="fas fa-chevron-down"></i>';
const parentLink = subMenuParent.querySelector( 'a' );
if ( parentLink ) {
parentLink.insertAdjacentElement( 'afterend', toggleBtn );
}
toggleBtn.addEventListener( 'click', function( e ) {
e.stopPropagation();
if ( window.innerWidth <= 992 ) {
const isOpen = subMenuParent.classList.toggle( 'active' );
toggleBtn.setAttribute( 'aria-expanded', isOpen ? 'true' : 'false' );
// Icon drehen
toggleBtn.querySelector('i').style.transform = isOpen ? 'rotate(180deg)' : 'rotate(0deg)';
} }
} ); } );
}
subMenuParents.forEach( function ( item ) {
var btn = document.createElement( 'button' );
btn.className = 'submenu-toggle';
btn.setAttribute( 'aria-expanded', 'false' );
btn.innerHTML = '<i class="fas fa-chevron-down"></i>';
var link = item.querySelector( ':scope > a' );
if ( link ) link.insertAdjacentElement( 'afterend', btn );
btn.addEventListener( 'click', function ( e ) {
e.stopPropagation();
var open = item.classList.toggle( 'active' );
btn.setAttribute( 'aria-expanded', open ? 'true' : 'false' );
} );
} );
document.addEventListener( 'click', function ( e ) {
if ( ! e.target.closest( '.menu-item-has-children' ) ) {
subMenuParents.forEach( function ( item ) {
item.classList.remove( 'active' );
var b = item.querySelector( '.submenu-toggle' );
if ( b ) b.setAttribute( 'aria-expanded', 'false' );
} );
}
} ); } );
} )(); } )();

View File

@@ -1,24 +1,25 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Hole den Slider-Container
const heroSlider = document.querySelector('.hero-slider');
// Stelle sicher, dass der Slider auf der Seite existiert const heroSlider = document.querySelector('.hero-slider');
if (!heroSlider) { if (!heroSlider) return;
// BUG-FIX: sliderSettings wird via wp_localize_script gesetzt. Fehlt es
// (z.B. wegen Caching oder falschem Enqueue), würde ein ReferenceError
// den gesamten Slider-Init abschießen.
if (typeof sliderSettings === 'undefined') {
console.warn('Minecraft Modern Theme: sliderSettings nicht gefunden. Slider wird nicht initialisiert.');
heroSlider.classList.add('swiper-initialized'); // Opacity-Fix trotzdem aufheben
return; return;
} }
// Konfiguration für den Slider vorbereiten
const swiperConfig = { const swiperConfig = {
// Der Effekt ist jetzt fest auf "Überblenden" eingestellt
effect: 'fade', effect: 'fade',
fadeEffect: { fadeEffect: {
crossFade: true crossFade: true
}, },
// Loop-Einstellung ist jetzt DYNAMISCH
loop: sliderSettings.loop === '1', loop: sliderSettings.loop === '1',
// Autoplay
autoplay: { autoplay: {
delay: 5000, delay: 5000,
disableOnInteraction: false, disableOnInteraction: false,
@@ -26,13 +27,11 @@ document.addEventListener('DOMContentLoaded', function() {
pauseOnMouseEnter: true, pauseOnMouseEnter: true,
// Prüfe, ob die Pfeile NICHT ausgeblendet werden sollen
navigation: sliderSettings.hideArrows !== '1' ? { navigation: sliderSettings.hideArrows !== '1' ? {
nextEl: '.swiper-button-next', nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev', prevEl: '.swiper-button-prev',
} : false, } : false,
// Prüfe, ob die Paginierung NICHT ausgeblendet werden soll
pagination: sliderSettings.hidePagination !== '1' ? { pagination: sliderSettings.hidePagination !== '1' ? {
el: '.swiper-pagination', el: '.swiper-pagination',
clickable: true, clickable: true,
@@ -40,13 +39,12 @@ document.addEventListener('DOMContentLoaded', function() {
on: { on: {
init: function () { init: function () {
setTimeout(() => { setTimeout(function() {
heroSlider.classList.add('swiper-initialized'); heroSlider.classList.add('swiper-initialized');
}, 50); }, 50);
}, },
}, },
}; };
// Initialisiere den Slider mit der konfigurierten Optionen
new Swiper('.hero-slider', swiperConfig); new Swiper('.hero-slider', swiperConfig);
}); });

View File

@@ -1,25 +1,21 @@
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
// FIX: Null-Check Login-Seite hat keinen Toggle-Button
const toggle = document.querySelector('.theme-toggle'); const toggle = document.querySelector('.theme-toggle');
if ( ! toggle ) { if ( ! toggle ) return;
return;
}
const html = document.documentElement; const html = document.documentElement;
const iconMoon = toggle.querySelector('.icon-moon'); const iconMoon = toggle.querySelector('.icon-moon');
const iconSun = toggle.querySelector('.icon-sun'); const iconSun = toggle.querySelector('.icon-sun');
const defaultMode = typeof sliderSettings !== 'undefined' ? sliderSettings.defaultMode : 'dark'; const defaultMode = typeof sliderSettings !== 'undefined' && sliderSettings.defaultMode
? sliderSettings.defaultMode
: 'dark';
// FIX: Systemschema respektieren wenn kein gespeicherter Wert vorhanden // Gespeicherten Wert laden oder OS-Schema/Theme-Default als Fallback
let saved = localStorage.getItem('themeMode'); let saved = localStorage.getItem('themeMode');
if ( ! saved ) { if ( ! saved ) {
// Prüfe OS-Einstellung, falle sonst auf Theme-Default zurück saved = ( window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches )
if ( window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches ) { ? 'light'
saved = 'light'; : defaultMode;
} else {
saved = defaultMode;
}
} }
function applyMode( mode ) { function applyMode( mode ) {
@@ -36,17 +32,19 @@ document.addEventListener('DOMContentLoaded', function () {
applyMode( saved ); applyMode( saved );
// BUG-FIX: Vorher wurde html.classList.toggle() aufgerufen und danach
// applyMode() das hat die Klasse doppelt manipuliert. Jetzt lesen wir
// den aktuellen Zustand aus und rufen nur applyMode() auf.
toggle.addEventListener('click', function () { toggle.addEventListener('click', function () {
const isLight = html.classList.toggle('light-mode'); const isCurrentlyLight = html.classList.contains('light-mode');
const newMode = isLight ? 'light' : 'dark'; const newMode = isCurrentlyLight ? 'dark' : 'light';
applyMode( newMode ); applyMode( newMode );
localStorage.setItem('themeMode', newMode); localStorage.setItem('themeMode', newMode);
}); });
// Live-Reaktion auf OS-Umschalten (optional aber nice-to-have) // Live-Reaktion auf OS-Umschalten (nur wenn keine manuelle Auswahl)
if ( window.matchMedia ) { if ( window.matchMedia ) {
window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', function( e ) { window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', function( e ) {
// Nur reagieren wenn der User noch keine manuelle Auswahl getroffen hat
if ( ! localStorage.getItem('themeMode') ) { if ( ! localStorage.getItem('themeMode') ) {
applyMode( e.matches ? 'light' : 'dark' ); applyMode( e.matches ? 'light' : 'dark' );
} }