diff --git a/src/components/DecodeViewer.tsx b/src/components/DecodeViewer.tsx index 2e24c90e..9bf1d70 100644 --- a/src/components/DecodeViewer.tsx +++ b/src/components/DecodeViewer.tsx @@ -7,6 +7,7 @@ import { type DecodedData, } from "@/lib/decode-parser"; import { useGrimoire } from "@/core/state"; +import { useCopy } from "../hooks/useCopy"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; @@ -16,7 +17,7 @@ interface DecodeViewerProps { export default function DecodeViewer({ args }: DecodeViewerProps) { const { addWindow } = useGrimoire(); - const [copied, setCopied] = useState(false); + const { copy, copied } = useCopy(); const [relays, setRelays] = useState([]); const [newRelay, setNewRelay] = useState(""); const [error, setError] = useState(null); @@ -56,9 +57,7 @@ export default function DecodeViewer({ args }: DecodeViewerProps) { const copyToClipboard = () => { if (reencoded) { - navigator.clipboard.writeText(reencoded); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + copy(reencoded); } }; diff --git a/src/components/EncodeViewer.tsx b/src/components/EncodeViewer.tsx index 6847ef0..0b2d393 100644 --- a/src/components/EncodeViewer.tsx +++ b/src/components/EncodeViewer.tsx @@ -5,6 +5,7 @@ import { encodeToNostr, type ParsedEncodeCommand, } from "@/lib/encode-parser"; +import { useCopy } from "../hooks/useCopy"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; @@ -13,7 +14,7 @@ interface EncodeViewerProps { } export default function EncodeViewer({ args }: EncodeViewerProps) { - const [copied, setCopied] = useState(false); + const { copy, copied } = useCopy(); const [relays, setRelays] = useState([]); const [newRelay, setNewRelay] = useState(""); const [error, setError] = useState(null); @@ -46,9 +47,7 @@ export default function EncodeViewer({ args }: EncodeViewerProps) { const copyToClipboard = () => { if (encoded) { - navigator.clipboard.writeText(encoded); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + copy(encoded); } }; diff --git a/src/components/EventDetailViewer.tsx b/src/components/EventDetailViewer.tsx index c02c1e9..d9b58e9 100644 --- a/src/components/EventDetailViewer.tsx +++ b/src/components/EventDetailViewer.tsx @@ -9,6 +9,7 @@ import { Kind9802DetailRenderer } from "./nostr/kinds/Kind9802DetailRenderer"; import { KindBadge } from "./KindBadge"; import { Copy, + Check, ChevronDown, ChevronRight, FileJson, @@ -16,6 +17,7 @@ import { Circle, } from "lucide-react"; import { nip19 } from "nostr-tools"; +import { useCopy } from "../hooks/useCopy"; import { getSeenRelays } from "applesauce-core/helpers/relays"; export interface EventDetailViewerProps { @@ -40,10 +42,7 @@ export function EventDetailViewer({ pointer }: EventDetailViewerProps) { ); } - // Helper to copy to clipboard - const copyToClipboard = (text: string) => { - navigator.clipboard.writeText(text); - }; + const { copy, copied } = useCopy(); // Get relays this event was seen on using applesauce const seenRelaysSet = getSeenRelays(event); @@ -79,11 +78,15 @@ export function EventDetailViewer({ pointer }: EventDetailViewerProps) {
{/* Left: Event ID */}
diff --git a/src/components/Home.tsx b/src/components/Home.tsx
index 9856543..3acaf07 100644
--- a/src/components/Home.tsx
+++ b/src/components/Home.tsx
@@ -14,6 +14,7 @@ import { EventDetailViewer } from "./EventDetailViewer";
 import { ProfileViewer } from "./ProfileViewer";
 import EncodeViewer from "./EncodeViewer";
 import DecodeViewer from "./DecodeViewer";
+import { RelayViewer } from "./RelayViewer";
 import KindRenderer from "./KindRenderer";
 import { Terminal } from "lucide-react";
 import UserMenu from "./nostr/user-menu";
diff --git a/src/components/JsonViewer.tsx b/src/components/JsonViewer.tsx
index d34670a..1b05622 100644
--- a/src/components/JsonViewer.tsx
+++ b/src/components/JsonViewer.tsx
@@ -7,6 +7,7 @@ import {
   DialogTitle,
 } from "@/components/ui/dialog";
 import { Button } from "@/components/ui/button";
+import { useCopy } from "../hooks/useCopy";
 
 interface JsonViewerProps {
   data: any;
@@ -21,14 +22,12 @@ export function JsonViewer({
   onOpenChange,
   title = "Raw JSON",
 }: JsonViewerProps) {
-  const [copied, setCopied] = useState(false);
+  const { copy, copied } = useCopy();
 
   const jsonString = JSON.stringify(data, null, 2);
 
   const handleCopy = () => {
-    navigator.clipboard.writeText(jsonString);
-    setCopied(true);
-    setTimeout(() => setCopied(false), 2000);
+    copy(jsonString);
   };
 
   return (
diff --git a/src/components/ProfileViewer.tsx b/src/components/ProfileViewer.tsx
index ddf4475..e8e564f 100644
--- a/src/components/ProfileViewer.tsx
+++ b/src/components/ProfileViewer.tsx
@@ -4,6 +4,7 @@ import { UserName } from "./nostr/UserName";
 import Nip05 from "./nostr/nip05";
 import {
   Copy,
+  Check,
   ChevronDown,
   ChevronRight,
   User as UserIcon,
@@ -14,6 +15,7 @@ import {
 import { kinds, nip19 } from "nostr-tools";
 import { useEventStore, useObservableMemo } from "applesauce-react/hooks";
 import { getInboxes, getOutboxes } from "applesauce-core/helpers/mailboxes";
+import { useCopy } from "../hooks/useCopy";
 import { RichText } from "./nostr/RichText";
 
 export interface ProfileViewerProps {
@@ -46,10 +48,7 @@ export function ProfileViewer({ pubkey }: ProfileViewerProps) {
     [eventStore, pubkey],
   );
 
-  // Helper to copy to clipboard
-  const copyToClipboard = (text: string) => {
-    navigator.clipboard.writeText(text);
-  };
+  const { copy, copied } = useCopy();
 
   // Combine all relays (inbox + outbox) for nprofile
   const allRelays = [...new Set([...inboxRelays, ...outboxRelays])];
@@ -69,11 +68,15 @@ export function ProfileViewer({ pubkey }: ProfileViewerProps) {
       
{/* Left: npub/nprofile */}