parent
eb83cfa97c
commit
2e33b8d762
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@fwdekker/template",
|
"name": "@fwdekker/template",
|
||||||
"version": "3.3.5",
|
"version": "3.3.6",
|
||||||
"description": "The base template for pages on fwdekker.com.",
|
"description": "The base template for pages on fwdekker.com.",
|
||||||
"author": "Florine W. Dekker",
|
"author": "Florine W. Dekker",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
@ -29,10 +29,6 @@ nav.fwd-nav li > :first-child {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.fwd-nav a {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav.fwd-nav ul ul {
|
nav.fwd-nav ul ul {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
|
@ -44,7 +40,7 @@ nav.fwd-nav ul ul {
|
||||||
box-shadow: var(--fwd-nav-box-shadow);
|
box-shadow: var(--fwd-nav-box-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.fwd-nav li:where(:active, :focus-within, :hover) > ul {
|
nav.fwd-nav li:where(:active, :focus-within, :hover, .fwd-nav-active) > ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
|
@ -70,15 +66,15 @@ nav.fwd-nav ul {
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.fwd-nav li.border-above {
|
nav.fwd-nav li.fwd-nav-separator {
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.fwd-nav li:where(:active, :focus-within, :hover) {
|
nav.fwd-nav li:where(:active, :focus-within, :hover, .fwd-nav-active) {
|
||||||
background-color: var(--primary-focus-dark);
|
background-color: var(--primary-focus-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.fwd-nav li.current-page:not(:where(:active, :focus-within, :hover)) {
|
nav.fwd-nav li.fwd-nav-highlighted:not(:where(:active, :focus-within, :hover, .fwd-nav-active)) {
|
||||||
background-color: var(--primary-focus-opaque);
|
background-color: var(--primary-focus-opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +121,7 @@ nav.fwd-nav #fwd-nav-hamburger-label {
|
||||||
color: var(--primary-inverse);
|
color: var(--primary-inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.fwd-nav #fwd-nav-hamburger-label:where(:active, :focus-within, :hover) {
|
nav.fwd-nav #fwd-nav-hamburger-label:where(:active, :focus-within, :hover, .fwd-nav-active) {
|
||||||
background-color: var(--primary-focus-dark);
|
background-color: var(--primary-focus-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,12 @@ function nav(highlightPath?: string, cb?: (json: any) => void): HTMLElement {
|
||||||
if (cb !== undefined)
|
if (cb !== undefined)
|
||||||
cb(json);
|
cb(json);
|
||||||
|
|
||||||
json.entries.forEach(
|
json.entries.forEach((it: any) => base.appendChild(unpackEntry(it, "/", highlightPath)));
|
||||||
(entry: any) => base.appendChild(stringToHtml(unpackEntry(entry, "/", highlightPath)))
|
|
||||||
|
document.body.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => $a("li", base).forEach(it => it.classList.remove("fwd-nav-active")),
|
||||||
|
{capture: true}
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch(error => console.error("Failed to fetch navigation elements", error));
|
.catch(error => console.error("Failed to fetch navigation elements", error));
|
||||||
|
@ -113,38 +117,41 @@ function nav(highlightPath?: string, cb?: (json: any) => void): HTMLElement {
|
||||||
* @param parentPath the current path traversed, found by joining the names of the entries with `/`s; always starts and
|
* @param parentPath the current path traversed, found by joining the names of the entries with `/`s; always starts and
|
||||||
* ends with a `/`
|
* ends with a `/`
|
||||||
* @param highlightPath the path to highlight together with its parents, or `undefined` if no path should be highlighted
|
* @param highlightPath the path to highlight together with its parents, or `undefined` if no path should be highlighted
|
||||||
* @returns the navigation list entry as HTML, described by its children
|
* @returns the navigation list entry
|
||||||
*/
|
*/
|
||||||
function unpackEntry(entry: any, parentPath: string = "/", highlightPath?: string): string {
|
function unpackEntry(entry: any, parentPath: string = "/", highlightPath?: string): HTMLLIElement {
|
||||||
const path = `${parentPath + entry.name}/`;
|
const path = `${parentPath + entry.name}/`;
|
||||||
|
const hasChildren = entry.entries.length !== 0;
|
||||||
|
|
||||||
const classList = [];
|
const li = document.createElement("li");
|
||||||
if (highlightPath?.startsWith(path) ?? false) classList.push("current-page");
|
if (highlightPath === path) li.setAttribute("aria-current", "page");
|
||||||
if (entry.border) classList.push("border-above");
|
if (highlightPath?.startsWith(path) ?? false) li.classList.add("fwd-nav-highlighted");
|
||||||
const classString = classList.length === 0 ? "" : `class="${classList.join(" ")}"`;
|
if (entry.border) li.classList.add("fwd-nav-separator");
|
||||||
|
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.innerText = entry.name;
|
||||||
|
if (hasChildren) {
|
||||||
|
const depth = parentPath.split("/").length - 2; // -1 because count parts, then another -1 because of leading /
|
||||||
|
a.innerText += ` ${depth === 0 ? "▾" : "▸"}`;
|
||||||
|
}
|
||||||
|
if (entry.link != null) {
|
||||||
|
a.href = entry.link;
|
||||||
|
|
||||||
let hrefString;
|
|
||||||
if (entry.link == null) {
|
|
||||||
hrefString = "";
|
|
||||||
} else {
|
|
||||||
hrefString = `href="${entry.link}"`;
|
|
||||||
if (entry.link !== "#" && !/^https:\/\/.*fwdekker.com/i.test(entry.link))
|
if (entry.link !== "#" && !/^https:\/\/.*fwdekker.com/i.test(entry.link))
|
||||||
hrefString += ` target="_blank"`;
|
a.target = "_blank";
|
||||||
|
}
|
||||||
|
li.addEventListener("click", () => li.classList.add("fwd-nav-active"));
|
||||||
|
li.appendChild(a);
|
||||||
|
|
||||||
|
if (hasChildren) {
|
||||||
|
const ul = document.createElement("ul");
|
||||||
|
entry.entries
|
||||||
|
.map((it: any) => unpackEntry(it, path, highlightPath))
|
||||||
|
.forEach((it: HTMLLIElement) => ul.appendChild(it));
|
||||||
|
li.appendChild(ul);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.entries.length === 0)
|
return li;
|
||||||
return `<li ${classString}><a ${hrefString}>${entry.name}</a></li>`;
|
|
||||||
|
|
||||||
const depth = parentPath.split("/").length - 2; // -1 because count parts, then another -1 because of leading `/`
|
|
||||||
const arrow = depth === 0 ? "▾" : "▸";
|
|
||||||
|
|
||||||
return "" +
|
|
||||||
`<li ${classString}>` +
|
|
||||||
/**/`<a ${hrefString}>${entry.name} ${arrow}</a>` +
|
|
||||||
/**/`<ul>` +
|
|
||||||
/**//**/entry.entries.map((it: any) => unpackEntry(it, path, highlightPath)).join("") +
|
|
||||||
/**/`</ul>` +
|
|
||||||
`</li>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue