Add callout as a seperate type
This commit is contained in:
parent
be5f48feba
commit
cccfccc299
127
src/index.ts
127
src/index.ts
|
|
@ -4,14 +4,27 @@ import { toHast } from "mdast-util-to-hast"
|
||||||
import { toHtml } from "hast-util-to-html"
|
import { toHtml } from "hast-util-to-html"
|
||||||
import { toString } from 'mdast-util-to-string';
|
import { toString } from 'mdast-util-to-string';
|
||||||
import { FindAndReplaceList, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace"
|
import { FindAndReplaceList, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace"
|
||||||
|
import type { Callout, Root, Tag } from "mdast";
|
||||||
|
|
||||||
declare module 'mdast'
|
declare module 'mdast'
|
||||||
{
|
{
|
||||||
interface Tag extends Literal {
|
interface Tag extends Literal
|
||||||
|
{
|
||||||
type: "tag";
|
type: "tag";
|
||||||
data?: TagData | undefined;
|
data?: TagData | undefined;
|
||||||
}
|
}
|
||||||
interface TagData extends Data {}
|
interface TagData extends Data {}
|
||||||
|
interface Callout extends Parent
|
||||||
|
{
|
||||||
|
type: "callout";
|
||||||
|
data?: CalloutData | undefined;
|
||||||
|
}
|
||||||
|
interface CalloutData extends Data
|
||||||
|
{
|
||||||
|
type: string;
|
||||||
|
title?: string;
|
||||||
|
fold?: boolean;
|
||||||
|
}
|
||||||
interface PhrasingContentMap
|
interface PhrasingContentMap
|
||||||
{
|
{
|
||||||
tag: Tag;
|
tag: Tag;
|
||||||
|
|
@ -19,6 +32,7 @@ declare module 'mdast'
|
||||||
interface RootContentMap
|
interface RootContentMap
|
||||||
{
|
{
|
||||||
tag: Tag;
|
tag: Tag;
|
||||||
|
callout: Callout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,9 +153,9 @@ function pathToRoot(slug: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ofm() {
|
export default function ofm() {
|
||||||
return function (tree: any, file: any) {
|
return function (tree: Root, file: any) {
|
||||||
const base = pathToRoot(file?.data?.slug ?? '');
|
const base = pathToRoot(file?.data?.slug ?? '');
|
||||||
const replacements: FindAndReplaceList = []
|
const replacements: FindAndReplaceList = [];
|
||||||
|
|
||||||
replacements.push([
|
replacements.push([
|
||||||
wikilinkRegex,
|
wikilinkRegex,
|
||||||
|
|
@ -164,7 +178,7 @@ export default function ofm() {
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
])
|
]);
|
||||||
|
|
||||||
replacements.push([
|
replacements.push([
|
||||||
highlightRegex,
|
highlightRegex,
|
||||||
|
|
@ -175,7 +189,7 @@ export default function ofm() {
|
||||||
value: `<span class="text-highlight">${inner}</span>`,
|
value: `<span class="text-highlight">${inner}</span>`,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
])
|
]);
|
||||||
|
|
||||||
replacements.push([
|
replacements.push([
|
||||||
commentRegex,
|
commentRegex,
|
||||||
|
|
@ -186,7 +200,7 @@ export default function ofm() {
|
||||||
value: `<span class="text-comment">${inner}</span>`,
|
value: `<span class="text-comment">${inner}</span>`,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
])
|
]);
|
||||||
|
|
||||||
replacements.push([
|
replacements.push([
|
||||||
tagRegex,
|
tagRegex,
|
||||||
|
|
@ -210,11 +224,11 @@ export default function ofm() {
|
||||||
{ type: 'text', value: tag }
|
{ type: 'text', value: tag }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
} as Tag;
|
||||||
},
|
},
|
||||||
])
|
]);
|
||||||
|
|
||||||
visit(tree, "html", (node) => {
|
/*visit(tree, "html", (node) => {
|
||||||
for (const [regex, replace] of replacements) {
|
for (const [regex, replace] of replacements) {
|
||||||
if (typeof replace === "string") {
|
if (typeof replace === "string") {
|
||||||
node.value = node.value.replace(regex, replace)
|
node.value = node.value.replace(regex, replace)
|
||||||
|
|
@ -233,93 +247,48 @@ export default function ofm() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})*/
|
||||||
|
|
||||||
mdastFindReplace(tree, replacements);
|
mdastFindReplace(tree, replacements);
|
||||||
|
|
||||||
visit(tree, "blockquote", (node) => {
|
visit(tree, "blockquote", (node, index, parent) => {
|
||||||
if (node.children.length === 0) {
|
if (node.children.length === 0 || parent === null || index === null) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find first line
|
// find first line
|
||||||
const firstChild = node.children[0]
|
const firstChild = node.children[0];
|
||||||
if (firstChild.type !== "paragraph" || firstChild.children[0]?.type !== "text") {
|
if (firstChild.type !== "paragraph" || firstChild.children[0]?.type !== "text") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = firstChild.children[0].value
|
const text = firstChild.children[0].value;
|
||||||
const restChildren = firstChild.children.slice(1)
|
const [firstLine, ...remainingLines] = text.split("\n");
|
||||||
const [firstLine, ...remainingLines] = text.split("\n")
|
|
||||||
const remainingText = remainingLines.join("\n")
|
|
||||||
|
|
||||||
const match = firstLine.match(/^\[\!(\w+)\]([+-]?)/);
|
const match = firstLine.match(/^\[\!(\w+)\]([+-]?)/);
|
||||||
if (match && match.input) {
|
if (match && match.input) {
|
||||||
const [calloutDirective, typeString, collapseChar] = match
|
const [calloutTitle, typeString, foldChar] = match;
|
||||||
const calloutType = canonicalizeCallout(
|
const type = canonicalizeCallout(
|
||||||
typeString.toLowerCase() as keyof typeof calloutMapping,
|
typeString.toLowerCase() as keyof typeof calloutMapping,
|
||||||
)
|
);
|
||||||
const collapse = collapseChar === "+" || collapseChar === "-"
|
const fold = foldChar === "+" || foldChar === "-" ? foldChar === "-" : undefined;
|
||||||
const defaultState = collapseChar === "-" ? "collapsed" : "expanded"
|
const title = match.input.slice(calloutTitle.length).trim() || capitalize(type);
|
||||||
const titleContent =
|
|
||||||
match.input.slice(calloutDirective.length).trim() || capitalize(calloutType)
|
|
||||||
const titleNode = {
|
|
||||||
type: "paragraph",
|
|
||||||
children: [{ type: "text", value: titleContent + " " }, ...restChildren],
|
|
||||||
}
|
|
||||||
const title = mdastToHtml(titleNode)
|
|
||||||
|
|
||||||
const toggleIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="fold">
|
firstChild.children[0].value = remainingLines.join('\n');
|
||||||
<polyline points="6 9 12 15 18 9"></polyline>
|
parent.children[index] = {
|
||||||
</svg>`
|
type: 'callout',
|
||||||
|
data: {
|
||||||
const titleHtml = {
|
type,
|
||||||
type: "html",
|
fold,
|
||||||
value: `<div
|
title,
|
||||||
class="callout-title"
|
hName: 'callout',
|
||||||
>
|
|
||||||
<div class="callout-icon">${callouts[calloutType]}</div>
|
|
||||||
<div class="callout-title-inner">${title}</div>
|
|
||||||
${collapse ? toggleIcon : ""}
|
|
||||||
</div>`,
|
|
||||||
}
|
|
||||||
|
|
||||||
const blockquoteContent: any[] = [titleHtml]
|
|
||||||
if (remainingText.length > 0) {
|
|
||||||
blockquoteContent.push({
|
|
||||||
type: "paragraph",
|
|
||||||
hProperties: { className: "callout-content" },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
value: remainingText,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace first line of blockquote with title and rest of the paragraph text
|
|
||||||
node.children.splice(0, 1, ...blockquoteContent)
|
|
||||||
|
|
||||||
// add properties to base blockquote
|
|
||||||
node.data = {
|
|
||||||
hProperties: {
|
hProperties: {
|
||||||
...(node.data?.hProperties ?? {}),
|
type,
|
||||||
className: `callout ${collapse ? "is-collapsible" : ""} ${defaultState === "collapsed" ? "is-collapsed" : ""
|
fold,
|
||||||
}`,
|
title,
|
||||||
"data-callout": calloutType,
|
|
||||||
"data-callout-fold": collapse,
|
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
visit(tree, "code", (node) => {
|
|
||||||
if (node.lang === "mermaid") {
|
|
||||||
node.data = {
|
|
||||||
hProperties: {
|
|
||||||
className: ["mermaid"],
|
|
||||||
},
|
},
|
||||||
|
children: firstChild.children,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue