diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/main.ts | 71 | ||||
-rw-r--r-- | js/navigation.ts | 97 | ||||
-rw-r--r-- | js/page.ts | 104 | ||||
-rw-r--r-- | js/theme.ts | 11 |
4 files changed, 58 insertions, 225 deletions
@@ -1,31 +1,66 @@ -/// <reference path="navigation.ts" /> -/// <reference path="page.ts" /> /// <reference path="theme.ts" /> namespace Ach { - export async function init() { + export async function init(): Promise<void> { Ach.loadTheme(); - Ach.initImages(); - Ach.initLinks(); - - window.addEventListener("popstate", (_e) => { - location.reload(); - }); - } - - export function currentPage() { - let body = Ach.getFirstElement(document, "body"); - let page = body.getAttribute("data-page"); + let glyph = Ach.getOnlyElementIn(document, "glyph"); + let page = glyph.getAttribute("alt"); if (!page) { - throw new Error("body does not specify page"); + throw new Error('glyph does not specify page in "alt" attribute'); } - return page; + let portrait = matchMedia("(orientation: portrait)"); + let reducedMotion = matchMedia("(prefers-reduced-motion)"); + + let updateDynamicGlyph = (): void => { + console.log("updating dynamic glyph"); + console.log(`note: configuration is { page: "${page}", portrait: ${portrait.matches}, reducedMotion: ${reducedMotion.matches} }`); + + let newGlyphAddr: string | undefined = undefined; + switch (page) { + case "achernar": + switch (true) { + case portrait.matches && reducedMotion.matches: + newGlyphAddr = "/svg/glyph/achernarVertical.svg"; + break; + + case portrait.matches && !reducedMotion.matches: + newGlyphAddr = "/image/achernarVerticalAnimated.webp"; + break; + + case !portrait.matches && reducedMotion.matches: + newGlyphAddr = "/svg/glyph/achernar.svg"; + break; + + case !portrait.matches && !reducedMotion.matches: + newGlyphAddr = "/image/achernarAnimated.webp"; + break; + } + + break; + + default: + break; + } + + if (newGlyphAddr) { + console.log(`note: new glyph is at "${newGlyphAddr}"`); + + glyph.setAttribute("src", newGlyphAddr); + } else { + console.log("note: no new glyph was found suitable"); + } + }; + + updateDynamicGlyph(); + + portrait .addEventListener("change", updateDynamicGlyph); + reducedMotion.addEventListener("change", updateDynamicGlyph); } - export function getFirstElement(dom: Document, tag: string): Element { + export function getFirstElementIn(dom: Document, tag: string): Element { let elements = dom.getElementsByTagName(tag); if (elements.length < 0x0) { @@ -35,7 +70,7 @@ namespace Ach { return elements[0x0]; } - export function getOnlyElement(dom: Document, id: string): Element { + export function getOnlyElementIn(dom: Document, id: string): Element { let element = dom.getElementById(id); if (!element) { diff --git a/js/navigation.ts b/js/navigation.ts deleted file mode 100644 index c1af99f..0000000 --- a/js/navigation.ts +++ /dev/null @@ -1,97 +0,0 @@ -namespace Ach { - export async function loadPage(page_name: string, anchor?: string) { - console.log(`loading page \`${page_name}\``); - - window.scrollTo({ - top: 0.0, - left: undefined, - behavior: "smooth", - }); - - let url = `/html/${page_name}.html`; - console.log(`note: page is at "${url}"`); - - window.history.pushState(page_name, "", url); - - let response = await fetch(url); - - if (!response.ok) { - throw new Error(`unable to load page: \"${response.status}\"`); - } - - let markup = await response.text(); - - let parser = new DOMParser(); - let dom = parser.parseFromString(markup, "text/html"); - - let body = Ach.getFirstElement(document, "body"); - - let title = Ach.getFirstElement(document, "title"); - let page = Ach.getOnlyElement(document, "page"); - - let newTitle = Ach.getFirstElement(dom, "title"); - let newPage = Ach.getOnlyElement(dom, "page"); - - title.replaceWith(newTitle); - body.setAttribute("data-page", page_name); - page.replaceWith(newPage); - - initImages(); - initLinks(); - - if (anchor) { - console.log(`going to anchor \`${anchor}\``); - - anchor = `anchor.${anchor}`; - - console.log(`note: anchor has id "${anchor}"`); - - let anchor_element = document.getElementById(anchor); - - if (!anchor_element) { - throw new Error(`unable to find anchor "${anchor}"`); - } - - anchor_element.scrollIntoView({ - behavior: "smooth", - }); - } - } - - export function toggleSideMenu() { - window.scrollTo({ - top: 0.0, - left: undefined, - behavior: "smooth", - }); - - let sideMenu = Ach.getOnlyElement(document, "sideMenu"); - let navBar = Ach.getOnlyElement(document, "navBar"); - let glyph = Ach.getOnlyElement(document, "glyph"); - - sideMenu.classList.toggle("visible"); - glyph.classList.toggle("hidden"); - - for (let link of navBar.getElementsByTagName("a")) { - link.classList.toggle("hidden"); - } - } - - export function parseInternalLink(address: string): [string, string | undefined] | undefined { - let regex = /\/html\/([A-Za-z0-9]+)\.html(?:#([A-Za-z0-9]+)){0,1}/; - let regex_result = regex.exec(address); - - if (!regex_result) { - return; - } - - let page = regex_result[0x1]; - let anchor = regex_result[0x2]; - - if (!page) { - return; - } - - return [page, anchor]; - } -} diff --git a/js/page.ts b/js/page.ts deleted file mode 100644 index c4f0d71..0000000 --- a/js/page.ts +++ /dev/null @@ -1,104 +0,0 @@ -namespace Ach { - export async function initImages() { - let page = Ach.getOnlyElement(document, "page"); - - let imageList = Array.from(page.getElementsByTagName("x-image")); - - for (let image of imageList) { - let alt = image.getAttribute("alt"); - let file = image.getAttribute("data-file"); - - if (!alt) { - alert("stupid superuser forgot to add image caption, please notify"); - alt = ""; - } - - if (!file) { - throw new Error("file not set for image element"); - } - - console.log("initialising image that links to \"" + file + "\""); - - let sourceUrl = "/image/source/" + file + ".webp"; - let thumbnailUrl = "/image/thumbnail/" + file + ".avif"; - - let blurElement = document.createElement("img"); - blurElement.setAttribute("class", "blur"); - blurElement.setAttribute("src", thumbnailUrl); - - let hyperlinkElement = document.createElement("a"); - hyperlinkElement.setAttribute("href", sourceUrl); - hyperlinkElement.setAttribute("rel", "noopener noreferrer"); - hyperlinkElement.setAttribute("target", "_blank"); - hyperlinkElement.setAttribute("title", "Click to view image source."); - - let image_element = document.createElement("img"); - image_element.setAttribute("alt", alt); - image_element.setAttribute("src", thumbnailUrl); - - hyperlinkElement.appendChild(image_element); - - image.appendChild(blurElement); - image.appendChild(hyperlinkElement); - } - } - - export async function initLinks() { - console.log("initialising links"); - - let stats = { - total: 0x0, - overrideCount: 0x0, - currentCount: 0x0, - }; - - for (let link of document.getElementsByTagName("a")) { - ++stats.total; - - let address = link.getAttribute("href"); - - if (!address) { - console.log("note: skipping override of empty link"); - continue; - } - - let pageAnchor = Ach.parseInternalLink(address); - - if (!pageAnchor) { - console.log(`note: skipping override of link to "${address}"`); - continue; - } - - console.log(`note: overriding link to "${address}"`); - ++stats.overrideCount; - - let command = `Ach.loadPage(${JSON.stringify(pageAnchor[0x0])}, ${JSON.stringify(pageAnchor[0x1])})` - - link.removeAttribute("href"); - link.setAttribute("data-page", pageAnchor[0x0]); - link.setAttribute("onclick", command); - - if (pageAnchor[0x1]) { - link.setAttribute("data-anchor", pageAnchor[0x1]); - } - } - - let currentPage = Ach.currentPage(); - - for (let link of document.getElementsByTagName("a")) { - let page = link.getAttribute("data-page"); - let anchor = link.getAttribute("data-anchor"); - - if (page == currentPage && !anchor) { - ++stats.currentCount; - link.setAttribute("aria-current", "page"); - } else { - link.setAttribute("aria-current", "false"); - } - } - - console.log(`note: initialised (${stats.total}) links`); - console.log(`note: of which (${stats.overrideCount}) overrides were done`); - console.log(`note: and of which (${stats.currentCount}) were marked as current`); - } -} diff --git a/js/theme.ts b/js/theme.ts index 45101da..611f225 100644 --- a/js/theme.ts +++ b/js/theme.ts @@ -1,9 +1,8 @@ namespace Ach { - export function toggleTheme() { - let body = Ach.getFirstElement(document, "body"); + export function toggleTheme(): void { + let body = Ach.getFirstElementIn(document, "body"); let theme = "light"; - if (body.classList.contains("light")) { theme = "dark"; } @@ -14,7 +13,7 @@ namespace Ach { sessionStorage.setItem("theme", theme); } - export function loadTheme() { + export function loadTheme(): void { let theme = sessionStorage.getItem("theme"); if (!theme) { @@ -24,11 +23,11 @@ namespace Ach { switch (theme) { case "dark": - // We assume this theme in our stylesheets. + // We already assume this theme in our stylesheets. break; case "light": - let body = Ach.getFirstElement(document, "body"); + let body = Ach.getFirstElementIn(document, "body"); body.classList.add("light"); break; |