mirror of
https://github.com/pheralb/svgl.git
synced 2025-12-29 08:01:36 +08:00
🛠️ Update copyBtn styles for rehypeCopyBtn plugin + create generateToC() + return createdAt, updatedAt & tableOfContents
This commit is contained in:
+19
-5
@@ -1,16 +1,21 @@
|
||||
import { z } from "zod";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
// Content Collections:
|
||||
import { compileMarkdown } from "@content-collections/markdown";
|
||||
import { defineCollection, defineConfig } from "@content-collections/core";
|
||||
|
||||
// Plugings:
|
||||
// Plugins:
|
||||
import rehypeSlug from "rehype-slug";
|
||||
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
import rehypeShiki from "@shikijs/rehype/core";
|
||||
import { shikiHighlighter, rehypeShikiOptions } from "./src/utils/shiki";
|
||||
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
|
||||
// Custom Plugins:
|
||||
import { rehypeCopyBtn } from "./src/markdown/rehypeCopyBtn";
|
||||
import { getTableOfContents } from "./src/markdown/generateToC";
|
||||
import { rehypeExternalLinks } from "./src/markdown/rehypeExternalLinks";
|
||||
import { shikiHighlighter, rehypeShikiOptions } from "./src/utils/shiki";
|
||||
|
||||
const docs = defineCollection({
|
||||
name: "docs",
|
||||
@@ -22,18 +27,27 @@ const docs = defineCollection({
|
||||
}),
|
||||
transform: async (document, context) => {
|
||||
const highlighter = await shikiHighlighter();
|
||||
const filePath = path.join(
|
||||
context.collection.directory,
|
||||
document._meta.filePath,
|
||||
);
|
||||
const { mtimeMs, birthtimeMs } = await fs.stat(filePath);
|
||||
const html = await compileMarkdown(context, document, {
|
||||
rehypePlugins: [
|
||||
rehypeSlug,
|
||||
rehypeAutolinkHeadings,
|
||||
[rehypeShiki, highlighter, rehypeShikiOptions],
|
||||
rehypeExternalLinks,
|
||||
rehypeSlug,
|
||||
rehypeAutolinkHeadings,
|
||||
rehypeCopyBtn,
|
||||
],
|
||||
});
|
||||
const tableOfContents = getTableOfContents(document.content);
|
||||
return {
|
||||
...document,
|
||||
html,
|
||||
createdAt: new Date(birthtimeMs),
|
||||
updatedAt: new Date(mtimeMs),
|
||||
tableOfContents,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import GithubSlugger from "github-slugger";
|
||||
|
||||
type ToCItem = {
|
||||
id: number;
|
||||
level: number;
|
||||
text: string;
|
||||
slug: string;
|
||||
};
|
||||
|
||||
const getTableOfContents = (markdown: string): ToCItem[] => {
|
||||
const slugger = new GithubSlugger();
|
||||
const regXHeader = /(?:^|\n)(?<flag>#+)\s+(?<content>.+)/g;
|
||||
|
||||
// Delete # from code blocks and inline code:
|
||||
let clean = markdown.replace(/<pre[\s\S]*?<\/pre>/gi, "");
|
||||
clean = clean.replace(/<code[\s\S]*?<\/code>/gi, "");
|
||||
|
||||
return Array.from(clean.matchAll(regXHeader))
|
||||
.map((match, idx): ToCItem | null => {
|
||||
const groups = match.groups;
|
||||
if (
|
||||
groups &&
|
||||
typeof groups.flag === "string" &&
|
||||
typeof groups.content === "string" &&
|
||||
groups.flag.length > 1
|
||||
) {
|
||||
return {
|
||||
id: idx,
|
||||
level: groups.flag.length,
|
||||
text: groups.content,
|
||||
slug: slugger.slug(groups.content),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter((x): x is ToCItem => x !== null);
|
||||
};
|
||||
|
||||
export { getTableOfContents, type ToCItem };
|
||||
@@ -7,13 +7,14 @@ export const rehypeCopyBtn = () => {
|
||||
return (tree: UnistTree) => {
|
||||
visit(tree, "element", (node: UnistNode, index, parent) => {
|
||||
if (node.tagName === "pre" && parent && typeof index === "number") {
|
||||
const iconSize = 14;
|
||||
const copyIcon = {
|
||||
type: "element",
|
||||
tagName: "svg",
|
||||
properties: {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
width: "14",
|
||||
height: "14",
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
@@ -27,8 +28,8 @@ export const rehypeCopyBtn = () => {
|
||||
type: "element",
|
||||
tagName: "rect",
|
||||
properties: {
|
||||
width: "14",
|
||||
height: "14",
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
x: "8",
|
||||
y: "8",
|
||||
rx: "2",
|
||||
@@ -51,15 +52,15 @@ export const rehypeCopyBtn = () => {
|
||||
tagName: "svg",
|
||||
properties: {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
width: "14",
|
||||
height: "14",
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
strokeWidth: "2",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
style: "display: none;",
|
||||
class: "hidden",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -89,9 +90,9 @@ export const rehypeCopyBtn = () => {
|
||||
type: "button",
|
||||
title: "Copy code to clipboard",
|
||||
class: cn(
|
||||
"absolute top-2 right-2 px-1.5 py-0.5 rounded-md",
|
||||
"bg-transparent hover:bg-neutral-200 dark:hover:bg-neutral-800",
|
||||
"transition-colors",
|
||||
"cursor-pointer absolute top-0 right-0 px-1.5 py-0.5 rounded-bl-md",
|
||||
"border-b border-l border-neutral-200 dark:border-neutral-800",
|
||||
"transition-colors hover:text-neutral-700 dark:hover:text-neutral-300",
|
||||
),
|
||||
onclick: `
|
||||
const button = this;
|
||||
|
||||
Reference in New Issue
Block a user