Add people search

This commit is contained in:
artur 2023-03-01 14:58:21 +03:00 committed by Kieran
parent 59038d118e
commit 01d6839080
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
4 changed files with 60 additions and 25 deletions

View File

@ -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));
},

View File

@ -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,
});

View File

@ -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<string | undefined>(params.keyword);
const [keyword, setKeyword] = useState<string | undefined>(params.keyword);
const [allUsers, setAllUsers] = useState<MetadataCache[]>();
// tabs
const SearchTab = {
Posts: { text: formatMessage(messages.Posts), value: POSTS },
Profiles: { text: formatMessage(messages.People), value: PROFILES },
};
const [tab, setTab] = useState<Tab>(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 (
<>
<Timeline
key={keyword + (pf ? "_p" : "")}
subject={{
type: pf ? "profile_keyword" : "post_keyword",
items: [keyword],
discriminator: keyword,
}}
postsOnly={false}
noSort={pf}
method={"LIMIT_UNTIL"}
/>
</>
);
}
function renderTab(v: Tab) {
return <TabElement key={v.value} t={v} tab={tab} setTab={setTab} />;
}
return (
<div className="main-content">
<h2>
@ -65,20 +95,11 @@ const SearchPage = () => {
autoFocus={true}
/>
</div>
<div className="tabs" ref={horizontalScroll}>
{[SearchTab.Posts, SearchTab.Profiles].map(renderTab)}
</div>
{!keyword && <TrendingUsers />}
{keyword && allUsers?.slice(0, 3).map(u => <ProfilePreview actions={<></>} className="card" pubkey={u.pubkey} />)}
{keyword && (
<Timeline
key={keyword}
subject={{
type: "keyword",
items: [keyword],
discriminator: keyword,
}}
postsOnly={false}
method={"TIME_RANGE"}
/>
)}
{tabContent()}
</div>
);
};

View File

@ -46,4 +46,6 @@ export default defineMessages({
},
Bookmarks: { defaultMessage: "Bookmarks" },
BookmarksCount: { defaultMessage: "{n} Bookmarks" },
KeyPlaceholder: { defaultMessage: "nsec, npub, nip-05, hex" },
People: { defaultMessage: "People" },
});