Files
2026-08-07 21:17:17 +03:30

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>