UX improvements
parent
09cefeb12d
commit
eca4da86c3
|
@ -16,11 +16,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<nav>
|
{{ partial "nav.html" . }}
|
||||||
<ul>{{ range .Site.Menus.main }}
|
|
||||||
<li><a href="{{ .URL | relURL }}">{{ .Name }}</a></li>{{ end }}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</header>
|
</header>
|
||||||
{{ block "main" . }} {{ end }}
|
{{ block "main" . }} {{ end }}
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script src="/js/clicky-menus.js"></script>
|
||||||
|
<nav id="navigation">
|
||||||
|
<ul class="clicky-menu no-js">
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
<li><a href="/about">About</a></li>
|
||||||
|
<li><a href="https://acefox.life" rel="me">Blog</a></li>
|
||||||
|
<li><a href="#">Projects</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/commissions">Art</a></li>
|
||||||
|
<li><a href="/programs">Programs</a></li>
|
||||||
|
<li><a href="/recipe">Recipes</a></li>
|
||||||
|
<li><a href="/translations">Translations</a></li>
|
||||||
|
</ul></li>
|
||||||
|
<li><a href="/system">System Reference</a></li>
|
||||||
|
<li><a href="/links">Links</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
|
@ -2,6 +2,9 @@ html {
|
||||||
font-family: var(--font);
|
font-family: var(--font);
|
||||||
}
|
}
|
||||||
article, hr, footer {
|
article, hr, footer {
|
||||||
max-width: 40em;
|
width: 48em;
|
||||||
margin: 0 auto;
|
margin-left: calc(3em / 5);
|
||||||
|
}
|
||||||
|
article p {
|
||||||
|
text-indent: 3em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
:root {
|
:root {
|
||||||
--font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
--font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||||
--font-size: 14pt;
|
--font-size: 14pt;
|
||||||
|
/* for whatever reason, this is how wide a character is. 1em is wider. */
|
||||||
|
--char-width: calc(3em / 5);
|
||||||
|
|
||||||
/* colours */
|
/* colours */
|
||||||
--normal-red: #B00;
|
--normal-red: #B00;
|
||||||
|
@ -29,10 +31,12 @@
|
||||||
--bold: var(--bright-white);
|
--bold: var(--bright-white);
|
||||||
--italic: var(--normal-purple);
|
--italic: var(--normal-purple);
|
||||||
}
|
}
|
||||||
body {
|
html {
|
||||||
background-color: var(--terminal-bg);
|
background-color: var(--terminal-bg);
|
||||||
color: var(--terminal-fg);
|
color: var(--terminal-fg);
|
||||||
font-size: var(--font-size);
|
font-size: var(--font-size);
|
||||||
|
}
|
||||||
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
@ -63,33 +67,48 @@ a:visited {
|
||||||
nav a {
|
nav a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
nav a:link, nav a:visited, nav {
|
nav button {
|
||||||
|
font-family: var(--font);
|
||||||
|
font-size: var(--font-size);
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
nav a:link, nav a:visited, nav, nav button {
|
||||||
color: var(--normal-black);
|
color: var(--normal-black);
|
||||||
background-color: var(--normal-white);
|
background-color: var(--normal-white);
|
||||||
}
|
}
|
||||||
nav a:hover, nav a:active, nav a:visited:hover {
|
nav a:hover, nav a:active, nav a:visited:hover, nav button:hover {
|
||||||
color: var(--bright-white);
|
color: var(--bright-white);
|
||||||
background-color: var(--normal-black);
|
background-color: var(--normal-black);
|
||||||
}
|
}
|
||||||
nav > ul {
|
nav > ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
nav li {
|
nav li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 1em;
|
margin: 0 var(--char-width);
|
||||||
margin-right: 1em;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
article, hr, footer {
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: 2ex;
|
}
|
||||||
margin-bottom: 2ex;
|
nav li > ul {
|
||||||
margin-left: 2em;
|
position: absolute;
|
||||||
margin-right: 2em;
|
padding: 12px 0;
|
||||||
|
background-color: var(--normal-white);
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
nav li > ul li {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
nav li:hover.no-js > ul {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
nav li:focus-within.no-js > ul { /* separate from above for older browsers. */
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
/* JavaScript menus */
|
||||||
|
nav ul[aria-hidden="false"] {
|
||||||
|
visibility: visible;
|
||||||
}
|
}
|
||||||
article ul {
|
article ul {
|
||||||
list-style-type: '- ';
|
list-style-type: '- ';
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
/**
|
||||||
|
* Object for creating click-triggered navigation submenus
|
||||||
|
*
|
||||||
|
* Thanks for the inspiration:
|
||||||
|
* - https://www.lottejackson.com/learning/a-reusable-javascript-toggle-pattern
|
||||||
|
* - https://codepen.io/lottejackson/pen/yObQRM
|
||||||
|
*
|
||||||
|
* from https://github.com/mrwweb/clicky-menus
|
||||||
|
*/
|
||||||
|
|
||||||
|
( function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const ClickyMenus = function( menu ) {
|
||||||
|
// DOM element(s)
|
||||||
|
const container = menu.parentElement;
|
||||||
|
let currentMenuItem,
|
||||||
|
i,
|
||||||
|
len;
|
||||||
|
|
||||||
|
this.init = function() {
|
||||||
|
menuSetup();
|
||||||
|
document.addEventListener( 'click', closeOpenMenu );
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===================================================
|
||||||
|
= Menu Open / Close Functions =
|
||||||
|
===================================================*/
|
||||||
|
function toggleOnMenuClick( e ) {
|
||||||
|
const button = e.currentTarget;
|
||||||
|
|
||||||
|
// close open menu if there is one
|
||||||
|
if ( currentMenuItem && button !== currentMenuItem ) {
|
||||||
|
toggleSubmenu( currentMenuItem );
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSubmenu( button );
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSubmenu( button ) {
|
||||||
|
const submenu = document.getElementById( button.getAttribute( 'aria-controls' ) );
|
||||||
|
|
||||||
|
if ( 'true' === button.getAttribute( 'aria-expanded' ) ) {
|
||||||
|
button.setAttribute( 'aria-expanded', false );
|
||||||
|
submenu.setAttribute( 'aria-hidden', true );
|
||||||
|
currentMenuItem = false;
|
||||||
|
} else {
|
||||||
|
button.setAttribute( 'aria-expanded', true );
|
||||||
|
submenu.setAttribute( 'aria-hidden', false );
|
||||||
|
preventOffScreenSubmenu( submenu );
|
||||||
|
currentMenuItem = button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function preventOffScreenSubmenu( submenu ) {
|
||||||
|
const screenWidth = window.innerWidth ||
|
||||||
|
document.documentElement.clientWidth ||
|
||||||
|
document.body.clientWidth,
|
||||||
|
parent = submenu.offsetParent,
|
||||||
|
menuLeftEdge = parent.getBoundingClientRect().left,
|
||||||
|
menuRightEdge = menuLeftEdge + submenu.offsetWidth;
|
||||||
|
|
||||||
|
if ( menuRightEdge + 32 > screenWidth ) { // adding 32 so it's not too close
|
||||||
|
submenu.classList.add( 'sub-menu--right' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOnEscKey( e ) {
|
||||||
|
if ( 27 === e.keyCode ) {
|
||||||
|
// we're in a submenu item
|
||||||
|
if ( null !== e.target.closest( 'ul[aria-hidden="false"]' ) ) {
|
||||||
|
currentMenuItem.focus();
|
||||||
|
toggleSubmenu( currentMenuItem );
|
||||||
|
|
||||||
|
// we're on a parent item
|
||||||
|
} else if ( 'true' === e.target.getAttribute( 'aria-expanded' ) ) {
|
||||||
|
toggleSubmenu( currentMenuItem );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOpenMenu( e ) {
|
||||||
|
if ( currentMenuItem && ! e.target.closest( '#' + container.id ) ) {
|
||||||
|
toggleSubmenu( currentMenuItem );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================
|
||||||
|
= Modify Menu Markup & Bind Listeners =
|
||||||
|
=============================================================*/
|
||||||
|
function menuSetup() {
|
||||||
|
menu.classList.remove( 'no-js' );
|
||||||
|
const submenuSelector = 'clickySubmenuSelector' in menu.dataset ? menu.dataset.clickySubmenuSelector : 'ul';
|
||||||
|
|
||||||
|
menu.querySelectorAll( submenuSelector ).forEach( ( submenu ) => {
|
||||||
|
const menuItem = submenu.parentElement;
|
||||||
|
|
||||||
|
if ( 'undefined' !== typeof submenu ) {
|
||||||
|
const button = convertLinkToButton( menuItem );
|
||||||
|
|
||||||
|
setUpAria( submenu, button );
|
||||||
|
|
||||||
|
// bind event listener to button
|
||||||
|
button.addEventListener( 'click', toggleOnMenuClick );
|
||||||
|
menu.addEventListener( 'keyup', closeOnEscKey );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Why do this? See https://justmarkup.com/articles/2019-01-21-the-link-to-button-enhancement/
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} menuItem An element representing a link to be converted to a button
|
||||||
|
*/
|
||||||
|
function convertLinkToButton( menuItem ) {
|
||||||
|
const link = menuItem.getElementsByTagName( 'a' )[ 0 ],
|
||||||
|
linkHTML = link.innerHTML,
|
||||||
|
linkAtts = link.attributes,
|
||||||
|
button = document.createElement( 'button' );
|
||||||
|
|
||||||
|
if ( null !== link ) {
|
||||||
|
// copy button attributes and content from link
|
||||||
|
button.innerHTML = linkHTML.trim();
|
||||||
|
for ( i = 0, len = linkAtts.length; i < len; i++ ) {
|
||||||
|
const attr = linkAtts[ i ];
|
||||||
|
if ( 'href' !== attr.name ) {
|
||||||
|
button.setAttribute( attr.name, attr.value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem.replaceChild( button, link );
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUpAria( submenu, button ) {
|
||||||
|
const submenuId = submenu.getAttribute( 'id' );
|
||||||
|
|
||||||
|
let id;
|
||||||
|
if ( null === submenuId ) {
|
||||||
|
id = button.textContent.trim().replace( /\s+/g, '-' ).toLowerCase() + '-submenu';
|
||||||
|
} else {
|
||||||
|
id = submenuId + '-submenu';
|
||||||
|
}
|
||||||
|
|
||||||
|
// set button ARIA
|
||||||
|
button.setAttribute( 'aria-controls', id );
|
||||||
|
button.setAttribute( 'aria-expanded', false );
|
||||||
|
|
||||||
|
// set submenu ARIA
|
||||||
|
submenu.setAttribute( 'id', id );
|
||||||
|
submenu.setAttribute( 'aria-hidden', true );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create a ClickMenus object and initiate menu for any menu with .clicky-menu class */
|
||||||
|
document.addEventListener( 'DOMContentLoaded', function() {
|
||||||
|
const menus = document.querySelectorAll( '.clicky-menu' );
|
||||||
|
|
||||||
|
menus.forEach( ( menu ) => {
|
||||||
|
const clickyMenu = new ClickyMenus( menu );
|
||||||
|
clickyMenu.init();
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}() );
|
Loading…
Reference in New Issue