<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title | default(value="adminx") }}</title>
<script>window.tailwind = { config: { darkMode: 'class' } };</script>
<script src="https://cdn.tailwindcss.com"></script>
<script>
(function () {
try {
var stored = localStorage.getItem('adminx-theme');
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
var theme = stored || (prefersDark ? 'dark' : 'light');
if (theme === 'dark') document.documentElement.classList.add('dark');
} catch (_) {}
})();
</script>
<style>
:root { --bg: #f1f5f9; --fg: #0f172a; }
html.dark { --bg: #0b1220; --fg: #e5e7eb; }
body { background: var(--bg) !important; color: var(--fg) !important; }
</style>
</head>
<body class="h-full flex flex-col bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-100 selection:bg-indigo-200/50 dark:selection:bg-indigo-400/30">
{% include "header.html" %}
<main class="flex-1">
<div class="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8 py-8">
{% if toast %}
<div class="mb-4 px-4 py-3 rounded-lg bg-emerald-50 dark:bg-emerald-900/20 border border-emerald-200 dark:border-emerald-800 text-emerald-700 dark:text-emerald-300 text-sm">{{ toast }}</div>
{% endif %}
{% block content %}{% endblock content %}
</div>
</main>
{% include "footer.html" %}
<script>
(function () {
var root = document.documentElement;
function applyTheme(theme) {
if (theme === 'dark') root.classList.add('dark'); else root.classList.remove('dark');
try { localStorage.setItem('adminx-theme', theme); } catch (_) {}
document.querySelectorAll('[data-icon-sun]').forEach(function (el) { el.classList.toggle('hidden', theme !== 'dark'); });
document.querySelectorAll('[data-icon-moon]').forEach(function (el) { el.classList.toggle('hidden', theme === 'dark'); });
}
applyTheme(root.classList.contains('dark') ? 'dark' : 'light');
document.querySelectorAll('[data-theme-toggle]').forEach(function (btn) {
btn.addEventListener('click', function () { applyTheme(root.classList.contains('dark') ? 'light' : 'dark'); });
});
var openId = null;
function closeMenus() {
document.querySelectorAll('[data-menu-panel]').forEach(function (p) {
p.classList.add('pointer-events-none', 'opacity-0', 'translate-y-1', 'scale-95');
p.classList.remove('opacity-100', 'translate-y-0', 'scale-100');
});
document.querySelectorAll('[data-menu-trigger]').forEach(function (t) { t.setAttribute('aria-expanded', 'false'); });
openId = null;
}
function openMenu(id) {
closeMenus();
var panel = document.querySelector('[data-menu-panel][data-id="' + id + '"]');
var trigger = document.querySelector('[data-menu-trigger][data-id="' + id + '"]');
if (!panel || !trigger) return;
panel.classList.remove('pointer-events-none', 'opacity-0', 'translate-y-1', 'scale-95');
panel.classList.add('opacity-100', 'translate-y-0', 'scale-100');
trigger.setAttribute('aria-expanded', 'true');
openId = id;
}
document.querySelectorAll('[data-menu-trigger]').forEach(function (btn) {
btn.addEventListener('click', function (e) {
e.stopPropagation();
var id = btn.getAttribute('data-id');
if (openId === id) { closeMenus(); } else { openMenu(id); }
});
});
document.addEventListener('mousedown', function (e) {
var nav = document.getElementById('desktop-nav');
if (!nav || openId === null) return;
if (!nav.contains(e.target)) closeMenus();
});
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeMenus(); });
document.querySelectorAll('[data-menu-item]').forEach(function (a) { a.addEventListener('click', closeMenus); });
var drawer = document.getElementById('mobile-menu');
var burger = document.querySelector('[data-mobile-toggle]');
function setDrawer(open) {
if (!drawer) return;
drawer.classList.toggle('opacity-100', open);
drawer.classList.toggle('opacity-0', !open);
drawer.classList.toggle('pointer-events-auto', open);
drawer.classList.toggle('pointer-events-none', !open);
}
if (burger) burger.addEventListener('click', function () { setDrawer(drawer.classList.contains('opacity-0')); });
document.querySelectorAll('[data-mobile-link]').forEach(function (a) { a.addEventListener('click', function () { setDrawer(false); }); });
document.querySelectorAll('[data-mobile-accordion]').forEach(function (btn) {
btn.addEventListener('click', function () {
var panel = btn.nextElementSibling;
if (!panel) return;
panel.classList.toggle('max-h-0');
panel.classList.toggle('max-h-96');
panel.classList.toggle('opacity-0');
panel.classList.toggle('opacity-100');
var icon = btn.querySelector('svg'); if (icon) icon.classList.toggle('rotate-180');
});
});
})();
</script>
</body>
</html>