From ba1f0164ba8131090419dfb33ad423661056bd3c Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 20:02:14 +0200 Subject: [PATCH] fixed feed display --- src/app.css | 6 +- src/lib/components/LoginMenu.svelte | 440 --------------- src/lib/components/Navigation.svelte | 7 +- src/lib/components/RelayActions.svelte | 2 +- src/lib/components/cards/BlogHeader.svelte | 20 +- .../publications/PublicationFeed.svelte | 64 ++- .../publications/PublicationHeader.svelte | 49 +- src/lib/components/util/CardActions.svelte | 3 +- src/lib/components/util/Profile.svelte | 523 +++++++++++++++--- src/lib/utils/nostrEventService.ts | 3 +- src/routes/+page.svelte | 12 - 11 files changed, 544 insertions(+), 585 deletions(-) delete mode 100644 src/lib/components/LoginMenu.svelte diff --git a/src/app.css b/src/app.css index 1f07464..fbaca62 100644 --- a/src/app.css +++ b/src/app.css @@ -159,6 +159,10 @@ @apply bg-primary-100 dark:bg-primary-800; } + div.skeleton-leather { + @apply h-48; + } + div.textarea-leather { @apply bg-primary-0 dark:bg-primary-1000; } @@ -246,7 +250,7 @@ } .ArticleBox.grid.active .ArticleBoxImage { - @apply max-h-72; + @apply max-h-40; } .tags span { diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte deleted file mode 100644 index 4ac4222..0000000 --- a/src/lib/components/LoginMenu.svelte +++ /dev/null @@ -1,440 +0,0 @@ - - -
- {#if !user.signedIn} - -
- - -
-

Login with...

- - - -
-
Network Status:
- -
-
-
- {#if result} -
- {result} - -
- {/if} -
- {:else} - -
- - -
-
-

- {user.profile?.displayName || - user.profile?.name || - (user.npub ? shortenNpub(user.npub) : "Unknown")} -

-
    -
  • - -
  • -
  • - {#if user.loginMethod === "extension"} - Logged in with extension - {:else if user.loginMethod === "amber"} - Logged in with Amber - {:else if user.loginMethod === "npub"} - Logged in with npub - {:else} - Unknown login method - {/if} -
  • -
  • -
    Network Status:
    - -
  • -
  • - -
  • -
-
-
-
-
- {/if} -
- -{#if showQrCode && qrCodeDataUrl} - -
-
-
-

- Scan with Amber -

-

- Open Amber on your phone and scan this QR code -

-
- Nostr Connect QR Code -
-
- -
- - -
-
-
-

1. Open Amber on your phone

-

2. Scan the QR code above

-

3. Approve the connection in Amber

-
- -
-
-
-{/if} - -{#if showAmberFallback} -
-
-
-

- Amber Session Restored -

-

- Your Amber wallet session could not be restored automatically, so - you've been switched to read-only mode.
- You can still browse and read content, but you'll need to reconnect Amber - to publish or comment. -

- - -
-
-
-{/if} diff --git a/src/lib/components/Navigation.svelte b/src/lib/components/Navigation.svelte index aa6b7e2..fdcfe32 100644 --- a/src/lib/components/Navigation.svelte +++ b/src/lib/components/Navigation.svelte @@ -7,9 +7,12 @@ NavHamburger, NavBrand, } from "flowbite-svelte"; - import LoginMenu from "./LoginMenu.svelte"; + import Profile from "./util/Profile.svelte"; + import { userStore } from "$lib/stores/userStore"; let { class: className = "" } = $props(); + + let userState = $derived($userStore); @@ -19,7 +22,7 @@
- +
diff --git a/src/lib/components/RelayActions.svelte b/src/lib/components/RelayActions.svelte index 041f4a4..e7f289c 100644 --- a/src/lib/components/RelayActions.svelte +++ b/src/lib/components/RelayActions.svelte @@ -55,7 +55,7 @@ const relaySet = createRelaySetFromUrls([relay], ndk); const found = await ndk .fetchEvent({ ids: [event?.id || ""] }, undefined, relaySet) - .withTimeout(3000); + .withTimeout(2000); relaySearchResults = { ...relaySearchResults, [relay]: found ? "found" : "notfound", diff --git a/src/lib/components/cards/BlogHeader.svelte b/src/lib/components/cards/BlogHeader.svelte index adaa6bf..0696d89 100644 --- a/src/lib/components/cards/BlogHeader.svelte +++ b/src/lib/components/cards/BlogHeader.svelte @@ -54,24 +54,28 @@ ? 'active' : ''}" > -
+
{@render userBadge(authorPubkey, author)} {publishedAt()}
-
{#if image && active}
- + {title
{/if} -
+ +
@@ -83,9 +87,15 @@
{/if}
+ {#if active} {/if} + + +
+ +
{/if} diff --git a/src/lib/components/publications/PublicationFeed.svelte b/src/lib/components/publications/PublicationFeed.svelte index 14bd331..2236dce 100644 --- a/src/lib/components/publications/PublicationFeed.svelte +++ b/src/lib/components/publications/PublicationFeed.svelte @@ -137,9 +137,10 @@ allRelays.map((r: string) => [r, "pending"]), ); let allEvents: NDKEvent[] = []; + const eventMap = new Map(); // Helper to fetch from a single relay with timeout - async function fetchFromRelay(relay: string): Promise { + async function fetchFromRelay(relay: string): Promise { try { console.debug(`[PublicationFeed] Fetching from relay: ${relay}`); const relaySet = NDKRelaySetFromNDK.fromRelayUrls([relay], ndk); @@ -156,57 +157,60 @@ }, relaySet, ) - .withTimeout(10000); // Increased timeout to 10 seconds + .withTimeout(5000); // Reduced timeout to 5 seconds for faster response console.debug(`[PublicationFeed] Raw events from ${relay}:`, eventSet.size); eventSet = filterValidIndexEvents(eventSet); console.debug(`[PublicationFeed] Valid events from ${relay}:`, eventSet.size); relayStatuses = { ...relayStatuses, [relay]: "found" }; - return Array.from(eventSet); + + // Add new events to the map and update the view immediately + const newEvents: NDKEvent[] = []; + for (const event of eventSet) { + const tagAddress = event.tagAddress(); + if (!eventMap.has(tagAddress)) { + eventMap.set(tagAddress, event); + newEvents.push(event); + } + } + + if (newEvents.length > 0) { + // Update allIndexEvents with new events + allIndexEvents = Array.from(eventMap.values()); + // Sort by created_at descending + allIndexEvents.sort((a, b) => b.created_at! - a.created_at!); + + // Update the view immediately with new events + eventsInView = allIndexEvents.slice(0, 30); + endOfFeed = allIndexEvents.length <= 30; + + console.debug(`[PublicationFeed] Updated view with ${newEvents.length} new events from ${relay}, total: ${allIndexEvents.length}`); + } } catch (err) { console.error(`[PublicationFeed] Error fetching from relay ${relay}:`, err); relayStatuses = { ...relayStatuses, [relay]: "notfound" }; - return []; } } - // Fetch from all relays in parallel, do not block on any single relay + // Fetch from all relays in parallel, return events as they arrive console.debug(`[PublicationFeed] Starting fetch from ${allRelays.length} relays`); - const results = await Promise.allSettled(allRelays.map(fetchFromRelay)); - for (const result of results) { - if (result.status === "fulfilled") { - allEvents = allEvents.concat(result.value); - } - } + // Start all relay fetches in parallel + const fetchPromises = allRelays.map(fetchFromRelay); - console.debug(`[PublicationFeed] Total events fetched:`, allEvents.length); + // Wait for all to complete (but events are shown as they arrive) + await Promise.allSettled(fetchPromises); - // Deduplicate by tagAddress - const eventMap = new Map( - allEvents.map((event) => [event.tagAddress(), event]), - ); - allIndexEvents = Array.from(eventMap.values()); - console.debug(`[PublicationFeed] Events after deduplication:`, allIndexEvents.length); + console.debug(`[PublicationFeed] All relays completed, final event count:`, allIndexEvents.length); - // Sort by created_at descending - allIndexEvents.sort((a, b) => b.created_at! - a.created_at!); - // Cache the fetched events indexEventCache.set(allRelays, allIndexEvents); - // Initially show first page + // Final update to ensure we have the latest view eventsInView = allIndexEvents.slice(0, 30); endOfFeed = allIndexEvents.length <= 30; loading = false; - - console.debug(`[PublicationFeed] Final state:`, { - totalEvents: allIndexEvents.length, - eventsInView: eventsInView.length, - endOfFeed, - loading - }); } // Function to filter events based on search query @@ -332,7 +336,7 @@ } function getSkeletonIds(): string[] { - const skeletonHeight = 124; // The height of the skeleton component in pixels. + const skeletonHeight = 192; // The height of the card component in pixels (h-48 = 12rem = 192px). const skeletonCount = Math.floor(window.innerHeight / skeletonHeight) - 2; const skeletonIds = []; for (let i = 0; i < skeletonCount; i++) { diff --git a/src/lib/components/publications/PublicationHeader.svelte b/src/lib/components/publications/PublicationHeader.svelte index 465c423..2a0ea56 100644 --- a/src/lib/components/publications/PublicationHeader.svelte +++ b/src/lib/components/publications/PublicationHeader.svelte @@ -1,9 +1,7 @@ {#if title != null && href != null} - + {#if image}
- + {title
{/if} -
+ + + + +
+
{/if} diff --git a/src/lib/components/util/CardActions.svelte b/src/lib/components/util/CardActions.svelte index 2083d4e..d5d49c5 100644 --- a/src/lib/components/util/CardActions.svelte +++ b/src/lib/components/util/CardActions.svelte @@ -8,8 +8,7 @@ import CopyToClipboard from "$components/util/CopyToClipboard.svelte"; import { userBadge } from "$lib/snippets/UserSnippets.svelte"; import { neventEncode, naddrEncode } from "$lib/utils"; - import { communityRelays, secondaryRelays, FeedType } from "$lib/consts"; - import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; + import { activeInboxRelays } from "$lib/ndk"; import { userStore } from "$lib/stores/userStore"; import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; diff --git a/src/lib/components/util/Profile.svelte b/src/lib/components/util/Profile.svelte index 19fb0bb..399539a 100644 --- a/src/lib/components/util/Profile.svelte +++ b/src/lib/components/util/Profile.svelte @@ -1,7 +1,13 @@
-
- - -
-
- {#if username} -

{username}

- {#if isNav}

@{tag}

{/if} - {:else} -

Loading...

- {/if} -
    -
  • - -
  • -
  • - -
  • -
  • - -
  • - {#if isNav} + {#if !userState.signedIn} + +
    + + +
    +

    Login with...

    + + + +
    +
    Network Status:
    + +
    +
    +
    + {#if result} +
    + {result} + +
    + {/if} +
    + {:else} + +
    + + +
    +
    + {#if username} +

    {username}

    + {#if isNav}

    @{tag}

    {/if} + {:else if isProfileLoading} +

    Loading profile...

    + {:else} +

    Loading...

    + {/if} +
      +
    • + +
    • - {:else} - - {/if} -
    +
  • + {#if userState.loginMethod === "extension"} + Logged in with extension + {:else if userState.loginMethod === "amber"} + Logged in with Amber + {:else if userState.loginMethod === "npub"} + Logged in with npub + {:else} + Unknown login method + {/if} +
  • +
  • + +
  • + {#if isNav} +
  • + +
  • + {:else} + + {/if} +
+
+
+
+
+ {/if} +
+ +{#if showQrCode && qrCodeDataUrl} + +
+
+
+

+ Scan with Amber +

+

+ Open Amber on your phone and scan this QR code +

+
+ Nostr Connect QR Code +
+
+ +
+ + +
+
+

1. Open Amber on your phone

+

2. Scan the QR code above

+

3. Approve the connection in Amber

+
+
- +
-
+{/if} + +{#if showAmberFallback} +
+
+
+

+ Amber Session Restored +

+

+ Your Amber wallet session could not be restored automatically, so + you've been switched to read-only mode.
+ You can still browse and read content, but you'll need to reconnect Amber + to publish or comment. +

+ + +
+
+
+{/if} diff --git a/src/lib/utils/nostrEventService.ts b/src/lib/utils/nostrEventService.ts index e7d437f..1a233a8 100644 --- a/src/lib/utils/nostrEventService.ts +++ b/src/lib/utils/nostrEventService.ts @@ -1,6 +1,5 @@ import { nip19 } from "nostr-tools"; import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils"; -import { communityRelays, secondaryRelays } from "$lib/consts"; import { get } from "svelte/store"; import { goto } from "$app/navigation"; import type { NDKEvent } from "./nostrUtils"; @@ -381,7 +380,7 @@ export async function publishEvent( try { // Publish with timeout - await event.publish(relaySet).withTimeout(10000); + await event.publish(relaySet).withTimeout(5000); // For now, assume all relays were successful // In a more sophisticated implementation, you'd track individual relay responses diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 8461bd4..03a9c14 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -14,18 +14,6 @@ } - - - - Pardon our dust! The publication view is currently using an experimental - loader, and may be unstable. - - -