mirror of
https://github.com/KazooTTT/kazoottt-blog-v2.git
synced 2025-06-23 02:31:31 +08:00
Initial commit
This commit is contained in:
102
src/plugins/remark-admonitions.ts
Normal file
102
src/plugins/remark-admonitions.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import type { AdmonitionType } from "@/types";
|
||||
import { type Properties, h as _h } from "hastscript";
|
||||
import type { Node, Paragraph as P, Parent, PhrasingContent, Root } from "mdast";
|
||||
import type { Directives, LeafDirective, TextDirective } from "mdast-util-directive";
|
||||
import { directiveToMarkdown } from "mdast-util-directive";
|
||||
import { toMarkdown } from "mdast-util-to-markdown";
|
||||
import { toString as mdastToString } from "mdast-util-to-string";
|
||||
import type { Plugin } from "unified";
|
||||
import { visit } from "unist-util-visit";
|
||||
|
||||
// Supported admonition types
|
||||
const Admonitions = new Set<AdmonitionType>(["tip", "note", "important", "caution", "warning"]);
|
||||
|
||||
/** Checks if a string is a supported admonition type. */
|
||||
function isAdmonition(s: string): s is AdmonitionType {
|
||||
return Admonitions.has(s as AdmonitionType);
|
||||
}
|
||||
|
||||
/** Checks if a node is a directive. */
|
||||
function isNodeDirective(node: Node): node is Directives {
|
||||
return (
|
||||
node.type === "containerDirective" ||
|
||||
node.type === "leafDirective" ||
|
||||
node.type === "textDirective"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* From Astro Starlight:
|
||||
* Transforms directives not supported back to original form as it can break user content and result in 'broken' output.
|
||||
*/
|
||||
function transformUnhandledDirective(
|
||||
node: LeafDirective | TextDirective,
|
||||
index: number,
|
||||
parent: Parent,
|
||||
) {
|
||||
const textNode = {
|
||||
type: "text",
|
||||
value: toMarkdown(node, { extensions: [directiveToMarkdown()] }),
|
||||
} as const;
|
||||
if (node.type === "textDirective") {
|
||||
parent.children[index] = textNode;
|
||||
} else {
|
||||
parent.children[index] = {
|
||||
children: [textNode],
|
||||
type: "paragraph",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** From Astro Starlight: Function that generates an mdast HTML tree ready for conversion to HTML by rehype. */
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
function h(el: string, attrs: Properties = {}, children: any[] = []): P {
|
||||
const { properties, tagName } = _h(el, attrs);
|
||||
return {
|
||||
children,
|
||||
data: { hName: tagName, hProperties: properties },
|
||||
type: "paragraph",
|
||||
};
|
||||
}
|
||||
|
||||
export const remarkAdmonitions: Plugin<[], Root> = () => (tree) => {
|
||||
visit(tree, (node, index, parent) => {
|
||||
if (!parent || index === undefined || !isNodeDirective(node)) return;
|
||||
if (node.type === "textDirective" || node.type === "leafDirective") {
|
||||
transformUnhandledDirective(node, index, parent);
|
||||
return;
|
||||
}
|
||||
|
||||
const admonitionType = node.name;
|
||||
if (!isAdmonition(admonitionType)) return;
|
||||
|
||||
let title: string = admonitionType;
|
||||
let titleNode: PhrasingContent[] = [{ type: "text", value: title }];
|
||||
|
||||
// Check if there's a custom title
|
||||
const firstChild = node.children[0];
|
||||
if (
|
||||
firstChild?.type === "paragraph" &&
|
||||
firstChild.data &&
|
||||
"directiveLabel" in firstChild.data &&
|
||||
firstChild.children.length > 0
|
||||
) {
|
||||
titleNode = firstChild.children;
|
||||
title = mdastToString(firstChild.children);
|
||||
// The first paragraph contains a custom title, we can safely remove it.
|
||||
node.children.splice(0, 1);
|
||||
}
|
||||
|
||||
// Do not change prefix to AD, ADM, or similar, adblocks will block the content inside.
|
||||
const admonition = h(
|
||||
"aside",
|
||||
{ "aria-label": title, class: "admonition", "data-admonition-type": admonitionType },
|
||||
[
|
||||
h("p", { class: "admonition-title", "aria-hidden": "true" }, [...titleNode]),
|
||||
h("div", { class: "admonition-content" }, node.children),
|
||||
],
|
||||
);
|
||||
|
||||
parent.children[index] = admonition;
|
||||
});
|
||||
};
|
11
src/plugins/remark-reading-time.ts
Normal file
11
src/plugins/remark-reading-time.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { toString as mdastToString } from "mdast-util-to-string";
|
||||
import getReadingTime from "reading-time";
|
||||
|
||||
export function remarkReadingTime() {
|
||||
// @ts-expect-error:next-line
|
||||
return (tree, { data }) => {
|
||||
const textOnPage = mdastToString(tree);
|
||||
const readingTime = getReadingTime(textOnPage);
|
||||
data.astro.frontmatter.readingTime = readingTime.text;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user