From a49e0b2fc1a59b54043b9ca93828346c027973eb Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Tue, 16 Sep 2025 23:31:29 +0900
Subject: feat(frontend): add copy button to code block

---
 frontend/app/components/Gaming/CodeBlock.tsx | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

(limited to 'frontend/app/components/Gaming/CodeBlock.tsx')

diff --git a/frontend/app/components/Gaming/CodeBlock.tsx b/frontend/app/components/Gaming/CodeBlock.tsx
index 019709a..360f352 100644
--- a/frontend/app/components/Gaming/CodeBlock.tsx
+++ b/frontend/app/components/Gaming/CodeBlock.tsx
@@ -1,3 +1,5 @@
+import { faCopy } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { JSX, useLayoutEffect, useState } from "react";
 import { type BundledLanguage, highlight } from "../../highlight";
 
@@ -8,14 +10,34 @@ type Props = {
 
 export default function CodeBlock({ code, language }: Props) {
 	const [nodes, setNodes] = useState<JSX.Element | null>(null);
+	const [showCopied, setShowCopied] = useState(false);
 
 	useLayoutEffect(() => {
 		highlight(code, language).then(setNodes);
 	}, [code, language]);
 
+	const handleCopy = () => {
+		navigator.clipboard.writeText(code).then(() => {
+			setShowCopied(true);
+			setTimeout(() => setShowCopied(false), 3000);
+		});
+	};
+
 	return (
-		<pre className="h-full w-full p-2 bg-gray-50 rounded-lg border border-gray-300 whitespace-pre-wrap break-words">
-			{nodes === null ? <code>{code}</code> : nodes}
-		</pre>
+		<div className="relative">
+			<button
+				onClick={handleCopy}
+				className="absolute top-2 right-2 z-10 px-2 py-1 bg-white border border-gray-300 rounded shadow-md hover:bg-gray-100 transition-colors"
+				title="コードをコピーする"
+			>
+				<FontAwesomeIcon icon={faCopy} className="text-gray-600" />
+				{showCopied && (
+					<span className="ml-1 text-xs text-blue-600">Copied!</span>
+				)}
+			</button>
+			<pre className="h-full w-full p-2 bg-gray-50 rounded-lg border border-gray-300 whitespace-pre-wrap break-words">
+				{nodes === null ? <code>{code}</code> : nodes}
+			</pre>
+		</div>
 	);
 }
-- 
cgit v1.2.3-70-g09d2

