mermaid js
All checks were successful
Build Org Website / build (push) Successful in 46s

This commit is contained in:
gitea-actions
2026-05-18 15:10:47 +01:00
parent d08965126f
commit 5cccf8a822
7 changed files with 414 additions and 73 deletions

View File

@@ -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(/&lt;/g, '<')
.replace(/&amp;/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 = `
<button class="zoom-in">+</button>
<button class="zoom-out">-</button>
<button class="zoom-in" type="button" aria-label="Zoom in">+</button>
<button class="zoom-out" type="button" aria-label="Zoom out">-</button>
`;
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})`;
});
// Optional: scroll wheel zoom
container.addEventListener('wheel', (e) => {
if (e.ctrlKey) { // zoom only with ctrl+wheel
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();
if (e.deltaY < 0) scale += 0.05;
else scale = Math.max(0.1, scale - 0.05);
svg.style.transform = `scale(${scale})`;
}
setScale(scale + (e.deltaY < 0 ? 0.05 : -0.05));
});
});
}
});
// Finally, render Mermaid diagrams
mermaid.run({ querySelector: '.mermaid' });
});
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", renderMermaid);
} else {
renderMermaid();
}
})();

View File

@@ -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);
}

View File

@@ -231,19 +231,7 @@ FMT / ARGS are passed to `format'."
"hidden-details.js"
)
"\n")
(format "<script src=\"%s\"></script>
<script>
window.addEventListener('load', function() {
mermaid.initialize({ startOnLoad: false, theme: 'neutral' });
document.querySelectorAll('.mermaid').forEach(el => {
el.innerHTML = el.innerHTML
.replace(/&gt;/g, '>')
.replace(/&lt;/g, '<')
.replace(/&amp;/g, '&');
});
mermaid.run({ querySelector: '.mermaid' });
});
</script>"
(format "<script src=\"%s\"></script>"
(z/asset-url "assets/scripts/mermaid.min.js"))
)
"Shared <head> HTML fragment injected into every page.")

View File

@@ -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.

View File

@@ -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.

View File

@@ -4,7 +4,7 @@
See the categories: @@html:<a href="../home/categories.html">Categories</a>@@
* Posts:
- [[file:career/career-list.org][Career List]] @@html:<span class="post-date">17-05-2026 01:00</span>@@
- [[file:career/career-list.org][Career List]] @@html:<span class="post-date">18-05-2026 15:07</span>@@
- [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:<span class="post-date">11-03-2026 17:18</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
- [[file:career/javascript.org][Understands the Javascript language]] @@html:<span class="post-date">11-03-2026 16:52</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
- [[file:career/restful-api.org][Restful API]] @@html:<span class="post-date">15-02-2026 23:00</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@

View File

@@ -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]]