TypeScript · 4166 bytes Raw Blame History
1 import type { MDXComponents } from "mdx/types";
2 import ShellHighlighter from "@/components/ShellHighlighter";
3 import LuaHighlighter from "@/components/LuaHighlighter";
4
5 function slugify(text: string): string {
6 return text
7 .toLowerCase()
8 .replace(/[^a-z0-9]+/g, "-")
9 .replace(/(^-|-$)/g, "");
10 }
11
12 export function useMDXComponents(components: MDXComponents): MDXComponents {
13 return {
14 h1: ({ children }) => (
15 <h1 className="text-3xl font-bold text-surface-900 dark:text-surface-100 mb-6 mt-8 first:mt-0">
16 {children}
17 </h1>
18 ),
19 h2: ({ children }) => {
20 const id = typeof children === "string" ? slugify(children) : "";
21 return (
22 <h2
23 id={id}
24 className="text-2xl font-semibold text-surface-900 dark:text-surface-100 mb-4 mt-8 border-b border-surface-200 dark:border-surface-700 pb-2"
25 >
26 {children}
27 </h2>
28 );
29 },
30 h3: ({ children }) => {
31 const id = typeof children === "string" ? slugify(children) : "";
32 return (
33 <h3
34 id={id}
35 className="text-xl font-semibold text-surface-900 dark:text-surface-100 mb-3 mt-6"
36 >
37 {children}
38 </h3>
39 );
40 },
41 h4: ({ children }) => (
42 <h4 className="text-lg font-medium text-surface-900 dark:text-surface-100 mb-2 mt-4">
43 {children}
44 </h4>
45 ),
46 p: ({ children }) => (
47 <p className="text-surface-700 dark:text-surface-300 mb-4 leading-relaxed">
48 {children}
49 </p>
50 ),
51 ul: ({ children }) => (
52 <ul className="list-disc list-inside mb-4 text-surface-700 dark:text-surface-300 space-y-1">
53 {children}
54 </ul>
55 ),
56 ol: ({ children }) => (
57 <ol className="list-decimal list-inside mb-4 text-surface-700 dark:text-surface-300 space-y-1">
58 {children}
59 </ol>
60 ),
61 li: ({ children }) => <li className="ml-4">{children}</li>,
62 code: ({ children, className }) => {
63 const isBlock = className?.includes("language-");
64 const isShell =
65 className?.includes("language-bash") ||
66 className?.includes("language-sh") ||
67 className?.includes("language-shell");
68 const isLua = className?.includes("language-lua");
69
70 if (isBlock) {
71 if (isShell && typeof children === "string") {
72 return <ShellHighlighter code={children} className="block text-sm font-mono" />;
73 }
74 if (isLua && typeof children === "string") {
75 return <LuaHighlighter code={children} className="block text-sm font-mono" />;
76 }
77 return (
78 <code className={`block text-surface-100 text-sm font-mono ${className || ""}`}>
79 {children}
80 </code>
81 );
82 }
83 return (
84 <code className="bg-surface-200 dark:bg-surface-700 text-surface-800 dark:text-surface-200 px-1.5 py-0.5 rounded text-sm font-mono">
85 {children}
86 </code>
87 );
88 },
89 pre: ({ children }) => (
90 <pre className="bg-surface-900 dark:bg-surface-950 rounded-lg mb-4 overflow-x-auto p-4">
91 {children}
92 </pre>
93 ),
94 blockquote: ({ children }) => (
95 <blockquote className="border-l-4 border-surface-300 dark:border-surface-600 pl-4 italic text-surface-600 dark:text-surface-400 mb-4">
96 {children}
97 </blockquote>
98 ),
99 a: ({ href, children }) => (
100 <a href={href} className="text-accent hover:underline">
101 {children}
102 </a>
103 ),
104 table: ({ children }) => (
105 <div className="overflow-x-auto mb-4">
106 <table className="min-w-full border border-surface-200 dark:border-surface-700">
107 {children}
108 </table>
109 </div>
110 ),
111 th: ({ children }) => (
112 <th className="border border-surface-200 dark:border-surface-700 px-4 py-2 bg-surface-100 dark:bg-surface-800 font-semibold text-left">
113 {children}
114 </th>
115 ),
116 td: ({ children }) => (
117 <td className="border border-surface-200 dark:border-surface-700 px-4 py-2">
118 {children}
119 </td>
120 ),
121 hr: () => (
122 <hr className="border-surface-200 dark:border-surface-700 my-8" />
123 ),
124 ...components,
125 };
126 }