-
Notifications
You must be signed in to change notification settings - Fork 243
feat: Add support for TikZJax diagrams. #337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -202,6 +202,11 @@ module.exports = function (eleventyConfig) { | |
| )}</div></div>`; | ||
| return res | ||
| } | ||
| if (token.info === "tikz") { | ||
| const code = token.content.trim(); | ||
| const b64 = Buffer.from(code, "utf8").toString("base64"); // Encode into Base64 to avoid issues with special characters in TeX code | ||
| return `<div class="block-language-tikz">${b64}</div>`; | ||
| } | ||
|
|
||
| // Other languages | ||
| return origFenceRule(tokens, idx, options, env, slf); | ||
|
|
@@ -501,6 +506,81 @@ module.exports = function (eleventyConfig) { | |
| return str && parsed.innerHTML; | ||
| }); | ||
|
|
||
| eleventyConfig.addTransform("render-tikzjax", (() => { | ||
| // Lazy loading to save resources. | ||
| const tex2svg = require("node-tikzjax").default; | ||
|
|
||
| // Serialize renderings. | ||
| // Running node-tikzjax instances concurrently is problematic. See: https://github.com/prinsss/node-tikzjax/blob/main/README.md | ||
| let tikzQueue = Promise.resolve(); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment explaining why rendering is serialized (TeX engine likely isn't concurrency-safe), since the promise chain pattern is non-obvious.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| // https://github.com/artisticat1/obsidian-tikzjax/blob/main/main.ts | ||
| function tidyTikzSource(src) { | ||
| if (!src) return src; | ||
| return src | ||
| .replaceAll(" ", "") // Remove non-breaking space characters, otherwise we get errors | ||
| .replace(/\u00A0/g, "") | ||
| .replace(/\r\n/g, "\n") // Normalize line endings & Split into lines | ||
| .split("\n") | ||
| .map((line) => line.trim()) // Trim whitespace that is inserted when pasting in code, otherwise TikZJax complains | ||
| .filter((line) => line.length > 0) // Remove empty lines | ||
| .join("\n"); | ||
| } | ||
|
|
||
| return async function (content, outputPath) { | ||
| if (!outputPath || !outputPath.endsWith(".html")) return content; | ||
| if (!content || !content.includes('class="block-language-tikz"')) return content; | ||
|
|
||
| const root = parse(content); | ||
| const blocks = root.querySelectorAll("div.block-language-tikz"); | ||
| if (!blocks.length) return content; | ||
|
|
||
| for (const block of blocks) { | ||
| const srcB64 = block.text || ""; | ||
| const texSource = tidyTikzSource(Buffer.from(srcB64, "base64").toString("utf8")); | ||
| try { | ||
| const run = tikzQueue | ||
| .catch(() => {}) | ||
| .then(() => | ||
| tex2svg(texSource, { | ||
| // SvgOptions | ||
| embedFontCss: true, // Whether to embed the font CSS file in the SVG. | ||
| // TeXOptions | ||
| showConsole: false, // Print log of TeX engine to console. | ||
| texPackages: {}, // Additional TeX packages to load. e.g. texPackages: { pgfplots: '', amsmath: 'intlimits' }, | ||
| tikzLibraries: '', // Additional TikZ libraries to load. e.g. tikzLibraries: 'arrows.meta,calc' | ||
| }) | ||
| ); | ||
| tikzQueue = run.catch(() => {}); | ||
| const svg = await run; | ||
|
|
||
| const svgElement = parse(svg) | ||
| .querySelector("svg"); | ||
| if (svgElement) { | ||
| // Zooming would result in other TikZ diagrams being overlapped or partly invisible. | ||
| svgElement.setAttribute("style", "margin:auto; display:block;"); // e.g. oleeskild/obsidian-digital-garden#667 | ||
| block.replaceWith(svgElement); | ||
| } | ||
| } catch (e) { | ||
| console.warn("\n[TikZJax] render failed at:", outputPath); | ||
| console.warn("[TikZJax] TeX source (first 400 chars):\n", texSource.slice(0, 400)); | ||
| console.warn("[TikZJax] Warn:", e); | ||
| // Escape texSource to be interpreted as HTML properly. | ||
| // https://stackoverflow.com/a/7382028 | ||
| const texSource_escaped = texSource | ||
| .replaceAll("&", "&") | ||
| .replaceAll("<", "<") | ||
| .replaceAll(">", ">") | ||
| .replaceAll('"', """) | ||
| .replaceAll("'", "'"); | ||
| block.replaceWith(`<pre><code class="language-tikz">TikZ render failed. See build log.\n\n${(texSource_escaped)}</code></pre>`); | ||
| } | ||
| } | ||
|
|
||
| return root.toString(); | ||
| }; | ||
| })()); | ||
|
|
||
| eleventyConfig.addTransform("htmlMinifier", async (content, outputPath) => { | ||
| if ( | ||
| (process.env.NODE_ENV === "production" || process.env.ELEVENTY_ENV === "prod") && | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is registered after htmlMinifier, so in production the minifier runs first. Consider moving it before htmlMinifier to avoid fragile ordering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LukeBriton@3a3176e#diff-c306e0a99961a16f5c5c83996caa0958b94006d97f97475049ea3a08036bb5b0L535

