diff --git a/assets/scripts/script.js b/assets/scripts/script.js index f492837..49417cf 100755 --- a/assets/scripts/script.js +++ b/assets/scripts/script.js @@ -238,64 +238,101 @@ document.addEventListener("DOMContentLoaded", () => { }); -// Make Mermaid diagrams zoomable -window.addEventListener('load', function() { - // Initialize Mermaid (if not already) - mermaid.initialize({ startOnLoad: false, theme: 'neutral' }); +// Make Mermaid diagrams use the active site theme and zoom controls. +(function () { + function cssVar(name, fallback) { + const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim(); + return value || fallback; + } - // Find all Mermaid divs - document.querySelectorAll('.mermaid').forEach(el => { - // Decode HTML entities - el.innerHTML = el.innerHTML - .replace(/>/g, '>') - .replace(/</g, '<') - .replace(/&/g, '&'); + function mermaidConfig() { + return { + startOnLoad: false, + theme: "base", + themeVariables: { + background: cssVar("--bg", "#faf9f6"), + mainBkg: cssVar("--surface", "#ffffff"), + primaryColor: cssVar("--surface", "#ffffff"), + primaryTextColor: cssVar("--fg", "#000000"), + primaryBorderColor: cssVar("--accent", "#2563eb"), + secondaryColor: cssVar("--surface-soft", "#f3f1eb"), + tertiaryColor: cssVar("--bg", "#faf9f6"), + clusterBkg: cssVar("--surface-soft", "#f3f1eb"), + clusterBorder: cssVar("--border", "#d7d7d7"), + lineColor: cssVar("--border", "#d7d7d7"), + textColor: cssVar("--fg", "#000000"), + edgeLabelBackground: cssVar("--surface", "#ffffff"), + fontFamily: cssVar("--font-body", "Noto, system-ui, sans-serif") + }, + flowchart: { + htmlLabels: true, + curve: "basis" + } + }; + } - // Wrap in container if not already wrapped - if (!el.parentElement.classList.contains('mermaid-container')) { - const container = document.createElement('div'); - container.classList.add('mermaid-container'); + function decodeMermaidSource(source) { + const textarea = document.createElement("textarea"); + textarea.innerHTML = source; + return textarea.value.trim(); + } - // Add zoom controls - const controls = document.createElement('div'); - controls.classList.add('mermaid-zoom-controls'); + async function renderMermaid() { + if (!window.mermaid) return; + const diagrams = document.querySelectorAll(".mermaid"); + if (!diagrams.length) return; + + diagrams.forEach((el) => { + if (!el.dataset.source) { + el.dataset.source = decodeMermaidSource(el.textContent || el.innerHTML); + } + el.removeAttribute("data-processed"); + el.innerHTML = el.dataset.source; + }); + + mermaid.initialize(mermaidConfig()); + await mermaid.run({ querySelector: ".mermaid" }); + wrapMermaidDiagrams(); + } + + function wrapMermaidDiagrams() { + document.querySelectorAll(".mermaid").forEach((el) => { + if (el.closest(".mermaid-container")) return; + + const container = document.createElement("div"); + container.className = "mermaid-container"; + const controls = document.createElement("div"); + controls.className = "mermaid-zoom-controls"; controls.innerHTML = ` - - + + `; - container.appendChild(controls); - // Move the mermaid diagram into container - container.appendChild(el.cloneNode(true)); el.replaceWith(container); + container.appendChild(controls); + container.appendChild(el); - // Select the SVG inside - const svg = container.querySelector('.mermaid svg'); let scale = 1; - - // Zoom functions - controls.querySelector('.zoom-in').addEventListener('click', () => { - scale += 0.1; + const setScale = (next) => { + const svg = container.querySelector(".mermaid svg"); + if (!svg) return; + scale = Math.max(0.2, Math.min(3, next)); svg.style.transform = `scale(${scale})`; - }); + }; - controls.querySelector('.zoom-out').addEventListener('click', () => { - scale = Math.max(0.1, scale - 0.1); - svg.style.transform = `scale(${scale})`; + controls.querySelector(".zoom-in").addEventListener("click", () => setScale(scale + 0.1)); + controls.querySelector(".zoom-out").addEventListener("click", () => setScale(scale - 0.1)); + container.addEventListener("wheel", (e) => { + if (!e.ctrlKey) return; + e.preventDefault(); + setScale(scale + (e.deltaY < 0 ? 0.05 : -0.05)); }); + }); + } - // Optional: scroll wheel zoom - container.addEventListener('wheel', (e) => { - if (e.ctrlKey) { // zoom only with ctrl+wheel - e.preventDefault(); - if (e.deltaY < 0) scale += 0.05; - else scale = Math.max(0.1, scale - 0.05); - svg.style.transform = `scale(${scale})`; - } - }); - } - }); - - // Finally, render Mermaid diagrams - mermaid.run({ querySelector: '.mermaid' }); -}); + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", renderMermaid); + } else { + renderMermaid(); + } +})(); diff --git a/assets/styles/style.css b/assets/styles/style.css index ca5bd97..3c46e8f 100755 --- a/assets/styles/style.css +++ b/assets/styles/style.css @@ -799,11 +799,14 @@ body.no-sidenotes { /* Mermaid container for zooming and panning */ .mermaid-container { - overflow: auto; /* allow scrolling */ + overflow: auto; width: 100%; - max-height: 800px; /* adjust to your page */ - border: 1px solid #ccc; /* optional, visual boundary */ + max-height: 800px; + border: 1px solid var(--border); + border-radius: 8px; + background: color-mix(in oklab, var(--surface) 88%, var(--bg) 12%); position: relative; + margin: 1.5rem 0; } /* Make SVG scale properly */ @@ -825,13 +828,14 @@ body.no-sidenotes { .mermaid-zoom-controls button { padding: 5px 10px; margin-left: 5px; - background: #007bff; - color: white; - border: none; + background: var(--surface); + color: var(--fg); + border: 1px solid var(--border); border-radius: 4px; cursor: pointer; } .mermaid-zoom-controls button:hover { - background: #0056b3; + background: var(--accent); + color: var(--surface); } diff --git a/build-site.el b/build-site.el index ed59f65..06795e7 100755 --- a/build-site.el +++ b/build-site.el @@ -231,19 +231,7 @@ FMT / ARGS are passed to `format'." "hidden-details.js" ) "\n") - (format " -" + (format "" (z/asset-url "assets/scripts/mermaid.min.js")) ) "Shared
HTML fragment injected into every page.") diff --git a/gitea-build-monitor.log b/gitea-build-monitor.log index 9977376..2795a2f 100644 --- a/gitea-build-monitor.log +++ b/gitea-build-monitor.log @@ -161,3 +161,9 @@ 2026-05-18T01:00:54.1945780+01:00 [INFO] Running authoring server tests with /home/zaine/master-folder/projects/authoring-service/.venv/bin/python. 2026-05-18T01:00:54.2750851+01:00 [INFO] Authoring server tests passed: ran=0, failures=0, errors=0, skipped=0, exit=0 2026-05-18T01:00:54.5820786+01:00 [INFO] Sent authoring server test notification. +2026-05-18T15:00:01.3540920+01:00 [INFO] Prepared current build status for zaine/org_web: severity=Info, status=success +2026-05-18T15:00:01.3628060+01:00 [INFO] Fetching recent Gitea Actions runs for zaine/org_web. +2026-05-18T15:00:02.4300030+01:00 [INFO] Sent build status notification with 1 embed(s). +2026-05-18T15:00:02.4501777+01:00 [INFO] Running authoring server tests with /home/zaine/master-folder/projects/authoring-service/.venv/bin/python. +2026-05-18T15:00:02.5300951+01:00 [INFO] Authoring server tests passed: ran=0, failures=0, errors=0, skipped=0, exit=0 +2026-05-18T15:00:02.8652186+01:00 [INFO] Sent authoring server test notification. diff --git a/lisp/sitemaps.el b/lisp/sitemaps.el index 52bcacd..aa798d0 100755 --- a/lisp/sitemaps.el +++ b/lisp/sitemaps.el @@ -57,9 +57,84 @@ Returns an empty string when TAGS-RAW is nil or blank." (cons (car node) children))))) (defun z/main-sitemap (title list) - "Default sitemap with hidden pages removed." - (org-publish-sitemap-default title - (z/sitemap--filter-hidden list z/site-root))) + "Default sitemap with hidden pages removed, plus an automatic Mermaid map." + (let ((filtered (z/sitemap--filter-hidden list z/site-root))) + (concat + "#+TITLE: " title "\n" + "#+OPTIONS: toc:nil num:nil\n\n" + "#+begin_src mermaid\n" + (z/sitemap--mermaid filtered) + "\n#+end_src\n\n" + "* Pages\n" + (replace-regexp-in-string + "\\`#\\+TITLE: .*\n+" "" + (org-publish-sitemap-default title filtered))))) + +(defun z/sitemap--mermaid-label (text) + "Escape TEXT for a Mermaid quoted label." + (replace-regexp-in-string + "\"" "\\\\\"" + (replace-regexp-in-string + "[\n\r\t ]+" " " + (string-trim (or text ""))) + t t)) + +(defun z/sitemap--link-data (link) + "Return (REL TITLE) from an Org sitemap LINK, or nil for directory nodes." + (when (and (stringp link) + (string-match "\\[\\[file:\\([^]]+\\)\\]\\[\\([^]]+\\)\\]\\]" link)) + (list (match-string 1 link) + (match-string 2 link)))) + +(defun z/sitemap--html-href (rel) + "Return published HTML href for Org path REL." + (concat (file-name-sans-extension rel) ".html")) + +(defun z/sitemap--mermaid (tree) + "Render sitemap TREE as Mermaid flowchart source." + (let ((counter 0) + (lines nil) + (clicks '())) + (cl-labels + ((next-id () + (setq counter (1+ counter)) + (format "n%d" counter)) + (node-label (node) + (let ((data (z/sitemap--link-data (car node)))) + (if data + (cadr data) + (car node)))) + (walk (node parent) + (when (consp node) + (if (not (stringp (car node))) + (dolist (child (cdr node)) + (walk child parent)) + (let* ((id (next-id)) + (data (z/sitemap--link-data (car node))) + (label (z/sitemap--mermaid-label (node-label node))) + (children (cdr node)) + (shape (if data "[\"%s\"]" "{{\"%s\"}}"))) + (push (format " %s%s" id (format shape label)) lines) + (push (format " %s --> %s" parent id) lines) + (when data + (push (format " click %s \"%s\" \"%s\"" + id + (z/sitemap--html-href (car data)) + (z/sitemap--mermaid-label (cadr data))) + clicks)) + (dolist (child children) + (walk child id))))))) + (dolist (node (if (and (consp tree) (not (stringp (car tree)))) + (cdr tree) + tree)) + (walk node "root"))) + (mapconcat #'identity + (append + '("flowchart TD" + " root([\"zxh\"])") + (nreverse lines) + (nreverse clicks)) + "\n"))) (defun z/sitemap--entry-data (link base-dir) "Extract (FULL-PATH DATE-STR TAGS-STR) for a sitemap ENTRY under BASE-DIR. diff --git a/posts/posts-list.org b/posts/posts-list.org index 2674782..cf3c6aa 100755 --- a/posts/posts-list.org +++ b/posts/posts-list.org @@ -4,7 +4,7 @@ See the categories: @@html:Categories@@ * Posts: -- [[file:career/career-list.org][Career List]] @@html:17-05-2026 01:00@@ +- [[file:career/career-list.org][Career List]] @@html:18-05-2026 15:07@@ - [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:11-03-2026 17:18@@ @@html:learning@@ @@html:notes@@ - [[file:career/javascript.org][Understands the Javascript language]] @@html:11-03-2026 16:52@@ @@html:learning@@ @@html:notes@@ - [[file:career/restful-api.org][Restful API]] @@html:15-02-2026 23:00@@ @@html:learning@@ @@html:notes@@ diff --git a/sitemap.org b/sitemap.org index 6bbf08a..de838a7 100755 --- a/sitemap.org +++ b/sitemap.org @@ -1,5 +1,236 @@ #+TITLE: Sitemap +#+OPTIONS: toc:nil num:nil +#+begin_src mermaid +flowchart TD + root(["zxh"]) + n1["Home"] + root --> n1 + n2["Play"] + root --> n2 + n3["Work in progress"] + root --> n3 + n4["Recently Updated"] + root --> n4 + n5{{"books"}} + root --> n5 + n6["Books List"] + n5 --> n6 + n7{{"clean-code"}} + n5 --> n7 + n8["Clean Code Notes"] + n7 --> n8 + n9{{"blogs"}} + root --> n9 + n10["Blogs Introduction"] + n9 --> n10 + n11["How to publish pages using Org Publish"] + n9 --> n11 + n12["Blogs List"] + n9 --> n12 + n13{{"home"}} + root --> n13 + n14["Countdown"] + n13 --> n14 + n15["Backlog"] + n13 --> n15 + n16["Competency Status Board"] + n13 --> n16 + n17["hidden-soul"] + n13 --> n17 + n18["Wird Tracker"] + n13 --> n18 + n19["Contact"] + n13 --> n19 + n20["Service"] + n13 --> n20 + n21["Notes"] + n13 --> n21 + n22["Categories"] + n13 --> n22 + n23{{"guide"}} + n13 --> n23 + n24["Setup"] + n23 --> n24 + n25["Wird Tracker — Technical Guide"] + n23 --> n25 + n26{{"lima"}} + root --> n26 + n27["Lima"] + n26 --> n27 + n28{{"tags"}} + root --> n28 + n29["Tag: review"] + n28 --> n29 + n30["Tag: life"] + n28 --> n30 + n31["Tag: introduction"] + n28 --> n31 + n32["Tag: learning"] + n28 --> n32 + n33["Tag: notes"] + n28 --> n33 + n34["Tag: review"] + n28 --> n34 + n35["Tag: website"] + n28 --> n35 + n36["Tag: life"] + n28 --> n36 + n37["Tag: update"] + n28 --> n37 + n38["Tag: insights"] + n28 --> n38 + n39["Tag: emacs"] + n28 --> n39 + n40["Tag: education"] + n28 --> n40 + n41["Tag: maths"] + n28 --> n41 + n42["Tag: reading"] + n28 --> n42 + n43{{"posts"}} + root --> n43 + n44["Posts Introduction"] + n43 --> n44 + n45["Posts List"] + n43 --> n45 + n46{{"career"}} + n43 --> n46 + n47["SOLID Principles"] + n46 --> n47 + n48["OWASP Top Ten"] + n46 --> n48 + n49["Retrospectives"] + n46 --> n49 + n50["Lean"] + n46 --> n50 + n51["Invest Principles"] + n46 --> n51 + n52["Career Introduction"] + n46 --> n52 + n53["Management of self training"] + n46 --> n53 + n54["Wireframe Designs"] + n46 --> n54 + n55["Requirements, features, user stories, tasks, walking skeletons"] + n46 --> n55 + n56["Benefits of Normalisation"] + n46 --> n56 + n57["Datamarts, Airflow and DAG's"] + n46 --> n57 + n58["Probation Objectives:"] + n46 --> n58 + n59["Database Permissions, Roles, and Accounts"] + n46 --> n59 + n60["Monitoring and Logging"] + n46 --> n60 + n61["Pipelines and how they work (as well as CI/CD)"] + n46 --> n61 + n62["Restful API"] + n46 --> n62 + n63["Understands the Javascript language"] + n46 --> n63 + n64["High Availability, Disaster Recovery and Business Continuity"] + n46 --> n64 + n65["Career List"] + n46 --> n65 + n66{{"play"}} + root --> n66 + n67["Sigil Press"] + n66 --> n67 + n68["Ash Below the Lake"] + n66 --> n68 + n69["Timeline Tangle"] + n66 --> n69 + n70["Ink Pond"] + n66 --> n70 + n71["Supper Wheel"] + n66 --> n71 + n72["Bookshelf Sort"] + n66 --> n72 + n73["Constellation Desk"] + n66 --> n73 + n74["Memory Cabinet"] + n66 --> n74 + n75["Archive Terminal"] + n66 --> n75 + n76["Study Lamp"] + n66 --> n76 + n77["Marginalia Machine"] + n66 --> n77 + n78["The Rain Index"] + n66 --> n78 + click n1 "index.html" "Home" + click n2 "play.html" "Play" + click n3 "wip.html" "Work in progress" + click n4 "recently-updated.html" "Recently Updated" + click n6 "books/books-list.html" "Books List" + click n8 "books/clean-code/clean-code-notes.html" "Clean Code Notes" + click n10 "blogs/blogs-intro.html" "Blogs Introduction" + click n11 "blogs/publish-pages.html" "How to publish pages using Org Publish" + click n12 "blogs/blogs-list.html" "Blogs List" + click n14 "home/countdown.html" "Countdown" + click n15 "home/backlog.html" "Backlog" + click n16 "home/status.html" "Competency Status Board" + click n17 "home/hidden-soul.html" "hidden-soul" + click n18 "home/wird-tracker.html" "Wird Tracker" + click n19 "home/contact.html" "Contact" + click n20 "home/services.html" "Service" + click n21 "home/notes.html" "Notes" + click n22 "home/categories.html" "Categories" + click n24 "home/guide/setup.html" "Setup" + click n25 "home/guide/wird-tracker-guide.html" "Wird Tracker — Technical Guide" + click n27 "lima/lima-list.html" "Lima" + click n29 "tags/review.sync-conflict-20260328-203248-VT6366A.html" "Tag: review" + click n30 "tags/life.sync-conflict-20260417-233423-VT6366A.html" "Tag: life" + click n31 "tags/introduction.html" "Tag: introduction" + click n32 "tags/learning.html" "Tag: learning" + click n33 "tags/notes.html" "Tag: notes" + click n34 "tags/review.html" "Tag: review" + click n35 "tags/website.html" "Tag: website" + click n36 "tags/life.html" "Tag: life" + click n37 "tags/update.html" "Tag: update" + click n38 "tags/insights.html" "Tag: insights" + click n39 "tags/emacs.html" "Tag: emacs" + click n40 "tags/education.html" "Tag: education" + click n41 "tags/maths.html" "Tag: maths" + click n42 "tags/reading.html" "Tag: reading" + click n44 "posts/posts-intro.html" "Posts Introduction" + click n45 "posts/posts-list.html" "Posts List" + click n47 "posts/career/solid-principles.html" "SOLID Principles" + click n48 "posts/career/owasp.html" "OWASP Top Ten" + click n49 "posts/career/retrospectives.html" "Retrospectives" + click n50 "posts/career/lean.html" "Lean" + click n51 "posts/career/invest-principles.html" "Invest Principles" + click n52 "posts/career/career-intro.html" "Career Introduction" + click n53 "posts/career/management-of-self.html" "Management of self training" + click n54 "posts/career/wireframe-designs.html" "Wireframe Designs" + click n55 "posts/career/requirements-features.html" "Requirements, features, user stories, tasks, walking skeletons" + click n56 "posts/career/normalisation.html" "Benefits of Normalisation" + click n57 "posts/career/airflow.html" "Datamarts, Airflow and DAG's" + click n58 "posts/career/probation-objectives.html" "Probation Objectives:" + click n59 "posts/career/database-permissions.html" "Database Permissions, Roles, and Accounts" + click n60 "posts/career/monitoring-and-logging.html" "Monitoring and Logging" + click n61 "posts/career/pipelines.html" "Pipelines and how they work (as well as CI/CD)" + click n62 "posts/career/restful-api.html" "Restful API" + click n63 "posts/career/javascript.html" "Understands the Javascript language" + click n64 "posts/career/ha-dr.html" "High Availability, Disaster Recovery and Business Continuity" + click n65 "posts/career/career-list.html" "Career List" + click n67 "play/sigil.html" "Sigil Press" + click n68 "play/rpg.html" "Ash Below the Lake" + click n69 "play/timeline.html" "Timeline Tangle" + click n70 "play/ink.html" "Ink Pond" + click n71 "play/recipe.html" "Supper Wheel" + click n72 "play/bookshelf.html" "Bookshelf Sort" + click n73 "play/constellation.html" "Constellation Desk" + click n74 "play/memory.html" "Memory Cabinet" + click n75 "play/terminal.html" "Archive Terminal" + click n76 "play/study.html" "Study Lamp" + click n77 "play/poem.html" "Marginalia Machine" + click n78 "play/the-rain-index.html" "The Rain Index" +#+end_src + +* Pages - [[file:index.org][Home]] - [[file:play.org][Play]] - [[file:wip.org][Work in progress]] @@ -40,8 +271,8 @@ - [[file:tags/insights.org][Tag: insights]] - [[file:tags/emacs.org][Tag: emacs]] - [[file:tags/education.org][Tag: education]] - - [[file:tags/reading.org][Tag: reading]] - [[file:tags/maths.org][Tag: maths]] + - [[file:tags/reading.org][Tag: reading]] - posts - [[file:posts/posts-intro.org][Posts Introduction]] - [[file:posts/posts-list.org][Posts List]]