diff --git a/website/src/components/Messages/RenderedCodeblock.tsx b/website/src/components/Messages/RenderedCodeblock.tsx
new file mode 100644
index 0000000000..8ec91189aa
--- /dev/null
+++ b/website/src/components/Messages/RenderedCodeblock.tsx
@@ -0,0 +1,71 @@
+import { Button, Flex, useToast } from "@chakra-ui/react";
+import { Copy, Check } from "lucide-react";
+import { useState, MouseEvent } from "react";
+import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
+import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
+
+export const RenderedCodeblock = ({ node, inline, className, children, style, ...props }) => {
+ const match = /language-(\w+)/.exec(className || "");
+ const lang = match ? match[1] : "";
+
+ const [isCopied, setIsCopied] = useState(false);
+ const toast = useToast();
+
+ const handleCopyClick = async (event: MouseEvent) => {
+ event.stopPropagation();
+ toast.closeAll();
+
+ try {
+ await navigator.clipboard.writeText(String(children));
+
+ toast({
+ title: "Copied to clipboard",
+ status: "info",
+ duration: 2000,
+ isClosable: true,
+ });
+
+ setIsCopied(true);
+ setTimeout(() => setIsCopied(false), 2000);
+ } catch {
+ toast({
+ title: "Failed to copy",
+ status: "error",
+ duration: 2000,
+ isClosable: true,
+ });
+ }
+ };
+
+ return !inline ? (
+
+
+ {String(children).replace(/\n$/, "")}
+
+
+
+ ) : (
+
+ {children}
+
+ );
+};
diff --git a/website/src/components/Messages/RenderedMarkdown.tsx b/website/src/components/Messages/RenderedMarkdown.tsx
index 93364b12ed..06c59abf87 100644
--- a/website/src/components/Messages/RenderedMarkdown.tsx
+++ b/website/src/components/Messages/RenderedMarkdown.tsx
@@ -17,9 +17,9 @@ import { useTranslation } from "next-i18next";
import { memo, MouseEvent, useMemo, useState } from "react";
import ReactMarkdown from "react-markdown";
import type { ReactMarkdownOptions } from "react-markdown/lib/react-markdown";
-import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
-import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import remarkGfm from "remark-gfm";
+import { RenderedCodeblock } from "src/components/Messages/RenderedCodeblock";
+
interface RenderedMarkdownProps {
markdown: string;
}
@@ -27,6 +27,7 @@ interface RenderedMarkdownProps {
const sx: SystemStyleObject = {
overflowX: "auto",
pre: {
+ width: "100%",
bg: "transparent",
},
code: {
@@ -36,6 +37,12 @@ const sx: SystemStyleObject = {
bg: "gray.300",
p: 0.5,
borderRadius: "2px",
+ _rtl: {
+ marginLeft: "3.2rem",
+ },
+ _ltr: {
+ marginRight: "3.2rem",
+ },
_dark: {
bg: "gray.700",
},
@@ -87,19 +94,7 @@ const RenderedMarkdown = ({ markdown }: RenderedMarkdownProps) => {
const components: ReactMarkdownOptions["components"] = useMemo(() => {
return {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- code({ node, inline, className, children, style, ...props }) {
- const match = /language-(\w+)/.exec(className || "");
- const lang = match ? match[1] : "";
- return !inline ? (
-
- {String(children).replace(/\n$/, "")}
-
- ) : (
-
- {children}
-
- );
- },
+ code: RenderedCodeblock,
a({ href, ...props }) {
if (!href) {
return props.children;