PD08▸📊 Data Display · 資料展示▸程式碼
Code Block
程式碼區塊
難度 ★★★★★標籤 code · highlight · 複製3 min read
模式簡述
Code Block:程式碼展示。語法 highlight + 複製按鈕。docs 站必備。
page.tsx
export default function Page() {
return <h1>Hello</h1>
}Claude Code Prompt
參考:PD08 codeblock 組件:Codeblock.tsx Code Block:程式碼展示。語法 highlight + 複製按鈕。docs 站必備。 限制: - 沒複製按鈕 - copy 後沒反饋 - 語法 highlight 顏色太花
完整程式碼
"use client";
import { useEffect, useState } from "react";
import { Copy, Check } from "lucide-react";
import { cn } from "@/lib/utils";
type State = "single" | "tabs" | "diff";
const FILES = [
{ name: "page.tsx", code: `export default function Page() {
return <h1>Hello</h1>
}` },
{ name: "layout.tsx", code: `export default function Layout({ children }) {
return <div>{children}</div>
}` },
];
const DIFF = [
{ type: "ctx", line: `export default function Page() {` },
{ type: "del", line: ` return <h1>Hello</h1>` },
{ type: "add", line: ` return <h1>Hello, Lab</h1>` },
{ type: "add", line: ` // version 2` },
{ type: "ctx", line: `}` },
];
export function Codeblock({ state = "single" }: { state?: State }) {
const [active, setActive] = useState(0);
const [copied, setCopied] = useState(false);
useEffect(() => setActive(0), [state]);
return (
<div className="w-full max-w-md overflow-hidden rounded-lg border border-border bg-[#0a0a0a] font-mono text-xs">
<div className="flex items-center justify-between border-b border-border/60 bg-background/30 px-3 py-1.5">
{state === "tabs" ? (
<div className="flex gap-1">
{FILES.map((f, i) => (
<button
key={f.name}
onClick={() => setActive(i)}
className={cn(
"rounded-t px-2.5 py-1 text-[11px]",
i === active
? "bg-background text-foreground"
: "text-muted-foreground hover:text-foreground",
)}
>
{f.name}
</button>
))}
</div>
) : (
<span className="text-[11px] text-muted-foreground">
{state === "diff" ? "page.tsx (diff)" : "page.tsx"}
</span>
)}
<button
onClick={() => {
setCopied(true);
setTimeout(() => setCopied(false), 1200);
}}
className="text-muted-foreground hover:text-foreground"
>
{copied ? <Check className="h-3 w-3 text-emerald-500" /> : <Copy className="h-3 w-3" />}
</button>
</div>
<pre className="overflow-x-auto p-3 leading-relaxed">
{state === "diff" ? (
DIFF.map((l, i) => (
<div
key={i}
className={cn(
"px-1",
l.type === "add" && "bg-emerald-500/10 text-emerald-400",
l.type === "del" && "bg-red-500/10 text-red-400",
l.type === "ctx" && "text-muted-foreground",
)}
>
<span className="select-none opacity-60">
{l.type === "add" ? "+ " : l.type === "del" ? "- " : " "}
</span>
{l.line}
</div>
))
) : (
<code>{FILES[active].code}</code>
)}
</pre>
</div>
);
}何時用
- ✅ 技術文件、blog
- ✅ 教學步驟中的範例
- ✅ API 回應、設定檔展示
何時別用
- ❌ 極短的單行命令(用內聯
code即可) - ❌ 需要編輯的 code(用 codemirror/monaco)
- ❌ 需要執行的 code(接 sandbox)
我踩過的坑
-
沒複製按鈕:使用者要圈選文字超痛苦。右上角放 copy icon。
-
copy 後沒反饋:點完不知道有沒有成功。秀「Copied!」2 秒。
-
語法 highlight 顏色太花:colorful 主題在 docs 太雜。用單色主題或 GitHub 系列。
相關模式
- PA01