From ab5b5e967f3b1044115c92ceb39fb9a04d4b5fa7 Mon Sep 17 00:00:00 2001 From: martyy-code Date: Wed, 29 Jul 2026 14:09:32 +0200 Subject: [PATCH] feat(web): add code-block styling and copy button to install commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each bash install command (visible + inside
) is now rendered through a new client component that: - Wraps the command in a rounded, bordered container with a muted bg-muted/30 header strip and a real (functional) copy button. The header label defaults to "bash" but is overridable. - Renders the command as a plain
 without going
  through Shiki. Shiki would have required the bash grammar to
  be preloaded in apps/web/lib/shiki.ts, which the project does
  not currently do — going through Shiki would have thrown
  ShikiError on every detail page render. Plain 
 avoids
  that surface entirely and keeps the visual idiom intact.
- copy state is local: navigator.clipboard.writeText with a
  silent catch (clipboard API can fail in non-secure contexts,
  e.g. http on a non-localhost origin; the user can still
  select-and-copy manually).
- copyLabel prop lets future i18n or test code inject custom
  "Copy"/"Copied" strings; default is English.

InstallCommand swaps its 4  calls
for . Otherwise the JSX structure is
unchanged.

Verification:
- typecheck exits 0
- visual shape matches the existing Code tab in the detail page
  (same border + rounded + label + copy header), reinforcing the
  visual idiom without depending on Shiki for shell languages.

Co-Authored-By: Claude 
---
 .../command-block/command-block.tsx           | 60 +++++++++++++++++++
 apps/web/components/command-block/index.ts    |  1 +
 .../install-command/install-command.tsx       | 10 ++--
 3 files changed, 66 insertions(+), 5 deletions(-)
 create mode 100644 apps/web/components/command-block/command-block.tsx
 create mode 100644 apps/web/components/command-block/index.ts

diff --git a/apps/web/components/command-block/command-block.tsx b/apps/web/components/command-block/command-block.tsx
new file mode 100644
index 0000000..69796d5
--- /dev/null
+++ b/apps/web/components/command-block/command-block.tsx
@@ -0,0 +1,60 @@
+"use client"
+
+import { useState } from "react"
+
+interface CommandBlockProps {
+  code: string
+  label?: string
+  showCopy?: boolean
+  /**
+   * Override the default "Copy" / "Copied" label pair (e.g. for localized
+   * UI). The function receives the current state and returns the label.
+   */
+  copyLabel?: (state: "idle" | "copied") => string
+}
+
+export function CommandBlock({
+  code,
+  label = "bash",
+  showCopy = true,
+  copyLabel,
+}: CommandBlockProps) {
+  const [copied, setCopied] = useState(false)
+
+  const onCopy = async () => {
+    try {
+      await navigator.clipboard.writeText(code)
+      setCopied(true)
+      window.setTimeout(() => setCopied(false), 1500)
+    } catch {
+      // Clipboard API can fail in non-secure contexts; silently ignore —
+      // the user can still select-and-copy manually.
+    }
+  }
+
+  return (
+    
+
+ + {label} + + {showCopy && ( + + )} +
+
+        {code}
+      
+
+ ) +} diff --git a/apps/web/components/command-block/index.ts b/apps/web/components/command-block/index.ts new file mode 100644 index 0000000..7bcfe17 --- /dev/null +++ b/apps/web/components/command-block/index.ts @@ -0,0 +1 @@ +export { CommandBlock } from "./command-block" diff --git a/apps/web/components/install-command/install-command.tsx b/apps/web/components/install-command/install-command.tsx index 3d288c0..784829d 100644 --- a/apps/web/components/install-command/install-command.tsx +++ b/apps/web/components/install-command/install-command.tsx @@ -1,4 +1,4 @@ -import { CodeBlock } from "@/components/code-block" +import { CommandBlock } from "@/components/command-block" interface InstallCommandProps { itemId: string @@ -20,7 +20,7 @@ export function InstallCommand({ itemId }: InstallCommandProps) { Add this component to your project with the shadcn CLI. Pick the mode that matches how you installed the registry.

- +
Other install modes @@ -30,14 +30,14 @@ export function InstallCommand({ itemId }: InstallCommandProps) {

URL mode — works against the deployed showcase site:

- +

Namespace mode — register once, then any item by short name:

- - + +