66 lines
3.3 KiB
HTML
66 lines
3.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="{{ .Language.LanguageCode | default .Language.Lang | default "en" }}">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="{{ .Site.Data.brand.primaryColor }}">
|
|
|
|
{{ partial "head-seo.html" . }}
|
|
|
|
{{/* Brand + locale data exposed to client-side scripts (age gate, locale switcher).
|
|
safeJS prevents html/template from escaping the JSON into a quoted string. */}}
|
|
<script>
|
|
window.__BRAND__ = {{ dict "name" .Site.Data.brand.name "defaultLocale" .Site.Data.brand.defaultLocale "ageRestrictionDefault" .Site.Data.brand.ageRestrictionDefault | jsonify | safeJS }};
|
|
window.__LOCALES__ = {{ .Site.Data.locales | jsonify | safeJS }};
|
|
</script>
|
|
|
|
{{/* Add the age-gate class as early as possible to avoid a flash for confirmed visitors. */}}
|
|
<script>
|
|
(function () {
|
|
try {
|
|
if (localStorage.getItem("ageConfirmed") !== "1") {
|
|
document.documentElement.classList.add("age-gate-active");
|
|
}
|
|
} catch (e) {
|
|
document.documentElement.classList.add("age-gate-active");
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
{{/* CSS pipeline: inject brand vars (ExecuteAsTemplate) -> Tailwind/PostCSS ->
|
|
minify (production only) -> fingerprint. Hugo's [minify] does not minify
|
|
Pipes resources, so we minify explicitly for production builds. */}}
|
|
{{ $css := resources.Get "css/main.css" | resources.ExecuteAsTemplate "css/main.css" . | css.PostCSS }}
|
|
{{ if hugo.IsProduction }}{{ $css = $css | minify }}{{ end }}
|
|
{{ $css = $css | fingerprint "sha256" }}
|
|
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous">
|
|
|
|
<link rel="icon" href="{{ "favicon.svg" | relURL }}" type="image/svg+xml">
|
|
</head>
|
|
<body class="flex min-h-screen flex-col bg-white">
|
|
<a href="#main" class="sr-only rounded bg-primary px-4 py-2 text-primary-contrast focus:not-sr-only focus:absolute focus:left-4 focus:top-4 focus:z-[110]">{{ i18n "skipToContent" }}</a>
|
|
|
|
{{ partial "age-gate-banner.html" . }}
|
|
{{ partial "header.html" . }}
|
|
|
|
<main id="main" class="flex-1">
|
|
{{ block "main" . }}{{ end }}
|
|
</main>
|
|
|
|
{{ partial "footer.html" . }}
|
|
{{ partial "cookie-consent.html" . }}
|
|
|
|
{{/* App bundle (age gate, cookie consent, games filter). Loads BEFORE Alpine so the
|
|
gamesFilter component is registered on the alpine:init event. */}}
|
|
{{ $appJs := slice (resources.Get "js/age-gate.js") (resources.Get "js/cookie-consent.js") (resources.Get "js/games-filter.js") | resources.Concat "js/app.js" | minify | fingerprint "sha256" }}
|
|
<script defer src="{{ $appJs.RelPermalink }}" integrity="{{ $appJs.Data.Integrity }}" crossorigin="anonymous"></script>
|
|
|
|
{{/* Alpine.js — vendored first-party (assets/js/vendor/alpine.js, pinned 3.14.8,
|
|
refreshed from node_modules by `npm run build:js`) and fingerprinted so it
|
|
ships with Subresource Integrity like the other assets. Deferred and placed
|
|
AFTER the app bundle so components register on alpine:init before core runs. */}}
|
|
{{ $alpine := resources.Get "js/vendor/alpine.js" | fingerprint "sha256" }}
|
|
<script defer src="{{ $alpine.RelPermalink }}" integrity="{{ $alpine.Data.Integrity }}" crossorigin="anonymous"></script>
|
|
</body>
|
|
</html>
|