initial
This commit is contained in:
commit
4cda1ca41b
72 files changed
+8169
No files matched your search
@@ -0,0 +1,122 @@
|
||||
---
|
||||
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: `${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>
|
||||
Reference in new issue
Block a user