Channel pill row outgrew the viewport once more channels were added, pushing the whole page sideways. Let the header wrap, scroll the nav inside its own pill, and clip body overflow as a safety net.
114 lines
6.5 KiB
HTML
114 lines
6.5 KiB
HTML
{{define "layout"}}<!doctype html>
|
|
<html lang="en" data-phase="{{if .Phase}}{{.Phase}}{{else}}day{{end}}"{{if .Phase}} data-phase-lock{{end}} data-season="{{.Weather.Season}}" data-weather="{{.Weather.Variant}}" data-intensity="{{.Weather.Intensity}}">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{block "title" .}}{{.SiteTitle}}{{end}}</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="/static/css/output.css">
|
|
<link rel="icon" href="/static/img/pete.avif" type="image/avif">
|
|
<script>
|
|
// Pick a palette phase from the browser clock and update it each minute.
|
|
(function () {
|
|
function phase(h) {
|
|
if (h >= 5 && h < 8) return "dawn";
|
|
if (h >= 8 && h < 17) return "day";
|
|
if (h >= 17 && h < 20) return "dusk";
|
|
return "night";
|
|
}
|
|
function apply() {
|
|
if (document.documentElement.hasAttribute("data-phase-lock")) return;
|
|
document.documentElement.dataset.phase = phase(new Date().getHours());
|
|
}
|
|
apply();
|
|
setInterval(apply, 60000);
|
|
})();
|
|
</script>
|
|
</head>
|
|
<body class="min-h-screen bg-[color:var(--bg)] text-[color:var(--ink)] transition-colors duration-1000">
|
|
<div class="pointer-events-none fixed inset-0 -z-10 bg-[color:var(--bg-grad)] transition-colors duration-1000"></div>
|
|
<canvas id="pete-weather" class="pointer-events-none fixed inset-0 -z-[5] h-full w-full" aria-hidden="true"></canvas>
|
|
|
|
<header class="mx-auto max-w-6xl px-4 pt-8 pb-4 sm:pt-12">
|
|
<div class="flex flex-wrap items-center justify-between gap-3 sm:gap-4">
|
|
<a href="/" class="flex items-center gap-3 group min-w-0">
|
|
<img src="/static/img/pete.avif" alt="Pete" width="48" height="48"
|
|
class="h-12 w-12 shrink-0 rounded-2xl bg-[color:var(--card)] shadow-pete border-2 border-[color:var(--ink)]/10 object-cover group-hover:-rotate-6 transition-transform">
|
|
<span class="font-display text-3xl font-bold tracking-tight">{{.SiteTitle}}</span>
|
|
<span class="hidden sm:inline rounded-full bg-[color:var(--accent)]/20 px-3 py-1 text-xs font-semibold uppercase tracking-wider text-[color:var(--ink)]/70" data-phase-label>day</span>
|
|
</a>
|
|
<div class="flex items-center gap-2 min-w-0 max-w-full">
|
|
<button type="button" data-search-trigger title="Search (⌘K)"
|
|
class="flex shrink-0 items-center gap-2 rounded-full bg-[color:var(--card)] px-3 py-2 text-sm shadow-pete border-2 border-[color:var(--ink)]/10 hover:bg-[color:var(--ink)]/5 transition">
|
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4 text-[color:var(--ink)]/60">
|
|
<circle cx="11" cy="11" r="7"></circle>
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
</svg>
|
|
<span class="hidden sm:inline text-[color:var(--ink)]/60 font-semibold">Search</span>
|
|
<kbd class="hidden sm:inline-flex items-center rounded-md bg-[color:var(--ink)]/5 px-1.5 py-0.5 text-[10px] font-mono font-semibold text-[color:var(--ink)]/60">⌘K</kbd>
|
|
</button>
|
|
<nav class="pete-channel-nav flex min-w-0 items-center gap-1 sm:gap-2 overflow-x-auto rounded-full bg-[color:var(--card)] p-1 shadow-pete border-2 border-[color:var(--ink)]/10">
|
|
{{$active := .Active}}
|
|
{{range .Channels}}
|
|
<a href="/{{.Slug}}"
|
|
class="shrink-0 rounded-full px-3 py-2 text-sm font-semibold transition
|
|
{{if eq $active .Slug}}bg-theme-{{.Theme}} text-white shadow-sm{{else}}hover:bg-[color:var(--ink)]/5{{end}}">
|
|
<span aria-hidden="true" class="mr-1">{{.Emoji}}</span><span class="hidden sm:inline">{{.Title}}</span>
|
|
</a>
|
|
{{end}}
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div id="pete-search" class="hidden fixed inset-0 z-50 bg-[color:var(--ink)]/40 backdrop-blur-sm flex items-start justify-center pt-[10vh] px-4" aria-modal="true" role="dialog">
|
|
<div class="w-full max-w-2xl rounded-3xl bg-[color:var(--card)] shadow-pete-lg border-2 border-[color:var(--ink)]/10 overflow-hidden">
|
|
<div class="flex items-center gap-3 px-5 py-4 border-b border-[color:var(--ink)]/10">
|
|
<kbd class="hidden sm:inline-flex items-center rounded-md bg-[color:var(--ink)]/5 px-1.5 py-0.5 text-[10px] font-mono font-semibold text-[color:var(--ink)]/60">⌘K</kbd>
|
|
<input type="search" data-search-input autocomplete="off" spellcheck="false"
|
|
placeholder="Search headlines…"
|
|
class="flex-1 bg-transparent text-lg outline-none placeholder:text-[color:var(--ink)]/40">
|
|
</div>
|
|
<div data-search-list class="max-h-[60vh] overflow-y-auto p-3 space-y-1"></div>
|
|
<div class="px-5 py-3 border-t border-[color:var(--ink)]/10 flex items-center justify-between text-xs text-[color:var(--ink)]/50">
|
|
<span><kbd class="font-mono">↑↓</kbd> navigate · <kbd class="font-mono">⏎</kbd> open · <kbd class="font-mono">esc</kbd> close</span>
|
|
<span data-search-meta></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<main class="mx-auto max-w-6xl px-4 pb-24">
|
|
{{block "main" .}}{{end}}
|
|
</main>
|
|
|
|
<footer class="mx-auto max-w-6xl px-4 pb-10 text-center text-sm text-[color:var(--ink)]/50">
|
|
<img src="/static/img/pete.avif" alt="" width="20" height="20"
|
|
class="inline-block h-5 w-5 rounded-full object-cover align-[-4px] mr-1">
|
|
served by <span class="font-semibold">Pete</span> · also a Matrix bot · <span data-clock>—</span>
|
|
</footer>
|
|
|
|
<script>
|
|
// Tiny clock + phase label updater for the header pill / footer.
|
|
(function () {
|
|
function tick() {
|
|
var now = new Date();
|
|
var hh = String(now.getHours()).padStart(2, "0");
|
|
var mm = String(now.getMinutes()).padStart(2, "0");
|
|
var el = document.querySelector("[data-clock]");
|
|
if (el) el.textContent = hh + ":" + mm;
|
|
var label = document.querySelector("[data-phase-label]");
|
|
if (label) label.textContent = document.documentElement.dataset.phase;
|
|
}
|
|
tick();
|
|
setInterval(tick, 30000);
|
|
})();
|
|
</script>
|
|
|
|
<script src="/static/js/weather.js" defer></script>
|
|
<script src="/static/js/search.js" defer></script>
|
|
</body>
|
|
</html>{{end}}
|