feat(codeblocks): codeblocks now have proper theming with highlighting

This commit is contained in:
2026-07-21 23:24:16 +02:00
parent 1311c79479
commit 9041c683f8
4 changed files with 146 additions and 9 deletions
+2
View File
@@ -18,6 +18,8 @@
"rehype-raw": "^7.0.0",
"rehype-sanitize": "^6.0.0",
"remark-gfm": "^4.0.1",
"shiki": "^4.3.1",
"@shikijs/rehype": "^4.3.1",
"tailwindcss": "^4.2.2"
},
"devDependencies": {
+12
View File
@@ -58,3 +58,15 @@
.stream-frame iframe {
@apply w-full h-full border-0;
}
.shiki,
.shiki .line span {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
}
.macchiato .shiki,
.macchiato .shiki .line span {
color: var(--shiki-dark);
background-color: var(--shiki-dark-bg);
}
+61 -9
View File
@@ -9,6 +9,7 @@ import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
import highlighter from "../utils/highlighter";
const toRawUrl = (repoUrl: string): string => {
if (!repoUrl) return repoUrl;
@@ -136,10 +137,7 @@ export default function MdProcessor({
if (isBlock) {
return (
<code
className={`${className || ""} text-sm block overflow-x-auto`}
{...props}
>
<code className="text-sm" {...props}>
{children}
</code>
);
@@ -157,13 +155,67 @@ export default function MdProcessor({
pre({
children,
...props
}: ComponentPropsWithoutRef<"pre">): ReactElement {
const codeChild = Array.isArray(children)
? children[0]
: children;
let lang = "";
let code = "";
if (
codeChild &&
typeof codeChild === "object" &&
"props" in codeChild
) {
const el = codeChild as {
props: {
className?: string;
children?: string;
};
};
const cls = el.props?.className;
const match = cls?.match(/language-(\w+)/);
if (match) lang = match[1];
if (
typeof el.props?.children === "string"
) {
code = el.props.children;
}
}
const highlighted =
lang && code
? highlighter.codeToHtml(code, {
lang,
themes: {
dark: "catppuccin-macchiato",
light: "catppuccin-latte",
},
defaultColor: false,
})
: null;
if (highlighted) {
return (
<div className="relative border-2 border-ctp-text/50 rounded-md overflow-hidden my-6 bg-ctp-base">
{lang && (
<span className="absolute top-0 left-0 px-2 py-1 text-xs font-mono text-ctp-mauve">
{lang}
</span>
)}
<div
className={`overflow-x-auto text-sm p-4 ${lang ? "pt-7" : ""}`}
dangerouslySetInnerHTML={{
__html: highlighted,
}}
/>
</div>
);
}
return (
<pre
className="bg-ctp-mantle p-4 rounded-lg overflow-x-auto text-sm my-4"
{...props}
>
<pre className="overflow-x-auto text-sm p-4 bg-ctp-mantle m-0 border-2 border-ctp-lavender/60 rounded-md my-6">
{children}
</pre>
);
+71
View File
@@ -0,0 +1,71 @@
import { createHighlighter } from "shiki";
export default await createHighlighter({
themes: ["catppuccin-macchiato", "catppuccin-latte"],
langs: [
"javascript",
"typescript",
"jsx",
"tsx",
"css",
"html",
"json",
"bash",
"shellscript",
"python",
"markdown",
"yaml",
"toml",
"rust",
"sql",
"diff",
"docker",
"graphql",
"go",
"java",
"kotlin",
"swift",
"c",
"cpp",
"odin",
"csharp",
"php",
"ruby",
"perl",
"lua",
"haskell",
"scala",
"elixir",
"erlang",
"r",
"matlab",
"sass",
"scss",
"less",
"vue",
"svelte",
"astro",
"solidity",
"nix",
"zig",
"ocaml",
"coq",
"lean",
"purescript",
"racket",
"scheme",
"clojure",
"common-lisp",
"makefile",
"cmake",
"powershell",
"proto",
"prisma",
"terraform",
"hcl",
"nginx",
"apache",
"latex",
"tex",
],
});