Rewrite without hyperscript

Fixes #5. Reduces bundle by 6kB.
This commit is contained in:
Florine W. Dekker 2021-03-26 02:58:50 +01:00
parent 55cce0c433
commit 0e4f973553
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
3 changed files with 68 additions and 51 deletions

BIN
package-lock.json generated

Binary file not shown.

View File

@ -24,7 +24,6 @@
"prepare": "grunt clean deploy"
},
"dependencies": {
"hyperscript": "^2.0.2",
"milligram": "^1.4.1"
},
"devDependencies": {

View File

@ -1,4 +1,3 @@
import h from "hyperscript";
import "../css/normalize.css";
import "milligram/dist/milligram.min.css";
import "../css/common.css";
@ -6,6 +5,17 @@ import "../css/nav.css";
import "../css/overrides.css";
/**
* Converts the given string to an HTML element.
*
* @param string the string to convert to an HTML element
* @param query the type of element to return
* @returns {HTMLElement} the HTML element described by the given string
*/
const stringToHtml = function (string, query) {
return new DOMParser().parseFromString(string, "text/html").body.querySelector(query);
}
/**
* Alias for `document.querySelector`.
*
@ -41,22 +51,28 @@ export const doAfterLoad = function (fun) {
* @returns {HTMLElement} a base navigation element that will eventually be filled with contents
*/
export const nav = function (highlightPath = "") {
const base = h("ul",
h("li", h("a", {href: "https://fwdekker.com/"},
h("div.logo", h("img.logo", {src: "https://fwdekker.com/favicon.png"})),
h("b", "FWDekker")
))
);
const base = stringToHtml(`
<ul>
<li><a href="https://fwdekker.com/">
<div class="logo"><img class="logo" src="https://fwdekker.com/favicon.png" alt="FWDekker" /></div>
<b>FWDekker</b>
</a></li>
</ul>
`, "ul");
fetch("https://fwdekker.com/api/nav/")
.then(it => it.json())
.then(json => json.entries.forEach(entry => base.appendChild(unpackEntry(entry, "/", highlightPath))))
.then(json => {
json.entries.forEach(entry => base.appendChild(stringToHtml(unpackEntry(entry, "/", highlightPath), "li")))
})
.catch(e => {
console.error("Failed to fetch navigation elements", e);
return [];
});
return h("nav.nav", base);
const nav = stringToHtml(`<nav class="nav"></nav>`, "nav");
nav.appendChild(base);
return nav;
};
/**
@ -66,25 +82,23 @@ export const nav = function (highlightPath = "") {
* @param [path] {number} the current path traversed, found by joining the names of the entries with `/`s; always starts
* and ends with a `/`
* @param [highlightPath] {String} the path to highlight together with its parents
* @returns {HTMLElement} the navigation list entry as HTML, described by its children
* @returns {string} the navigation list entry as HTML, described by its children
*/
const unpackEntry = function (entry, path = "/", highlightPath = "") {
const shouldHighlight = highlightPath.startsWith(`${path + entry.name}/`);
if (entry.entries.length === 0)
return h("li",
h("a", {href: entry.link, innerHTML: entry.name}),
{className: shouldHighlight ? "currentPage" : ""}
);
return `<li><a href="${entry.link}" class="${shouldHighlight ? "currentPage" : ""}">${entry.name}</a></li>`;
const depth = path.split("/").length - 2; // -1 because count parts, then another -1 because of leading `/`
const arrow = depth === 0 ? "&#9662;" : "&#9656;";
return h("li",
h("a", {href: entry.link, innerHTML: `${entry.name} ${arrow}`}),
h("ul", entry.entries.map(it => unpackEntry(it, `${path + entry.name}/`, highlightPath))),
{className: shouldHighlight ? "currentPage" : ""}
);
return `
<li class="${shouldHighlight ? "currentPage" : ""}">
<a href="${entry.link}">${entry.name} ${arrow}</a>
<ul>${entry.entries.map(it => unpackEntry(it, `${path + entry.name}/`, highlightPath)).join("")}</ul>
</li>
`;
};
@ -97,14 +111,16 @@ const unpackEntry = function (entry, path = "/", highlightPath = "") {
*/
export const header = function ({title, description}) {
if (title === undefined && description === undefined)
return h("header.header");
return stringToHtml(`<header class="header"></header>`, "header");
return h("header.header",
h("section.container",
title !== undefined ? h("h1", {innerHTML: title}) : undefined,
description !== undefined ? h("p", h("em", {innerHTML: description})) : undefined
)
);
return stringToHtml(`
<header class="header">
<section class="container">
${(title !== undefined ? `<h1>${title}</h1>` : "")}
${(description !== undefined ? `<p><em>${description}</em></p>` : "")}
</section>
</header>
`, "header");
};
@ -127,20 +143,22 @@ export const footer = function (
author, authorURL, license, licenseURL, vcs, vcsURL, version,
privacyPolicyURL = undefined
}) {
return h("footer.footer",
h("section.container",
footerLink("Made by ", author, authorURL, ". "),
footerLink("Licensed under the ", license, licenseURL, ". "),
footerLink("Source code available on ", vcs, vcsURL, ". "),
footerLink(
return stringToHtml(`
<footer class="footer">
<section class="container">
${footerLink("Made by ", author, authorURL, ". ")}
${footerLink("Licensed under the ", license, licenseURL, ". ")}
${footerLink("Source code available on ", vcs, vcsURL, ". ")}
${footerLink(
"Consider reading the ",
privacyPolicyURL === null ? undefined : "privacy policy",
privacyPolicyURL === undefined ? "https://fwdekker.com/privacy/" : privacyPolicyURL,
". "
),
h("div", version || "", {style: {"float": "right"}})
)
);
)}
<div style="float: right;">${version || ""}</div>
</section>
</footer>
`, "footer");
};
/**
@ -150,18 +168,18 @@ export const footer = function (
* @param text {string|undefined} the text to display, or `undefined` if the returned element should be empty
* @param url {string|undefined} the URL to link the text to, or `undefined` if the text should not be a link
* @param suffix {string} the text to display after the text if the text is not undefined
* @returns {HTMLElement} a footer link element
* @returns {string} a footer link element
*/
const footerLink = function (prefix, text, url, suffix) {
if (text === undefined) return h("span");
if (text === undefined) return "";
return h("span",
h("span", prefix),
url !== undefined
? h("a", text, {href: url})
: h("span", text),
h("span", suffix)
);
return `
<span>
${prefix}
${url !== undefined ? `<a href="${url}">${text}</a>` : text}
${suffix}
</span>
`;
};