Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
HUGO_ENVIRONMENT: production
HUGO_RELATIVEURLS: false
run: hugo config && hugo --minify --baseURL '${{ steps.pages.outputs.base_url }}/'
- uses: actions/setup-node@v5
- name: pre-render the Graphviz diagrams
run: npm ci && node ./script/graphviz-ssr.js
- uses: actions/upload-pages-artifact@v3
with:
path: ./public
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ jobs:
sudo dpkg -i /tmp/hugo.deb
- name: run Hugo to build the pages
run: hugo
- uses: actions/setup-node@v5
- run: npm ci && node ./script/graphviz-ssr.js
- name: build tar archive
run: cd public && tar czvf ../pages.tar.gz *
- name: Upload build artifact
Expand Down
236 changes: 111 additions & 125 deletions content/architecture.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions content/diagram-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
outputs:
- json
---
6 changes: 5 additions & 1 deletion hugo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ markup:
goldmark:
renderer:
unsafe: true
mediaTypes:
application/json:
suffixes:
- json
module:
mounts:
- source: content
target: content
params:
hugo_version: 0.145.0
hugo_version: 0.149.1
29 changes: 29 additions & 0 deletions layouts/_default/baseof.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,33 @@
{{ .Content }}
{{ end }}
</body>
{{- if .Store.Get "hasGraphviz" }}
<script src="{{ relURL "js/viz-global.js" }}"> </script>
<script type="text/javascript">
let vizInstance
window.addEventListener("DOMContentLoaded", async () => {
[...document.querySelectorAll("pre[class=graphviz]")].forEach(async (x) => {
if (!vizInstance) vizInstance = await Viz.instance()
if (x.style.display === 'none') return
const options = {
format: "svg",
graphAttributes: {
bgcolor: "transparent",
},
engine: x.getAttribute("engine") || "dot",
}
const svg = vizInstance.renderString(x.innerText, options)
const img = document.createElement('img')
img.setAttribute(
'src',
`data:image/svg+xml;utf8,${encodeURIComponent(svg.substring(svg.indexOf('<svg')))}`
)
const alt = x.getAttribute("alt")
if (alt) img.setAttribute("alt", alt)
x.parentNode.insertBefore(img, x);
x.style.display = 'none'
})
})
</script>
{{- end }}
</html>
2 changes: 2 additions & 0 deletions layouts/_default/single.json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{- $diagram_list := where .Site.Pages "RawContent" "like" "```graphviz" -}}
{{- $diagram_list | jsonify -}}
7 changes: 7 additions & 0 deletions layouts/_markup/render-codeblock-graphviz.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<pre class="graphviz"
{{- if (and (isset "engine" .Attributes) (ne "" .Attributes.engine)) }} engine="{{ .Attributes.engine }}"{{ end -}}
{{- if (and (isset "alt" .Attributes) (ne "" .Attributes.alt)) }} alt="{{ .Attributes.alt }}"{{ end -}}
>
{{- .Inner | htmlEscape | safeHTML -}}
</pre>
{{- .Page.Store.Set "hasGraphviz" true }}
145 changes: 145 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"node-html-parser": "^7.0.1"
}
}
45 changes: 45 additions & 0 deletions script/graphviz-ssr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env node

import { readFileSync, writeFileSync } from "node:fs"
import { parse } from "node-html-parser"
import Viz from "../static/js/viz-global.js"

/*
* This script post-processes the site as generated via Hugo, replacing the
* `<pre class="graphviz">` elements with inline `<svg>` ones, pre-rendered
* via `viz-js`.
*/
;(async () => {
for (const { Path: pathInPublic } of JSON.parse(readFileSync("public/diagram-list.json", "utf-8"))) {
const path = `public${pathInPublic}.html`
const contents = readFileSync(path, "utf-8")
const html = parse(contents)
const vizImport = html.querySelector('script[src$="viz-global.js"]')
if (!vizImport) {
console.error(`No 'viz-global.js' import found in ${path}; skipping`)
continue
}
vizImport.nextElementSibling.remove() // remove the inline script
vizImport.remove() // remove the import

for (const pre of html.querySelectorAll("pre.graphviz")) {
const engine = pre.getAttribute("engine") || "dot"
const svg = (await Viz.instance()).renderString(pre.textContent, {
format: "svg",
graphAttributes: {
bgcolor: "transparent",
},
engine,
})
const alt = pre.getAttribute("alt")
const altAttr = !alt ? '' : ` alt='${alt.replaceAll("&", "&amp;").replaceAll("'", "&#39;")}'`
const dataURL = `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`
pre.replaceWith(`<img${altAttr} src="${dataURL}" />`)
}
console.log(`Rewriting ${path}`)
writeFileSync(`${path}`, html.toString())
}
})().catch((e) => {
console.error(e)
process.exitCode = 1
})
9 changes: 9 additions & 0 deletions static/js/viz-global.js

Large diffs are not rendered by default.