Make navigation mobile-friendly

This commit is contained in:
Ben Visness 2024-07-05 12:15:32 -05:00
parent 5f2df52e1d
commit 352a102a6a
6 changed files with 187 additions and 84 deletions

View File

@ -8290,6 +8290,7 @@ header {
background-color: var(--bg-header); background-color: var(--bg-header);
border-bottom-style: solid; border-bottom-style: solid;
border-bottom-width: var(--border-header); border-bottom-width: var(--border-header);
position: relative;
} }
header .hmn-logo { header .hmn-logo {
font-family: "MohaveHMN", sans-serif; font-family: "MohaveHMN", sans-serif;
@ -8306,10 +8307,39 @@ header .avatar {
width: 1.8rem; width: 1.8rem;
height: 1.8rem; height: 1.8rem;
} }
header .header-nav {
position: absolute;
top: calc(100% + 1px);
left: 0;
width: 100%;
background-color: var(--bg-header);
z-index: 100;
}
@media screen and (min-width: 35em) {
header .header-nav {
display: flex;
flex-direction: column;
position: static;
width: auto;
flex-direction: row;
align-items: center;
background-color: none;
}
}
header .header-nav > a, header .header-nav > a,
header .header-nav > .root-item > a { header .header-nav > .root-item > a {
display: block;
padding: var(--spacing-3); padding: var(--spacing-3);
border-bottom: var(--border-header) solid var(--border-color);
}
header .header-nav > a:not(.db),
header .header-nav > .root-item > a:not(.db) {
display: block;
}
@media screen and (min-width: 35em) {
header .header-nav > a,
header .header-nav > .root-item > a {
border-bottom: none;
}
} }
header .root-item { header .root-item {
position: relative; position: relative;
@ -8317,22 +8347,33 @@ header .root-item {
header .submenu { header .submenu {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: absolute; }
z-index: 100; @media screen and (min-width: 35em) {
min-width: 8rem; header .submenu {
background-color: var(--bg-header); position: absolute;
border-style: solid; z-index: 100;
border-width: var(--border-header); min-width: 8rem;
border-top-width: 0; background-color: var(--bg-header);
top: 100%; border-style: solid;
border-width: var(--border-header);
border-top-width: 0;
top: 100%;
}
} }
header .submenu > a { header .submenu > a {
padding: var(--spacing-2) var(--spacing-3); padding: var(--spacing-2) var(--spacing-3) var(--spacing-2) var(--spacing-4);
display: block; display: block;
white-space: nowrap; white-space: nowrap;
z-index: 1; z-index: 1;
border-bottom: var(--border-header) solid var(--border-color);
} }
header .root-item:not(:hover):not(.clicked) > .submenu { @media screen and (min-width: 35em) {
header .submenu > a {
padding: var(--spacing-2) var(--spacing-3);
border-bottom: none;
}
}
header .root-item:not(:hover):not(.clicked) .submenu {
display: none; display: none;
} }
header .root-item.clicked .svgicon { header .root-item.clicked .svgicon {

View File

@ -120,6 +120,7 @@ header {
background-color: var(--bg-header); background-color: var(--bg-header);
border-bottom-style: solid; border-bottom-style: solid;
border-bottom-width: var(--border-header); border-bottom-width: var(--border-header);
position: relative;
.hmn-logo { .hmn-logo {
font-family: 'MohaveHMN', sans-serif; font-family: 'MohaveHMN', sans-serif;
@ -141,11 +142,35 @@ header {
} }
.header-nav { .header-nav {
position: absolute;
top: calc(100% + 1px);
left: 0;
width: 100%;
background-color: var(--bg-header);
z-index: 100;
@media screen and (min-width: 35em) {
display: flex;
flex-direction: column;
position: static;
width: auto;
flex-direction: row;
align-items: center;
background-color: none;
}
>a, >a,
>.root-item>a { >.root-item>a {
display: block; &:not(.db) {
display: block;
}
padding: var(--spacing-3); padding: var(--spacing-3);
border-bottom: var(--border-header) solid var(--border-color);
@media screen and (min-width: 35em) {
border-bottom: none;
}
} }
} }
@ -156,25 +181,34 @@ header {
.submenu { .submenu {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: absolute;
z-index: 100; @media screen and (min-width: 35em) {
min-width: 8rem; position: absolute;
background-color: var(--bg-header); z-index: 100;
border-style: solid; min-width: 8rem;
border-width: var(--border-header); background-color: var(--bg-header);
border-top-width: 0; border-style: solid;
top: 100%; border-width: var(--border-header);
border-top-width: 0;
top: 100%;
}
>a { >a {
padding: var(--spacing-2) var(--spacing-3); padding: var(--spacing-2) var(--spacing-3) var(--spacing-2) var(--spacing-4);
display: block; display: block;
white-space: nowrap; white-space: nowrap;
z-index: 1; z-index: 1;
border-bottom: var(--border-header) solid var(--border-color);
@media screen and (min-width: 35em) {
padding: var(--spacing-2) var(--spacing-3);
border-bottom: none;
}
} }
} }
.root-item { .root-item {
&:not(:hover):not(.clicked)>.submenu { &:not(:hover):not(.clicked) .submenu {
display: none; display: none;
} }

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-3,-4)">
<path d="M3,4L21,4L21,6L3,6L3,4ZM3,11L21,11L21,13L3,13L3,11ZM3,18L21,18L21,20L3,20L3,18Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -1,11 +1,11 @@
<header id="site-header" class="flex flex-row items-stretch link-normal"> <header id="site-header" class="flex flex-row items-stretch link-normal">
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo flex-shrink-0"> <a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo flex-shrink-0">
Handmade Handmade
</a> </a>
<div class="flex-grow-1 flex-shrink-1"></div> <div class="flex-grow-1 flex-shrink-1"></div>
<div class="header-nav flex flex-row items-center lh-solid f6"> <div class="header-nav lh-solid f6 dn" id="header_nav">
<a href="{{ .Header.ProjectIndexUrl }}">Projects</a> <a href="{{ .Header.ProjectIndexUrl }}">Projects</a>
<a href="{{ .Header.JamsUrl }}">Jams</a> <a href="{{ .Header.JamsUrl }}">Jams</a>
<div class="root-item"> <div class="root-item">
<a aria-expanded="false" aria-controls="events-submenu" class="menu-dropdown-js" href="#"> <a aria-expanded="false" aria-controls="events-submenu" class="menu-dropdown-js" href="#">
Events <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div> Events <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div>
@ -17,7 +17,7 @@
</div> </div>
<div class="root-item"> <div class="root-item">
<a aria-expanded="false" aria-controls="resource-submenu" class="menu-dropdown-js" href="#"> <a aria-expanded="false" aria-controls="resource-submenu" class="menu-dropdown-js" href="#">
Resources <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div> Resources <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div>
</a> </a>
<div class="submenu" id="resource-submenu"> <div class="submenu" id="resource-submenu">
<a href="{{ .Header.ForumsUrl }}">Forums</a> <a href="{{ .Header.ForumsUrl }}">Forums</a>
@ -29,7 +29,7 @@
<a href="https://guide.handmadehero.org/hmcon/">HandmadeCon</a> <a href="https://guide.handmadehero.org/hmcon/">HandmadeCon</a>
</div> </div>
</div> </div>
<div class="root-item"> <div class="root-item">
<a aria-expanded="false" aria-controls="about-submenu" class="menu-dropdown-js" href="#"> <a aria-expanded="false" aria-controls="about-submenu" class="menu-dropdown-js" href="#">
About <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div> About <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div>
</a> </a>
@ -38,67 +38,84 @@
<a href="{{ .Header.AboutUrl }}">About the Team</a> <a href="{{ .Header.AboutUrl }}">About the Team</a>
</div> </div>
</div> </div>
</div> <div class="root-item db dn-ns">
<div class="root-item f6"> <a aria-expanded="false" aria-controls="profile-submenu" class="menu-dropdown-js" href="#">
<a class="db {{ if .User }}pv2 ph3{{ else }}pa3{{ end }} lh-solid flex f6 {{ if not .User }}bl{{ end }}" href="{{ or .Header.UserProfileUrl .LoginPageUrl }}"> User <div class="menu-chevron svgicon-lite">{{ svg "chevron-down" }}</div>
</a>
<div class="submenu" id="profile-submenu-mobile">
<a href="{{ .Header.UserProfileUrl }}">Profile</a>
<a href="{{ .Header.UserSettingsUrl }}">Settings</a>
</div>
</div>
<a class="db dn-ns" href="{{ .Header.LogoutUrl }}">Log Out</a>
</div>
<div class="root-item f6 {{ if not .User }}bl-ns{{ end }} flex items-stretch">
<a class="db pl3 pr2 pr3-ns lh-solid flex items-center" href="{{ or .Header.UserProfileUrl .LoginPageUrl }}">
{{ with .User }} {{ with .User }}
<img class="avatar avatar-user" src="{{ .AvatarUrl }}"> <img class="avatar avatar-user" src="{{ .AvatarUrl }}">
{{ else }} {{ else }}
Log In Log In
{{ end }} {{ end }}
</a> </a>
<a class="pl2 pr3 flex dn-ns items-center" href="#" id="mobile_menu">
{{ svg "menu" }}
</a>
{{ if .User }} {{ if .User }}
<div class="dn db-ns">
<div class="submenu right-0" id="profile-submenu"> <div class="submenu right-0" id="profile-submenu">
<a href="{{ .Header.UserProfileUrl }}">Profile</a> <a href="{{ .Header.UserProfileUrl }}">Profile</a>
<a href="{{ .Header.UserSettingsUrl }}">Settings</a> <a href="{{ .Header.UserSettingsUrl }}">Settings</a>
<a href="{{ .Header.LogoutUrl }}">Log Out</a> <a href="{{ .Header.LogoutUrl }}">Log Out</a>
</div> </div>
</div>
{{ end }} {{ end }}
</div> </div>
</header> </header>
{{ if and .Header.BannerEvent (not .Header.SuppressBanners) }} {{ if and .Header.BannerEvent (not .Header.SuppressBanners) }}
{{ with .Header.BannerEvent }} {{ with .Header.BannerEvent }}
{{ if eq .Slug "VJ2024" }} {{ if eq .Slug "VJ2024" }}
<a <a
class="db tc pv2 link-normal c-white" class="db tc pv2 link-normal c-white"
style="background: linear-gradient(to bottom right, #20dddd, #007178)" style="background: linear-gradient(to bottom right, #20dddd, #007178)"
href="{{ .Url }}" href="{{ .Url }}"
> >
<b>Visibility Jam.</b> <b>Visibility Jam.</b>
July 19-21, 2024. July 19-21, 2024.
{{ if gt .DaysUntilEnd 0 }} {{ if gt .DaysUntilEnd 0 }}
{{ if eq .DaysUntilStart 0 }} {{ if eq .DaysUntilStart 0 }}
<b>Happening now.</b> <b>Happening now.</b>
{{ else if eq .DaysUntilStart 1 }} {{ else if eq .DaysUntilStart 1 }}
<b>Starting tomorrow.</b> <b>Starting tomorrow.</b>
{{ else }} {{ else }}
<b>In {{ .DaysUntilStart }} days.</b> <b>In {{ .DaysUntilStart }} days.</b>
{{ end }} {{ end }}
{{ else }} {{ else }}
<b>See the results.</b> <b>See the results.</b>
{{ end }} {{ end }}
</a> </a>
{{ end }} {{ end }}
{{ end }} {{ end }}
{{ end }} {{ end }}
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const header = document.querySelector('#site-header'); const header = document.querySelector("#site-header");
const headerNav = document.querySelector("#header_nav");
const mobileMenuButton = document.querySelector("#mobile_menu");
// set up dropdown stuff for mobile / touch // set up dropdown stuff for mobile / touch
{ {
const rootItems = header.querySelectorAll('.root-item'); const rootItems = header.querySelectorAll('.root-item');
function clearDropdowns() { function clearDropdowns() {
for (const item of rootItems) { for (const item of rootItems) {
item.classList.remove('clicked'); item.classList.remove('clicked');
} }
} }
function clickDropdown(el) { function clickDropdown(el) {
header.classList.add('clicked'); header.classList.add('clicked');
if (el.classList.contains('clicked')) { if (el.classList.contains('clicked')) {
clearDropdowns(); clearDropdowns();
} else { } else {
@ -106,7 +123,7 @@
el.classList.add('clicked'); el.classList.add('clicked');
} }
} }
for (const item of rootItems) { for (const item of rootItems) {
if (item.querySelector('.submenu')) { if (item.querySelector('.submenu')) {
item.addEventListener('click', e => { item.addEventListener('click', e => {
@ -116,27 +133,33 @@
} }
} }
} }
// dropdown accessiblity // dropdown accessiblity
{ {
const dropdowns = document.querySelectorAll('.menu-dropdown-js'); const dropdowns = document.querySelectorAll('.menu-dropdown-js');
for(let i = 0; i < dropdowns.length; i++) { for(let i = 0; i < dropdowns.length; i++) {
let dropdown = dropdowns[i]; let dropdown = dropdowns[i];
dropdown.addEventListener('click', e => { dropdown.addEventListener('click', e => {
e.preventDefault(); e.preventDefault();
for(let j = 0; j < dropdowns.length; j++){ for(let j = 0; j < dropdowns.length; j++){
let each = dropdowns[j]; let each = dropdowns[j];
if(each != dropdown){ if(each != dropdown){
each.setAttribute("aria-expanded", false); each.setAttribute("aria-expanded", false);
} }
} }
// getAttribute returns a string so we have to do it this way // getAttribute returns a string so we have to do it this way
var toSetTo = dropdown.getAttribute("aria-expanded") == "false" ? "true" : "false"; var toSetTo = dropdown.getAttribute("aria-expanded") == "false" ? "true" : "false";
dropdown.setAttribute("aria-expanded", toSetTo); dropdown.setAttribute("aria-expanded", toSetTo);
console.log(dropdown); console.log(dropdown);
}); });
} }
} }
mobileMenuButton.addEventListener("click", e => {
e.preventDefault();
e.stopPropagation();
headerNav.classList.toggle("dn");
});
}); });
</script> </script>

View File

@ -18,7 +18,7 @@
<div class="jam-grid g3"> <div class="jam-grid g3">
<a href="{{ .VJ2024Url }}"> <a href="{{ .VJ2024Url }}">
<div class="overflow-hidden flex"> <div class="overflow-hidden flex">
<img src="{{ static "visjam2024/2024VJTwitterCard.png" }}"> <img src="{{ static "visjam2024/TwitterCard.png" }}">
</div> </div>
</a> </a>
<a href="{{ .LJ2024Url }}"> <a href="{{ .LJ2024Url }}">

View File

@ -85,7 +85,7 @@
<div class="flex justify-center pa3"> <div class="flex justify-center pa3">
<div class="w-100 mw-site flex g3"> <div class="w-100 mw-site flex g3">
<!-- Sidebar --> <!-- Sidebar -->
<div class="w5 flex flex-column g2 flex-shrink-0"> <div class="w5 dn flex-ns flex-column g2 flex-shrink-0">
{{ if .User }} {{ if .User }}
<div class="sidebar-card bg3 link-normal"> <div class="sidebar-card bg3 link-normal">
<div onclick="collapse(event)" class="pa3 flex justify-between items-center pointer"> <div onclick="collapse(event)" class="pa3 flex justify-between items-center pointer">