Merge pull request #37 from madrilene/optional-drawer
Reactivate drawer menu as opt-in
This commit is contained in:
commit
687a77382d
15 changed files with 299 additions and 32 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "eleventy-excellent",
|
||||
"version": "2.1.4",
|
||||
"description": "Eleventy starter based on the workflow suggested by Andy Bell's buildexcellentwebsit.es.",
|
||||
"description": "Eleventy starter built around the workflow suggested by Andy Bell's buildexcellentwebsit.es.",
|
||||
"author": "Lene Saile",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ module.exports = {
|
|||
url: process.env.URL || 'http://localhost:8080',
|
||||
siteName: 'Eleventy Excellent',
|
||||
siteDescription:
|
||||
'Eleventy starter based on the workflow suggested by buildexcellentwebsit.es',
|
||||
'Eleventy starter built around the CSS workflow suggested by buildexcellentwebsit.es',
|
||||
siteType: 'Person', // schema
|
||||
locale: 'en_EN',
|
||||
lang: 'en',
|
||||
|
|
@ -23,14 +23,20 @@ module.exports = {
|
|||
themeBgColor: '#FBFBFB', // Manifest: defines a placeholder background color for the application page to display before its stylesheet is loaded
|
||||
opengraph_default: '/assets/images/template/opengraph-default.jpg', // fallback/default meta image
|
||||
opengraph_default_alt:
|
||||
'Visible content: Eleventy starter based on workflow for Cube CSS, Every Layout, Design Tokens and Tailwind for uitility, based on the concepts explained in buildexcellentwebsit.es', // alt text for default meta image
|
||||
'Visible content: Eleventy starter built around the CSS workflow for Cube CSS, Every Layout, Design Tokens and Tailwind for uitility, based on the concepts explained in buildexcellentwebsit.es', // alt text for default meta image
|
||||
blog: {
|
||||
// RSS feed
|
||||
name: 'My Web Development Blog',
|
||||
description:
|
||||
'Tell the word what you are writing about in your blog. It will show up on feed readers.',
|
||||
// feed links are looped over in the head. You may add more to the array.
|
||||
feedLinks: [{title: 'Atom Feed', url: '/feed.xml', type: 'application/atom+xml'}],
|
||||
feedLinks: [
|
||||
{
|
||||
title: 'Atom Feed',
|
||||
url: '/feed.xml',
|
||||
type: 'application/atom+xml'
|
||||
}
|
||||
],
|
||||
// Tags
|
||||
tagSingle: 'Tag',
|
||||
tagPlural: 'Tags',
|
||||
|
|
@ -51,7 +57,9 @@ module.exports = {
|
|||
ariaTop: 'Main',
|
||||
ariaBottom: 'Complementary',
|
||||
ariaPlatforms: 'Platforms',
|
||||
closedText: 'Menu'
|
||||
// activate alternative mobile menu with drawer
|
||||
drawerNav: false,
|
||||
navLabel: 'Menu'
|
||||
},
|
||||
themeSwitch: {
|
||||
title: 'Theme',
|
||||
|
|
|
|||
24
src/_includes/components/burger-template.njk
Normal file
24
src/_includes/components/burger-template.njk
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!-- template element holding a button that needs to be injected when JavaScript is finally available. -->
|
||||
<!-- based on an article by Manuel Matuzovic, https://web.dev/website-navigation/ -->
|
||||
<!-- see also: https://kittygiraudel.com/2022/09/30/templating-in-html/ -->
|
||||
|
||||
<template id="burger-template">
|
||||
<button type="button" aria-expanded="false" aria-label="Menu" aria-controls="mainnav">
|
||||
<span>{{ meta.navigation.navLabel }}</span>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
|
|
@ -10,6 +10,6 @@
|
|||
{% include "svg/star.svg" %}
|
||||
<span>{{ meta.siteName }}</span>
|
||||
</a>
|
||||
{% include "partials/menu.njk" %}
|
||||
{% include "partials/main-nav.njk" %}
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
|||
34
src/_includes/partials/main-nav.njk
Normal file
34
src/_includes/partials/main-nav.njk
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{% set drawerNav = meta.navigation.drawerNav %}
|
||||
|
||||
{% if drawerNav %}
|
||||
<!-- check for drawer menu being activated in meta.js -->
|
||||
{% set drawerClass = "site-nav-drawer" %}
|
||||
{% endif %}
|
||||
|
||||
<nav
|
||||
id="mainnav"
|
||||
class=" {{ drawerClass or 'site-nav' }}"
|
||||
aria-label="{{ meta.navigation.ariaTop }}"
|
||||
>
|
||||
<ul class="cluster" role="list">
|
||||
{% for item in navigation.top %}
|
||||
<li>
|
||||
<a
|
||||
class="nav"
|
||||
href="{{ item.url }}"
|
||||
{{
|
||||
helpers.getLinkActiveState(item.url,
|
||||
page.url)
|
||||
|
|
||||
safe
|
||||
}}
|
||||
>{{ item.text }}</a
|
||||
>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{% if drawerNav %}
|
||||
{% include "components/burger-template.njk" %}
|
||||
{% endif %}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<nav id="mainnav" class="site-nav" aria-label="{{ meta.navigation.ariaTop }}">
|
||||
<ul class="cluster" role="list">
|
||||
{% for item in navigation.top %}
|
||||
<li>
|
||||
<a
|
||||
class="nav"
|
||||
href="{{ item.url }}"
|
||||
{{
|
||||
helpers.getLinkActiveState(item.url,
|
||||
page.url)
|
||||
|
|
||||
safe
|
||||
}}
|
||||
>{{ item.text }}</a
|
||||
>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="{{ meta.lang }}">
|
||||
<!-- The order of elements in the head follows recommendations by Harry Roberts. learn more here: https://www.youtube.com/watch?v=MHyAOZ45vnU -->
|
||||
|
||||
<head>
|
||||
<!-- charset/http-equiv/viewport -->
|
||||
<meta charset="UTF-8" />
|
||||
|
|
@ -64,10 +66,11 @@
|
|||
|
||||
<!-- defered js -->
|
||||
|
||||
<!-- masonry fallback, if true in frontmatter -->
|
||||
{% if masonry %}
|
||||
<!-- masonry fallback, if true in frontmatter -->
|
||||
<script src="/assets/scripts/masonry.js?{{ assetHash }}" defer></script>
|
||||
{% endif %}
|
||||
|
||||
{% if youtube %}
|
||||
<!-- youtube, if true in frontmatter -->
|
||||
<script
|
||||
|
|
@ -76,8 +79,13 @@
|
|||
></script>
|
||||
{% endif %}
|
||||
|
||||
<!-- easteregg js, if true in meta -->
|
||||
{% if meta.navigation.drawerNav %}
|
||||
<!-- menu drawer js, if true in meta -->
|
||||
<script src="/assets/scripts/nav-drawer.js?{{ assetHash }}" defer></script>
|
||||
{% endif %}
|
||||
|
||||
{% if meta.easteregg %}
|
||||
<!-- easteregg js, if true in meta -->
|
||||
<script src="/assets/scripts/easteregg.js?{{ assetHash }}" defer></script>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
|||
150
src/assets/css/blocks/site-nav-drawer.css
Normal file
150
src/assets/css/blocks/site-nav-drawer.css
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* set on parent div to get the right z-index context */
|
||||
.ontop {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.site-nav-drawer {
|
||||
position: var(--nav-position, absolute);
|
||||
inset-inline-end: 0.1rem;
|
||||
}
|
||||
|
||||
/* Remove default list styling and create layout for list */
|
||||
.site-nav-drawer ul {
|
||||
--cluster-vertical-alignment: normal;
|
||||
--gutter: var(--space-xs);
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
line-height: 0.5em;
|
||||
padding: var(--nav-list-padding, var(--space-2xl) var(--space-s));
|
||||
background: var(--nav-list-background, var(--color-bg));
|
||||
box-shadow: var(--nav-list-shadow, -5px 0 11px 0 rgb(0 0 0 / 0.2));
|
||||
flex-direction: var(--nav-list-layout, column);
|
||||
block-size: var(--nav-list-height, 100vh);
|
||||
position: var(--nav-list-position, fixed);
|
||||
inset-block-start: 0;
|
||||
inset-inline-end: 0;
|
||||
inline-size: var(--nav-list-width, min(22rem, 100vw));
|
||||
visibility: var(--nav-list-visibility, visible);
|
||||
}
|
||||
|
||||
.site-nav-drawer [aria-expanded='false'] + ul {
|
||||
transform: var(--nav-list-transform, translateX(100%));
|
||||
visibility: var(--nav-list-visibility, hidden);
|
||||
}
|
||||
|
||||
/* animates ul only when opening to avoid flash on page load, svg always */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.site-nav-drawer [aria-expanded='true'] + ul,
|
||||
.site-nav-drawer svg {
|
||||
transition:
|
||||
transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55),
|
||||
visibility 0.05s linear;
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic link styling */
|
||||
.site-nav-drawer a {
|
||||
--text-color: var(--color-text);
|
||||
--background-color: var(--color-bg);
|
||||
--border-color: transparent;
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
padding: var(--anchor-padding, var(--space-s));
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* Change the border-color on :hover and :focus */
|
||||
.site-nav-drawer a:where(:hover, :focus) {
|
||||
--background-color: var(--color-bg-accent);
|
||||
--text-color: var(--color-text-accent);
|
||||
--border-color: var(--color-bg-accent);
|
||||
}
|
||||
|
||||
/* Change border-color and color for the active page */
|
||||
.site-nav-drawer [aria-current='page'],
|
||||
.site-nav-drawer [data-state='active'] {
|
||||
--background-color: var(--color-bg-accent);
|
||||
--text-color: var(--color-text);
|
||||
--border-color: var(--color-bg-accent);
|
||||
}
|
||||
|
||||
/* Reset button styling */
|
||||
.site-nav-drawer button {
|
||||
all: unset;
|
||||
display: var(--nav-button-display, flex);
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
padding: var(--space-xs) 0;
|
||||
}
|
||||
|
||||
.site-nav-drawer span {
|
||||
font-size: var(--size-step-min-1);
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
padding-inline-end: var(--space-2xs);
|
||||
}
|
||||
|
||||
.site-nav-drawer svg {
|
||||
block-size: 100%;
|
||||
inline-size: auto;
|
||||
transform: translateY(-0.1em);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.site-nav-drawer [aria-expanded='true'] svg {
|
||||
transform: var(--nav-list-rotate, rotate(45deg));
|
||||
}
|
||||
|
||||
@media screen(sm) {
|
||||
.site-nav-drawer {
|
||||
--nav-button-display: none;
|
||||
--nav-position: static;
|
||||
}
|
||||
|
||||
.site-nav-drawer ul {
|
||||
--nav-list-background: transparent;
|
||||
--nav-list-layout: row;
|
||||
--nav-list-position: static;
|
||||
--nav-list-padding: 0;
|
||||
--nav-list-height: auto;
|
||||
--nav-list-width: 100%;
|
||||
--nav-list-shadow: none;
|
||||
--nav-list-transform: none;
|
||||
--nav-list-visibility: visible;
|
||||
}
|
||||
|
||||
.site-nav-drawer a {
|
||||
--anchor-padding: var(--space-xs) 0.2em;
|
||||
--text-color: var(--color-text);
|
||||
--background-color: transparent;
|
||||
--border-color: transparent;
|
||||
--text-decoration: transparent;
|
||||
text-decoration-line: underline;
|
||||
text-decoration-color: var(--text-decoration, transparent);
|
||||
text-decoration-thickness: 3px;
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
.site-nav-drawer a:where(:hover, :focus) {
|
||||
--text-color: var(--color-text);
|
||||
--background-color: transparent;
|
||||
--border-color: transparent;
|
||||
--text-decoration: var(--color-text-accent);
|
||||
}
|
||||
|
||||
/* Change border-color and color for the active page */
|
||||
.site-nav-drawer [aria-current='page'],
|
||||
.site-nav-drawer [data-state='active'] {
|
||||
--text-color: var(--color-primary);
|
||||
--background-color: transparent;
|
||||
--border-color: transparent;
|
||||
--text-decoration: var(--color-primary);
|
||||
}
|
||||
}
|
||||
34
src/assets/scripts/nav-drawer.js
Normal file
34
src/assets/scripts/nav-drawer.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// © Manuel Matuzović: https://web.dev/website-navigation/
|
||||
|
||||
const nav = document.querySelector('nav');
|
||||
const list = nav.querySelector('ul');
|
||||
const burgerClone = document.querySelector('#burger-template').content.cloneNode(true);
|
||||
const svg = nav.querySelector('svg');
|
||||
|
||||
const button = burgerClone.querySelector('button');
|
||||
button.addEventListener('click', e => {
|
||||
const isOpen = button.getAttribute('aria-expanded') === 'true';
|
||||
button.setAttribute('aria-expanded', !isOpen);
|
||||
});
|
||||
|
||||
// avoid DRY: disabling menu
|
||||
const disableMenu = () => {
|
||||
button.setAttribute('aria-expanded', false);
|
||||
};
|
||||
|
||||
// close on escape
|
||||
nav.addEventListener('keyup', e => {
|
||||
if (e.code === 'Escape') {
|
||||
disableMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// close if clicked outside of event target
|
||||
document.addEventListener('click', e => {
|
||||
const isClickInsideElement = nav.contains(e.target);
|
||||
if (!isClickInsideElement) {
|
||||
disableMenu();
|
||||
}
|
||||
});
|
||||
|
||||
nav.insertBefore(burgerClone, list);
|
||||
|
|
@ -4,10 +4,11 @@ title: Less JavaScript
|
|||
|
||||
The only "real" JavaScript dependency is **theme-toggle.js**, which is inlined.
|
||||
|
||||
There are two more scripts that are generated but you have to opt in:
|
||||
There are three more scripts that are available, but you have to opt in:
|
||||
|
||||
**nav-drawer.js**, to opt in to a drawer menu on small screens. See the [navigation documentation](/docs/navigation/).
|
||||
|
||||
**masonry.js**, creating the masonry effect used on the cards.
|
||||
A fallback until [maybe, one day](https://caniuse.com/mdn-css_properties_grid-template-rows_masonry) we get to use `grid-template-rows: masonry;`.
|
||||
Search for `masonry: true` to see where it is activated, and set to `false`, an empty string, or delete the front matter field, if you don't want to use it. The script won't be included then. Nothing breaks, the cards just won't rise up to completely fill the gaps in their grid.
|
||||
|
||||
The **easteregg.js** is an opt-in JS-file set in `src/_data/meta.js`.
|
||||
|
|
|
|||
9
src/docs/masonry.md
Normal file
9
src/docs/masonry.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
title: Masonry
|
||||
---
|
||||
|
||||
There is the idea of making masonry layout a native part of CSS grid, using `grid-template-rows: masonry;`. It is [not yet to be seen on the horizon](https://caniuse.com/mdn-css_properties_grid-template-rows_masonry), but it is already included in the starter (inside the `grid.css` composition).
|
||||
Until then, a small script will help us to get the effect.
|
||||
|
||||
It gets loaded by opt-in.
|
||||
Set `masonry: true` in your front matter to activate.
|
||||
19
src/docs/navigation.md
Normal file
19
src/docs/navigation.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: Navigation
|
||||
---
|
||||
|
||||
Edit your navigation items in `src/_data/navigation.js`.
|
||||
|
||||
You have two options for mobile navigation: by default, the navigation on small displays is converted to small pills that wrap. This does not require any additional JavaScript.
|
||||
|
||||
Before version 2.0 a slide out drawer was the default, you can activate it again in `src/_data/meta.js`:
|
||||
|
||||
```js
|
||||
navigation: {
|
||||
// other settings
|
||||
drawerNav: true,
|
||||
navLabel: 'Menu'
|
||||
},
|
||||
```
|
||||
|
||||
`drawerNav` activates the navigation drawer, [built according to Manuel Matuzović's article on web.dev.](https://web.dev/articles/website-navigation)
|
||||
|
|
@ -8,7 +8,7 @@ youtube: true
|
|||
|
||||
This starter uses modern CSS, fluid type & space, flexible Layouts and Progressive Enhancement, wrapped in a basic template.
|
||||
|
||||
Based on the CSS boilerplate by Andy Bell and inspired by Andy's talk **'Be the browser’s mentor, not its micromanager'**.
|
||||
It is built around the CSS boilerplate by Andy Bell and inspired by Andy's talk **'Be the browser’s mentor, not its micromanager'**.
|
||||
|
||||
If you want to know exactly how it all works, [read this article on piccalil.li](https://piccalil.li/blog/a-css-project-boilerplate/).
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ You can use this starter as a template for your blog and you are ready to go! Bu
|
|||
- `src/_data/meta.js` - sets different "hard coded" text values all over the template, you can change the language, etc.
|
||||
- edit your personal details and social media in `src/_data/personal.yaml`.
|
||||
- Open `src/assets/css/blocks/external-link.css`. Replace "eleventy-excellent.netlify.app" with your own domain. This is about the external link indicators, they are matched with your domain. If you don't want to use external link indicators, feel free to delete the whole style rule. You can also add the class `no-indicator` to any anchor element you want to except from this rule.
|
||||
- Edit your navigation items in `src/_data/navigation.js`.
|
||||
|
||||
If you are working with **VS Code** I recommend installing the "Tailwind CSS IntelliSense" addon, as it works also for our custom utility classes. That said, you will find that Tailwind CSS does not work as you might expect. I explain this in [one of the blog posts](/blog/what-is-tailwind-css-doing-here/).
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ blog:
|
|||
|
||||
## An Eleventy starter
|
||||
|
||||
This [Eleventy](https://www.11ty.dev/) starter is based on [Andy Bell's](https://andy-bell.co.uk/) talk 'Be the browser’s mentor, not its micromanager' and its companion website buildexcellentwebsit.es.
|
||||
This [Eleventy](https://www.11ty.dev/) starter was inspired [Andy Bell's](https://andy-bell.co.uk/) talk 'Be the browser’s mentor, not its micromanager' and its companion website buildexcellentwebsit.es.
|
||||
|
||||
In his words, it's about hinting the browser rather than micromanaging it, using progressive enhancement, CSS layout, fluid type & spacing, as well as modern CSS features.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue