mirror of
https://github.com/glassflame/glassflame.github.io.git
synced 2024-12-04 14:04:23 +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>
|
<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>
|
|
@ -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"
|
||||||
|
|
|
@ -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.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`.
|
* 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")
|
||||||
|
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.recreateCollapseElement()
|
||||||
this.recreateAdmonitionElement()
|
this.recreateAdmonitionElement()
|
||||||
this.recreateContentsElement()
|
this.recreateContentsSlotElement()
|
||||||
}
|
this.resetParentBlockquoteStyle()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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"
|
||||||
|
|
|
@ -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>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -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
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-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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue