forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCodeBlock.tsx
More file actions
125 lines (111 loc) · 3.45 KB
/
Copy pathCodeBlock.tsx
File metadata and controls
125 lines (111 loc) · 3.45 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
121
122
123
124
125
"use client";
import { FC, memo } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { vscDarkPlus as highlightStyle } from "react-syntax-highlighter/dist/esm/styles/prism";
import { useCopyToClipboard } from "../../hooks/use-copy-to-clipboard";
import { CheckIcon, CopyIcon, DownloadIcon } from "./Icons";
interface CodeActionButtonProps {
onClick: () => void;
children: React.ReactNode;
}
interface Props {
language: string;
value: string;
}
interface languageMap {
[key: string]: string | undefined;
}
export const programmingLanguages: languageMap = {
javascript: ".js",
python: ".py",
java: ".java",
c: ".c",
cpp: ".cpp",
"c++": ".cpp",
"c#": ".cs",
ruby: ".rb",
php: ".php",
swift: ".swift",
"objective-c": ".m",
kotlin: ".kt",
typescript: ".ts",
go: ".go",
perl: ".pl",
rust: ".rs",
scala: ".scala",
haskell: ".hs",
lua: ".lua",
shell: ".sh",
sql: ".sql",
html: ".html",
css: ".css",
// add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
};
export const generateRandomString = (length: number, lowercase = false) => {
const chars = "ABCDEFGHJKLMNPQRSTUVWXY3456789"; // excluding similar looking characters like Z, 2, I, 1, O, 0
let result = "";
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return lowercase ? result.toLowerCase() : result;
};
const CodeBlock: FC<Props> = memo(({ language, value }) => {
const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 });
const downloadAsFile = () => {
if (typeof window === "undefined") {
return;
}
const fileExtension = programmingLanguages[language] || ".file";
const suggestedFileName = `file-${generateRandomString(3, true)}${fileExtension}`;
const fileName = window.prompt("Enter file name" || "", suggestedFileName);
if (!fileName) {
// User pressed cancel on prompt.
return;
}
const blob = new Blob([value], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = fileName;
link.href = url;
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const onCopy = () => {
if (isCopied) return;
copyToClipboard(value);
};
return (
<div className="copilotKitCodeBlock">
<div className="copilotKitCodeBlockToolbar">
<span className="copilotKitCodeBlockToolbarLanguage">{language}</span>
<div className="copilotKitCodeBlockToolbarButtons">
<button className="copilotKitCodeBlockToolbarButton" onClick={downloadAsFile}>
<DownloadIcon />
<span className="sr-only">Download</span>
</button>
<button className="copilotKitCodeBlockToolbarButton" onClick={onCopy}>
{isCopied ? <CheckIcon /> : <CopyIcon />}
<span className="sr-only">Copy code</span>
</button>
</div>
</div>
<SyntaxHighlighter
language={language}
style={highlightStyle}
PreTag="div"
customStyle={{
margin: 0,
borderBottomLeftRadius: "0.375rem",
borderBottomRightRadius: "0.375rem",
}}
>
{value}
</SyntaxHighlighter>
</div>
);
});
CodeBlock.displayName = "CodeBlock";
export { CodeBlock };