Skip to content

Commit

Permalink
Add callouts
Browse files Browse the repository at this point in the history
  • Loading branch information
Steffo99 committed Nov 17, 2023
1 parent 9617895 commit 16cf58f
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 146 deletions.
2 changes: 0 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,6 @@ <h1 class="node-file-label">
<slot name="wikilink-anchor">{Wikilink}</slot></template>
<template id="template-math">
<slot name="math-katex">{Math}</slot></template>
<template id="template-callout">
<slot name="callout-contents">{Callout}</slot></template>
</head>
<body is="x-browse"></body>
</html>
2 changes: 1 addition & 1 deletion src/elements/index.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export {CanvasElement, NodeFileElement, NodeGroupElement, NodeTextElement, EdgeElement} from "./canvas/index.mjs"
export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement, MathElement} from "./markdown/index.mjs"
export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement, MathElement, CalloutElement} from "./markdown/index.mjs"
export {DisplayElement} from "./display.mjs"
export {VaultElement} from "./vault.mjs"
export {BrowseElement} from "./browse.mjs"
Expand Down
181 changes: 57 additions & 124 deletions src/elements/markdown/callout.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import {CustomElement} from "../base.mjs";

export class CalloutElement extends CustomElement {
static get template() {
return document.getElementById("template-callout")
}

export class CalloutElement extends HTMLElement {
/**
* The kind of callout this element represents, in UPPERCASE.
*
Expand Down Expand Up @@ -44,78 +40,19 @@ export class CalloutElement extends CustomElement {
this.setAttribute("collapse", value)
}

/**
* The title of this callout, in UPPERCASE, as casing is handled by CSS, or `undefined`, if the {@link kind} should be used.
*
* @return {string|undefined}
*/
get admonition() {
return this.getAttribute("admonition")?.toUpperCase()
}
set admonition(value) {
if(value === undefined) {
this.removeAttribute("admonition")
return
}
this.setAttribute("admonition", value.toUpperCase())
}

/**
* The contents of this callout, or `undefined`, if there are none.
*
* @return {string}
*/
get contents() {
const value = this.getAttribute("contents")
if(value === "undefined") {
return undefined
}
return value
}
set contents(value) {
if(value === undefined) {
this.removeAttribute("contents")
return
}
this.setAttribute("contents", value)
}

/**
* Whether this element should consume its parent {@link onConnect}.
* @return {boolean}
*/
get cronus() {
return this.hasAttribute("cronus")
}
set cronus(value) {
if(value) {
this.setAttribute("cronus", "")
}
else {
this.removeAttribute("cronus")
}
}

/**
* Replace the contents of the {@link parentElement} with this element.
* Also sets {@link cronus} to `false`.
* @returns {void}
*/
replaceParentElement() {
const grandpa = this.parentElement.parentElement
this.remove()
this.parentElement.remove()
this.cronus = false
grandpa.appendChild(this)
}

/**
* The element displaying the admonition of this callout, or `null` if {@link admonition} is `undefined`.
* Can be recreated with {@link recreateAdmonitionElement}.
* @type {HTMLElement}
*/
admonitionElement

/**
* The slot where the admonition of this callout will be inserted in.
* @type {HTMLSlotElement}
*/
admonitionSlotElement

/**
* Recreate {@link collapseElement} with the current value of {@link collapse}.
* {@link collapseElement} must not be null.
Expand All @@ -125,42 +62,38 @@ export class CalloutElement extends CustomElement {
if(this.admonitionElement) {
this.admonitionElement.remove()
this.admonitionElement = null
this.admonitionSlotElement = null
}

this.admonitionElement = document.createElement("summary")
this.admonitionElement.innerText = this.admonition
this.admonitionElement = document.createElement("summary")

this.admonitionSlotElement = document.createElement("slot")
this.admonitionSlotElement.name = "callout-admonition"
this.admonitionElement.appendChild(this.admonitionSlotElement)

this.collapseElement.appendChild(this.admonitionElement)
this.collapseElement.appendChild(this.admonitionElement)
}

/**
* The element displaying the contents of this callout, or `null` if {@link contents} is `undefined`.
* Can be recreated with {@link recreateContentsElement}.
* @type {HTMLDivElement|null}
* The slot where the contents of this callout will be inserted in.
* @type {HTMLSlotElement}
*/
contentsElement
contentsSlotElement

/**
* Recreate {@link contentsElement} with the current value of {@link contents} and {@link collapseElement} or {@link containerElement}.
* Recreate {@link contentsElement} with the current value of {@link contents} and {@link collapseElement}.
* @returns {void}
*/
recreateContentsElement() {
if(this.contentsElement) {
this.contentsElement.remove()
recreateContentsSlotElement() {
if(this.contentsSlotElement) {
this.contentsSlotElement.remove()
this.contentsElement = null
}

if(this.contents) {
this.contentsElement = document.createElement("summary")
this.contentsElement.innerText = this.contents
this.contentsSlotElement = document.createElement("slot")
this.contentsSlotElement.name = "callout-contents"

if(this.collapseElement) {
this.collapseElement.appendChild(this.contentsElement)
}
else {
this.containerElement.appendChild(this.contentsElement)
}
}
this.collapseElement.appendChild(this.contentsSlotElement)
}

/**
Expand All @@ -178,51 +111,51 @@ export class CalloutElement extends CustomElement {
if(this.collapseElement) {
this.collapseElement.remove()
this.collapseElement = null
this.admonitionElement = null
this.admonitionSlotElement = null
this.contentsElement = null
this.contentsSlotElement = null
}

if(this.collapse !== undefined) {
if(this.collapse === undefined) {
this.collapseElement = document.createElement("div")
}
else {
this.collapseElement = document.createElement("details")
this.containerElement.appendChild(this.collapseElement)
if(this.collapse === "+") {
this.collapseElement.open = true
}
if(this.collapse === "-") {
this.collapseElement.open = false
}
}
}

/**
* The element containing this callout.
* Can be recreated with {@link recreateContainerElement}.
* @type {HTMLQuoteElement}
*/
containerElement

/**
* The name of the slot where {@link containerElement} should be placed in.
* @type {string}
*/
static CONTAINER_ELEMENT_SLOT = "callout-contents"
this.shadowRoot.appendChild(this.collapseElement)
}

/**
* Reset the style of the parent {@link HTMLQuoteElement}.
* @returns {void}
*/
recreateContainerElement() {
if(this.containerElement) {
this.containerElement.remove()
this.containerElement = null
resetParentBlockquoteStyle() {
const parentClassList = this.parentElement.classList

for(const className in parentClassList.entries()) {
if(className.startsWith("callout")) {
parentClassList.remove(className)
}
}

this.containerElement = document.createElement("blockquote")
this.containerElement.slot = this.constructor.CONTAINER_ELEMENT_SLOT
this.appendChild(this.containerElement)
parentClassList.add("callout")
parentClassList.add(`callout-${this.kind.toLowerCase()}`)
}

onConnect() {
super.onConnect()
if(this.cronus) {
this.replaceParentElement()
}
else {
this.recreateContainerElement()
this.recreateCollapseElement()
this.recreateAdmonitionElement()
this.recreateContentsElement()
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
this.attachShadow({ mode: "open" })
this.recreateCollapseElement()
this.recreateAdmonitionElement()
this.recreateContentsSlotElement()
this.resetParentBlockquoteStyle()
}
}
1 change: 1 addition & 0 deletions src/elements/markdown/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export {FrontMatterElement} from "./frontmatter.mjs"
export {HashtagElement} from "./hashtag.mjs"
export {WikilinkElement} from "./wikilink.mjs"
export {MathElement} from "./math.mjs"
export {CalloutElement} from "./callout.mjs"
18 changes: 14 additions & 4 deletions src/elements/markdown/renderer.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Marked } from "https://unpkg.com/[email protected]/lib/marked.esm.js";
import { CustomElement } from "../base.mjs";
import {toTitleCase} from "../../utils/case.mjs";


/**
Expand Down Expand Up @@ -31,10 +32,13 @@ export class MarkdownElement extends CustomElement {
}
},
blockquote(raw) {
console.log(raw)
const calloutMatch = raw.match(/^\[!(.+)]([-+])? ?([^\n]+)?(?:\n+(.*))?/)
if(calloutMatch) {
const [, kind, collapse, admonition, contents] = calloutMatch
const [, kind, collapse, rawAdmonition, rawContents] = calloutMatch
const admonition = []
const contents = []
this.lexer.inlineTokens(rawAdmonition, admonition)
this.lexer.blockTokens(rawContents, contents)
const result = {
type: "callout",
raw,
Expand Down Expand Up @@ -176,8 +180,14 @@ export class MarkdownElement extends CustomElement {
name: "callout",
level: "block",
renderer(token) {
console.log(token)
return `<x-callout kind="${token.kind}" collapse="${token.collapse}" admonition="${token.admonition}" contents="${token.contents}" cronus></x-callout>`
let admonition = this.parser.parseInline(token.admonition)
const contents = this.parser.parse(token.contents)

if(admonition === "") {
admonition = toTitleCase(token.kind)
}

return `<x-callout kind="${token.kind}" collapse="${token.collapse}"><span slot="callout-admonition">${admonition}</span><div slot="callout-contents">${contents}</div></x-callout>`
}
}
],
Expand Down
5 changes: 4 additions & 1 deletion src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
MarkdownElement,
VaultElement,
BrowseElement,
LandingElement, MathElement,
LandingElement,
MathElement,
CalloutElement,
} from "./elements/index.mjs";

customElements.define("x-landing", LandingElement)
Expand All @@ -27,4 +29,5 @@ customElements.define("x-frontmatter", FrontMatterElement)
customElements.define("x-hashtag", HashtagElement)
customElements.define("x-wikilink", WikilinkElement)
customElements.define("x-math", MathElement)
customElements.define("x-callout", CalloutElement)
customElements.define("x-browse", BrowseElement, {extends: "body"})
9 changes: 9 additions & 0 deletions src/utils/case.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// https://stackoverflow.com/a/196991/4334568
export function toTitleCase(str) {
return str.replace(
/\w\S*/g,
function(txt) {
return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
}
);
}
Loading

0 comments on commit 16cf58f

Please sign in to comment.