aboutsummaryrefslogtreecommitdiff
path: root/src/routes/+page.svelte
blob: 852021b9c93b99eb92a8a5e358afae37e48c3386 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<script lang="ts">
  import ArticleHeader from "$lib/ArticleHeader.svelte";
  import { FeedType, indexKind } from "$lib/consts";
  import { ndk } from "$lib/ndk";
  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>> =>
    // @ts-ignore
    $ndk.fetchEvents({ kinds: [indexKind] }).then(filterValidIndexEvents);

  const getEventsFromUserRelays = (userRelays: NDKRelayList): Promise<Set<NDKEvent>> => {
    const relaySet = NDKRelaySet.fromRelayUrls(userRelays!.readRelayUrls, $ndk);

    return $ndk.fetchEvents(
      // @ts-ignore
      { kinds: [indexKind] },
      relaySet,
    ).then(filterValidIndexEvents);
  };

  const getEventsFromUserFollows = (follows: Set<NDKUser>, userRelays: NDKRelayList): Promise<Set<NDKEvent>> => {
    const relaySet = NDKRelaySet.fromRelayUrls(userRelays?.readRelayUrls ?? [], $ndk);
    const pubkeys = Array.from(follows ?? []).map(user => user.pubkey);

    return $ndk.fetchEvents(
      { 
        authors: pubkeys,
        // @ts-ignore
        kinds: [indexKind]
      },
      relaySet,
    ).then(filterValidIndexEvents);
  };

  const getFeedTypeFriendlyName = (feedType: FeedType): string => {
    switch (feedType) {
    case FeedType.Relays:
      return 'Relays';
    case FeedType.Follows:
      return 'Follows';
    default:
      return '';
    }
  };

  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;
  let feedType: FeedType = FeedType.Relays;

  $: {
    user = $ndk.activeUser;
    user?.relayList().then(relays => readRelays = relays);
    user?.follows().then(follows => userFollows = follows);
  }
</script>

<div class='leather flex flex-col flex-grow-0 space-y-4 overflow-y-auto w-max p-2'>
  {#key user}
    {#if user == null || readRelays == null}
      {#await getEvents()}
        {#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'>
        <Button>
          {`Showing articles from: ${getFeedTypeFriendlyName(feedType)}`}<ChevronDownOutline class='w-6 h-6' />
        </Button>
        <Dropdown class='w-fit p-2 space-y-2 text-sm'>
          <li>
            <Radio name='relays' bind:group={feedType} value={FeedType.Relays}>Relays</Radio>
          </li>
          <li>
            <Radio name='follows' bind:group={feedType} value={FeedType.Follows}>Follows</Radio>
          </li>
        </Dropdown>
      </div>
      {#if feedType === FeedType.Relays && readRelays != null}
        {#await getEventsFromUserRelays(readRelays)}
          {#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)}
          {#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}
  {/key}
</div>