chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

138
resources/js/core/router.js Normal file
View File

@@ -0,0 +1,138 @@
// modules/core/router.js
import { init as initClickManager } from './ClickManager.js';
import { navigateTo } from './navigateTo.js';
const routes = new Map();
const wildcards = [];
const guards = new Map();
let currentRoute = null;
let layoutCallback = null;
let metaCallback = null;
/**
* Registriert eine neue Route mit optionalem Handler
* @param {string} path - Pfad der Route
* @param {Function} handler - Callback bei Treffer
*/
export function defineRoute(path, handler) {
if (path.includes('*')) {
wildcards.push({ pattern: new RegExp('^' + path.replace('*', '.*') + '$'), handler });
} else {
routes.set(path, handler);
}
}
/**
* Definiert einen Guard für eine Route
* @param {string} path - Pfad
* @param {Function} guard - Guard-Funktion (return false = block)
*/
export function guardRoute(path, guard) {
guards.set(path, guard);
}
/**
* Gibt die aktuell aktive Route zurück
*/
export function getRouteContext() {
return currentRoute;
}
/**
* Setzt eine Callback-Funktion für dynamische Layout-Switches
*/
export function onLayoutSwitch(fn) {
layoutCallback = fn;
}
/**
* Setzt eine Callback-Funktion für Meta-Daten (z.B. title, theme)
*/
export function onMetaUpdate(fn) {
metaCallback = fn;
}
function matchRoute(href) {
if (routes.has(href)) return routes.get(href);
for (const entry of wildcards) {
if (entry.pattern.test(href)) return entry.handler;
}
return null;
}
function runGuard(href) {
const guard = guards.get(href);
return guard ? guard(href) !== false : true;
}
function extractMetaFromHTML(html) {
const temp = document.createElement('div');
temp.innerHTML = html;
const metaTags = {};
temp.querySelectorAll('[data-meta]').forEach(el => {
for (const attr of el.attributes) {
if (attr.name.startsWith('data-meta-')) {
const key = attr.name.replace('data-meta-', '');
metaTags[key] = attr.value;
}
}
})
//const title = temp.querySelector('[data-meta-title]')?.getAttribute('data-meta-title');
//const theme = temp.querySelector('[data-meta-theme]')?.getAttribute('data-meta-theme');
return { metaTags };
}
function animateLayoutSwitch(type) {
document.body.dataset.layout = type;
document.body.classList.add('layout-transition');
setTimeout(() => document.body.classList.remove('layout-transition'), 300);
}
/**
* Startet den Router
*/
export function startRouter() {
initClickManager((href, link, options) => {
if (!runGuard(href)) return;
if (options.modal) {
const handler = matchRoute(href);
currentRoute = { href, modal: true, link, options };
handler?.(currentRoute);
layoutCallback?.(currentRoute);
metaCallback?.(currentRoute);
} else {
navigateTo(href, {
...options,
onUpdate: (html) => {
const container = document.querySelector('main');
if (container) container.innerHTML = html;
const routeHandler = matchRoute(href);
currentRoute = { href, html, modal: false };
const meta = extractMetaFromHTML(html);
if (meta.title) document.title = meta.title;
if (meta.theme) document.documentElement.style.setProperty('--theme-color', meta.theme);
routeHandler?.(currentRoute);
layoutCallback?.(currentRoute);
metaCallback?.(currentRoute);
}
});
}
});
// Bei Seitenstart erste Route prüfen
window.addEventListener('DOMContentLoaded', () => {
const href = location.pathname;
const routeHandler = matchRoute(href);
currentRoute = { href, modal: false };
routeHandler?.(currentRoute);
layoutCallback?.(currentRoute);
metaCallback?.(currentRoute);
});
}
export { animateLayoutSwitch, extractMetaFromHTML };