diff --git a/src/components/ShareSpellbookDialog.tsx b/src/components/ShareSpellbookDialog.tsx index bce47bb..1a3e350 100644 --- a/src/components/ShareSpellbookDialog.tsx +++ b/src/components/ShareSpellbookDialog.tsx @@ -43,7 +43,7 @@ export function ShareSpellbookDialog({ // Get relays from event or fallback to author's outbox relays let relays = event.tags.filter((t) => t[0] === "r").map((t) => t[1]); - + if (relays.length === 0) { const authorRelays = await relayListCache.getOutboxRelays(event.pubkey); if (authorRelays) { @@ -149,4 +149,4 @@ export function ShareSpellbookDialog({ ); -} \ No newline at end of file +} diff --git a/src/components/SpellbooksViewer.tsx b/src/components/SpellbooksViewer.tsx index 0bc9bb8..d6f7d3d 100644 --- a/src/components/SpellbooksViewer.tsx +++ b/src/components/SpellbooksViewer.tsx @@ -390,13 +390,13 @@ export function SpellbooksViewer() { content: spellbook.content, }), ); - + if (event) { await publishEvent(event); // Only mark as published AFTER successful relay publish await markSpellbookPublished(spellbook.id, event as SpellbookEvent); } - + toast.success("Spellbook published"); } catch (error) { toast.error( diff --git a/src/components/layouts/AppShell.tsx b/src/components/layouts/AppShell.tsx index 7a7a3a4..3129136 100644 --- a/src/components/layouts/AppShell.tsx +++ b/src/components/layouts/AppShell.tsx @@ -70,9 +70,11 @@ export function AppShell({ children }: AppShellProps) { -
{children}
+
+ {children} +
); -} \ No newline at end of file +} diff --git a/src/components/nostr/MediaEmbed.tsx b/src/components/nostr/MediaEmbed.tsx index f7291ae..9e1a08a 100644 --- a/src/components/nostr/MediaEmbed.tsx +++ b/src/components/nostr/MediaEmbed.tsx @@ -363,7 +363,8 @@ export function MediaEmbed({
- + {zapMessage && ( - + - + + -
+
{getEventDisplayTitle(parentEvent, false) || ( { if (!actor) { - // Should not happen in this route, but safe guard + // Should not happen in this route, but safe guard return; } @@ -101,8 +101,10 @@ export default function SpellbookPage() { useEffect(() => { if (spellbookEvent && !hasLoadedSpellbook) { try { - const parsedSpellbook = parseSpellbook(spellbookEvent as SpellbookEvent); - + const parsedSpellbook = parseSpellbook( + spellbookEvent as SpellbookEvent, + ); + const isPreviewPath = location.pathname.startsWith("/preview/"); // Check if it's a preview route if (isPreviewPath) { @@ -118,60 +120,58 @@ export default function SpellbookPage() { // Navigating to / (Home) will restore the user's dashboard. switchToTemporary(parsedSpellbook); } - - setHasLoadedSpellbook(true); // Mark as loaded, regardless of preview or direct load + setHasLoadedSpellbook(true); // Mark as loaded, regardless of preview or direct load } catch (e) { console.error("Failed to parse spellbook:", e); toast.error("Failed to load spellbook"); setHasLoadedSpellbook(true); // Ensure we don't re-attempt on error } } - }, [spellbookEvent, hasLoadedSpellbook, switchToTemporary, applyTemporaryToPersistent, location.pathname]); + }, [ + spellbookEvent, + hasLoadedSpellbook, + switchToTemporary, + applyTemporaryToPersistent, + location.pathname, + ]); // Cleanup when leaving the page (unmounting) // But wait, if we navigate to /, we want to discard. // If we apply, we navigate to / but we applied first. useEffect(() => { - return () => { - // If we are unmounting and still temporary, check if we need to cleanup? - // Actually, AppShell wraps this. If we navigate to /, DashboardPage mounts. - // DashboardPage doesn't enforce cleanup. - // So we should cleanup here if we leave this route without applying. - - // Ideally, we'd check if we are navigating to "Apply". - // But applyTemporaryToPersistent clears temporary state internally? - // No, it just merges it. - - // Let's look at `useGrimoire`: - // applyTemporaryToPersistent -> dispatch({ type: "APPLY_TEMP" }) -> sets grimoireStateAtom = temp, internalTemporaryStateAtom = null. - - // So if we applied, isTemporary is false. - // If we navigate away without applying, isTemporary is true. - // But we can't easily check "isTemporary" in cleanup function because of closure staleness? - // Use a ref or rely on the next component to not show temporary state? - // Actually, the global state holds the temporary state. - // If the user clicks "Home", they expect their old state. - - // The previous logic in Home.tsx was: - // useEffect(() => { if (!actor && isTemporary) discardTemporary() }, [actor, isTemporary]) - - // Since we are unmounting SpellbookPage, we are going somewhere else. - // If that somewhere else is NOT a spellbook page, we might want to discard. - // But maybe we want to keep it if we navigate to "Settings" (modal) or something? - // But those are likely overlays. - - // For now, let's rely on the user explicitly discarding or applying via the banner, - // OR implement the "Guard" in DashboardPage to discard if it finds itself in temporary mode? - // Or just discard on unmount if we didn't apply? - // That's hard to track. - - // Let's implement the cleanup in DashboardPage! - // If DashboardPage mounts and isTemporary is true, it means we navigated back home. - // But wait, what if we "Applied"? Then isTemporary is false. - // So if DashboardPage mounts and isTemporary is TRUE, we should discard? - // Yes, that replicates the Home.tsx logic: "if (!actor) ... discard". - }; + return () => { + // If we are unmounting and still temporary, check if we need to cleanup? + // Actually, AppShell wraps this. If we navigate to /, DashboardPage mounts. + // DashboardPage doesn't enforce cleanup. + // So we should cleanup here if we leave this route without applying. + // Ideally, we'd check if we are navigating to "Apply". + // But applyTemporaryToPersistent clears temporary state internally? + // No, it just merges it. + // Let's look at `useGrimoire`: + // applyTemporaryToPersistent -> dispatch({ type: "APPLY_TEMP" }) -> sets grimoireStateAtom = temp, internalTemporaryStateAtom = null. + // So if we applied, isTemporary is false. + // If we navigate away without applying, isTemporary is true. + // But we can't easily check "isTemporary" in cleanup function because of closure staleness? + // Use a ref or rely on the next component to not show temporary state? + // Actually, the global state holds the temporary state. + // If the user clicks "Home", they expect their old state. + // The previous logic in Home.tsx was: + // useEffect(() => { if (!actor && isTemporary) discardTemporary() }, [actor, isTemporary]) + // Since we are unmounting SpellbookPage, we are going somewhere else. + // If that somewhere else is NOT a spellbook page, we might want to discard. + // But maybe we want to keep it if we navigate to "Settings" (modal) or something? + // But those are likely overlays. + // For now, let's rely on the user explicitly discarding or applying via the banner, + // OR implement the "Guard" in DashboardPage to discard if it finds itself in temporary mode? + // Or just discard on unmount if we didn't apply? + // That's hard to track. + // Let's implement the cleanup in DashboardPage! + // If DashboardPage mounts and isTemporary is true, it means we navigated back home. + // But wait, what if we "Applied"? Then isTemporary is false. + // So if DashboardPage mounts and isTemporary is TRUE, we should discard? + // Yes, that replicates the Home.tsx logic: "if (!actor) ... discard". + }; }, []); const handleApplySpellbook = () => { @@ -191,7 +191,7 @@ export default function SpellbookPage() { navigator.clipboard.writeText(link); toast.success("Link copied to clipboard"); }; - + const formatTimestamp = (timestamp: number) => { const date = new Date(timestamp * 1000); const now = Date.now(); @@ -213,68 +213,68 @@ export default function SpellbookPage() { return (
- {/* Banner Layer */} - {showBanner && ( -
-
- -
- - {spellbookEvent?.tags.find((t) => t[0] === "title")?.[1] || - "Spellbook"} + {/* Banner Layer */} + {showBanner && ( +
+
+ +
+ + {spellbookEvent?.tags.find((t) => t[0] === "title")?.[1] || + "Spellbook"} + + {spellbookEvent && ( + + {authorProfile?.name || resolvedPubkey?.slice(0, 8)} + + {formatTimestamp(spellbookEvent.created_at)} - {spellbookEvent && ( - - {authorProfile?.name || resolvedPubkey?.slice(0, 8)} - - {formatTimestamp(spellbookEvent.created_at)} - - )} -
-
-
- - - + )}
- )} +
+ + + +
+
+ )} {/* Loading States */} {isResolving && ( -
- - Resolving {actor}... -
+
+ + Resolving {actor}... +
)} {resolutionError && ( -
- Failed to resolve actor: {resolutionError} -
+
+ Failed to resolve actor: {resolutionError} +
)} {/* Main Content */} @@ -283,7 +283,9 @@ export default function SpellbookPage() {
-

Loading Spellbook...

+

+ Loading Spellbook... +

Fetching from the relays

diff --git a/src/root.tsx b/src/root.tsx index 0fb5a3a..86e569e 100644 --- a/src/root.tsx +++ b/src/root.tsx @@ -32,4 +32,4 @@ const router = createBrowserRouter([ export default function Root() { return ; -} \ No newline at end of file +}