diff options
author | buttercat1791 <mjjurkoic@gmail.com> | 2024-08-22 09:30:47 -0500 |
---|---|---|
committer | limina1 <liminal@duck.com> | 2024-08-27 08:22:01 -0400 |
commit | a67ac58d5ed173f039be67d491db8d4f2a785884 (patch) | |
tree | 3bf5a9ef6887aae76d900ffbde90a96bb3c42ddc | |
parent | f0567c160e2b2b3448fbe41a1eabeb953dd3829f (diff) |
Filter for valid NKBIP-01 events
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/lib/utils.ts | 25 | ||||
-rw-r--r-- | src/routes/+layout.svelte | 19 | ||||
-rw-r--r-- | src/routes/+page.svelte | 71 |
4 files changed, 85 insertions, 32 deletions
diff --git a/package.json b/package.json index bec892a..d3b92a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "alexandria", - "version": "0.0.3", + "version": "0.0.4", "private": true, "type": "module", "scripts": { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index c709bbd..67d6e08 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,5 +1,6 @@ import type { NDKEvent } from "@nostr-dev-kit/ndk"; import { nip19 } from "nostr-tools"; + export function neventEncode(event: NDKEvent, relays: string[]) { return nip19.neventEncode({ id: event.id, @@ -81,3 +82,27 @@ export function isElementInViewport(el: string | HTMLElement) { rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } + +/** + * Removes `kind: 30040` index events that don't comply with the NKBIP-01 specification. + * @param events A set of events. + * @returns The filtered set of events. + */ +export function filterValidIndexEvents(events: Set<NDKEvent>): Set<NDKEvent> { + // The filter object supports only limited parameters, so we need to filter out events that + // don't respect NKBIP-01. + events.forEach(event => { + // Index events have no content, and they must have `title`, `d`, and `e` tags. + if ( + event.content != null + || event.getMatchingTags('title').length === 0 + || event.getMatchingTags('d').length === 0 + || event.getMatchingTags('e').length === 0 + ) { + events.delete(event); + } + }); + + console.debug(`Filtered index events: ${events.size} events remaining.`); + return events; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index dddce98..d8c30ea 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,18 +1,17 @@ <script> import "../app.css"; - // import Login from '$lib/login.svelte'; - import { tabs, userPublickey } from "$lib/state"; - // import {ndk} from '$lib/ndk'; - import { browser } from "$app/environment"; - import { NDKNip07Signer } from "@nostr-dev-kit/ndk"; - import { onMount } from "svelte"; import Navigation from "$lib/components/Navigation.svelte"; + import { onMount } from "svelte"; + + // Compute viewport height. + $: displayHeight = window.innerHeight; + + onMount(() => { + document.body.style.height = `${displayHeight}px`; + }); </script> -<div class='leather h-full w-full flex flex-col items-center'> +<div class={'leather h-full w-full flex flex-col items-center'}> <Navigation class='sticky top-0' /> <slot /> </div> - -<style> -</style> diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 243acd0..852021b 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,25 +2,23 @@ import ArticleHeader from "$lib/ArticleHeader.svelte"; import { FeedType, indexKind } from "$lib/consts"; import { ndk } from "$lib/ndk"; - import { NDKEvent, NDKRelayList, NDKRelaySet, NDKSubscriptionCacheUsage, type NDKUser } from "@nostr-dev-kit/ndk"; - import { Button, Dropdown, Radio } from "flowbite-svelte"; + import { filterValidIndexEvents } from "$lib/utils"; + import { NDKEvent, NDKRelayList, NDKRelaySet, type NDKUser } from "@nostr-dev-kit/ndk"; + import { Button, Dropdown, Radio, Skeleton } from "flowbite-svelte"; import { ChevronDownOutline } from "flowbite-svelte-icons"; const getEvents = (): Promise<Set<NDKEvent>> => - $ndk.fetchEvents( - // @ts-ignore - { kinds: [indexKind] }, - ); + // @ts-ignore + $ndk.fetchEvents({ kinds: [indexKind] }).then(filterValidIndexEvents); const getEventsFromUserRelays = (userRelays: NDKRelayList): Promise<Set<NDKEvent>> => { const relaySet = NDKRelaySet.fromRelayUrls(userRelays!.readRelayUrls, $ndk); - // TODO: Add more filter parameters to customize the event feed. return $ndk.fetchEvents( // @ts-ignore { kinds: [indexKind] }, relaySet, - ); + ).then(filterValidIndexEvents); }; const getEventsFromUserFollows = (follows: Set<NDKUser>, userRelays: NDKRelayList): Promise<Set<NDKEvent>> => { @@ -34,7 +32,7 @@ kinds: [indexKind] }, relaySet, - ); + ).then(filterValidIndexEvents); }; const getFeedTypeFriendlyName = (feedType: FeedType): string => { @@ -48,6 +46,19 @@ } }; + const getSkeletonIds = (): string[] => { + const skeletonHeight = 124; // The height of the skeleton component in pixels. + + // Determine the number of skeletons to display based on the height of the screen. + const skeletonCount = Math.floor(window.innerHeight / skeletonHeight) - 2; + + const skeletonIds = []; + for (let i = 0; i < skeletonCount; i++) { + skeletonIds.push(`skeleton-${i}`); + } + return skeletonIds; + } + let user: NDKUser | null | undefined; let readRelays: NDKRelayList | null | undefined; let userFollows: Set<NDKUser> | null | undefined; @@ -64,11 +75,17 @@ {#key user} {#if user == null || readRelays == null} {#await getEvents()} - <p>Loading...</p> - {:then events} - {#each Array.from(events) as event} - <ArticleHeader {event} /> + {#each getSkeletonIds() as id} + <Skeleton size='lg' id={id} /> {/each} + {:then events} + {#if events.size > 0} + {#each Array.from(events) as event} + <ArticleHeader {event} /> + {/each} + {:else} + <p class='text-center'>No articles found.</p> + {/if} {/await} {:else} <div class='leather w-full flex justify-end'> @@ -86,19 +103,31 @@ </div> {#if feedType === FeedType.Relays && readRelays != null} {#await getEventsFromUserRelays(readRelays)} - <p>Loading...</p> - {:then events} - {#each Array.from(events) as event} - <ArticleHeader {event} /> + {#each getSkeletonIds() as id} + <Skeleton size='lg' id={id} /> {/each} + {:then events} + {#if events.size > 0} + {#each Array.from(events) as event} + <ArticleHeader {event} /> + {/each} + {:else} + <p class='text-center'>No articles found.</p> + {/if} {/await} {:else if feedType === FeedType.Follows && userFollows != null} {#await getEventsFromUserFollows(userFollows, readRelays)} - <p>Loading...</p> - {:then events} - {#each Array.from(events) as event} - <ArticleHeader {event} /> + {#each getSkeletonIds() as id} + <Skeleton size='lg' id={id} /> {/each} + {:then events} + {#if events.size > 0} + {#each Array.from(events) as event} + <ArticleHeader {event} /> + {/each} + {:else} + <p class='text-center'>No articles found.</p> + {/if} {/await} {/if} {/if} |