chore: complete update
This commit is contained in:
138
resources/js/core/router.js
Normal file
138
resources/js/core/router.js
Normal 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 };
|
||||
Reference in New Issue
Block a user