show "followed by" on profile pages
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
Martti Malmi 2023-11-24 16:18:32 +02:00
parent 47aec5437d
commit 13b76e7709
5 changed files with 56 additions and 8 deletions

View File

@ -50,10 +50,12 @@ export default function SearchBox() {
const combinedResults = fuseResults.map(result => { const combinedResults = fuseResults.map(result => {
const fuseScore = result.score === undefined ? 1 : result.score; const fuseScore = result.score === undefined ? 1 : result.score;
const followDistance = socialGraphInstance.getFollowDistance(result.item.pubkey) / followDistanceNormalizationFactor; const followDistance =
socialGraphInstance.getFollowDistance(result.item.pubkey) / followDistanceNormalizationFactor;
const startsWithSearchString = [result.item.name, result.item.display_name, result.item.nip05] const startsWithSearchString = [result.item.name, result.item.display_name, result.item.nip05].some(
.some(field => field && field.toLowerCase?.().startsWith(searchString.toLowerCase())); field => field && field.toLowerCase?.().startsWith(searchString.toLowerCase()),
);
const boostFactor = startsWithSearchString ? 0.25 : 1; const boostFactor = startsWithSearchString ? 0.25 : 1;
@ -65,12 +67,11 @@ export default function SearchBox() {
return { ...result, combinedScore }; return { ...result, combinedScore };
}); });
// Sort by combined score, lower is better // Sort by combined score, lower is better
combinedResults.sort((a, b) => a.combinedScore - b.combinedScore); combinedResults.sort((a, b) => a.combinedScore - b.combinedScore);
setResults(combinedResults.map(r => r.item));
}, [search, main]);
setResults(combinedResults.map(r => r.item));
}, [search, main]);
useEffect(() => { useEffect(() => {
const handleGlobalKeyDown = (e: KeyboardEvent) => { const handleGlobalKeyDown = (e: KeyboardEvent) => {

View File

@ -9,6 +9,7 @@ import {
MetadataCache, MetadataCache,
NostrLink, NostrLink,
NostrPrefix, NostrPrefix,
socialGraphInstance,
TLVEntryType, TLVEntryType,
tryParseNostrLink, tryParseNostrLink,
} from "@snort/system"; } from "@snort/system";
@ -152,6 +153,8 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
} }
function username() { function username() {
const followedByFriends = user.pubkey ? socialGraphInstance.followedByFriends(user.pubkey) : new Set<string>();
const MAX_FOLLOWED_BY_FRIENDS = 3;
return ( return (
<> <>
<div className="flex flex-col g4"> <div className="flex flex-col g4">
@ -160,6 +163,31 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
<FollowsYou followsMe={follows.includes(loginPubKey ?? "")} /> <FollowsYou followsMe={follows.includes(loginPubKey ?? "")} />
</h2> </h2>
{user?.nip05 && <Nip05 nip05={user.nip05} pubkey={user.pubkey} />} {user?.nip05 && <Nip05 nip05={user.nip05} pubkey={user.pubkey} />}
{followedByFriends.size > 0 && (
<div className="text-gray-light">
<span className="mr-1">
<FormattedMessage defaultMessage="Followed by" id="6mr8WU" />
</span>
{Array.from(followedByFriends)
.slice(0, MAX_FOLLOWED_BY_FRIENDS)
.map(a => {
return (
<span className="inline-block" key={a}>
<ProfileImage showFollowDistance={false} pubkey={a} size={24} showUsername={false} />
</span>
);
})}
{followedByFriends.size > MAX_FOLLOWED_BY_FRIENDS && (
<span>
<FormattedMessage
defaultMessage="and {count} others you follow"
id="CYkOCI"
values={{ count: followedByFriends.size - MAX_FOLLOWED_BY_FRIENDS }}
/>
</span>
)}
</div>
)}
</div> </div>
{showBadges && <BadgeList badges={badges} />} {showBadges && <BadgeList badges={badges} />}
{showStatus && <>{musicStatus()}</>} {showStatus && <>{musicStatus()}</>}

View File

@ -234,6 +234,9 @@
"6k7xfM": { "6k7xfM": {
"defaultMessage": "Trending notes" "defaultMessage": "Trending notes"
}, },
"6mr8WU": {
"defaultMessage": "Followed by"
},
"6uMqL1": { "6uMqL1": {
"defaultMessage": "Unpaid" "defaultMessage": "Unpaid"
}, },
@ -368,6 +371,9 @@
"CVWeJ6": { "CVWeJ6": {
"defaultMessage": "Trending People" "defaultMessage": "Trending People"
}, },
"CYkOCI": {
"defaultMessage": "and {count} others you follow"
},
"CbM2hK": { "CbM2hK": {
"defaultMessage": "Trending hashtags" "defaultMessage": "Trending hashtags"
}, },

View File

@ -77,6 +77,7 @@
"6bgpn+": "Not all clients support this, you may still receive some zaps as if zap splits was not configured", "6bgpn+": "Not all clients support this, you may still receive some zaps as if zap splits was not configured",
"6ewQqw": "Likes ({n})", "6ewQqw": "Likes ({n})",
"6k7xfM": "Trending notes", "6k7xfM": "Trending notes",
"6mr8WU": "Followed by",
"6uMqL1": "Unpaid", "6uMqL1": "Unpaid",
"7+Domh": "Notes", "7+Domh": "Notes",
"712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node", "712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node",
@ -121,6 +122,7 @@
"C8HhVE": "Suggested Follows", "C8HhVE": "Suggested Follows",
"CHTbO3": "Failed to load invoice", "CHTbO3": "Failed to load invoice",
"CVWeJ6": "Trending People", "CVWeJ6": "Trending People",
"CYkOCI": "and {count} others you follow",
"CbM2hK": "Trending hashtags", "CbM2hK": "Trending hashtags",
"CmZ9ls": "{n} Muted", "CmZ9ls": "{n} Muted",
"CsCUYo": "{n} sats", "CsCUYo": "{n} sats",

View File

@ -211,6 +211,17 @@ export default class SocialGraph {
return count; return count;
} }
followedByFriends(address: HexKey) {
const id = ID(address);
const set = new Set<HexKey>();
for (const follower of this.followersByUser.get(id) ?? []) {
if (this.followedByUser.get(this.root)?.has(follower)) {
set.add(STR(follower));
}
}
return set;
}
getFollowedByUser(user: HexKey, includeSelf = false): Set<HexKey> { getFollowedByUser(user: HexKey, includeSelf = false): Set<HexKey> {
const userId = ID(user); const userId = ID(user);
const set = new Set<HexKey>(); const set = new Set<HexKey>();