First Commit
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import { Check, Copy } from "lucide-react";
|
||||
import React, {
|
||||
type DetailedHTMLProps,
|
||||
type HTMLAttributes,
|
||||
type PropsWithChildren,
|
||||
} from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import Stack from "../layout/Stack";
|
||||
import Row from "../layout/Row";
|
||||
import Button from "../layout/Button";
|
||||
import Divider from "../layout/Divider";
|
||||
|
||||
export const TWUIPrismLanguages = ["shell", "javascript"] as const;
|
||||
|
||||
type Props = PropsWithChildren &
|
||||
DetailedHTMLProps<HTMLAttributes<HTMLPreElement>, HTMLPreElement> & {
|
||||
wrapperProps?: DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
>;
|
||||
"data-title"?: string;
|
||||
backgroundColor?: string;
|
||||
singleBlock?: boolean;
|
||||
language?: (typeof TWUIPrismLanguages)[number];
|
||||
};
|
||||
|
||||
/**
|
||||
* # CodeBlock
|
||||
*
|
||||
* @className `twui-code-block-wrapper`
|
||||
* @className `twui-code-pre-wrapper`
|
||||
* @className `twui-code-block-pre`
|
||||
* @className `twui-code-block-header`
|
||||
*/
|
||||
export default function CodeBlock({
|
||||
children,
|
||||
wrapperProps,
|
||||
backgroundColor,
|
||||
singleBlock,
|
||||
language,
|
||||
...props
|
||||
}: Props) {
|
||||
const codeRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
|
||||
const title = props?.["data-title"];
|
||||
|
||||
const finalBackgroundColor = backgroundColor || "#28272b";
|
||||
|
||||
return (
|
||||
<div
|
||||
{...wrapperProps}
|
||||
className={twMerge(
|
||||
"outline-[1px] outline-slate-200 dark:outline-white/10",
|
||||
`rounded w-full transition-all items-start`,
|
||||
"relative max-w-[80vw] sm:max-w-[85vw] xl:max-w-[880px]",
|
||||
"twui-code-block-wrapper",
|
||||
wrapperProps?.className,
|
||||
)}
|
||||
style={{
|
||||
boxShadow: copied
|
||||
? "0 0 10px 10px rgba(18, 139, 99, 0.2)"
|
||||
: undefined,
|
||||
backgroundColor: finalBackgroundColor,
|
||||
...props.style,
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
className={twMerge(
|
||||
"gap-0 w-full overflow-x-auto relative",
|
||||
"max-h-[600px] overflow-y-auto",
|
||||
)}
|
||||
>
|
||||
<Row
|
||||
className={twMerge(
|
||||
"w-full px-1 h-10 sticky top-0 py-2",
|
||||
singleBlock ? "absolute !bg-transparent" : "",
|
||||
"twui-code-block-header",
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: finalBackgroundColor,
|
||||
}}
|
||||
>
|
||||
{title && <span className="text-white/70">{title}</span>}
|
||||
<div className="ml-auto">
|
||||
{copied ? (
|
||||
<Row>
|
||||
<span className="text-white text-xs twui-code-block-copied-text">
|
||||
Copied!
|
||||
</span>
|
||||
<div className="w-5 h-5 rounded-full bg-emerald-600 text-white flex items-center justify-center">
|
||||
<Check size={15} />
|
||||
</div>
|
||||
</Row>
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
color="gray"
|
||||
beforeIcon={<Copy size={17} color="white" />}
|
||||
className="!p-1 !bg-transparent opacity-50"
|
||||
onClick={() => {
|
||||
const content =
|
||||
codeRef.current?.textContent;
|
||||
if (!content) {
|
||||
window.alert("No Content to copy");
|
||||
return;
|
||||
}
|
||||
|
||||
window.navigator.clipboard
|
||||
.writeText(content)
|
||||
.then(() => {
|
||||
setCopied(true);
|
||||
setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 3000);
|
||||
});
|
||||
}}
|
||||
title="Copy Code Snippet"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Row>
|
||||
{!singleBlock && (
|
||||
<Divider className="!border-white/10 sticky top-10" />
|
||||
)}
|
||||
<div
|
||||
className={twMerge(
|
||||
`p-1 w-full [&_pre]:!bg-transparent`,
|
||||
singleBlock ? "" : "-mt-1",
|
||||
"twui-code-pre-wrapper",
|
||||
)}
|
||||
ref={codeRef as any}
|
||||
>
|
||||
<pre
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"!my-0 whitespace-pre-wrap",
|
||||
language ? `language-${language}` : "",
|
||||
"twui-code-block-pre",
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</pre>
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user