From 6494b4d3b4758979527ba2825a8950ff64cba7d3 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 6 Nov 2023 16:48:20 +0100 Subject: [PATCH] Implement math via KaTeX --- .idea/jsLibraryMappings.xml | 1 + index.html | 4 ++ src/elements/index.mjs | 4 +- src/elements/markdown/index.mjs | 1 + src/elements/markdown/math.mjs | 82 ++++++++++++++++++++++++++++++ src/elements/markdown/renderer.mjs | 49 ++++++++++++++++-- src/index.mjs | 5 +- style/base.css | 15 ++++++ 8 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 src/elements/markdown/math.mjs diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml index 6dfc345..08eb54a 100644 --- a/.idea/jsLibraryMappings.xml +++ b/.idea/jsLibraryMappings.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/index.html b/index.html index 44a1e23..44292d7 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,7 @@ @import "style/light.css"; @import "style/dark.css"; + + \ No newline at end of file diff --git a/src/elements/index.mjs b/src/elements/index.mjs index 96bb5ba..7e92bac 100644 --- a/src/elements/index.mjs +++ b/src/elements/index.mjs @@ -1,6 +1,6 @@ export {CanvasElement, NodeFileElement, NodeGroupElement, NodeTextElement, EdgeElement} from "./canvas/index.mjs" -export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement} from "./markdown/index.mjs" +export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement, MathElement} from "./markdown/index.mjs" export {DisplayElement} from "./display.mjs" export {VaultElement} from "./vault.mjs" export {BrowseElement} from "./browse.mjs" -export {LandingElement} from "./landing.mjs" +export {LandingElement} from "./landing.mjs" \ No newline at end of file diff --git a/src/elements/markdown/index.mjs b/src/elements/markdown/index.mjs index 6aa7023..3761428 100644 --- a/src/elements/markdown/index.mjs +++ b/src/elements/markdown/index.mjs @@ -2,3 +2,4 @@ export {MarkdownElement} from "./renderer.mjs" export {FrontMatterElement} from "./frontmatter.mjs" export {HashtagElement} from "./hashtag.mjs" export {WikilinkElement} from "./wikilink.mjs" +export {MathElement} from "./math.mjs" diff --git a/src/elements/markdown/math.mjs b/src/elements/markdown/math.mjs new file mode 100644 index 0000000..f5ae7c1 --- /dev/null +++ b/src/elements/markdown/math.mjs @@ -0,0 +1,82 @@ +import {CustomElement} from "../base.mjs"; +import {default as katex} from 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.mjs'; + +/** + * Element rendering TeX math. + */ +export class MathElement extends CustomElement { + static get template() { + return document.getElementById("template-math") + } + + /** + * The math to render, obtained from the `document` attribute. + * @returns {string} + */ + get texDocument() { + return this.getAttribute("document") + } + set texDocument(value) { + this.setAttribute("document", value) + } + + /** + * The display mode of the KaTeX element, obtained from the `block` attribute. + * @returns {boolean} `true` if block, `false` if inline. + */ + get isBlock() { + return this.hasAttribute("block") + } + set isBlock(value) { + if(value) { + this.setAttribute("block", "") + } + else { + this.removeAttribute("block") + } + } + + /** + * The element displaying the math. + * Can be recreated with {@link recreateKatexElement}. + */ + katexElement + + /** + * The name of the slot where {@link katexElement} should be placed in. + * @type {string} + */ + static KATEX_ELEMENT_SLOT = "math-katex" + + /** + * Recreate {@link katexElement} with the current values of {@link texDocument} and {@link isBlock}. + */ + recreateKatexElement() { + if(this.katexElement) { + this.katexElement.remove() + this.katexElement = null + } + + this.katexElement = document.createElement(this.isBlock ? "div" : "span") + this.katexElement.slot = this.constructor.KATEX_ELEMENT_SLOT + this.katexElement.classList.add("math") + this.katexElement.classList.add(this.isBlock ? "math-block" : "math-inline") + + katex.render( + this.texDocument, + this.katexElement, + { + throwOnError: false, + globalGroup: true, + } + ) + + this.appendChild(this.katexElement) + } + + onConnect() { + super.onConnect() + + this.recreateKatexElement() + } +} diff --git a/src/elements/markdown/renderer.mjs b/src/elements/markdown/renderer.mjs index 450201b..c8dbd0d 100644 --- a/src/elements/markdown/renderer.mjs +++ b/src/elements/markdown/renderer.mjs @@ -20,7 +20,7 @@ export class MarkdownElement extends CustomElement { name: "frontmatter", level: "block", start(src) { - return src.match(/^(-{3,})/)?.index + return src.match(/(-{3,})/)?.index }, tokenizer(src, _) { const match = src.match(/^(-{3,})(.+)?\n((?:.+\n)*)\1\n/) @@ -42,7 +42,7 @@ export class MarkdownElement extends CustomElement { name: "wikilink", level: "inline", start(src) { - return src.match(/^\[\[/)?.index + return src.match(/\[\[/)?.index }, tokenizer(src, _) { const match = src.match(/^\[\[([^|\]]+)(?:\|([^\]]+))?]]/) @@ -63,7 +63,7 @@ export class MarkdownElement extends CustomElement { name: "hashtag", level: "inline", start(src) { - return src.match(/^#/)?.index + return src.match(/#/)?.index }, tokenizer(src, _) { const match = src.match(/^#([A-Za-z0-9]+)/) @@ -78,7 +78,48 @@ export class MarkdownElement extends CustomElement { renderer(token) { return `` } - } + }, + { + name: "mathBlock", + level: "block", + start(src) { + return src.match(/[$][$]/)?.index + }, + tokenizer(src, _) { + const match = src.match(/^[$][$](.+?)[$][$]/s) + if(match) { + return { + type: "mathBlock", + raw: match[0], + document: match[1], + } + } + }, + renderer(token) { + return `` + } + }, + { + name: "mathInline", + level: "inline", + start(src) { + return src.match(/[$]/)?.index + }, + tokenizer(src, _) { + const match = src.match(/^[$](.+?)[$]/) + if(match) { + console.log(match) + return { + type: "mathInline", + raw: match[0], + document: match[1], + } + } + }, + renderer(token) { + return `` + } + }, ] }) diff --git a/src/index.mjs b/src/index.mjs index 02e8e6d..93232d6 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -11,7 +11,7 @@ import { MarkdownElement, VaultElement, BrowseElement, - LandingElement, + LandingElement, MathElement, } from "./elements/index.mjs"; customElements.define("x-landing", LandingElement) @@ -26,4 +26,5 @@ customElements.define("x-markdown", MarkdownElement) customElements.define("x-frontmatter", FrontMatterElement) customElements.define("x-hashtag", HashtagElement) customElements.define("x-wikilink", WikilinkElement) -customElements.define("x-browse", BrowseElement, {extends: "body"}) +customElements.define("x-math", MathElement) +customElements.define("x-browse", BrowseElement, {extends: "body"}) \ No newline at end of file diff --git a/style/base.css b/style/base.css index e62340e..7fa2d18 100644 --- a/style/base.css +++ b/style/base.css @@ -19,6 +19,7 @@ --edge-width: 2px; --font-text: sans-serif; --font-mono: monospace; + --math-border-width: 1px; } @media screen { @@ -65,3 +66,17 @@ svg line { stroke: var(--color-node); stroke-width: var(--edge-width); } + +.math { + overflow-x: auto; +} + +.math-inline { + +} + +.math-block { + margin: 1em 0; + + text-align: center; +} \ No newline at end of file