-
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathCodeHighlighter.tsx
More file actions
120 lines (114 loc) · 3.25 KB
/
CodeHighlighter.tsx
File metadata and controls
120 lines (114 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { Box, Code } from "@mantine/core";
import Prism from "prismjs";
import "prismjs/components/prism-bash";
import "prismjs/components/prism-shell-session";
import { useEffect, useRef } from "react";
import { useNotifier } from "../../hooks/useNotifier";
import { ThemeName } from "../../theme/types";
import { NotificationType } from "../../types/notification";
import { getConfigForTheme, themeMapper } from "./config";
interface CodeHighlighterProps {
children: string;
className?: string;
copyButton?: boolean;
theme?: ThemeName;
}
export function CodeHighlighter({
children,
className,
copyButton,
theme,
}: CodeHighlighterProps) {
const codeRef = useRef<HTMLElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const { setNotification } = useNotifier();
const config = getConfigForTheme(theme);
const finalCopyButton =
copyButton !== undefined ? copyButton : config.defaultCopyButton;
const language = "bash";
// Dynamically load Prism theme CSS based on app theme via themeMapper
useEffect(() => {
const loadTheme = async () => {
const variant = theme ? themeMapper[theme] ?? "default" : "default";
if (variant === "dark") {
await import("prismjs/themes/prism-dark.css");
} else {
await import("prismjs/themes/prism.css");
}
};
void loadTheme();
}, [theme]);
useEffect(() => {
if (codeRef.current) {
Prism.highlightElement(codeRef.current);
}
}, [children]);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(children);
setNotification({
title: "Code copied to clipboard",
message: "The code has been copied to your clipboard.",
type: NotificationType.Success,
autoClose: true,
});
} catch (error) {
setNotification({
title: "Failed to copy code",
message: "The code has not been copied to your clipboard.",
type: NotificationType.Error,
autoClose: true,
});
console.error(error);
}
};
return (
<Box className={className}>
<Box
ref={containerRef}
pos="relative"
style={{
overflow: "hidden",
}}
>
{finalCopyButton && (
<Box pos="absolute" top={8} right={8} style={{ zIndex: 10 }}>
<Code
component="button"
onClick={handleCopy}
style={{
cursor: "pointer",
...config.styling.copyButtonStyle,
color: "inherit",
fontFamily: "inherit",
}}
>
Copy
</Code>
</Box>
)}
<pre
style={{
margin: 0,
padding: config.styling.padding,
background: config.styling.backgroundColor,
border: "none",
overflow: "auto",
fontSize: config.styling.fontSize,
lineHeight: config.styling.lineHeight,
}}
>
<code
ref={codeRef}
className={`language-${language}`}
style={{
fontFamily: "var(--mantine-font-family-monospace)",
}}
>
{children}
</code>
</pre>
</Box>
</Box>
);
}