1
Fork 0
mirror of https://github.com/glassflame/glassflame.github.io.git synced 2024-12-04 05:54:23 +00:00

Add callouts

This commit is contained in:
Steffo 2023-11-17 16:50:43 +01:00
parent 9617895c8e
commit 16cf58f9d7
Signed by: steffo
GPG key ID: 2A24051445686895
8 changed files with 113 additions and 154 deletions

View file

@ -249,8 +249,6 @@
<slot name="wikilink-anchor">{Wikilink}</slot></template> <slot name="wikilink-anchor">{Wikilink}</slot></template>
<template id="template-math"> <template id="template-math">
<slot name="math-katex">{Math}</slot></template> <slot name="math-katex">{Math}</slot></template>
<template id="template-callout">
<slot name="callout-contents">{Callout}</slot></template>
</head> </head>
<body is="x-browse"></body> <body is="x-browse"></body>
</html> </html>

View file

@ -1,5 +1,5 @@
export {CanvasElement, NodeFileElement, NodeGroupElement, NodeTextElement, EdgeElement} from "./canvas/index.mjs" 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 {DisplayElement} from "./display.mjs"
export {VaultElement} from "./vault.mjs" export {VaultElement} from "./vault.mjs"
export {BrowseElement} from "./browse.mjs" export {BrowseElement} from "./browse.mjs"

View file

@ -1,10 +1,6 @@
import {CustomElement} from "../base.mjs"; import {CustomElement} from "../base.mjs";
export class CalloutElement extends CustomElement { export class CalloutElement extends HTMLElement {
static get template() {
return document.getElementById("template-callout")
}
/** /**
* The kind of callout this element represents, in UPPERCASE. * The kind of callout this element represents, in UPPERCASE.
* *
@ -44,71 +40,6 @@ export class CalloutElement extends CustomElement {
this.setAttribute("collapse", value) 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`. * The element displaying the admonition of this callout, or `null` if {@link admonition} is `undefined`.
* Can be recreated with {@link recreateAdmonitionElement}. * Can be recreated with {@link recreateAdmonitionElement}.
@ -116,6 +47,12 @@ export class CalloutElement extends CustomElement {
*/ */
admonitionElement 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}. * Recreate {@link collapseElement} with the current value of {@link collapse}.
* {@link collapseElement} must not be null. * {@link collapseElement} must not be null.
@ -125,42 +62,38 @@ export class CalloutElement extends CustomElement {
if(this.admonitionElement) { if(this.admonitionElement) {
this.admonitionElement.remove() this.admonitionElement.remove()
this.admonitionElement = null this.admonitionElement = null
this.admonitionSlotElement = null
} }
this.admonitionElement = document.createElement("summary") this.admonitionElement = document.createElement("summary")
this.admonitionElement.innerText = this.admonition
this.collapseElement.appendChild(this.admonitionElement) this.admonitionSlotElement = document.createElement("slot")
this.admonitionSlotElement.name = "callout-admonition"
this.admonitionElement.appendChild(this.admonitionSlotElement)
this.collapseElement.appendChild(this.admonitionElement)
} }
/** /**
* The element displaying the contents of this callout, or `null` if {@link contents} is `undefined`. * The slot where the contents of this callout will be inserted in.
* Can be recreated with {@link recreateContentsElement}. * @type {HTMLSlotElement}
* @type {HTMLDivElement|null}
*/ */
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} * @returns {void}
*/ */
recreateContentsElement() { recreateContentsSlotElement() {
if(this.contentsElement) { if(this.contentsSlotElement) {
this.contentsElement.remove() this.contentsSlotElement.remove()
this.contentsElement = null this.contentsElement = null
} }
if(this.contents) { this.contentsSlotElement = document.createElement("slot")
this.contentsElement = document.createElement("summary") this.contentsSlotElement.name = "callout-contents"
this.contentsElement.innerText = this.contents
if(this.collapseElement) { this.collapseElement.appendChild(this.contentsSlotElement)
this.collapseElement.appendChild(this.contentsElement)
}
else {
this.containerElement.appendChild(this.contentsElement)
}
}
} }
/** /**
@ -178,51 +111,51 @@ export class CalloutElement extends CustomElement {
if(this.collapseElement) { if(this.collapseElement) {
this.collapseElement.remove() this.collapseElement.remove()
this.collapseElement = null 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("details") this.collapseElement = document.createElement("div")
this.containerElement.appendChild(this.collapseElement)
}
}
/**
* 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"
/**
* @returns {void}
*/
recreateContainerElement() {
if(this.containerElement) {
this.containerElement.remove()
this.containerElement = null
}
this.containerElement = document.createElement("blockquote")
this.containerElement.slot = this.constructor.CONTAINER_ELEMENT_SLOT
this.appendChild(this.containerElement)
}
onConnect() {
super.onConnect()
if(this.cronus) {
this.replaceParentElement()
} }
else { else {
this.recreateContainerElement() this.collapseElement = document.createElement("details")
this.recreateCollapseElement() if(this.collapse === "+") {
this.recreateAdmonitionElement() this.collapseElement.open = true
this.recreateContentsElement() }
if(this.collapse === "-") {
this.collapseElement.open = false
}
} }
this.shadowRoot.appendChild(this.collapseElement)
}
/**
* Reset the style of the parent {@link HTMLQuoteElement}.
* @returns {void}
*/
resetParentBlockquoteStyle() {
const parentClassList = this.parentElement.classList
for(const className in parentClassList.entries()) {
if(className.startsWith("callout")) {
parentClassList.remove(className)
}
}
parentClassList.add("callout")
parentClassList.add(`callout-${this.kind.toLowerCase()}`)
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
this.attachShadow({ mode: "open" })
this.recreateCollapseElement()
this.recreateAdmonitionElement()
this.recreateContentsSlotElement()
this.resetParentBlockquoteStyle()
} }
} }

View file

@ -3,3 +3,4 @@ export {FrontMatterElement} from "./frontmatter.mjs"
export {HashtagElement} from "./hashtag.mjs" export {HashtagElement} from "./hashtag.mjs"
export {WikilinkElement} from "./wikilink.mjs" export {WikilinkElement} from "./wikilink.mjs"
export {MathElement} from "./math.mjs" export {MathElement} from "./math.mjs"
export {CalloutElement} from "./callout.mjs"

View file

@ -1,5 +1,6 @@
import { Marked } from "https://unpkg.com/marked@9.1.2/lib/marked.esm.js"; import { Marked } from "https://unpkg.com/marked@9.1.2/lib/marked.esm.js";
import { CustomElement } from "../base.mjs"; import { CustomElement } from "../base.mjs";
import {toTitleCase} from "../../utils/case.mjs";
/** /**
@ -31,10 +32,13 @@ export class MarkdownElement extends CustomElement {
} }
}, },
blockquote(raw) { blockquote(raw) {
console.log(raw)
const calloutMatch = raw.match(/^\[!(.+)]([-+])? ?([^\n]+)?(?:\n+(.*))?/) const calloutMatch = raw.match(/^\[!(.+)]([-+])? ?([^\n]+)?(?:\n+(.*))?/)
if(calloutMatch) { 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 = { const result = {
type: "callout", type: "callout",
raw, raw,
@ -176,8 +180,14 @@ export class MarkdownElement extends CustomElement {
name: "callout", name: "callout",
level: "block", level: "block",
renderer(token) { renderer(token) {
console.log(token) let admonition = this.parser.parseInline(token.admonition)
return `<x-callout kind="${token.kind}" collapse="${token.collapse}" admonition="${token.admonition}" contents="${token.contents}" cronus></x-callout>` 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>`
} }
} }
], ],

View file

@ -11,7 +11,9 @@ import {
MarkdownElement, MarkdownElement,
VaultElement, VaultElement,
BrowseElement, BrowseElement,
LandingElement, MathElement, LandingElement,
MathElement,
CalloutElement,
} from "./elements/index.mjs"; } from "./elements/index.mjs";
customElements.define("x-landing", LandingElement) customElements.define("x-landing", LandingElement)
@ -27,4 +29,5 @@ customElements.define("x-frontmatter", FrontMatterElement)
customElements.define("x-hashtag", HashtagElement) customElements.define("x-hashtag", HashtagElement)
customElements.define("x-wikilink", WikilinkElement) customElements.define("x-wikilink", WikilinkElement)
customElements.define("x-math", MathElement) customElements.define("x-math", MathElement)
customElements.define("x-callout", CalloutElement)
customElements.define("x-browse", BrowseElement, {extends: "body"}) customElements.define("x-browse", BrowseElement, {extends: "body"})

9
src/utils/case.mjs Normal file
View file

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

View file

@ -85,7 +85,7 @@ blockquote {
margin-block-end: 0; margin-block-end: 0;
margin-inline-start: 0; margin-inline-start: 0;
margin-inline-end: 0; margin-inline-end: 0;
padding-left: 1.5ex; padding-left: 12px;
} }
.math { .math {
@ -128,53 +128,58 @@ h1 a:hover, .wikilink.wikilink-heading:hover {
} }
.callout { .callout {
background-color: color-mix(in srgb, var(--color-accent) 15%, transparent);
}
.callout [slot="callout-admonition"] {
color: var(--color-accent);
font-weight: bold;
} }
.callout-abstract, .callout-summary, .callout-tldr { .callout-abstract, .callout-summary, .callout-tldr {
--color-callout: var(--color-callout-cyan); --color-accent: var(--color-callout-cyan);
} }
.callout-info { .callout-info, .callout-note, .callout-default {
--color-callout: var(--color-callout-blue); --color-accent: var(--color-callout-blue);
} }
.callout-todo { .callout-todo {
--color-callout: var(--color-callout-blue) --color-accent: var(--color-callout-blue)
} }
.callout-tip, .callout-hint, .callout-important { .callout-tip, .callout-hint, .callout-important {
--color-callout: var(--color-callout-cyan); --color-accent: var(--color-callout-cyan);
} }
.callout-success, .callout-check, .callout-done { .callout-success, .callout-check, .callout-done {
--color-callout: var(--color-callout-green); --color-accent: var(--color-callout-green);
} }
.callout-question, .callout-help, .callout-faq { .callout-question, .callout-help, .callout-faq {
--color-callout: var(--color-callout-orange); --color-accent: var(--color-callout-orange);
} }
.callout-warning, .callout-caution, .callout-attention { .callout-warning, .callout-caution, .callout-attention {
--color-callout: var(--color-callout-orange); --color-accent: var(--color-callout-orange);
} }
.callout-failure, .callout-fail, .callout-mission { .callout-failure, .callout-fail, .callout-mission {
--color-callout: var(--color-callout-red); --color-accent: var(--color-callout-red);
} }
.callout-danger, .callout-error { .callout-danger, .callout-error {
--color-callout: var(--color-callout-red); --color-accent: var(--color-callout-red);
} }
.callout-bug { .callout-bug {
--color-callout: var(--color-callout-red); --color-accent: var(--color-callout-red);
} }
.callout-example { .callout-example {
--color-callout: var(--color-callout-purple); --color-accent: var(--color-callout-purple);
} }
.callout-quote, .callout-cite { .callout-quote, .callout-cite {
--color-callout: var(--color-callout-gray); --color-accent: var(--color-callout-gray);
} }