Skip to content

Commit

Permalink
Add button to copy code in markdown (#1845)
Browse files Browse the repository at this point in the history
  • Loading branch information
Slowlife01 committed Feb 25, 2023
1 parent 61e4b38 commit 188010c
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 15 deletions.
71 changes: 71 additions & 0 deletions website/src/components/Messages/RenderedCodeblock.tsx
Original file line number Diff line number Diff line change
@@ -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 ? (
<Flex pos="relative" flexDir="row" role="group">
<SyntaxHighlighter style={oneDark} language={lang} {...props}>
{String(children).replace(/\n$/, "")}
</SyntaxHighlighter>
<Button
onClick={handleCopyClick}
top="0"
pos="absolute"
display="none"
_rtl={{
left: "0",
transform: "translate(10px,40%)",
}}
_ltr={{
right: "0",
transform: "translate(-10px,40%)",
}}
_groupHover={{
display: "flex",
}}
colorScheme={isCopied ? "blue" : "gray"}
>
{isCopied ? <Check /> : <Copy />}
</Button>
</Flex>
) : (
<code className={className} {...props}>
{children}
</code>
);
};
25 changes: 10 additions & 15 deletions website/src/components/Messages/RenderedMarkdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ 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;
}

const sx: SystemStyleObject = {
overflowX: "auto",
pre: {
width: "100%",
bg: "transparent",
},
code: {
Expand All @@ -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",
},
Expand Down Expand Up @@ -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 ? (
<SyntaxHighlighter style={oneDark} language={lang} {...props}>
{String(children).replace(/\n$/, "")}
</SyntaxHighlighter>
) : (
<code className={className} {...props}>
{children}
</code>
);
},
code: RenderedCodeblock,
a({ href, ...props }) {
if (!href) {
return props.children;
Expand Down

0 comments on commit 188010c

Please sign in to comment.