Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions apps/web/components/command-block/command-block.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="border-border/60 overflow-hidden rounded-lg border">
<div className="border-border/60 flex items-center justify-between bg-muted/30 px-4 py-2">
<span className="text-muted-foreground font-mono text-xs">
{label}
</span>
{showCopy && (
<button
type="button"
onClick={onCopy}
className="text-muted-foreground hover:text-foreground transition-colors text-xs"
>
{copyLabel
? copyLabel(copied ? "copied" : "idle")
: copied
? "Copied"
: "Copy"}
</button>
)}
</div>
<pre className="bg-muted/10 overflow-x-auto p-4 text-sm [&_code]:font-mono">
<code>{code}</code>
</pre>
</div>
)
}
1 change: 1 addition & 0 deletions apps/web/components/command-block/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CommandBlock } from "./command-block"
10 changes: 5 additions & 5 deletions apps/web/components/install-command/install-command.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CodeBlock } from "@/components/code-block"
import { CommandBlock } from "@/components/command-block"

interface InstallCommandProps {
itemId: string
Expand All @@ -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.
</p>
<CodeBlock code={githubCmd} lang="bash" />
<CommandBlock code={githubCmd} label="bash" />
<details className="text-muted-foreground text-sm">
<summary className="cursor-pointer select-none">
Other install modes
Expand All @@ -30,14 +30,14 @@ export function InstallCommand({ itemId }: InstallCommandProps) {
<p className="text-xs">
URL mode — works against the deployed showcase site:
</p>
<CodeBlock code={urlCmd} lang="bash" />
<CommandBlock code={urlCmd} label="bash" />
</div>
<div className="flex flex-col gap-2">
<p className="text-xs">
Namespace mode — register once, then any item by short name:
</p>
<CodeBlock code={namespaceSetup} lang="bash" />
<CodeBlock code={namespaceUse} lang="bash" />
<CommandBlock code={namespaceSetup} label="bash" />
<CommandBlock code={namespaceUse} label="bash" />
</div>
</div>
</details>
Expand Down
Loading