From e7a7bb05a49febf9a83c68761782685521040dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20G=C3=B3mez?= Date: Sun, 21 Dec 2025 22:54:44 +0100 Subject: [PATCH] feat: clickable spell and spellbook links --- src/components/SpellbooksViewer.tsx | 35 ++++++++++++++++++++++++++++- src/components/SpellsViewer.tsx | 20 ++++++++++++++++- src/components/layouts/AppShell.tsx | 7 ++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/components/SpellbooksViewer.tsx b/src/components/SpellbooksViewer.tsx index d6f7d3d..f34ccb1 100644 --- a/src/components/SpellbooksViewer.tsx +++ b/src/components/SpellbooksViewer.tsx @@ -63,6 +63,7 @@ function SpellbookCard({ showAuthor = false, isOwner = true, }: SpellbookCardProps) { + const { addWindow } = useGrimoire(); const [isPublishing, setIsPublishing] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const displayName = spellbook.title || "Untitled Spellbook"; @@ -108,6 +109,26 @@ function SpellbookCard({ onApply(parsed); }; + const handleOpenEvent = () => { + const id = spellbook.eventId || (spellbook.event?.id as string); + if (id && id.length === 64) { + addWindow("open", { pointer: { id } }, `open ${id}`); + } else if (spellbook.isPublished && spellbook.slug && authorPubkey) { + // For addressable events (kind 30003) + addWindow( + "open", + { + pointer: { + kind: SPELLBOOK_KIND, + pubkey: authorPubkey, + identifier: spellbook.slug, + }, + }, + `open ${SPELLBOOK_KIND}:${authorPubkey}:${spellbook.slug}`, + ); + } + }; + return (
- + {displayName}
diff --git a/src/components/SpellsViewer.tsx b/src/components/SpellsViewer.tsx index 530b1fc..0c32096 100644 --- a/src/components/SpellsViewer.tsx +++ b/src/components/SpellsViewer.tsx @@ -47,6 +47,7 @@ interface SpellCardProps { } function SpellCard({ spell, onDelete, onPublish }: SpellCardProps) { + const { addWindow } = useGrimoire(); const [isPublishing, setIsPublishing] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const displayName = spell.name || spell.alias || "Untitled Spell"; @@ -80,6 +81,13 @@ function SpellCard({ spell, onDelete, onPublish }: SpellCardProps) { } }; + const handleOpenEvent = () => { + const id = spell.eventId || (spell.event?.id as string); + if (id && id.length === 64) { + addWindow("open", { pointer: { id } }, `open ${id}`); + } + }; + return (
- + {displayName}
diff --git a/src/components/layouts/AppShell.tsx b/src/components/layouts/AppShell.tsx index 3129136..a3eb309 100644 --- a/src/components/layouts/AppShell.tsx +++ b/src/components/layouts/AppShell.tsx @@ -1,4 +1,5 @@ import { useState, useEffect, ReactNode } from "react"; +import { Terminal } from "lucide-react"; import { useAccountSync } from "@/hooks/useAccountSync"; import { useRelayListCacheSync } from "@/hooks/useRelayListCacheSync"; import { useRelayState } from "@/hooks/useRelayState"; @@ -59,10 +60,12 @@ export function AppShell({ children }: AppShellProps) {
+ > + +