This commit is contained in:
Felix Klement committed 2026-10-04 22:43:25 +02:00
1 parent f84687d745
commit 7508f6e084
9 files changed
+55 -14

No files matched your search

+14 -3
View File
@@ -2,8 +2,8 @@
import Wordmark from './Wordmark.astro';
import { localePath, t, type Lang } from '../i18n/ui';
interface Props { lang: Lang }
const { lang } = Astro.props;
interface Props { lang: Lang; tone?: 'paper' | 'night' }
const { lang, tone = 'paper' } = Astro.props;
const ui = t(lang);
const home = localePath(lang, '/');
const items = [
@@ -16,7 +16,7 @@ const contactHref = `${home}#contact`;
const path = Astro.url.pathname.replace(/\/$/, '') || '/';
const isCurrent = (href: string) => href.split('#')[0] === path && !href.includes('#');
---
<header class="header" data-header data-tone="paper">
<header class="header" data-header data-tone={tone} data-tone-init>
<div class="container header__shell">
<div class="header__bar hud-frame">
<a class="header__home" href={home} aria-label={ui.nav.homeLabel}>
@@ -102,6 +102,12 @@ const isCurrent = (href: string) => href.split('#')[0] === path && !href.include
background: var(--glass-solid);
transition: background-color var(--dur) var(--ease);
}
/* Until the script has settled the tone on load, it changes without a fade: the tone is a fact
about where the page is, not a change the visitor made. */
.header[data-tone-init],
.header[data-tone-init] *,
.header[data-tone-init] ::before,
.header[data-tone-init] ::after { transition: none !important; }
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.header__bar::before,
.header__nav[data-open]::before {
@@ -242,6 +248,8 @@ const isCurrent = (href: string) => href.split('#')[0] === path && !href.include
/* Tone: watch a one-pixel line through the middle of the bar and switch to night while a
.night section crosses it. An IntersectionObserver, so nothing runs on scroll. */
const sections = document.querySelectorAll<HTMLElement>('.night');
// Transitions come back once the first tone is drawn (two frames, so it has been painted).
const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => header?.removeAttribute('data-tone-init')));
if (header && sections.length && 'IntersectionObserver' in window) {
const under = new Set<Element>();
let observer: IntersectionObserver | undefined;
@@ -254,6 +262,7 @@ const isCurrent = (href: string) => href.split('#')[0] === path && !href.include
if (entry.isIntersecting) under.add(entry.target); else under.delete(entry.target);
}
header.dataset.tone = under.size ? 'night' : 'paper';
if (header.hasAttribute('data-tone-init')) settle();
}, { rootMargin: `-${mid}px 0px -${window.innerHeight - mid - 1}px 0px` });
sections.forEach((section) => observer!.observe(section));
};
@@ -263,5 +272,7 @@ const isCurrent = (href: string) => href.split('#')[0] === path && !href.include
window.clearTimeout(resize);
resize = window.setTimeout(watch, 150);
});
} else {
settle();
}
</script>