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: {}