feat(website): Add Clipboard component and inject into <code> blocks (#5904)

Fixes #3866 
<img width="948" alt="Screenshot 2024-07-18 at 1 05 43 AM"
src="https://github.com/user-attachments/assets/4ad3b742-ea4e-4202-a7f8-a016914ef308">
This commit is contained in:
Jamil
2024-07-18 08:14:26 -07:00
committed by GitHub
parent 32014eafbf
commit e8c832fe73
5 changed files with 63 additions and 20 deletions

View File

@@ -3,7 +3,13 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with
## Getting Started
First, run the development server:
First, install dependencies and populate the `timestamps.json` file:
```
pnpm setup
```
Then, run the development server:
```bash
npm run dev

View File

@@ -1,14 +1,11 @@
import type { MDXComponents } from "mdx/types";
import CodeBlock from "@/components/CodeBlock";
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
// Flowbite typography and highlight together create ugly code block
// offspring, so disable typography for code blocks.
pre: ({ children }) => (
<div className="not-format mb-4 lg:mb-8">
<pre>{children}</pre>
</div>
),
pre: ({ children }) => {
return <CodeBlock>{children}</CodeBlock>;
},
...components,
};
}

View File

@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"setup": "pnpm install && bash ./timestamps.sh",
"dev": "next dev",
"prebuild": "bash ./timestamps.sh",
"build": "next build",

View File

@@ -0,0 +1,21 @@
import { Clipboard as FlowbiteClipboard } from "flowbite-react";
import type { CustomFlowbiteTheme } from "flowbite-react";
const clipboardTheme: CustomFlowbiteTheme["clipboard"] = {
withIcon: {
base: "absolute end-2 top-2 inline-flex items-center justify-center rounded p-1.5 text-neutral-500 transition transform duration-200 hover:text-neutral-800 hover:bg-neutral-50",
icon: {
defaultIcon: "h-4 w-4",
successIcon: "h-4 w-4 text-accent-500",
},
},
};
export default function Clipboard({ valueToCopy }: { valueToCopy: string }) {
return (
<FlowbiteClipboard.WithIcon
theme={clipboardTheme?.withIcon}
valueToCopy={valueToCopy}
/>
);
}

View File

@@ -1,17 +1,35 @@
"use client";
import SyntaxHighlighter from "react-syntax-highlighter";
import { a11yDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
export default function CodeBlock({
language,
codeString,
}: {
language: string;
codeString: string;
}) {
import Clipboard from "@/components/Clipboard";
import { useState, useRef, useEffect } from "react";
export default function CodeBlock({ children }: { children: React.ReactNode }) {
const [isHovered, setIsHovered] = useState(false);
const [codeString, setCodeString] = useState("");
const preRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (preRef.current) {
const codeElement = preRef.current.querySelector("code");
if (codeElement) {
setCodeString(codeElement.innerText);
}
}
}, []);
return (
<SyntaxHighlighter language={language} style={a11yDark}>
{codeString}
</SyntaxHighlighter>
<div
// Flowbite typography and highlight together create ugly code block
// offspring, so disable typography for code blocks.
className="not-format mb-4 lg:mb-8 relative"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
ref={preRef}
>
<pre>
{children}
{isHovered && <Clipboard valueToCopy={codeString} />}
</pre>
</div>
);
}