From 9574e2ecda92b3513084f3be0427593a6718af99 Mon Sep 17 00:00:00 2001 From: shiro Date: Wed, 24 Apr 2024 14:06:58 +0900 Subject: [PATCH] Cleanup, improve article parsing, add terminal grammar --- .gitignore | 1 + app.config.ts | 5 +- package.json | 1 + .../article.mdx | 3 +- src/ssg/getArticles.ssg.ts | 14 +++- src/style/global.style.tsx | 9 +++ .../shikiColorNotation/shikiColorNotation.ts | 68 +++++++++++++++++++ .../shikiDiffNotation/shikiDiffNotation.ts | 0 vite/markdown/shikiGrammars/terminal.json | 24 +++++++ .../viteMarkdownPlugin.ts} | 22 +++++- 10 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 vite/markdown/shikiColorNotation/shikiColorNotation.ts rename {ext => vite/markdown}/shikiDiffNotation/shikiDiffNotation.ts (100%) create mode 100644 vite/markdown/shikiGrammars/terminal.json rename vite/{viteMDPlugin.ts => markdown/viteMarkdownPlugin.ts} (65%) diff --git a/.gitignore b/.gitignore index 7f86790..8576a0d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules/ app.config.timestamp* input/ generated/ +*.bundled_*.mjs diff --git a/app.config.ts b/app.config.ts index 58da154..74608f8 100644 --- a/app.config.ts +++ b/app.config.ts @@ -17,9 +17,10 @@ import remarkGfm from "remark-gfm"; import { parseDelimitedString } from "./src/util/parseDelimitedString"; import tsconfig from "./tsconfig.json"; // import { ssrBabelPlugin } from "./vite/ssrBabelPlugin"; +// @ts-ignore import SSPreloadBabel from "solid-start-preload/babel"; import { viteImagePlugin } from "./vite/viteImagePlugin"; -import { viteMDPlugin } from "./vite/viteMDPlugin"; +import { viteMarkdownPlugin } from "./vite/markdown/viteMarkdownPlugin"; // import devtools from "solid-devtools/vite"; @@ -78,7 +79,7 @@ export default defineConfig({ viteImagePlugin(), compileTime(), solidSvg(), - viteMDPlugin(), + viteMarkdownPlugin(), // devtools({ // autoname: true, // locator: { diff --git a/package.json b/package.json index a2d4a66..ad7bb74 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "node": ">=18" }, "devDependencies": { + "shiki": "1.3.0", "@shikijs/core": "1.3.0", "@shikijs/rehype": "1.3.0", "@shikijs/transformers": "1.3.0", diff --git a/src/articles/2024-04-14-deploying-nixos-to-digital-ocean/article.mdx b/src/articles/2024-04-14-deploying-nixos-to-digital-ocean/article.mdx index 4cd6ec7..380c005 100644 --- a/src/articles/2024-04-14-deploying-nixos-to-digital-ocean/article.mdx +++ b/src/articles/2024-04-14-deploying-nixos-to-digital-ocean/article.mdx @@ -2,7 +2,6 @@ title: Deploying NixOS to Digital Ocean private: false --- - import DialogImage from "~/DialogImage"; import NoNixOSImg from "./no-nixos.jpg?lazy"; @@ -137,7 +136,7 @@ the new packages we specified. After switching, the packages should be available as globally installed system packages. -```txt +```terminal colors [nix-shell:/etc/nixos]# exit [root@droplet:~]# nixos-rebuild switch [root@droplet:~]# echo "NixOS in the cloud!" | cowsay diff --git a/src/ssg/getArticles.ssg.ts b/src/ssg/getArticles.ssg.ts index 09db14a..845e1d5 100644 --- a/src/ssg/getArticles.ssg.ts +++ b/src/ssg/getArticles.ssg.ts @@ -12,13 +12,23 @@ export const getArticlesSSG = () => { const raw = fs .readFileSync(path.join(base, slug, "article.mdx")) .toString(); - const { data: frontmatter, content } = matter(raw); + let { data: frontmatter, content } = matter(raw); if (frontmatter.private) return; const title = frontmatter.title; if (!title) return; - const description = content.match(/\n\n\n([\s\S]+?)(?=\n\n)/)?.[1]; + // trim import statements and empty lines + content = (() => { + const c = content.split("\n"); + while (c.length && (!c[0] || c[0].startsWith("import "))) { + c.splice(0, 1); + } + console.log(c[0]); + return c.join("\n"); + })(); + + const description = content.match(/([\s\S]+?)(?=\n\n)/)?.[1]; const url = `/articles/${slug.split(".")[0]}`; const date = slug.split("-").slice(0, 3).reverse().join("."); diff --git a/src/style/global.style.tsx b/src/style/global.style.tsx index b2b1ba3..ff57b7c 100644 --- a/src/style/global.style.tsx +++ b/src/style/global.style.tsx @@ -218,6 +218,15 @@ export const globals = css` .language-id { display: none; } + .color-red { + color: #f97583 !important; + } + .color-blue { + color: rgb(158, 203, 255) !important; + } + .color-gray { + color: ${color("colors/text-300a")} !important; + } &.diff { .line { &::before { diff --git a/vite/markdown/shikiColorNotation/shikiColorNotation.ts b/vite/markdown/shikiColorNotation/shikiColorNotation.ts new file mode 100644 index 0000000..1980f18 --- /dev/null +++ b/vite/markdown/shikiColorNotation/shikiColorNotation.ts @@ -0,0 +1,68 @@ +import type { ShikiTransformer } from "@shikijs/core"; +import type { Element } from "hast"; + +export interface shikiColorNotationOptions { + colors?: string[]; +} + +type MetaNode = Element & { meta?: Record }; + +export function shikiColorNotation( + options: shikiColorNotationOptions = {} +): ShikiTransformer { + const { colors = ["red", "blue", "green", "orange", "gray"] } = options; + + return { + name: "shiki-color-notation", + code(node: MetaNode) { + if (!node.meta?.colors) return; + + const lines = node.children.filter( + (node) => node.type === "element" + ) as Element[]; + + lines.forEach((line) => { + for (let i = 0; i < line.children.length; i++) { + const child = line.children[i]; + + if (child.type !== "element") continue; + const text = child.children[0]; + if (text.type !== "text") continue; + + const m = /(.*)%(.+)%(.*)%\2%(.*)/.exec(text.value); + + if (!m) continue; + + const [raw, before, color, inner, after] = m; + + if (colors.includes(color)) { + text.value = inner; + + if (inner) { + child.properties.class = `color-${color}`; + } + + if (after) { + line.children.splice(i + 1, 0, { + type: "element", + tagName: "span", + properties: {}, + children: [{ type: "text", value: after }], + }); + } + + if (before) { + line.children.splice(i, 0, { + type: "element", + tagName: "span", + properties: {}, + children: [{ type: "text", value: before }], + }); + i--; + } + } + } + }); + }, + }; +} diff --git a/ext/shikiDiffNotation/shikiDiffNotation.ts b/vite/markdown/shikiDiffNotation/shikiDiffNotation.ts similarity index 100% rename from ext/shikiDiffNotation/shikiDiffNotation.ts rename to vite/markdown/shikiDiffNotation/shikiDiffNotation.ts diff --git a/vite/markdown/shikiGrammars/terminal.json b/vite/markdown/shikiGrammars/terminal.json new file mode 100644 index 0000000..c75b245 --- /dev/null +++ b/vite/markdown/shikiGrammars/terminal.json @@ -0,0 +1,24 @@ +{ + "displayName": "Terminal", + "name": "terminal", + "patterns": [ + { + "include": "#prompt" + } + ], + "repository": { + "prompt": { + "begin": "^\\[", + "end": "\\]# ([^ ]+)", + "beginCaptures": { + "0": { "name": "string" } + }, + "endCaptures": { + "0": { "name": "string" }, + "1": { "name": "variable" } + }, + "name": "variable" + } + }, + "scopeName": "text.colors" +} diff --git a/vite/viteMDPlugin.ts b/vite/markdown/viteMarkdownPlugin.ts similarity index 65% rename from vite/viteMDPlugin.ts rename to vite/markdown/viteMarkdownPlugin.ts index a72d15d..3d5292a 100644 --- a/vite/viteMDPlugin.ts +++ b/vite/markdown/viteMarkdownPlugin.ts @@ -1,4 +1,5 @@ import { nodeTypes } from "@mdx-js/mdx"; +import fs from "fs"; import rehypeRaw from "rehype-raw"; import remarkFrontmatter from "remark-frontmatter"; // @ts-ignore @@ -8,12 +9,14 @@ import _mdx from "@vinxi/plugin-mdx"; // @ts-ignore import remarkCaptions from "remark-captions"; import remarkGfm from "remark-gfm"; -import { parseDelimitedString } from "../src/util/parseDelimitedString"; -import { shikiDiffNotation } from "../ext/shikiDiffNotation/shikiDiffNotation"; +import { bundledLanguages } from "shiki"; +import { parseDelimitedString } from "../../src/util/parseDelimitedString"; +import { shikiColorNotation } from "./shikiColorNotation/shikiColorNotation"; +import { shikiDiffNotation } from "./shikiDiffNotation/shikiDiffNotation"; const { default: mdx } = _mdx; -export const viteMDPlugin = () => +export const viteMarkdownPlugin = () => mdx.withImports({})({ jsx: true, jsxImportSource: "solid-js", @@ -28,6 +31,18 @@ export const viteMDPlugin = () => rehypeShiki, { theme: "github-dark", + langs: [ + ...Object.keys(bundledLanguages), + // theme colors: https://github.com/shikijs/textmate-grammars-themes/blob/45c05724db7ce7015e81d68b5b3f56dfcc0e8a2b/packages/tm-themes/themes/github-dark.json + JSON.parse( + fs + .readFileSync( + "vite/markdown/shikiGrammars/terminal.json", + "utf-8" + ) + .toString() + ), + ], transformers: [ // codeblock meta parser (() => { @@ -50,6 +65,7 @@ export const viteMDPlugin = () => }; })(), shikiDiffNotation(), + shikiColorNotation(), ], }, ],