From 540f29dd697f72f405692628ddbd85d18582c385 Mon Sep 17 00:00:00 2001 From: Kieran Date: Mon, 13 Nov 2023 15:58:14 +0000 Subject: [PATCH] feat: hashtags header --- packages/app/src/Cache/FollowsFeed.ts | 2 +- .../app/src/Element/Feed/TimelineFollows.tsx | 22 +++-- packages/app/src/Element/Text.css | 4 + packages/app/src/Pages/HashTagsPage.tsx | 97 ++++++++++++------- packages/system/src/event-kind.ts | 1 - 5 files changed, 82 insertions(+), 44 deletions(-) diff --git a/packages/app/src/Cache/FollowsFeed.ts b/packages/app/src/Cache/FollowsFeed.ts index 46e44737..a4e58136 100644 --- a/packages/app/src/Cache/FollowsFeed.ts +++ b/packages/app/src/Cache/FollowsFeed.ts @@ -47,7 +47,7 @@ export class FollowsFeedCache extends RefreshFeedCache { const keys = (await this.table?.toCollection().primaryKeys()) ?? []; this.onTable = new Set(keys.map(a => a as string)); - // load only latest 10 posts, rest can be loaded on-demand + // load only latest 50 posts, rest can be loaded on-demand const latest = await this.table?.orderBy("created_at").reverse().limit(50).toArray(); latest?.forEach(v => this.cache.set(this.key(v), v)); diff --git a/packages/app/src/Element/Feed/TimelineFollows.tsx b/packages/app/src/Element/Feed/TimelineFollows.tsx index 79774c3a..bfde55f8 100644 --- a/packages/app/src/Element/Feed/TimelineFollows.tsx +++ b/packages/app/src/Element/Feed/TimelineFollows.tsx @@ -12,6 +12,7 @@ import useLogin from "Hooks/useLogin"; import { TimelineFragment, TimelineRenderer } from "./TimelineFragment"; import useHashtagsFeed from "Feed/HashtagsFeed"; import { ShowMoreInView } from "Element/Event/ShowMore"; +import { HashTagHeader } from "Pages/HashTagsPage"; export interface TimelineFollowsProps { postsOnly: boolean; @@ -67,6 +68,7 @@ const TimelineFollows = (props: TimelineFollowsProps) => { const included = new Set(); return (mixin.data.data ?? []) .filter(a => !mainFeedIds.has(a.id) && postsOnly(a)) + .filter(a => a.tags.filter(a => a[0] === "t").length < 5) .reduce( (acc, v) => { if (included.has(v.id)) return acc; @@ -116,9 +118,9 @@ const TimelineFollows = (props: TimelineFollowsProps) => { noteOnClick={props.noteOnClick} noteRenderer={props.noteRenderer} /> - 0 && await FollowsFeed.loadMore(system, login, sortedFeed[sortedFeed.length - 1].created_at)} - /> + />} ); }; @@ -129,28 +131,32 @@ function weaveTimeline( hashtags: Record>, ): Array { // always skip 5 posts from start to avoid heavy handed weaving - const skip = 5; + let skip = 5; if (main.length < skip) { - return [{ events: main, refTime: unixNow() }]; + skip = Math.min(skip, main.length - 1); } const frags = Object.entries(hashtags).map(([k, v]) => { const take = v.slice(0, 5); return { title: ( -
-

#{k}

+
+
), events: take, refTime: Math.min( - main[skip].created_at, + main.at(skip)?.created_at ?? unixNow(), take.reduce((acc, v) => (acc > v.created_at ? acc : v.created_at), 0), ), } as TimelineFragment; }); + if (main.length === 0) { + return frags; + } + return [ { events: main.slice(0, skip), @@ -162,4 +168,4 @@ function weaveTimeline( refTime: main[skip].created_at, }, ].sort((a, b) => (a.refTime > b.refTime ? -1 : 1)); -} +} \ No newline at end of file diff --git a/packages/app/src/Element/Text.css b/packages/app/src/Element/Text.css index 4448d84c..6710d669 100644 --- a/packages/app/src/Element/Text.css +++ b/packages/app/src/Element/Text.css @@ -39,6 +39,10 @@ margin-right: auto; } +.text iframe[src*="youtube.com"] { + aspect-ratio: 16/9; +} + .gallery { grid-template-columns: repeat(4, 1fr); gap: 2px; diff --git a/packages/app/src/Pages/HashTagsPage.tsx b/packages/app/src/Pages/HashTagsPage.tsx index 40e41ac8..78bcc837 100644 --- a/packages/app/src/Pages/HashTagsPage.tsx +++ b/packages/app/src/Pages/HashTagsPage.tsx @@ -1,51 +1,25 @@ import { useMemo } from "react"; import { useParams } from "react-router-dom"; -import { FormattedMessage } from "react-intl"; -import { NostrHashtagLink } from "@snort/system"; +import { FormattedMessage, FormattedNumber } from "react-intl"; +import { EventKind, NostrHashtagLink, NoteCollection, RequestBuilder } from "@snort/system"; +import { dedupe } from "@snort/shared"; +import { useRequestBuilder } from "@snort/system-react"; import Timeline from "Element/Feed/Timeline"; import useEventPublisher from "Hooks/useEventPublisher"; import useLogin from "Hooks/useLogin"; import { setTags } from "Login"; +import AsyncButton from "Element/AsyncButton"; +import ProfileImage from "Element/User/ProfileImage"; const HashTagsPage = () => { const params = useParams(); const tag = (params.tag ?? "").toLowerCase(); - const login = useLogin(); - const isFollowing = useMemo(() => { - return login.tags.item.includes(tag); - }, [login, tag]); - const { publisher, system } = useEventPublisher(); - - async function followTags(ts: string[]) { - if (publisher) { - const ev = await publisher.bookmarks( - ts.map(a => new NostrHashtagLink(a)), - "follow", - ); - system.BroadcastEvent(ev); - setTags(login, ts, ev.created_at * 1000); - } - } return ( <> -
-
-

#{tag}

- {isFollowing ? ( - - ) : ( - - )} -
+
+
{ }; export default HashTagsPage; + + + +export function HashTagHeader({ tag }: { tag: string }) { + const login = useLogin(); + const isFollowing = useMemo(() => { + return login.tags.item.includes(tag); + }, [login, tag]); + const { publisher, system } = useEventPublisher(); + + async function followTags(ts: string[]) { + if (publisher) { + const ev = await publisher.bookmarks( + ts.map(a => new NostrHashtagLink(a)), + "follow", + ); + setTags(login, ts, ev.created_at * 1000); + await system.BroadcastEvent(ev); + } + } + + const sub = useMemo(() => { + const rb = new RequestBuilder(`hashtag-counts:${tag}`); + rb.withFilter() + .kinds([EventKind.CategorizedBookmarks]) + .tag("d", ["follow"]) + .tag("t", [tag.toLowerCase()]); + return rb; + }, [tag]); + const followsTag = useRequestBuilder(NoteCollection, sub); + const pubkeys = dedupe((followsTag.data ?? []).map(a => a.pubkey)); + + return
+
+

#{tag}

+
+ {pubkeys.slice(0, 5).map(a => )} + {pubkeys.length > 5 && + + + } +
+
+ {isFollowing ? ( + followTags(login.tags.item.filter(t => t !== tag))}> + + + ) : ( + followTags(login.tags.item.concat([tag]))}> + + + )} +
+} \ No newline at end of file diff --git a/packages/system/src/event-kind.ts b/packages/system/src/event-kind.ts index b286eda1..579c56bc 100644 --- a/packages/system/src/event-kind.ts +++ b/packages/system/src/event-kind.ts @@ -31,7 +31,6 @@ enum EventKind { CategorizedPeople = 30000, // NIP-51a CategorizedBookmarks = 30001, // NIP-51b - TagLists = 30002, // NIP-51c Badge = 30009, // NIP-58 ProfileBadges = 30008, // NIP-58