Add people search
This commit is contained in:
parent
59038d118e
commit
01d6839080
@ -25,6 +25,7 @@ export interface TimelineProps {
|
|||||||
relay?: string;
|
relay?: string;
|
||||||
now?: number;
|
now?: number;
|
||||||
loadMore?: boolean;
|
loadMore?: boolean;
|
||||||
|
noSort?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,8 +47,9 @@ const Timeline = (props: TimelineProps) => {
|
|||||||
|
|
||||||
const filterPosts = useCallback(
|
const filterPosts = useCallback(
|
||||||
(nts: readonly TaggedRawEvent[]) => {
|
(nts: readonly TaggedRawEvent[]) => {
|
||||||
return [...nts]
|
const a = [...nts];
|
||||||
.sort((a, b) => b.created_at - a.created_at)
|
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.postsOnly ? !a.tags.some(b => b[0] === "e") : true))
|
||||||
.filter(a => props.ignoreModeration || !isMuted(a.pubkey));
|
.filter(a => props.ignoreModeration || !isMuted(a.pubkey));
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@ export interface TimelineFeedOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TimelineSubject {
|
export interface TimelineSubject {
|
||||||
type: "pubkey" | "hashtag" | "global" | "ptag" | "keyword";
|
type: "pubkey" | "hashtag" | "global" | "ptag" | "post_keyword" | "profile_keyword";
|
||||||
discriminator: string;
|
discriminator: string;
|
||||||
items: 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 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) {
|
if (options.relay) {
|
||||||
b.withOptions({
|
b.withOptions({
|
||||||
@ -58,7 +64,11 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
|||||||
f.tag("p", subject.items);
|
f.tag("p", subject.items);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "keyword": {
|
case "profile_keyword": {
|
||||||
|
f.search(subject.items[0] + " sort:popular");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "post_keyword": {
|
||||||
f.search(subject.items[0]);
|
f.search(subject.items[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -105,7 +115,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
|||||||
|
|
||||||
const subRealtime = useMemo(() => {
|
const subRealtime = useMemo(() => {
|
||||||
const rb = createBuilder();
|
const rb = createBuilder();
|
||||||
if (rb && !pref.autoShowLatest) {
|
if (rb && !pref.autoShowLatest && options.method !== "LIMIT_UNTIL") {
|
||||||
rb.builder.withOptions({
|
rb.builder.withOptions({
|
||||||
leaveOpen: true,
|
leaveOpen: true,
|
||||||
});
|
});
|
||||||
|
@ -1,33 +1,39 @@
|
|||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import ProfilePreview from "Element/ProfilePreview";
|
|
||||||
import Timeline from "Element/Timeline";
|
import Timeline from "Element/Timeline";
|
||||||
|
import { Tab, TabElement } from "Element/Tabs";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { debounce } from "Util";
|
import { debounce } from "Util";
|
||||||
import { router } from "index";
|
import { router } from "index";
|
||||||
import { SearchRelays } from "Const";
|
import { SearchRelays } from "Const";
|
||||||
import { System } from "System";
|
import { System } from "System";
|
||||||
import { MetadataCache } from "Cache";
|
|
||||||
import { UserCache } from "Cache/UserCache";
|
|
||||||
import TrendingUsers from "Element/TrendingUsers";
|
import TrendingUsers from "Element/TrendingUsers";
|
||||||
|
import useHorizontalScroll from "Hooks/useHorizontalScroll";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
|
||||||
|
const POSTS = 0;
|
||||||
|
const PROFILES = 1;
|
||||||
|
|
||||||
const SearchPage = () => {
|
const SearchPage = () => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const [search, setSearch] = useState<string | undefined>(params.keyword);
|
const [search, setSearch] = useState<string | undefined>(params.keyword);
|
||||||
const [keyword, setKeyword] = 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(() => {
|
useEffect(() => {
|
||||||
if (keyword) {
|
if (keyword) {
|
||||||
// "navigate" changing only url
|
// "navigate" changing only url
|
||||||
router.navigate(`/search/${encodeURIComponent(keyword)}`);
|
router.navigate(`/search/${encodeURIComponent(keyword)}`);
|
||||||
UserCache.search(keyword).then(v => setAllUsers(v));
|
|
||||||
} else {
|
} else {
|
||||||
router.navigate(`/search`);
|
router.navigate(`/search`);
|
||||||
setAllUsers([]);
|
|
||||||
}
|
}
|
||||||
}, [keyword]);
|
}, [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 (
|
return (
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
<h2>
|
<h2>
|
||||||
@ -65,20 +95,11 @@ const SearchPage = () => {
|
|||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="tabs" ref={horizontalScroll}>
|
||||||
|
{[SearchTab.Posts, SearchTab.Profiles].map(renderTab)}
|
||||||
|
</div>
|
||||||
{!keyword && <TrendingUsers />}
|
{!keyword && <TrendingUsers />}
|
||||||
{keyword && allUsers?.slice(0, 3).map(u => <ProfilePreview actions={<></>} className="card" pubkey={u.pubkey} />)}
|
{tabContent()}
|
||||||
{keyword && (
|
|
||||||
<Timeline
|
|
||||||
key={keyword}
|
|
||||||
subject={{
|
|
||||||
type: "keyword",
|
|
||||||
items: [keyword],
|
|
||||||
discriminator: keyword,
|
|
||||||
}}
|
|
||||||
postsOnly={false}
|
|
||||||
method={"TIME_RANGE"}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -46,4 +46,6 @@ export default defineMessages({
|
|||||||
},
|
},
|
||||||
Bookmarks: { defaultMessage: "Bookmarks" },
|
Bookmarks: { defaultMessage: "Bookmarks" },
|
||||||
BookmarksCount: { defaultMessage: "{n} Bookmarks" },
|
BookmarksCount: { defaultMessage: "{n} Bookmarks" },
|
||||||
|
KeyPlaceholder: { defaultMessage: "nsec, npub, nip-05, hex" },
|
||||||
|
People: { defaultMessage: "People" },
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user