From 6bf6129bd3209d30820caa594c05adfed4ea26fe Mon Sep 17 00:00:00 2001 From: taga3s Date: Tue, 10 Sep 2024 23:14:24 +0900 Subject: [PATCH] feat: show filename ui above the code block --- .../rehype-momiji/buildCodeBlockHTML.ts | 43 ++++++++++ app/modules/rehype-momiji/rehypeMomiji.ts | 12 +-- app/routes/posts/md_test.mdx | 2 +- package.json | 25 +++--- pnpm-lock.yaml | 85 ++++++++++++------- 5 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 app/modules/rehype-momiji/buildCodeBlockHTML.ts diff --git a/app/modules/rehype-momiji/buildCodeBlockHTML.ts b/app/modules/rehype-momiji/buildCodeBlockHTML.ts new file mode 100644 index 0000000..3db0926 --- /dev/null +++ b/app/modules/rehype-momiji/buildCodeBlockHTML.ts @@ -0,0 +1,43 @@ +import { bundledLanguages, bundledThemes, type BundledLanguage, type BundledTheme } from "shiki"; +import { getHighlighter } from "./highlighter"; +import { toHtml } from "hast-util-to-html"; +import type { Element } from "hast"; + +const defaultHighlighter = await getHighlighter({ themes: bundledThemes, langs: bundledLanguages }); + +const buildCodeBlockHTML = (rawCode: string, lang: string, filename: string, theme?: string) => { + const hast = defaultHighlighter.codeToHast(rawCode, { + lang: lang, + theme: theme ?? "github-dark", + }); + + const targetElem = hast.children[0] as Element; + + // Add filename to the code block if it exists + if (filename !== "" && targetElem) { + targetElem.properties = { + class: targetElem.properties.class, + style: `${targetElem.properties.style}; padding-top: 12px;`, + tabindex: targetElem.properties.tabindex, + }; + + targetElem.children.unshift({ + type: "element", + tagName: "div", + properties: { + style: + "width: fit-content; margin-bottom: 16px; padding: 4px 8px; font-size: 14px; color: white; background-color: gray;", + }, + children: [ + { + type: "text", + value: filename, + }, + ], + }); + } + + return toHtml(hast); +}; + +export { buildCodeBlockHTML }; diff --git a/app/modules/rehype-momiji/rehypeMomiji.ts b/app/modules/rehype-momiji/rehypeMomiji.ts index a52a0ea..bc835b9 100644 --- a/app/modules/rehype-momiji/rehypeMomiji.ts +++ b/app/modules/rehype-momiji/rehypeMomiji.ts @@ -5,6 +5,7 @@ import { visit } from "unist-util-visit"; import { getHighlighter } from "./highlighter"; import { parser } from "./parser"; import { isArray, isObject, isString } from "./utils/checkTypeOfOperandValue"; +import { buildCodeBlockHTML } from "./buildCodeBlockHTML"; type Options = { theme?: BundledTheme; fallbackLang?: BundledLanguage }; @@ -62,13 +63,14 @@ const rehypeMomiji: Plugin = (options: Options = { theme: "github-dark-default", return; } - const highlightCode = defaultHighlighter.codeToHtml(rawCode, { - lang: supportedLang, - theme: theme ?? "github-dark", - }); + const filename = (codeElem.properties["data-remark-code-filename"] as string) ?? ""; + + const highlightCode = buildCodeBlockHTML(rawCode, supportedLang, filename, theme); const container = ` -
${highlightCode}
+
+ ${highlightCode} +
`; const parsedRoot = parser.parse(container) as Root; diff --git a/app/routes/posts/md_test.mdx b/app/routes/posts/md_test.mdx index bb133aa..2fe32ee 100644 --- a/app/routes/posts/md_test.mdx +++ b/app/routes/posts/md_test.mdx @@ -35,6 +35,6 @@ publishedAt: "2024-09-XX" - 以下は、TypeScriptのサンプルコードです。 -```ts +```ts title="sample.ts" console.log("Hello, TypeScript!"); ``` diff --git a/package.json b/package.json index 53ab632..72e3afa 100644 --- a/package.json +++ b/package.json @@ -13,18 +13,8 @@ "prepare": "husky" }, "dependencies": { - "@types/hast": "^3.0.4", - "@types/mdast": "^4.0.4", - "@types/unist": "^3.0.3", - "hast": "^1.0.0", "hono": "^4.5.11", - "honox": "^0.1.24", - "mdast": "^3.0.0", - "rehype-parse": "^9.0.0", - "shiki": "^1.16.2", - "unified": "^11.0.5", - "unist": "^0.0.1", - "unist-util-visit": "^5.0.0" + "honox": "^0.1.24" }, "devDependencies": { "@biomejs/biome": "1.8.3", @@ -33,11 +23,22 @@ "@hono/vite-dev-server": "^0.14.0", "@hono/vite-ssg": "^0.1.0", "@mdx-js/rollup": "^3.0.1", - "husky": "^9.1.1", "lint-staged": "^15.2.7", + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3", + "hast": "^1.0.0", + "hast-util-to-html": "^9.0.2", + "husky": "^9.1.1", + "mdast": "^3.0.0", "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.0", "remark-mdx-frontmatter": "^5.0.0", + "rehype-parse": "^9.0.0", + "shiki": "^1.16.2", + "unified": "^11.0.5", + "unist": "^0.0.1", + "unist-util-visit": "^5.0.0", "vite": "^5.4.2", "wrangler": "^3.72.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7feace5..ca84c7c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,42 +8,12 @@ importers: .: dependencies: - '@types/hast': - specifier: ^3.0.4 - version: 3.0.4 - '@types/mdast': - specifier: ^4.0.4 - version: 4.0.4 - '@types/unist': - specifier: ^3.0.3 - version: 3.0.3 - hast: - specifier: ^1.0.0 - version: 1.0.0 hono: specifier: ^4.5.11 version: 4.5.11 honox: specifier: ^0.1.24 version: 0.1.24(hono@4.5.11) - mdast: - specifier: ^3.0.0 - version: 3.0.0 - rehype-parse: - specifier: ^9.0.0 - version: 9.0.0 - shiki: - specifier: ^1.16.2 - version: 1.16.2 - unified: - specifier: ^11.0.5 - version: 11.0.5 - unist: - specifier: ^0.0.1 - version: 0.0.1 - unist-util-visit: - specifier: ^5.0.0 - version: 5.0.0 devDependencies: '@biomejs/biome': specifier: 1.8.3 @@ -63,12 +33,33 @@ importers: '@mdx-js/rollup': specifier: ^3.0.1 version: 3.0.1(rollup@4.20.0) + '@types/hast': + specifier: ^3.0.4 + version: 3.0.4 + '@types/mdast': + specifier: ^4.0.4 + version: 4.0.4 + '@types/unist': + specifier: ^3.0.3 + version: 3.0.3 + hast: + specifier: ^1.0.0 + version: 1.0.0 + hast-util-to-html: + specifier: ^9.0.2 + version: 9.0.2 husky: specifier: ^9.1.1 version: 9.1.4 lint-staged: specifier: ^15.2.7 version: 15.2.8 + mdast: + specifier: ^3.0.0 + version: 3.0.0 + rehype-parse: + specifier: ^9.0.0 + version: 9.0.0 remark-frontmatter: specifier: ^5.0.0 version: 5.0.0 @@ -78,6 +69,18 @@ importers: remark-mdx-frontmatter: specifier: ^5.0.0 version: 5.0.0 + shiki: + specifier: ^1.16.2 + version: 1.16.2 + unified: + specifier: ^11.0.5 + version: 11.0.5 + unist: + specifier: ^0.0.1 + version: 0.0.1 + unist-util-visit: + specifier: ^5.0.0 + version: 5.0.0 vite: specifier: ^5.4.2 version: 5.4.2(@types/node@22.1.0) @@ -1162,6 +1165,9 @@ packages: hast-util-to-estree@3.1.0: resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==} + hast-util-to-html@9.0.2: + resolution: {integrity: sha512-RP5wNpj5nm1Z8cloDv4Sl4RS8jH5HYa0v93YB6Wb4poEzgMo/dAAL0KcT4974dCjcNG5pkLqTImeFHHCwwfY3g==} + hast-util-to-jsx-runtime@2.3.0: resolution: {integrity: sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==} @@ -1185,6 +1191,9 @@ packages: peerDependencies: hono: '>=4.*' + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -2938,6 +2947,20 @@ snapshots: transitivePeerDependencies: - supports-color + hast-util-to-html@9.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + hast-util-to-jsx-runtime@2.3.0: dependencies: '@types/estree': 1.0.5 @@ -2991,6 +3014,8 @@ snapshots: - supports-color - utf-8-validate + html-void-elements@3.0.0: {} + human-signals@5.0.0: {} husky@9.1.4: {}