From 641d5f36d25aa5d4ac1bd7cc51280824a417420d Mon Sep 17 00:00:00 2001 From: Krish Parekh <73629899+Krish-Parekh@users.noreply.github.com> Date: Sun, 7 Dec 2025 11:08:54 +0530 Subject: [PATCH] Feat/code blocks with copy --- apps/marketing/src/components/CodeExample.tsx | 15 +++--- packages/ui/src/code-block-with-copy.tsx | 53 +++++++++++++++++++ packages/ui/styles/globals.css | 7 ++- 3 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 packages/ui/src/code-block-with-copy.tsx diff --git a/apps/marketing/src/components/CodeExample.tsx b/apps/marketing/src/components/CodeExample.tsx index ef72fa9..e6667fd 100644 --- a/apps/marketing/src/components/CodeExample.tsx +++ b/apps/marketing/src/components/CodeExample.tsx @@ -1,5 +1,6 @@ import { Button } from "@usesend/ui/src/button"; import { CodeBlock } from "@usesend/ui/src/code-block"; +import { CodeBlockWithCopy } from "@usesend/ui/src/code-block-with-copy"; import { LangToggle } from "./CodeLangToggle"; const TS_CODE = `import { UseSend } from "usesend-js"; @@ -149,12 +150,14 @@ export function CodeExample() { className={idx === 0 ? "block" : "hidden"} > {/* Cast to any to align with shiki BundledLanguage without importing types here */} - - {l.code} - + + + {l.code} + + ))} diff --git a/packages/ui/src/code-block-with-copy.tsx b/packages/ui/src/code-block-with-copy.tsx new file mode 100644 index 0000000..7df4dc7 --- /dev/null +++ b/packages/ui/src/code-block-with-copy.tsx @@ -0,0 +1,53 @@ +"use client"; + +import * as React from "react"; +import { CheckIcon } from "lucide-react"; +import { Button } from "./button"; +import { cn } from "../lib/utils"; +import { Copy } from "lucide-react"; +interface CodeBlockWithCopyProps { + code: string; + children: React.ReactNode; + className?: string; +} + +export function CodeBlockWithCopy({ + code, + children, + className, +}: CodeBlockWithCopyProps) { + const [isCopied, setIsCopied] = React.useState(false); + + const copyToClipboard = async () => { + try { + await navigator.clipboard.writeText(code); + setIsCopied(true); + setTimeout(() => setIsCopied(false), 2000); + } catch (err) { + console.error("Failed to copy: ", err); + } + }; + + return ( +
+ {children} + +
+ ); +} + diff --git a/packages/ui/styles/globals.css b/packages/ui/styles/globals.css index 9d32116..711a5a5 100644 --- a/packages/ui/styles/globals.css +++ b/packages/ui/styles/globals.css @@ -139,13 +139,18 @@ } } +/* Prevent italic styling in Shiki code blocks */ +.shiki, +.shiki span { + font-style: normal !important; +} + @media (prefers-color-scheme: dark) { .shiki, .shiki span { color: var(--shiki-dark) !important; background-color: var(--shiki-dark-bg) !important; /* Optional, if you also want font styles */ - font-style: var(--shiki-dark-font-style) !important; font-weight: var(--shiki-dark-font-weight) !important; text-decoration: var(--shiki-dark-text-decoration) !important; }