File
Blob: src/client/islands/repo-admin/JsonResult.tsx
| 1 | import { useState } from "react"; |
| 2 | import { Check, Clipboard } from "lucide-react"; |
| 3 | |
| 4 | export function JsonResult({ data }: { data: unknown }) { |
| 5 | const [copied, setCopied] = useState(false); |
| 6 | const serialized = JSON.stringify(data, null, 2); |
| 7 | |
| 8 | async function copyJson() { |
| 9 | try { |
| 10 | await navigator.clipboard.writeText(serialized); |
| 11 | setCopied(true); |
| 12 | window.setTimeout(() => setCopied(false), 1200); |
| 13 | } catch (error) { |
| 14 | window.alert(`Failed to copy JSON: ${String(error)}`); |
| 15 | } |
| 16 | } |
| 17 | |
| 18 | return ( |
| 19 | <div className="relative mt-2"> |
| 20 | <pre className="overflow-x-auto rounded-xl bg-zinc-100 p-4 pr-12 text-sm dark:bg-zinc-800"> |
| 21 | {serialized} |
| 22 | </pre> |
| 23 | <button |
| 24 | type="button" |
| 25 | onClick={() => void copyJson()} |
| 26 | className="absolute right-2 top-2 rounded border border-zinc-300 bg-white/80 p-1.5 text-zinc-600 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:border-zinc-700 dark:bg-zinc-900/60 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-zinc-100" |
| 27 | title={copied ? "Copied" : "Copy JSON"} |
| 28 | aria-label="Copy JSON" |
| 29 | > |
| 30 | {copied ? ( |
| 31 | <Check className="block h-4 w-4 text-green-600 dark:text-green-400" aria-hidden="true" /> |
| 32 | ) : ( |
| 33 | <Clipboard className="block h-4 w-4" aria-hidden="true" /> |
| 34 | )} |
| 35 | </button> |
| 36 | </div> |
| 37 | ); |
| 38 | } |