Files
homepage_relaunch/src/components/Header.astro
T
2026-09-18 16:56:44 +02:00

124 lines
4.4 KiB
Plaintext

---
import Wordmark from './Wordmark.astro';
import { localePath, t, type Lang } from '../i18n/ui';
interface Props { lang: Lang }
const { lang } = Astro.props;
const ui = t(lang);
const home = localePath(lang, '/');
const items = [
{ href: `${home}#capabilities`, label: ui.nav.capabilities },
{ href: localePath(lang, '/cipherverifier'), label: ui.nav.product },
{ href: `${home}#sectors`, label: ui.nav.sectors },
{ href: localePath(lang, '/insights'), label: ui.nav.insights },
{ href: localePath(lang, '/team'), label: ui.nav.team },
];
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>
<div class="container header__inner">
<a class="header__home" href={home} aria-label={ui.nav.homeLabel}><Wordmark /></a>
<nav class="header__nav" aria-label="Primary" id="primary-nav">
<ul class="header__list" role="list">
{items.map((item) => (
<li><a href={item.href} aria-current={isCurrent(item.href) ? 'page' : undefined}>{item.label}</a></li>
))}
<li class="header__contact-mobile"><a href={contactHref}>{ui.nav.contact}</a></li>
</ul>
</nav>
<a class="button button--small header__contact" href={contactHref}>{ui.nav.contact}</a>
<button class="header__toggle" type="button" aria-expanded="false" aria-controls="primary-nav" data-nav-toggle>
<span data-label-open>{ui.nav.menu}</span>
<span data-label-close hidden>{ui.nav.close}</span>
</button>
</div>
</header>
<style>
.header {
position: sticky;
top: 0;
z-index: 20;
background: var(--paper);
border-bottom: var(--hairline) solid var(--line);
}
.header__inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--gap);
min-height: var(--header-height);
}
.header__home { text-decoration: none; }
.header__nav { margin-left: auto; }
.header__list {
display: flex;
gap: var(--space-6);
}
.header__list a {
text-decoration: none;
font-weight: var(--weight-regular);
padding-block: var(--space-2);
border-bottom: var(--hairline) solid transparent;
transition: border-color var(--dur-fast) var(--ease);
}
.header__list a:hover,
.header__list a[aria-current='page'] { border-bottom-color: currentColor; }
.header__contact { margin-left: var(--space-6); }
.header__contact-mobile { display: none; }
.header__toggle {
display: none;
font-weight: var(--weight-medium);
padding: var(--space-2) 0;
}
@media (max-width: 47.99rem) {
.header__contact { display: none; }
.header__contact-mobile { display: block; }
.header__toggle { display: inline-block; }
.header__nav {
position: absolute;
inset: 100% 0 auto 0;
display: none;
padding: var(--space-5) var(--gutter) var(--space-7);
background: var(--paper);
border-bottom: var(--hairline) solid var(--line);
}
.header__nav[data-open] { display: block; }
.header__list { flex-direction: column; gap: 0; }
.header__list li + li { border-top: var(--hairline) solid var(--line); }
.header__list a {
display: block;
padding-block: var(--space-4);
font-size: var(--step-h3);
letter-spacing: var(--track-h3);
border-bottom: 0;
}
.header__list a[aria-current='page'] { font-weight: var(--weight-medium); }
}
</style>
<script>
const header = document.querySelector<HTMLElement>('[data-header]');
const toggle = header?.querySelector<HTMLButtonElement>('[data-nav-toggle]');
const nav = header?.querySelector<HTMLElement>('#primary-nav');
if (header && toggle && nav) {
const open = toggle.querySelector<HTMLElement>('[data-label-open]')!;
const close = toggle.querySelector<HTMLElement>('[data-label-close]')!;
const set = (isOpen: boolean) => {
toggle.setAttribute('aria-expanded', String(isOpen));
if (isOpen) nav.setAttribute('data-open', ''); else nav.removeAttribute('data-open');
open.hidden = isOpen;
close.hidden = !isOpen;
};
toggle.addEventListener('click', () => set(toggle.getAttribute('aria-expanded') !== 'true'));
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') set(false); });
nav.addEventListener('click', (e) => { if ((e.target as HTMLElement).closest('a')) set(false); });
}
</script>