127 lines
2.3 KiB
Svelte
127 lines
2.3 KiB
Svelte
<script>
|
|
import {onMount} from "svelte";
|
|
import Icon from "../utils/Icon.svelte";
|
|
|
|
let open = false;
|
|
let locked = false;
|
|
|
|
function stopPropagation(e) {
|
|
e.stopPropagation();
|
|
}
|
|
|
|
function openMenu() {
|
|
if (locked) return;
|
|
open = true;
|
|
}
|
|
|
|
function closeMenu() {
|
|
if (locked) return;
|
|
open = false;
|
|
}
|
|
|
|
function lock() {
|
|
locked = true;
|
|
window.requestAnimationFrame(() => {
|
|
locked = false;
|
|
});
|
|
}
|
|
|
|
let nav;
|
|
onMount(() => {
|
|
nav.querySelectorAll('ul li > a, ul li > form > button')
|
|
.forEach(el => {
|
|
el.addEventListener('focus', () => {
|
|
openMenu();
|
|
});
|
|
el.addEventListener('blur', () => {
|
|
closeMenu();
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "../../scss/vars";
|
|
@import "../../scss/helpers";
|
|
|
|
nav {
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
padding: 16px;
|
|
|
|
font-size: 16px;
|
|
|
|
@include medium-le {
|
|
z-index: 1;
|
|
position: fixed;
|
|
padding: 16px;
|
|
|
|
@include surface(3);
|
|
|
|
transition: transform ease-out 150ms;
|
|
|
|
&:not(.open) {
|
|
transform: translateX(-100%);
|
|
}
|
|
}
|
|
|
|
ul {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
align-items: stretch;
|
|
width: 100%;
|
|
height: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
|
|
@include large-ge {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
button {
|
|
width: #{$headerHeight - 16px};
|
|
height: #{$headerHeight - 16px};
|
|
margin: 8px;
|
|
padding: 8px;
|
|
border: 0;
|
|
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
background: var(--surface);
|
|
color: var(--on-surface);
|
|
|
|
border-radius: $headerHeight;
|
|
|
|
:global(.icon) {
|
|
--icon-size: 28px;
|
|
margin: 0;
|
|
}
|
|
|
|
@include large-ge {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<svelte:window on:click={closeMenu}/>
|
|
|
|
<button on:click={openMenu} on:click={stopPropagation}
|
|
on:focus={openMenu} on:blur={closeMenu}
|
|
tabindex="0" aria-label="Toggle menu">
|
|
<Icon name="menu"/>
|
|
</button>
|
|
|
|
<nav class:open on:click={openMenu} on:click={stopPropagation} on:mousedown={lock} bind:this={nav}
|
|
aria-hidden={open ? 'false' : 'true'}>
|
|
<ul>
|
|
<slot/>
|
|
</ul>
|
|
</nav>
|