58 lines
1.5 KiB
TypeScript
58 lines
1.5 KiB
TypeScript
import { useState } from "react";
|
|
|
|
export function CodeBlock({
|
|
code,
|
|
language = "text",
|
|
}: {
|
|
code: string;
|
|
language?: string;
|
|
}) {
|
|
const [status, setStatus] = useState("复制");
|
|
async function copy() {
|
|
try {
|
|
await navigator.clipboard.writeText(code);
|
|
setStatus("已复制");
|
|
} catch {
|
|
setStatus("复制失败,请手动选择");
|
|
}
|
|
setTimeout(() => setStatus("复制"), 2400);
|
|
}
|
|
return (
|
|
<div className="code-block">
|
|
<div className="code-toolbar">
|
|
<span>{language === "sh" ? "Terminal" : language}</span>
|
|
<button onClick={copy} aria-label="复制代码">
|
|
{status}
|
|
</button>
|
|
<span className="sr-only" role="status">
|
|
{status === "复制" ? "" : status}
|
|
</span>
|
|
</div>
|
|
<pre>
|
|
<code>
|
|
{code
|
|
.replace(/\n$/, "")
|
|
.split("\n")
|
|
.map((line, i) => (
|
|
<span className="code-line" key={i}>
|
|
<span className="line-number" aria-hidden="true">
|
|
{i + 1}
|
|
</span>
|
|
<span>
|
|
{/^(pnpm|uv)\b/.test(line) ? (
|
|
<>
|
|
<span className="code-command">{line.split(" ")[0]}</span>
|
|
{line.slice(line.indexOf(" "))}
|
|
</>
|
|
) : (
|
|
line || "\u00a0"
|
|
)}
|
|
</span>
|
|
</span>
|
|
))}
|
|
</code>
|
|
</pre>
|
|
</div>
|
|
);
|
|
}
|