2026-02-17 17:53:00 +01:00
|
|
|
<!DOCTYPE html>
|
2026-02-22 11:20:04 +01:00
|
|
|
<html lang="{{@site.locale}}"
|
2026-02-19 18:07:46 +01:00
|
|
|
x-data="{
|
|
|
|
|
theme: localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'),
|
2026-02-19 21:13:24 +01:00
|
|
|
mobileMenuOpen: false,
|
2026-02-20 11:25:13 +01:00
|
|
|
currentPath: window.location.pathname,
|
2026-02-20 12:14:17 +01:00
|
|
|
showScrollTop: false,
|
2026-02-20 12:45:32 +01:00
|
|
|
isSticky: false,
|
2026-02-19 18:07:46 +01:00
|
|
|
init() {
|
|
|
|
|
$watch('theme', val => {
|
|
|
|
|
localStorage.setItem('theme', val);
|
|
|
|
|
document.documentElement.setAttribute('data-theme', val);
|
|
|
|
|
});
|
|
|
|
|
document.documentElement.setAttribute('data-theme', this.theme);
|
|
|
|
|
document.documentElement.classList.remove('hidden');
|
2026-02-20 11:25:13 +01:00
|
|
|
|
2026-02-20 12:45:32 +01:00
|
|
|
// Handle scroll for sticky header and scroll-to-top button
|
2026-02-20 12:14:17 +01:00
|
|
|
window.addEventListener('scroll', () => {
|
|
|
|
|
this.showScrollTop = window.scrollY > 400;
|
2026-02-20 12:45:32 +01:00
|
|
|
this.isSticky = window.scrollY > 50;
|
2026-02-20 12:14:17 +01:00
|
|
|
});
|
|
|
|
|
|
2026-02-20 11:25:13 +01:00
|
|
|
// Update currentPath on navigation to keep menu highlights in sync
|
|
|
|
|
document.addEventListener('htmx:afterSettle', () => {
|
|
|
|
|
this.currentPath = window.location.pathname;
|
|
|
|
|
this.mobileMenuOpen = false;
|
|
|
|
|
});
|
2026-02-19 18:07:46 +01:00
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
:data-theme="theme"
|
|
|
|
|
class="hidden">
|
2026-02-17 17:53:00 +01:00
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
2026-02-21 09:45:59 +01:00
|
|
|
<title>{{#is "index"}}{{@site.title}}{{else}}{{meta_title}} — {{@site.title}}{{/is}}</title>
|
2026-02-17 17:53:00 +01:00
|
|
|
<link rel="stylesheet" href="{{asset "built/screen.css"}}">
|
2026-02-19 20:10:16 +01:00
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
|
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
2026-02-20 09:49:13 +01:00
|
|
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap" rel="stylesheet">
|
2026-02-19 18:07:46 +01:00
|
|
|
|
2026-02-22 15:53:52 +01:00
|
|
|
<script defer src="https://unpkg.com/alpinejs@3.14.8/dist/cdn.min.js"></script>
|
2026-02-19 18:07:46 +01:00
|
|
|
<script src="https://unpkg.com/htmx.org@2.0.0"></script>
|
|
|
|
|
|
2026-02-17 17:53:00 +01:00
|
|
|
{{ghost_head}}
|
|
|
|
|
</head>
|
2026-02-19 21:20:23 +01:00
|
|
|
<body
|
2026-02-20 11:25:13 +01:00
|
|
|
class="{{body_class}} font-sans antialiased min-h-screen flex flex-col"
|
2026-02-20 11:17:21 +01:00
|
|
|
hx-boost="true"
|
2026-02-20 11:25:13 +01:00
|
|
|
hx-target="#main-content"
|
|
|
|
|
hx-select="#main-content"
|
2026-02-20 11:27:58 +01:00
|
|
|
hx-swap="innerHTML show:window:top"
|
2026-02-20 11:17:21 +01:00
|
|
|
>
|
2026-02-20 10:21:26 +01:00
|
|
|
{{!--
|
2026-02-20 11:25:13 +01:00
|
|
|
PERSISTENT SHELL:
|
|
|
|
|
These elements are OUTSIDE #main-content, so they never swap.
|
|
|
|
|
This keeps Alpine state (mobileMenuOpen) perfectly stable.
|
2026-02-20 10:21:26 +01:00
|
|
|
--}}
|
2026-02-20 11:25:13 +01:00
|
|
|
{{> mobile-menu}}
|
|
|
|
|
{{> header}}
|
2026-02-20 12:14:17 +01:00
|
|
|
{{> scroll-top}}
|
2026-02-17 17:53:00 +01:00
|
|
|
|
2026-02-21 20:12:26 +01:00
|
|
|
<main id="main-content" class="flex-grow animate-fadeInUp">
|
2026-02-20 11:25:13 +01:00
|
|
|
{{{body}}}
|
|
|
|
|
</main>
|
2026-02-17 17:53:00 +01:00
|
|
|
|
2026-02-20 11:25:13 +01:00
|
|
|
{{> footer}}
|
2026-02-17 18:29:09 +01:00
|
|
|
|
2026-02-17 17:53:00 +01:00
|
|
|
{{ghost_foot}}
|
2026-02-17 19:21:42 +01:00
|
|
|
<script src="{{asset "js/ghost-config.js"}}"></script>
|
2026-02-17 17:53:00 +01:00
|
|
|
<script src="{{asset "js/main.js"}}"></script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|