Setup lang

This commit is contained in:
2023-08-27 16:25:27 +01:00
parent 80d0e4975f
commit 2669af3250
85 changed files with 1152 additions and 1515 deletions

View File

@ -1,11 +1,6 @@
import { useMemo } from "react";
import {
TaggedNostrEvent,
EventKind,
NoteCollection,
RequestBuilder,
} from "@snort/system";
import { TaggedNostrEvent, EventKind, NoteCollection, RequestBuilder } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { findTag, toAddress, getTagValues } from "utils";
@ -20,10 +15,7 @@ export function useBadges(
const rb = new RequestBuilder(`badges:${pubkey.slice(0, 12)}`);
rb.withOptions({ leaveOpen });
rb.withFilter().authors([pubkey]).kinds([EventKind.Badge]);
rb.withFilter()
.authors([pubkey])
.kinds([EventKind.BadgeAward])
.since(since);
rb.withFilter().authors([pubkey]).kinds([EventKind.BadgeAward]).since(since);
return rb;
}, [pubkey, since]);
@ -31,15 +23,13 @@ export function useBadges(
const rawBadges = useMemo(() => {
if (badgeEvents) {
return badgeEvents
.filter((e) => e.kind === EventKind.Badge)
.sort((a, b) => b.created_at - a.created_at);
return badgeEvents.filter(e => e.kind === EventKind.Badge).sort((a, b) => b.created_at - a.created_at);
}
return [];
}, [badgeEvents]);
const badgeAwards = useMemo(() => {
if (badgeEvents) {
return badgeEvents.filter((e) => e.kind === EventKind.BadgeAward);
return badgeEvents.filter(e => e.kind === EventKind.BadgeAward);
}
return [];
}, [badgeEvents]);
@ -47,10 +37,7 @@ export function useBadges(
const acceptedSub = useMemo(() => {
if (rawBadges.length === 0) return null;
const rb = new RequestBuilder(`accepted-badges:${pubkey.slice(0, 12)}`);
rb.withFilter()
.kinds([EventKind.ProfileBadges])
.tag("d", ["profile_badges"])
.tag("a", rawBadges.map(toAddress));
rb.withFilter().kinds([EventKind.ProfileBadges]).tag("d", ["profile_badges"]).tag("a", rawBadges.map(toAddress));
return rb;
}, [rawBadges]);
@ -58,22 +45,16 @@ export function useBadges(
const acceptedEvents = acceptedStream.data ?? [];
const badges = useMemo(() => {
return rawBadges.map((e) => {
return rawBadges.map(e => {
const name = findTag(e, "d") ?? "";
const address = toAddress(e);
const awardEvents = badgeAwards.filter(
(b) => findTag(b, "a") === address
);
const awardees = new Set(
awardEvents.map((e) => getTagValues(e.tags, "p")).flat()
);
const awardEvents = badgeAwards.filter(b => findTag(b, "a") === address);
const awardees = new Set(awardEvents.map(e => getTagValues(e.tags, "p")).flat());
const accepted = new Set(
acceptedEvents
.filter((pb) => awardees.has(pb.pubkey))
.filter((pb) =>
pb.tags.find((t) => t.at(0) === "a" && t.at(1) === address)
)
.map((pb) => pb.pubkey)
.filter(pb => awardees.has(pb.pubkey))
.filter(pb => pb.tags.find(t => t.at(0) === "a" && t.at(1) === address))
.map(pb => pb.pubkey)
);
const thumb = findTag(e, "thumb");
const image = findTag(e, "image");

View File

@ -1,49 +1,34 @@
import { useMemo } from "react";
import {
TaggedNostrEvent,
ReplaceableNoteStore,
NoteCollection,
RequestBuilder,
} from "@snort/system";
import { TaggedNostrEvent, ReplaceableNoteStore, NoteCollection, RequestBuilder } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { USER_CARDS, CARD } from "const";
import { findTag } from "utils";
export function useUserCards(
pubkey: string,
userCards: Array<string[]>,
leaveOpen = false
): TaggedNostrEvent[] {
export function useUserCards(pubkey: string, userCards: Array<string[]>, leaveOpen = false): TaggedNostrEvent[] {
const related = useMemo(() => {
// filtering to only show CARD kinds for now, but in the future we could link and render anything
if (userCards?.length > 0) {
return userCards.filter(
(t) => t.at(0) === "a" && t.at(1)?.startsWith(`${CARD}:`)
);
return userCards.filter(t => t.at(0) === "a" && t.at(1)?.startsWith(`${CARD}:`));
}
return [];
}, [userCards]);
const subRelated = useMemo(() => {
if (!pubkey) return null;
const splitted = related.map((t) => t[1].split(":"));
const splitted = related.map(t => t[1].split(":"));
const authors = splitted
.map((s) => s.at(1))
.filter((s) => s)
.map((s) => s as string);
.map(s => s.at(1))
.filter(s => s)
.map(s => s as string);
const identifiers = splitted
.map((s) => s.at(2))
.filter((s) => s)
.map((s) => s as string);
.map(s => s.at(2))
.filter(s => s)
.map(s => s as string);
const rb = new RequestBuilder(`cards:${pubkey}`);
rb.withOptions({ leaveOpen })
.withFilter()
.kinds([CARD])
.authors(authors)
.tag("d", identifiers);
rb.withOptions({ leaveOpen }).withFilter().kinds([CARD]).authors(authors).tag("d", identifiers);
return rb;
}, [pubkey, related]);
@ -52,27 +37,19 @@ export function useUserCards(
const cards = useMemo(() => {
return related
.map((t) => {
.map(t => {
const [k, pubkey, identifier] = t[1].split(":");
const kind = Number(k);
return (data ?? []).find(
(e) =>
e.kind === kind &&
e.pubkey === pubkey &&
findTag(e, "d") === identifier
);
return (data ?? []).find(e => e.kind === kind && e.pubkey === pubkey && findTag(e, "d") === identifier);
})
.filter((e) => e)
.map((e) => e as TaggedNostrEvent);
.filter(e => e)
.map(e => e as TaggedNostrEvent);
}, [related, data]);
return cards;
}
export function useCards(
pubkey: string,
leaveOpen = false
): TaggedNostrEvent[] {
export function useCards(pubkey: string, leaveOpen = false): TaggedNostrEvent[] {
const sub = useMemo(() => {
const b = new RequestBuilder(`user-cards:${pubkey.slice(0, 12)}`);
b.withOptions({
@ -89,31 +66,25 @@ export function useCards(
const related = useMemo(() => {
// filtering to only show CARD kinds for now, but in the future we could link and render anything
if (userCards) {
return userCards.tags.filter(
(t) => t.at(0) === "a" && t.at(1)?.startsWith(`${CARD}:`)
);
return userCards.tags.filter(t => t.at(0) === "a" && t.at(1)?.startsWith(`${CARD}:`));
}
return [];
}, [userCards]);
const subRelated = useMemo(() => {
if (!pubkey) return null;
const splitted = related.map((t) => t[1].split(":"));
const splitted = related.map(t => t[1].split(":"));
const authors = splitted
.map((s) => s.at(1))
.filter((s) => s)
.map((s) => s as string);
.map(s => s.at(1))
.filter(s => s)
.map(s => s as string);
const identifiers = splitted
.map((s) => s.at(2))
.filter((s) => s)
.map((s) => s as string);
.map(s => s.at(2))
.filter(s => s)
.map(s => s as string);
const rb = new RequestBuilder(`cards:${pubkey}`);
rb.withOptions({ leaveOpen })
.withFilter()
.kinds([CARD])
.authors(authors)
.tag("d", identifiers);
rb.withOptions({ leaveOpen }).withFilter().kinds([CARD]).authors(authors).tag("d", identifiers);
return rb;
}, [pubkey, related]);
@ -123,18 +94,13 @@ export function useCards(
const cards = useMemo(() => {
return related
.map((t) => {
.map(t => {
const [k, pubkey, identifier] = t[1].split(":");
const kind = Number(k);
return cardEvents.find(
(e) =>
e.kind === kind &&
e.pubkey === pubkey &&
findTag(e, "d") === identifier
);
return cardEvents.find(e => e.kind === kind && e.pubkey === pubkey && findTag(e, "d") === identifier);
})
.filter((e) => e)
.map((e) => e as TaggedNostrEvent);
.filter(e => e)
.map(e => e as TaggedNostrEvent);
}, [related, cardEvents]);
return cards;

View File

@ -1,32 +1,17 @@
import { unwrap } from "@snort/shared";
import {
NostrEvent,
NostrLink,
NostrPrefix,
NoteCollection,
RequestBuilder,
TaggedNostrEvent,
} from "@snort/system";
import { NostrEvent, NostrLink, NostrPrefix, NoteCollection, RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { LIVE_STREAM } from "const";
import { useMemo } from "react";
export function useCurrentStreamFeed(
link: NostrLink,
leaveOpen = false,
evPreload?: NostrEvent
) {
const author =
link.type === NostrPrefix.Address ? unwrap(link.author) : link.id;
export function useCurrentStreamFeed(link: NostrLink, leaveOpen = false, evPreload?: NostrEvent) {
const author = link.type === NostrPrefix.Address ? unwrap(link.author) : link.id;
const sub = useMemo(() => {
const b = new RequestBuilder(`current-event:${link.id}`);
b.withOptions({
leaveOpen,
});
if (
link.type === NostrPrefix.PublicKey ||
link.type === NostrPrefix.Profile
) {
if (link.type === NostrPrefix.PublicKey || link.type === NostrPrefix.Profile) {
b.withFilter().authors([link.id]).kinds([LIVE_STREAM]).limit(1);
b.withFilter().tag("p", [link.id]).kinds([LIVE_STREAM]).limit(1);
} else if (link.type === NostrPrefix.Address) {
@ -49,12 +34,8 @@ export function useCurrentStreamFeed(
return useMemo(() => {
const hosting = q.data?.filter(
(a) =>
a.pubkey === author ||
a.tags.some((b) => b[0] === "p" && b[1] === author && b[3] === "host")
a => a.pubkey === author || a.tags.some(b => b[0] === "p" && b[1] === author && b[3] === "host")
);
return [...(hosting ?? [])]
.sort((a, b) => (b.created_at > a.created_at ? 1 : -1))
.at(0);
return [...(hosting ?? [])].sort((a, b) => (b.created_at > a.created_at ? 1 : -1)).at(0);
}, [q.data]);
}

View File

@ -1,12 +1,7 @@
import { useMemo } from "react";
import uniqBy from "lodash.uniqby";
import {
RequestBuilder,
ReplaceableNoteStore,
NoteCollection,
NostrEvent,
} from "@snort/system";
import { RequestBuilder, ReplaceableNoteStore, NoteCollection, NostrEvent } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { findTag } from "utils";
import { EMOJI_PACK, USER_EMOJIS } from "const";
@ -23,8 +18,8 @@ export function toEmojiPack(ev: NostrEvent): EmojiPack {
name: d,
author: ev.pubkey,
emojis: ev.tags
.filter((t) => t.at(0) === "emoji")
.map((t) => ["emoji", cleanShortcode(t.at(1)), t.at(2)]) as EmojiTag[],
.filter(t => t.at(0) === "emoji")
.map(t => ["emoji", cleanShortcode(t.at(1)), t.at(2)]) as EmojiTag[],
};
}
@ -35,24 +30,22 @@ export function packId(pack: EmojiPack): string {
export function useUserEmojiPacks(pubkey?: string, userEmoji?: Tags) {
const related = useMemo(() => {
if (userEmoji) {
return userEmoji?.filter(
(t) => t.at(0) === "a" && t.at(1)?.startsWith(`${EMOJI_PACK}:`)
);
return userEmoji?.filter(t => t.at(0) === "a" && t.at(1)?.startsWith(`${EMOJI_PACK}:`));
}
return [];
}, [userEmoji]);
const subRelated = useMemo(() => {
if (!pubkey) return null;
const splitted = related.map((t) => t[1].split(":"));
const splitted = related.map(t => t[1].split(":"));
const authors = splitted
.map((s) => s.at(1))
.filter((s) => s)
.map((s) => s as string);
.map(s => s.at(1))
.filter(s => s)
.map(s => s as string);
const identifiers = splitted
.map((s) => s.at(2))
.filter((s) => s)
.map((s) => s as string);
.map(s => s.at(2))
.filter(s => s)
.map(s => s as string);
const rb = new RequestBuilder(`emoji-related:${pubkey}`);

View File

@ -1,10 +1,5 @@
import { useMemo } from "react";
import {
NostrPrefix,
RequestBuilder,
ReplaceableNoteStore,
NostrLink,
} from "@snort/system";
import { NostrPrefix, RequestBuilder, ReplaceableNoteStore, NostrLink } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
export default function useEventFeed(link: NostrLink, leaveOpen = false) {
@ -24,7 +19,7 @@ export default function useEventFeed(link: NostrLink, leaveOpen = false) {
} else {
const f = b.withFilter().ids([link.id]);
if (link.relays) {
link.relays.slice(0, 2).forEach((r) => f.relay(r));
link.relays.slice(0, 2).forEach(r => f.relay(r));
}
if (link.author) {
f.authors([link.author]);

View File

@ -1,11 +1,6 @@
import { useMemo } from "react";
import {
NostrPrefix,
ReplaceableNoteStore,
RequestBuilder,
type NostrLink,
} from "@snort/system";
import { NostrPrefix, ReplaceableNoteStore, RequestBuilder, type NostrLink } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
export function useAddress(kind: number, pubkey: string, identifier: string) {
@ -34,7 +29,7 @@ export function useEvent(link: NostrLink) {
} else {
const f = b.withFilter().ids([link.id]);
if (link.relays) {
link.relays.slice(0, 2).forEach((r) => f.relay(r));
link.relays.slice(0, 2).forEach(r => f.relay(r));
}
if (link.author) {
f.authors([link.author]);

View File

@ -17,20 +17,13 @@ export function useZaps(goal: NostrEvent, leaveOpen = false) {
const sub = useMemo(() => {
const b = new RequestBuilder(`goal-zaps:${goal.id.slice(0, 12)}`);
b.withOptions({ leaveOpen });
b.withFilter()
.kinds([EventKind.ZapReceipt])
.tag("e", [goal.id])
.since(goal.created_at);
b.withFilter().kinds([EventKind.ZapReceipt]).tag("e", [goal.id]).since(goal.created_at);
return b;
}, [goal, leaveOpen]);
const { data } = useRequestBuilder(NoteCollection, sub);
return (
data
?.map((ev) => parseZap(ev, System.ProfileLoader.Cache))
.filter((z) => z && z.valid) ?? []
);
return data?.map(ev => parseZap(ev, System.ProfileLoader.Cache)).filter(z => z && z.valid) ?? [];
}
export function useZapGoal(host: string, link?: NostrLink, leaveOpen = false) {

View File

@ -1,9 +1,4 @@
import {
NostrLink,
RequestBuilder,
EventKind,
NoteCollection,
} from "@snort/system";
import { NostrLink, RequestBuilder, EventKind, NoteCollection } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { unixNow } from "@snort/shared";
import { useMemo } from "react";
@ -29,14 +24,14 @@ export function useLiveChatFeed(link: NostrLink, eZaps?: Array<string>) {
const feed = useRequestBuilder(NoteCollection, sub);
const messages = useMemo(() => {
return (feed.data ?? []).filter((ev) => ev.kind === LIVE_STREAM_CHAT);
return (feed.data ?? []).filter(ev => ev.kind === LIVE_STREAM_CHAT);
}, [feed.data]);
const zaps = useMemo(() => {
return (feed.data ?? []).filter((ev) => ev.kind === EventKind.ZapReceipt);
return (feed.data ?? []).filter(ev => ev.kind === EventKind.ZapReceipt);
}, [feed.data]);
const etags = useMemo(() => {
return messages.map((e) => e.id);
return messages.map(e => e.id);
}, [messages]);
const esub = useMemo(() => {
@ -45,9 +40,7 @@ export function useLiveChatFeed(link: NostrLink, eZaps?: Array<string>) {
rb.withOptions({
leaveOpen: true,
});
rb.withFilter()
.kinds([EventKind.Reaction, EventKind.ZapReceipt])
.tag("e", etags);
rb.withFilter().kinds([EventKind.Reaction, EventKind.ZapReceipt]).tag("e", etags);
return rb;
}, [etags]);

View File

@ -38,26 +38,18 @@ export function useStreamsFeed(tag?: string) {
const feedSorted = useMemo(() => {
if (feed.data) {
if (__XXX) {
return [...feed.data].filter(
(a) => findTag(a, "content-warning") !== undefined
);
return [...feed.data].filter(a => findTag(a, "content-warning") !== undefined);
} else {
return [...feed.data].filter(
(a) => findTag(a, "content-warning") === undefined
);
return [...feed.data].filter(a => findTag(a, "content-warning") === undefined);
}
}
return [];
}, [feed.data]);
const live = feedSorted
.filter((a) => findTag(a, "status") === StreamState.Live)
.sort(sortStarts);
const planned = feedSorted
.filter((a) => findTag(a, "status") === StreamState.Planned)
.sort(sortStarts);
const live = feedSorted.filter(a => findTag(a, "status") === StreamState.Live).sort(sortStarts);
const planned = feedSorted.filter(a => findTag(a, "status") === StreamState.Planned).sort(sortStarts);
const ended = feedSorted
.filter((a) => {
.filter(a => {
const hasEnded = findTag(a, "status") === StreamState.Ended;
const recording = findTag(a, "recording") ?? "";
return hasEnded && recording?.length > 0;

View File

@ -11,7 +11,7 @@ import { Login } from "index";
export function useLogin() {
const session = useSyncExternalStore(
(c) => Login.hook(c),
c => Login.hook(c),
() => Login.snapshot()
);
if (!session) return;
@ -26,7 +26,7 @@ export function useLogin() {
export function useLoginEvents(pubkey?: string, leaveOpen = false) {
const [userEmojis, setUserEmojis] = useState<Tags>([]);
const session = useSyncExternalStore(
(c) => Login.hook(c),
c => Login.hook(c),
() => Login.snapshot()
);

View File

@ -1,9 +1,6 @@
import { useMemo } from "react";
export default function usePlaceholder(pubkey: string) {
const url = useMemo(
() => `https://robohash.v0l.io/${pubkey}.png?set=2`,
[pubkey]
);
const url = useMemo(() => `https://robohash.v0l.io/${pubkey}.png?set=2`, [pubkey]);
return url;
}

View File

@ -1,11 +1,5 @@
import { useMemo } from "react";
import {
RequestBuilder,
NoteCollection,
NostrLink,
EventKind,
parseZap,
} from "@snort/system";
import { RequestBuilder, NoteCollection, NostrLink, EventKind, parseZap } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { LIVE_STREAM } from "const";
import { findTag } from "utils";
@ -31,7 +25,7 @@ export function useProfile(link: NostrLink, leaveOpen = false) {
const addresses = useMemo(() => {
if (streamsData) {
return streamsData.map((e) => `${e.kind}:${e.pubkey}:${findTag(e, "d")}`);
return streamsData.map(e => `${e.kind}:${e.pubkey}:${findTag(e, "d")}`);
}
return [];
}, [streamsData]);
@ -49,8 +43,8 @@ export function useProfile(link: NostrLink, leaveOpen = false) {
const { data: zapsData } = useRequestBuilder(NoteCollection, zapsSub);
const zaps = (zapsData ?? [])
.map((ev) => parseZap(ev, System.ProfileLoader.Cache))
.filter((z) => z && z.valid && z.receiver === link.id);
.map(ev => parseZap(ev, System.ProfileLoader.Cache))
.filter(z => z && z.valid && z.receiver === link.id);
const sortedStreams = useMemo(() => {
const sorted = [...streams];

View File

@ -3,7 +3,7 @@ import { useSyncExternalStore } from "react";
export function useStreamProvider() {
return useSyncExternalStore(
(c) => StreamProviderStore.hook(c),
c => StreamProviderStore.hook(c),
() => StreamProviderStore.snapshot()
);
}

View File

@ -2,19 +2,15 @@ import { useMemo } from "react";
import { ParsedZap } from "@snort/system";
function totalZapped(pubkey: string, zaps: ParsedZap[]) {
return zaps
.filter((z) => (z.anonZap ? pubkey === "anon" : z.sender === pubkey))
.reduce((acc, z) => acc + z.amount, 0);
return zaps.filter(z => (z.anonZap ? pubkey === "anon" : z.sender === pubkey)).reduce((acc, z) => acc + z.amount, 0);
}
export default function useTopZappers(zaps: ParsedZap[]) {
const zappers = zaps
.map((z) => (z.anonZap ? "anon" : z.sender))
.map((p) => p as string);
const zappers = zaps.map(z => (z.anonZap ? "anon" : z.sender)).map(p => p as string);
const sorted = useMemo(() => {
const pubkeys = [...new Set([...zappers])];
const result = pubkeys.map((pubkey) => {
const result = pubkeys.map(pubkey => {
return { pubkey, total: totalZapped(pubkey, zaps) };
});
result.sort((a, b) => b.total - a.total);