feat: complete Phase 2 network features for spellbooks

Sharing Enhancements:
- Install qrcode library for QR code generation
- Create ShareSpellbookDialog with tabbed interface
- Support multiple share formats: Web URL, naddr, nevent
- QR code generation and download for each format
- Quick copy buttons with visual feedback
- Integrated into SpellbookDetailRenderer

Network Discovery:
- Add "Discover" filter to browse spellbooks from other users
- Query AGGREGATOR_RELAYS for network spellbook discovery
- Show author names using UserName component
- Conditional UI: hide owner actions for discovered spellbooks
- Support viewing and applying layouts from the community

Preview Route Polish:
- Loading states with spinner during NIP-05 resolution
- 10-second timeout for NIP-05 resolution
- Error banners for resolution failures
- Author name and creation date in preview banner
- Copy link button in preview mode

Conflict Resolution:
- compareSpellbookVersions() function in spellbook-manager
- ConflictResolutionDialog component for version conflicts
- Side-by-side comparison of local vs network versions
- Show workspace/window counts and timestamps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gómez
2025-12-21 14:09:52 +01:00
parent 6d89a9d342
commit 0f7f154b80
8 changed files with 725 additions and 106 deletions

View File

@@ -5,6 +5,7 @@ import pool from "./relay-pool";
import { relayListCache } from "./relay-list-cache";
import { getSeenRelays } from "applesauce-core/helpers/relays";
import type { NostrEvent } from "nostr-tools/core";
import accountManager from "./accounts";
/**
* Publishes a Nostr event to relays using the author's outbox relays
@@ -25,7 +26,7 @@ async function publishEvent(event: NostrEvent): Promise<void> {
// If still no relays, throw error
if (relays.length === 0) {
throw new Error(
"No relays found for publishing. Please configure relay list (kind 10002) or ensure event has relay hints."
"No relays found for publishing. Please configure relay list (kind 10002) or ensure event has relay hints.",
);
}
@@ -36,6 +37,8 @@ async function publishEvent(event: NostrEvent): Promise<void> {
eventStore.add(event);
}
const factory = new EventFactory();
/**
* Global action hub for Grimoire
* Used to register and execute actions throughout the application
@@ -45,4 +48,10 @@ async function publishEvent(event: NostrEvent): Promise<void> {
* - EventFactory: Creates and signs events
* - publishEvent: Publishes events to author's outbox relays (with fallback to seen relays)
*/
export const hub = new ActionHub(eventStore, new EventFactory(), publishEvent);
export const hub = new ActionHub(eventStore, factory, publishEvent);
// Sync factory signer with active account
// This ensures the hub can sign events when an account is active
accountManager.active$.subscribe((account) => {
factory.setSigner(account?.signer || undefined);
});