<div id="header-72345-16168" class="header">
<div class="header__inner">
<a class="header__logo" href="#" title="zplane">
<img width="164" height="50" src="/assets/images/logo.7e7ebc0793.svg" alt="zplane" class="header__logo-img">
</a>
<div class="header__contents">
<div class="header__icon-buttons">
<button class="button" type="button" title="Open menu" aria-expanded="false" aria-controls="header-72345-16168-menu" data-action="open">
<span class="button__icon">
<svg class="icon icon--bars" viewBox="0 0 200 200" aria-hidden="true">
<use xlink:href="/assets/icons/icons.dcaca1c147.svg#bars"></use>
</svg> </span>
</button>
<div class="header__icon-button">
<a class="button" title="Partner Area" href="#">
<span class="button__icon">
<svg class="icon icon--lock-keyhole" viewBox="0 0 200 200" aria-hidden="true">
<use xlink:href="/assets/icons/icons.dcaca1c147.svg#lock-keyhole"></use>
</svg> </span>
</a>
</div>
</div>
<div class="header__menu" id="header-72345-16168-menu" hidden>
<div class="header__menu-close">
<button class="button" type="button" title="Close menu" data-action="close">
<span class="button__icon">
<svg class="icon icon--xmark" viewBox="0 0 200 200" aria-hidden="true">
<use xlink:href="/assets/icons/icons.dcaca1c147.svg#xmark"></use>
</svg> </span>
</button>
</div>
<ul class="header__navigation">
<li class="header__navigation-item" data-floating-root>
<span class="header__navigation-link">
<button class="link" type="button" data-link-block data-link-type="internal" aria-expanded="false" aria-haspopup="true" aria-controls="header-72345-16168-navigation-menu-1"><span class="link__text u-underline">Company</span><span class="link__icon"><svg class="icon icon--caret-down-solid" viewBox="0 0 200 200" aria-hidden="true">
<use xlink:href="/assets/icons/icons.dcaca1c147.svg#caret-down-solid"></use>
</svg></span></button>
</span>
<ul class="header__navigation-menu" id="header-72345-16168-navigation-menu-1" data-floating-placements="bottom" data-floating-offset="16" role="menu" hidden>
<li class="header__navigation-menu-item" role="presentation">
<a class="link" data-link-type="internal" href="#" role="menuitem"><span class="link__text u-underline">Overview</span></a>
</li>
<li class="header__navigation-menu-item" role="presentation">
<a class="link" data-link-type="internal" href="#" role="menuitem"><span class="link__text u-underline">Pressroom</span></a>
</li>
<li class="header__navigation-menu-item" role="presentation">
<a class="link" data-link-type="internal" href="#" role="menuitem"><span class="link__text u-underline">Blog & News</span></a>
</li>
</ul>
</li>
<li class="header__navigation-item" data-floating-root>
<span class="header__navigation-link">
<a class="link" data-link-block data-link-type="internal" href="#" aria-current="true"><span class="link__text u-underline">Technology</span></a>
</span>
</li>
<li class="header__navigation-item" data-floating-root>
<span class="header__navigation-link">
<a class="link" data-link-block data-link-type="internal" href="#"><span class="link__text u-underline">Licensing</span></a>
</span>
</li>
<li class="header__navigation-item" data-floating-root>
<span class="header__navigation-link">
<a class="link" data-link-block data-link-type="internal" href="#"><span class="link__text u-underline">Partner</span></a>
</span>
</li>
<li class="header__navigation-item" data-floating-root>
<span class="header__navigation-link">
<a class="link" data-link-block data-link-type="internal" href="#"><span class="link__text u-underline">Contact</span></a>
</span>
</li>
</ul>
<div class="header__navigation-highlight"></div>
</div>
<div class="header__login-button">
<a class="button" href="#">
<span class="button__icon">
<svg class="icon icon--lock-keyhole" viewBox="0 0 200 200" aria-hidden="true">
<use xlink:href="/assets/icons/icons.dcaca1c147.svg#lock-keyhole"></use>
</svg> </span>
<span class="button__text u-underline">Partner Area</span>
</a>
</div>
</div>
</div>
</div>
{% set id = id ??? html_id('header') %}
<div {{ html_attributes({
id,
class: 'header',
}, attrs ?? {}) }}>
<div class="header__inner">
{% if logo|default %}
<a class="header__logo" href="{{ logo.link }}" title="{{ logo.text }}">
<img {{ html_attributes({
width: 164,
height: 50,
src: asset('images/logo.svg'),
alt: logo.text,
class: 'header__logo-img',
}) }}>
</a>
{% endif %}
<div class="header__contents">
{% if navigation|default %}
<div class="header__icon-buttons">
{% include '@button' with {
icon: 'bars',
title: 'Open menu' | t('site'),
attrs: {
'aria-expanded': 'false',
'aria-controls': 'menu' | namespaceInputId(id),
'data-action': 'open',
},
} only %}
{% for iconButton in iconButtons|default([]) %}
<div {{ html_attributes({ class: 'header__icon-button' }, iconButton.containerAttrs ?? {}) }}>
{% include '@button' with iconButton only %}
</div>
{% endfor %}
</div>
<div {{ html_attributes({
class: 'header__menu',
id: 'menu' | namespaceInputId(id),
hidden: true,
}, menuAttrs ?? {}) }}>
<div class="header__menu-close">
{% include '@button' with {
icon: 'xmark',
title: 'Close menu' | t('site'),
attrs: {
'data-action': 'close',
},
} only %}
</div>
{% if navigation|default %}
<ul class="header__navigation">
{% for item in navigation %}
<li class="header__navigation-item" data-floating-root>
{% set hasChildren = item.children|default and item.children|length > 0 %}
{% set isActiveOrChildren = item.active|default or item.children|default([])|filter(child => child.active|default) %}
<span class="header__navigation-link">
{% if item.link|default or hasChildren %}
{% include '@link' with {
text: item.text,
link: not hasChildren ? item.link,
icon: hasChildren ? 'caret-down-solid',
iconPosition: 'after',
block: true,
attrs: {
'aria-expanded': hasChildren ? 'false',
'aria-haspopup': hasChildren ? 'true',
'aria-controls': hasChildren ? "navigation-menu-#{loop.index}" | namespaceInputId(id),
'aria-current': isActiveOrChildren ? 'true',
},
} only %}
{% else %}
{{- item.text -}}
{% endif %}
</span>
{% if hasChildren %}
<ul {{ html_attributes({
class: 'header__navigation-menu',
id: "navigation-menu-#{loop.index}" | namespaceInputId(id),
'data-floating-placements': 'bottom',
'data-floating-offset': '16',
role: 'menu',
hidden: true,
}) }}>
{% if item.link|default %}
<li class="header__navigation-menu-item" role="presentation">
{% include '@link' with {
text: 'Overview'|t('site'),
link: item.link,
attrs: {
role: 'menuitem',
'aria-current': item.active|default ? 'true',
},
} only %}
</li>
{% endif %}
{% for child in item.children %}
<li class="header__navigation-menu-item" role="presentation">
{% if child.link|default %}
{% include '@link' with {
text: child.text,
link: child.link,
attrs: {
role: 'menuitem',
'aria-current': child.active|default ? 'true',
},
} only %}
{% else %}
<span {{ html_attributes({
role: 'menuitem',
'aria-current': child.active|default ? 'true',
}) }}>
{{- item.text -}}
</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
<div class="header__navigation-highlight"></div>
</div>
{% endif %}
{% if loginButton|default %}
<div class="header__login-button">
{% include '@button' with loginButton only %}
</div>
{% endif %}
</div>
</div>
</div>
{
"logo": {
"text": "zplane",
"link": "#"
},
"navigation": [
{
"text": "Company",
"link": "#",
"children": [
{
"text": "Pressroom",
"link": "#"
},
{
"text": "Blog & News",
"link": "#"
}
]
},
{
"text": "Technology",
"link": "#",
"active": true
},
{
"text": "Licensing",
"link": "#"
},
{
"text": "Partner",
"link": "#"
},
{
"text": "Contact",
"link": "#"
}
],
"iconButtons": [
{
"link": "#",
"title": "Partner Area",
"icon": "lock-keyhole"
}
],
"loginButton": {
"link": "#",
"text": "Partner Area",
"icon": "lock-keyhole"
}
}
.header {
container-name: header;
container-type: inline-size;
}
.header__inner {
align-items: center;
display: flex;
justify-content: space-between;
position: relative;
@container header (inline-size >= 85rem) {
column-gap: 1.6rem;
flex-direction: column;
row-gap: 2.4rem;
}
@container header (inline-size >= 110rem) {
flex-direction: row;
}
}
.header__logo {
flex-shrink: 0;
inline-size: 40%;
line-height: 0;
max-inline-size: 17rem;
min-inline-size: 8rem;
position: relative;
translate: 0 -6%;
}
.header__contents {
column-gap: 1.6rem;
display: flex;
justify-content: center;
@container header (inline-size >= 110rem) {
display: contents;
}
}
.header__icon-buttons {
column-gap: 0.8rem;
display: flex;
@container header (inline-size >= 85rem) {
display: none;
}
}
.header__menu {
--_header-menu-padding: 4rem;
display: flex;
font-weight: var(--font-weight-bold);
line-height: var(--line-height-wide);
@container header (inline-size < 85rem) {
background-color: var(--color-gray-100);
color: var(--text-color);
flex-direction: column;
font-size: var(--font-size-large);
inset: 0;
overflow-y: auto;
overscroll-behavior: contain;
padding-block: var(--_header-menu-padding);
padding-inline-end: calc(4.4rem + var(--_header-menu-padding) + 3.2rem);
padding-inline-start: var(--_header-menu-padding);
position: fixed;
z-index: 2;
&:is([hidden]) {
display: none;
}
}
@container header (inline-size >= 85rem) {
background-color: var(--color-white);
block-size: 4.2rem;
border: 1px solid var(--color-gray-200);
border-radius: 99999px;
position: relative;
}
}
.header__menu-close {
inset-block-start: var(--_header-menu-padding);
inset-inline-end: var(--_header-menu-padding);
position: fixed;
@container header (inline-size >= 85rem) {
display: none;
}
}
.header__navigation {
--link-color: var(--color-steel-950);
--link-underline-color: transparent;
--link-color--engaged: var(--color-steel-950);
--link-underline-color--engaged: currentColor;
--link-display: block;
display: flex;
flex-direction: column;
row-gap: 0.8rem;
@container header (inline-size >= 85rem) {
align-items: center;
flex-direction: row;
padding-inline: 0.4rem;
position: relative;
z-index: 2;
}
}
.header__navigation-item {
position: relative;
}
.header__navigation-link {
@container header (inline-size >= 85rem) {
--link-padding-inline: 1.6rem;
--link-padding-block: calc((4.2rem - 1lh) / 2);
--link-underline-color--engaged: transparent;
}
}
.header__navigation-highlight {
background-color: var(--color-orange-300);
block-size: 4.2rem;
border-radius: 99999px;
opacity: 0;
position: absolute;
transition-property: inline-size, inset-inline-start, opacity;
transition-timing-function: ease-in-out;
translate: -1px -1px;
will-change: inline-size, inset-inline-start, opacity;
z-index: 1;
@container header (inline-size < 85rem) {
display: none;
}
}
.header__navigation-menu {
display: grid;
grid-template-columns: 100%;
margin-block-end: 2.4rem;
margin-block-start: 1.6rem;
padding-inline: 2.4rem;
row-gap: 0.8rem;
&:is([hidden]) {
display: none;
}
@container header (inline-size >= 85rem) {
background-color: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--border-radius-large);
box-shadow: var(--box-shadow-xxl);
color: var(--text-color);
inline-size: 25rem;
inset-block-start: 6.4rem;
inset-inline-start: 50%;
margin: 0;
opacity: 1;
padding: 0;
position: absolute;
row-gap: 0;
transition: opacity var(--duration-long), translate var(--duration-xx-long);
translate: -50% 0;
&::before {
background-color: var(--color-gray-200);
block-size: 1rem;
clip-path: path('M11.8.7a2 2 0 0 0-3 0L.3 10h20L11.8.7Z');
content: '';
inline-size: 2rem;
inset-block-start: -1rem;
inset-inline-start: calc(50% - 1rem);
position: absolute;
}
&::after {
background-color: var(--color-white);
block-size: 1rem;
clip-path: path('M11.8.7a2 2 0 0 0-3 0L.3 10h20L11.8.7Z');
content: '';
inline-size: 2rem;
inset-block-start: calc(-1rem + 0.1rem);
inset-inline-start: calc(50% - 1rem);
position: absolute;
}
@starting-style {
opacity: 0;
translate: -50% -0.6rem;
}
}
}
.header__navigation-menu-item {
font-size: var(--font-size-medium);
@container header (inline-size >= 85rem) {
--link-padding-inline: 1.6rem;
--link-padding-block: 0.8rem;
font-size: var(--font-size-default);
& + & {
border-block-start: 1px solid var(--color-gray-200);
}
}
}
.header__login-button {
@container header (inline-size < 85rem) {
display: none;
}
}
import { on } from 'delegated-events';
import { createFocusTrap, type FocusTrap } from 'focus-trap';
import collapse from '../../../javascripts/utils/collapse';
import moveFocus from '../../../javascripts/utils/moveFocus';
import onLostFocus from '../../../javascripts/utils/onLostFocus';
import onLoad from '../../../javascripts/utils/onLoad';
import abort from '../../../javascripts/utils/abort';
let $currentOpenLink: HTMLElement | null = null;
let currentLostFocusHandler: CallableFunction | null = null;
let focusTrap: FocusTrap | null = null;
let returnHighlight: CallableFunction | null = null;
on('click', '.header__navigation-item [aria-controls]', async (event) => {
const { currentTarget: $trigger } = event;
event.preventDefault();
const { isOpen, $target } = await collapse($trigger);
if (isOpen) {
if (currentLostFocusHandler) {
currentLostFocusHandler();
}
moveFocus($target);
currentLostFocusHandler = onLostFocus($target, () => {
collapse($trigger, false);
returnHighlight?.();
$currentOpenLink = null;
});
$currentOpenLink = $trigger.closest('.header__navigation-item')
?.querySelector<HTMLElement>('.header__navigation-link') ?? null;
} else if (currentLostFocusHandler) {
currentLostFocusHandler();
returnHighlight?.();
currentLostFocusHandler = null;
$currentOpenLink = null;
}
});
on('click', '.header [data-action="open"]', async (event) => {
const { currentTarget: $trigger } = event;
event.preventDefault();
const { $target } = await collapse($trigger, true);
focusTrap = createFocusTrap($target, {
initialFocus: '.header__navigation-item a, .header__navigation-item button',
clickOutsideDeactivates: false,
returnFocusOnDeactivate: true,
async onDeactivate() {
await collapse($trigger, false);
},
onPostDeactivate() {
focusTrap = null;
},
});
focusTrap.activate();
});
on('click', '.header [data-action="close"]', async (event) => {
event.preventDefault();
focusTrap?.deactivate();
});
onLoad<HTMLElement>('.header', ($header) => {
const resizeObserver = new ResizeObserver(() => {
focusTrap?.deactivate();
});
resizeObserver.observe($header);
const $highlight = $header.querySelector<HTMLElement>('.header__navigation-highlight') ?? abort();
const $menu = $header.querySelector('.header__menu') ?? abort();
const $currentActiveLink = $header.querySelector<HTMLElement>('.header__navigation-link [aria-current=true]');
let $currentHighlight: HTMLElement | null = $currentActiveLink;
const moveHighlight = ($target: HTMLElement | null) => {
if (!$target) {
$highlight.style.opacity = '0';
} else {
const { offsetWidth: inlineSize } = $target;
const { left: targetInlineStart } = $target.getBoundingClientRect();
const { left: menuInlineStart } = $menu.getBoundingClientRect();
$highlight.style.opacity = '1';
$highlight.style.insetInlineStart = `${targetInlineStart - menuInlineStart - 5}px`;
$highlight.style.inlineSize = `${inlineSize + 10}px`;
}
};
const highlightResizeObserver = new ResizeObserver(() => {
moveHighlight($currentHighlight);
});
moveHighlight($currentHighlight);
highlightResizeObserver.observe($menu);
returnHighlight = () => moveHighlight($currentActiveLink);
$header.querySelectorAll<HTMLElement>('.header__navigation-link').forEach(($link) => {
$link.addEventListener('mouseenter', () => {
$currentHighlight = $link;
moveHighlight($link);
});
$link.addEventListener('mouseleave', () => {
$currentHighlight = $currentActiveLink;
moveHighlight($currentOpenLink ?? $currentActiveLink);
});
});
});
No notes defined.