feat: integrated menu on mobile (closes #3)

This commit is contained in:
Corentin 2024-05-21 11:22:10 +02:00
parent e830a247b5
commit 0d28c2ffeb
6 changed files with 180 additions and 86 deletions

View File

@ -1,3 +1,5 @@
import './nav.js'
class ToggleMenuButton extends HTMLElement { class ToggleMenuButton extends HTMLElement {
connectedCallback() { connectedCallback() {
this.addEventListener('click', this.onClick.bind(this)) this.addEventListener('click', this.onClick.bind(this))

43
src/assets/js/nav.js Normal file
View File

@ -0,0 +1,43 @@
class NavBar extends HTMLElement {
connectedCallback() {
document.addEventListener("scroll", this.onScroll.bind(this))
}
onScroll(evt) {
const scrollThreshold = this.getAttribute('scroll-threshold')
if(window.scrollY > scrollThreshold) {
this.classList.add("nav-bar__scrolled")
}
else {
this.classList.remove("nav-bar__scrolled")
}
}
}
class ToggleNavBarButton extends HTMLElement {
connectedCallback() {
this.addEventListener('click', this.onClick.bind(this))
const windowsChangeEvent = ('onorientationchange' in window) ? 'orientationchange':'resize';
window.addEventListener(windowsChangeEvent, this.close.bind(this))
}
get navbar() {
const navbar = this.closest('nav-bar')
console.assert(navbar !== undefined)
return navbar
}
onClick(evt) {
this.navbar.classList.toggle('nav-bar__open')
evt.preventDefault()
}
close() {
this.navbar.classList.remove('nav-bar__open')
}
}
window.customElements.define('nav-bar', NavBar)
window.customElements.define('toggle-nav-bar-button', ToggleNavBarButton)

View File

@ -7,13 +7,13 @@ body {
color: var(--color); color: var(--color);
} }
.content { * {
margin: -60px auto 0 auto; box-sizing: border-box;
padding: 0 var(--space-small); }
max-width: 1100px;
.content {
@media ($mobile-breakpoint) { margin: 0 auto;
margin-top: 0; padding: 0 var(--space-small);
} max-width: 1100px;
} }

View File

@ -1,33 +1,36 @@
<nav class="nav" id="nav"> <nav-bar class="nav-bar" id="nav-bar">
<div class="nav--content"> <div class="nav-bar--content">
<div class="nav--menu"> <div class="nav-bar--menu">
<ul class="nav--menu-section"> <ul class="nav-bar--menu-section">
<li class="nav--menu-item"> <li class="nav-bar--menu-item">
<a href="#" class="nav--menu-link">Collective</a> <a href="#" class="nav-bar--menu-link">Collective</a>
</li> </li>
<li class="nav--menu-item"> <li class="nav-bar--menu-item">
<a href="#" class="nav--menu-link">Games</a> <a href="#" class="nav-bar--menu-link">Games</a>
</li> </li>
<li class="nav--menu-item"> <li class="nav-bar--menu-item">
<a href="#" class="nav--menu-link">News</a> <a href="#" class="nav-bar--menu-link">News</a>
</li> </li>
<li class="nav--menu-item"> <li class="nav-bar--menu-item">
<a href="#" class="nav--menu-link">Contact</a> <a href="#" class="nav-bar--menu-link">Contact</a>
</li> </li>
</ul> </ul>
<ul class="nav--menu-section"> <ul class="nav-bar--menu-section">
<li class="nav--menu-item"> <li class="nav-bar--menu-item">
<a href="#" class="nav--menu-link">Itch.io</a> <a href="#" class="nav-bar--menu-link">Itch.io</a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="nav--title"> <div class="nav-bar--brand">
<img class="nav--logo" src="img/nav-logo.png" title="Frog Collective"></img> <div class="nav-bar--logo-wrapper">
<img class="nav-bar--logo" src="/img/nav-logo.png"></img>
</div>
</div> </div>
<toggle-menu-button target="nav" class="nav--toggle-button"> <toggle-nav-bar-button class="nav-bar--toggle-button">
<s class="bar"></s> <s class="bar"></s>
<s class="bar"></s> <s class="bar"></s>
</toggle-menu-button> <s class="bar"></s>
</toggle-nav-bar-button>
</div> </div>
</nav> </nav-bar>

View File

@ -1,24 +1,67 @@
.nav { .nav-bar {
--background: var(--dark); --background: var(--dark);
--mobile-nav-height: 47px;
display: grid;
position: sticky; position: sticky;
top: 0; top: 0;
overflow: hidden; height: 82px;
padding: 0 var(--space-small); padding: 0;
&--title { grid-template-columns: auto minmax(0px, var(--width)) auto;
grid-area: 1 / 1 / 3 / 2; background: var(--background);
background: var(--background); box-shadow: var(--box-shadow);
padding: var(--space-small);
box-shadow: var(--box-shadow); @media ($mobile-breakpoint) {
height: var(--mobile-nav-height);
margin-bottom: 65px;
} }
&--content { &--content {
max-width: var(--width); margin: 0;
margin: 0 auto;
display: grid; display: grid;
grid-template-columns: auto 1fr auto; grid-area: 1 / 2 / 2 / 3;
grid-template-rows: auto auto; grid-template-columns: 155px 1fr auto;
}
&--brand {
position: relative;
grid-area: 1 / 1 / 2 / 2;
padding: 0;
transition: margin-top 0.2s ease-out;
@media ($mobile-breakpoint) {
width: 100px;
}
}
&__scrolled &--brand {
margin-top: -80px;
}
@media ($mobile-breakpoint) {
&__scrolled &--brand, &__open &--brand {
margin-top: -52px;
}
}
&--logo-wrapper {
width: 100%;
background: var(--dark);
position: absolute;
display: grid;
box-shadow: var(--box-shadow);
padding: var(--space-small);
transition: padding-bottom 0.2s ease-out;
}
&__scrolled &--logo-wrapper {
padding-bottom: 0;
box-shadow: none;
}
&--logo {
width: 100%;
} }
&--menu { &--menu {
@ -28,13 +71,10 @@
display: grid; display: grid;
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto;
box-shadow: var(--box-shadow);
/* make the nav background full page width */
margin: 0 -50vw;
padding: 0 50vw;
@media ($mobile-breakpoint) { @media ($mobile-breakpoint) {
position: absolute;
top: var(--mobile-nav-height);
width: 100%;
max-height: 0; max-height: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -42,6 +82,10 @@
} }
} }
&__open &--menu {
max-height: 230px;
}
&--menu-section { &--menu-section {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -50,6 +94,10 @@
margin: 0; margin: 0;
@media ($mobile-breakpoint) { @media ($mobile-breakpoint) {
flex-direction: column; flex-direction: column;
&:not(:last-child) {
border-bottom: 2px solid var(--primary-color);
}
} }
} }
@ -57,19 +105,26 @@
list-style: none; list-style: none;
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
} }
&--menu-link { &--menu-link {
flex-grow: 1; flex-grow: 1;
padding: var(--space-large) var(--space-small); display: flex;
justify-content: center;
align-items: center;
font-family: Knewave; font-family: Knewave;
font-size: var(--fz-4); font-size: var(--fz-4);
color: var(--primary-color); color: var(--primary-color);
text-transform: uppercase; text-transform: uppercase;
text-align: center;
text-decoration: none; text-decoration: none;
@media ($mobile-breakpoint) {
padding: var(--space-small);
justify-content: start;
}
&:hover { &:hover {
background: var(--primary-color); background: var(--primary-color);
color: var(--on-primary); color: var(--on-primary);
@ -77,50 +132,41 @@
} }
&--toggle-button { &--toggle-button {
display: none;
cursor: pointer;
margin: 0 var(--space-small);
align-self: center;
grid-area: 1 / 3 / 2 / 4;
@media ($mobile-breakpoint) { @media ($mobile-breakpoint) {
display: block; display: block;
} }
}
&__open &--menu {
@media ($mobile-breakpoint) {
max-height: 100vh;
}
}
}
toggle-menu-button {
width: 34px;
height: 34px;
position: absolute;
top: 0;
right: 0;
display: none;
cursor: pointer;
.bar {
display: block;
background-color: #777;
width: 20px;
height: 2px;
border-radius: 100px;
position: absolute;
top: 18px;
right: 7px;
transition: all 0.5s;
&:first-child {
transform: translateY(-6px);
}
}
.nav__open & {
.bar { .bar {
transform: rotate(45deg); display: block;
position: initial;
background-color: var(--primary-color);
width: 25px;
height: 3px;
transition: all 0.3s ease-out;
margin: 5px 0;
}
}
&__open &--toggle-button {
.bar {
opacity: 0;
&:first-child { &:first-child {
transform: rotate(-45deg); opacity: 1;
transform: translateY(8px) rotate(-45deg);
}
&:last-child {
opacity: 1;
transform: translateY(-8px) rotate(45deg);
} }
} }
} }
} }

View File

@ -8,7 +8,7 @@
<link href="https://fonts.googleapis.com/css2?family=Knewave&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Knewave&display=swap" rel="stylesheet">
<link rel="stylesheet" href="//brick.freetls.fastly.net/Montserrat:300"> <link rel="stylesheet" href="//brick.freetls.fastly.net/Montserrat:300">
<link rel="stylesheet" href="/style.css"/> <link rel="stylesheet" href="/style.css"/>
<script type="module" src="index.js"></script> <script type="module" src="js/index.js"></script>
</head> </head>
<body> <body>
{% include "lib/nav.html" %} {% include "lib/nav.html" %}