184 lines
4.6 KiB
JavaScript
184 lines
4.6 KiB
JavaScript
|
|
const hamburgerMenu = document.createElement('template')
|
|
hamburgerMenu.innerHTML = `
|
|
<style>
|
|
*{
|
|
padding: 0;
|
|
margin: 0;
|
|
-webkit-box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
}
|
|
:host{
|
|
display: flex;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow-y: auto;
|
|
scrollbar-width: thin;
|
|
--padding: 0 0 3rem 0;
|
|
--backdrop-color: rgba(0,0,0,0.5);
|
|
}
|
|
.backdrop{
|
|
position: fixed;
|
|
}
|
|
.side-nav{
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
}
|
|
.hide{
|
|
display: none !important;
|
|
}
|
|
@media screen and (max-width: 640px){
|
|
:host{
|
|
position: fixed;
|
|
z-index: 10;
|
|
}
|
|
.side-nav{
|
|
height: 100%;
|
|
overflow-y: auto;
|
|
width: calc(100% - 4rem);
|
|
transition: transform 0.3s;
|
|
background-color: rgba(var(--background-color, (255, 255, 255)), 1);
|
|
box-shadow: 0.5rem 0 2rem rgba(0,0,0, 0.1);
|
|
z-index: 1;
|
|
}
|
|
.side-nav:not(.reveal){
|
|
transform: translateX(-100%);
|
|
}
|
|
.reveal{
|
|
transform: none;
|
|
}
|
|
.backdrop{
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background-color: var(--backdrop-color);
|
|
-webkit-transition: opacity 0.3s;
|
|
-o-transition: opacity 0.3s;
|
|
transition: opacity 0.3s;
|
|
}
|
|
}
|
|
@media screen and (min-width: 640px){
|
|
.backdrop{
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
@media (any-hover: hover){
|
|
::-webkit-scrollbar{
|
|
width: 0.5rem;
|
|
}
|
|
::-webkit-scrollbar-thumb{
|
|
border-radius: 1rem;
|
|
background: rgba(var(--text-color, (17,17,17)), 0.3);
|
|
&:hover{
|
|
background: rgba(var(--text-color, (17,17,17)), 0.5);
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
<section class="backdrop hide"></section>
|
|
<nav class="side-nav">
|
|
<slot></slot>
|
|
</nav>
|
|
`
|
|
class HamburgerMenu extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.attachShadow({ mode: 'open' }).append(hamburgerMenu.content.cloneNode(true))
|
|
|
|
this.resumeScrolling = this.resumeScrolling.bind(this)
|
|
this.open = this.open.bind(this)
|
|
this.close = this.close.bind(this)
|
|
|
|
this.sideNav = this.shadowRoot.querySelector('.side-nav')
|
|
this.backdrop = this.shadowRoot.querySelector('.backdrop')
|
|
this.isOpen = false
|
|
|
|
this.animeOptions = {
|
|
duration: 300,
|
|
easing: 'ease'
|
|
}
|
|
}
|
|
static get observedAttributes() {
|
|
return ['open'];
|
|
}
|
|
resumeScrolling() {
|
|
const scrollY = document.body.style.top;
|
|
window.scrollTo(0, parseInt(scrollY || '0') * -1);
|
|
setTimeout(() => {
|
|
document.body.style.overflow = 'auto';
|
|
document.body.style.top = 'initial'
|
|
}, 300);
|
|
}
|
|
|
|
open() {
|
|
if (this.isOpen) return
|
|
document.body.style.overflow = 'hidden';
|
|
document.body.style.top = `-${window.scrollY}px`
|
|
this.classList.remove('hide')
|
|
this.sideNav.classList.add('reveal')
|
|
this.backdrop.classList.remove('hide')
|
|
this.backdrop.animate([
|
|
{
|
|
opacity: 0
|
|
},
|
|
{
|
|
opacity: 1
|
|
},
|
|
],
|
|
this.animeOptions)
|
|
.onfinish = () => {
|
|
this.isOpen = true
|
|
this.setAttribute('open', '')
|
|
}
|
|
|
|
}
|
|
close() {
|
|
if (!this.isOpen) return
|
|
this.sideNav.classList.remove('reveal')
|
|
this.backdrop.animate([
|
|
{
|
|
opacity: 1
|
|
},
|
|
{
|
|
opacity: 0
|
|
},
|
|
],
|
|
this.animeOptions)
|
|
.onfinish = () => {
|
|
this.backdrop.classList.add('hide')
|
|
this.classList.add('hide')
|
|
this.isOpen = false
|
|
this.removeAttribute('open')
|
|
}
|
|
}
|
|
connectedCallback() {
|
|
this.backdrop.addEventListener('click', this.close)
|
|
const resizeObserver = new ResizeObserver(entries => {
|
|
if (window.innerWidth < 640 && this.isOpen) {
|
|
this.classList.remove('hide')
|
|
}
|
|
else {
|
|
this.classList.add('hide')
|
|
}
|
|
if (window.innerWidth > 640) {
|
|
this.classList.remove('hide')
|
|
}
|
|
});
|
|
resizeObserver.observe(this)
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
this.backdrop.removeEventListener('click', this.close)
|
|
}
|
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
if (name === 'open') {
|
|
if (this.hasAttribute('open')) {
|
|
this.open()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
window.customElements.define('hamburger-menu', HamburgerMenu); |