diff --git a/packages/app/src/Element/Timeline.tsx b/packages/app/src/Element/Timeline.tsx index 8f6c6ef9..29660183 100644 --- a/packages/app/src/Element/Timeline.tsx +++ b/packages/app/src/Element/Timeline.tsx @@ -25,6 +25,7 @@ export interface TimelineProps { relay?: string; now?: number; loadMore?: boolean; + noSort?: boolean; } /** @@ -46,8 +47,9 @@ const Timeline = (props: TimelineProps) => { const filterPosts = useCallback( (nts: readonly TaggedRawEvent[]) => { - return [...nts] - .sort((a, b) => b.created_at - a.created_at) + const a = [...nts]; + props.noSort || a.sort((a, b) => b.created_at - a.created_at); + return a ?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true)) .filter(a => props.ignoreModeration || !isMuted(a.pubkey)); }, diff --git a/packages/app/src/Feed/TimelineFeed.ts b/packages/app/src/Feed/TimelineFeed.ts index fe1845ca..da814655 100644 --- a/packages/app/src/Feed/TimelineFeed.ts +++ b/packages/app/src/Feed/TimelineFeed.ts @@ -15,7 +15,7 @@ export interface TimelineFeedOptions { } export interface TimelineSubject { - type: "pubkey" | "hashtag" | "global" | "ptag" | "keyword"; + type: "pubkey" | "hashtag" | "global" | "ptag" | "post_keyword" | "profile_keyword"; discriminator: string; items: string[]; } @@ -37,7 +37,13 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel } const b = new RequestBuilder(`timeline:${subject.type}:${subject.discriminator}`); - const f = b.withFilter().kinds([EventKind.TextNote, EventKind.Repost, EventKind.Polls]); + const f = b + .withFilter() + .kinds( + subject.type === "profile_keyword" + ? [EventKind.SetMetadata] + : [EventKind.TextNote, EventKind.Repost, EventKind.Polls] + ); if (options.relay) { b.withOptions({ @@ -58,7 +64,11 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel f.tag("p", subject.items); break; } - case "keyword": { + case "profile_keyword": { + f.search(subject.items[0] + " sort:popular"); + break; + } + case "post_keyword": { f.search(subject.items[0]); break; } @@ -105,7 +115,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel const subRealtime = useMemo(() => { const rb = createBuilder(); - if (rb && !pref.autoShowLatest) { + if (rb && !pref.autoShowLatest && options.method !== "LIMIT_UNTIL") { rb.builder.withOptions({ leaveOpen: true, }); diff --git a/packages/app/src/Pages/SearchPage.tsx b/packages/app/src/Pages/SearchPage.tsx index 4f4361d4..e0903940 100644 --- a/packages/app/src/Pages/SearchPage.tsx +++ b/packages/app/src/Pages/SearchPage.tsx @@ -1,33 +1,39 @@ import { useIntl, FormattedMessage } from "react-intl"; import { useParams } from "react-router-dom"; -import ProfilePreview from "Element/ProfilePreview"; import Timeline from "Element/Timeline"; +import { Tab, TabElement } from "Element/Tabs"; import { useEffect, useState } from "react"; import { debounce } from "Util"; import { router } from "index"; import { SearchRelays } from "Const"; import { System } from "System"; -import { MetadataCache } from "Cache"; -import { UserCache } from "Cache/UserCache"; import TrendingUsers from "Element/TrendingUsers"; +import useHorizontalScroll from "Hooks/useHorizontalScroll"; import messages from "./messages"; +const POSTS = 0; +const PROFILES = 1; + const SearchPage = () => { const params = useParams(); const { formatMessage } = useIntl(); const [search, setSearch] = useState(params.keyword); const [keyword, setKeyword] = useState(params.keyword); - const [allUsers, setAllUsers] = useState(); + // tabs + const SearchTab = { + Posts: { text: formatMessage(messages.Posts), value: POSTS }, + Profiles: { text: formatMessage(messages.People), value: PROFILES }, + }; + const [tab, setTab] = useState(SearchTab.Posts); + const horizontalScroll = useHorizontalScroll(); useEffect(() => { if (keyword) { // "navigate" changing only url router.navigate(`/search/${encodeURIComponent(keyword)}`); - UserCache.search(keyword).then(v => setAllUsers(v)); } else { router.navigate(`/search`); - setAllUsers([]); } }, [keyword]); @@ -50,6 +56,30 @@ const SearchPage = () => { }; }, []); + function tabContent() { + if (!keyword) return null; + const pf = tab.value == PROFILES; + return ( + <> + + + ); + } + + function renderTab(v: Tab) { + return ; + } + return (

@@ -65,20 +95,11 @@ const SearchPage = () => { autoFocus={true} />

+
+ {[SearchTab.Posts, SearchTab.Profiles].map(renderTab)} +
{!keyword && } - {keyword && allUsers?.slice(0, 3).map(u => } className="card" pubkey={u.pubkey} />)} - {keyword && ( - - )} + {tabContent()} ); }; diff --git a/packages/app/src/Pages/messages.ts b/packages/app/src/Pages/messages.ts index b715720b..5b9ac6fb 100644 --- a/packages/app/src/Pages/messages.ts +++ b/packages/app/src/Pages/messages.ts @@ -46,4 +46,6 @@ export default defineMessages({ }, Bookmarks: { defaultMessage: "Bookmarks" }, BookmarksCount: { defaultMessage: "{n} Bookmarks" }, + KeyPlaceholder: { defaultMessage: "nsec, npub, nip-05, hex" }, + People: { defaultMessage: "People" }, });