mirror of
https://github.com/glassflame/glassflame.github.io.git
synced 2024-12-11 17:24:27 +00:00
Add callouts
This commit is contained in:
parent
9617895c8e
commit
16cf58f9d7
8 changed files with 113 additions and 154 deletions
|
@ -249,8 +249,6 @@
|
|||
<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>
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
@ -44,71 +40,6 @@ 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}.
|
||||
|
@ -116,6 +47,12 @@ export class CalloutElement extends CustomElement {
|
|||
*/
|
||||
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.
|
||||
|
@ -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.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`.
|
||||
* 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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
this.collapseElement = document.createElement("details")
|
||||
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()
|
||||
if(this.collapse === undefined) {
|
||||
this.collapseElement = document.createElement("div")
|
||||
}
|
||||
else {
|
||||
this.recreateContainerElement()
|
||||
this.recreateCollapseElement()
|
||||
this.recreateAdmonitionElement()
|
||||
this.recreateContentsElement()
|
||||
this.collapseElement = document.createElement("details")
|
||||
if(this.collapse === "+") {
|
||||
this.collapseElement.open = true
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Marked } from "https://unpkg.com/marked@9.1.2/lib/marked.esm.js";
|
||||
import { CustomElement } from "../base.mjs";
|
||||
import {toTitleCase} from "../../utils/case.mjs";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
|
@ -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>`
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -11,7 +11,9 @@ import {
|
|||
MarkdownElement,
|
||||
VaultElement,
|
||||
BrowseElement,
|
||||
LandingElement, MathElement,
|
||||
LandingElement,
|
||||
MathElement,
|
||||
CalloutElement,
|
||||
} from "./elements/index.mjs";
|
||||
|
||||
customElements.define("x-landing", LandingElement)
|
||||
|
@ -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
src/utils/case.mjs
Normal file
9
src/utils/case.mjs
Normal 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();
|
||||
}
|
||||
);
|
||||
}
|
|
@ -85,7 +85,7 @@ blockquote {
|
|||
margin-block-end: 0;
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
padding-left: 1.5ex;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.math {
|
||||
|
@ -128,53 +128,58 @@ h1 a:hover, .wikilink.wikilink-heading:hover {
|
|||
}
|
||||
|
||||
.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 {
|
||||
--color-callout: var(--color-callout-cyan);
|
||||
--color-accent: var(--color-callout-cyan);
|
||||
}
|
||||
|
||||
.callout-info {
|
||||
--color-callout: var(--color-callout-blue);
|
||||
.callout-info, .callout-note, .callout-default {
|
||||
--color-accent: var(--color-callout-blue);
|
||||
}
|
||||
|
||||
.callout-todo {
|
||||
--color-callout: var(--color-callout-blue)
|
||||
--color-accent: var(--color-callout-blue)
|
||||
}
|
||||
|
||||
.callout-tip, .callout-hint, .callout-important {
|
||||
--color-callout: var(--color-callout-cyan);
|
||||
--color-accent: var(--color-callout-cyan);
|
||||
}
|
||||
|
||||
.callout-success, .callout-check, .callout-done {
|
||||
--color-callout: var(--color-callout-green);
|
||||
--color-accent: var(--color-callout-green);
|
||||
}
|
||||
|
||||
.callout-question, .callout-help, .callout-faq {
|
||||
--color-callout: var(--color-callout-orange);
|
||||
--color-accent: var(--color-callout-orange);
|
||||
}
|
||||
|
||||
.callout-warning, .callout-caution, .callout-attention {
|
||||
--color-callout: var(--color-callout-orange);
|
||||
--color-accent: var(--color-callout-orange);
|
||||
}
|
||||
|
||||
.callout-failure, .callout-fail, .callout-mission {
|
||||
--color-callout: var(--color-callout-red);
|
||||
--color-accent: var(--color-callout-red);
|
||||
}
|
||||
|
||||
.callout-danger, .callout-error {
|
||||
--color-callout: var(--color-callout-red);
|
||||
--color-accent: var(--color-callout-red);
|
||||
}
|
||||
|
||||
.callout-bug {
|
||||
--color-callout: var(--color-callout-red);
|
||||
--color-accent: var(--color-callout-red);
|
||||
}
|
||||
|
||||
.callout-example {
|
||||
--color-callout: var(--color-callout-purple);
|
||||
--color-accent: var(--color-callout-purple);
|
||||
}
|
||||
|
||||
.callout-quote, .callout-cite {
|
||||
--color-callout: var(--color-callout-gray);
|
||||
--color-accent: var(--color-callout-gray);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue