86 lines
4.4 KiB
HTML
86 lines
4.4 KiB
HTML
<!doctype html>
|
|
<html lang="en" class="h-full">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
<title>{% block title %}Kavosh{% endblock %}</title>
|
|
<!--
|
|
Anti-FOUC: set the theme class synchronously, before the stylesheet
|
|
and before Alpine/htmx load, so there's no flash of the wrong theme
|
|
on first paint. Kept as a tiny inline script rather than waiting for
|
|
the bundled JS, which only arrives after the page has started
|
|
rendering.
|
|
-->
|
|
<script>
|
|
(function () {
|
|
var stored = localStorage.getItem('kavosh-theme');
|
|
var isDark = stored ? stored === 'dark' : window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
document.documentElement.classList.toggle('dark', isDark);
|
|
})();
|
|
</script>
|
|
<link rel="stylesheet" href="{{ asset('app/static/src/css/main.css') }}">
|
|
</head>
|
|
<body class="h-full bg-paper dark:bg-paper-dark text-ink dark:text-ink-dark antialiased">
|
|
<div id="app-shell" x-data="{ mobileNavOpen: false }">
|
|
<header class="border-b border-line dark:border-line-dark bg-surface dark:bg-surface-dark">
|
|
<nav class="flex gap-1 px-4 py-3 items-center max-w-6xl mx-auto">
|
|
<span class="font-display font-bold text-lg tracking-tight mr-4">Kavosh</span>
|
|
|
|
{% if current_user.is_authenticated %}
|
|
{% set tabs = [
|
|
('overview.overview', '/overview', 'house', 'Overview'),
|
|
('seo.seo', '/seo', 'search', 'SEO & Bots'),
|
|
('security.security', '/security', 'shield-alert', 'Security'),
|
|
] %}
|
|
{% for endpoint, path, icon, label in tabs %}
|
|
<a href="{{ path }}" hx-get="{{ path }}" hx-target="#main-content" hx-push-url="true"
|
|
class="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-colors
|
|
{% if request.endpoint == endpoint %}
|
|
bg-accent/10 text-accent dark:bg-accent-dark/15 dark:text-accent-dark
|
|
{% else %}
|
|
text-muted dark:text-muted-dark hover:text-ink dark:hover:text-ink-dark hover:bg-paper dark:hover:bg-paper-dark
|
|
{% endif %}">
|
|
<svg class="w-4 h-4 shrink-0"><use href="/static/dist/icons.svg#{{ icon }}"/></svg>
|
|
<span class="hidden sm:inline">{{ label }}</span>
|
|
</a>
|
|
{% endfor %}
|
|
|
|
<div class="ml-auto flex items-center gap-2">
|
|
<button type="button" onclick="toggleTheme()"
|
|
aria-label="Toggle dark mode"
|
|
class="p-2 rounded-md text-muted dark:text-muted-dark hover:text-ink dark:hover:text-ink-dark hover:bg-paper dark:hover:bg-paper-dark transition-colors">
|
|
<svg class="w-4 h-4 block dark:hidden"><use href="/static/dist/icons.svg#moon"/></svg>
|
|
<svg class="w-4 h-4 hidden dark:block"><use href="/static/dist/icons.svg#sun"/></svg>
|
|
</button>
|
|
<span class="text-sm text-muted dark:text-muted-dark font-data hidden md:inline">{{ current_user.email }}</span>
|
|
<form method="post" action="{{ url_for('auth.logout') }}">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<button type="submit" title="Log out"
|
|
class="p-2 rounded-md text-muted dark:text-muted-dark hover:text-danger dark:hover:text-danger-dark hover:bg-paper dark:hover:bg-paper-dark transition-colors">
|
|
<svg class="w-4 h-4"><use href="/static/dist/icons.svg#log-out"/></svg>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<div class="ml-auto">
|
|
<button type="button" onclick="toggleTheme()" aria-label="Toggle dark mode"
|
|
class="p-2 rounded-md text-muted dark:text-muted-dark hover:text-ink dark:hover:text-ink-dark hover:bg-paper dark:hover:bg-paper-dark transition-colors">
|
|
<svg class="w-4 h-4 block dark:hidden"><use href="/static/dist/icons.svg#moon"/></svg>
|
|
<svg class="w-4 h-4 hidden dark:block"><use href="/static/dist/icons.svg#sun"/></svg>
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</nav>
|
|
</header>
|
|
|
|
<!-- HTMX target swapped by the nav above (Ch01: single-page shell, no full reloads) -->
|
|
<main id="main-content" class="max-w-6xl mx-auto p-4 sm:p-6">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
</div>
|
|
|
|
<script type="module" src="{{ asset('app/static/src/js/main.js') }}"></script>
|
|
</body>
|
|
</html>
|