Include space urls in hints for profile derivation

This commit is contained in:
Jon Staab 2026-08-21 13:47:06 -07:00
parent 5ecb811b24
commit 3e4ae49eed
19 changed files with 42 additions and 30 deletions

View file

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import {removeUndefined} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {slide} from "@lib/transition" import {slide} from "@lib/transition"
import CloseCircle from "@assets/icons/close-circle.svg?dataurl" import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
@ -8,14 +9,15 @@
import {profiles} from "@app/core" import {profiles} from "@app/core"
type Props = { type Props = {
url?: string
verb: string verb: string
event: TrustedEvent event: TrustedEvent
clear: () => void clear: () => void
} }
const {verb, event, clear}: Props = $props() const {url, verb, event, clear}: Props = $props()
const display = $profiles.display(event.pubkey).$ const display = $profiles.display(event.pubkey, removeUndefined([url])).$
</script> </script>
<div <div

View file

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import {removeUndefined} from "@welshman/lib"
import type {ProfilePointer} from "@welshman/content" import type {ProfilePointer} from "@welshman/content"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import ProfileDetail from "@app/components/ProfileDetail.svelte" import ProfileDetail from "@app/components/ProfileDetail.svelte"
@ -12,7 +13,7 @@
const {value, url}: Props = $props() const {value, url}: Props = $props()
const display = $profiles.display(value.pubkey).$ const display = $profiles.display(value.pubkey, removeUndefined([url])).$
const openProfile = () => pushModal(ProfileDetail, {pubkey: value.pubkey, url}) const openProfile = () => pushModal(ProfileDetail, {pubkey: value.pubkey, url})
</script> </script>

View file

@ -109,7 +109,7 @@
class="left-content bottom-sai right-sai fixed z-feature mb-14 md:mb-0 w-full md:w-auto pr-2"> class="left-content bottom-sai right-sai fixed z-feature mb-14 md:mb-0 w-full md:w-auto pr-2">
<div class="card mx-2 my-2 shadow-md"> <div class="card mx-2 my-2 shadow-md">
{#if parent} {#if parent}
<ChatComposeParent event={parent} clear={() => onClearParent?.()} verb="Replying to" /> <ChatComposeParent {url} event={parent} clear={() => onClearParent?.()} verb="Replying to" />
{/if} {/if}
<div class="relative"> <div class="relative">
<div class="note-editor grow overflow-hidden"> <div class="note-editor grow overflow-hidden">

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import * as nip19 from "nostr-tools/nip19" import * as nip19 from "nostr-tools/nip19"
import {removeUndefined} from "@welshman/lib"
import {displayHandle} from "@welshman/util" import {displayHandle} from "@welshman/util"
import {displayPubkey} from "@welshman/domain" import {displayPubkey} from "@welshman/domain"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
@ -22,7 +23,7 @@
const {pubkey, url, showPubkey, inert, avatarSize = 10}: Props = $props() const {pubkey, url, showPubkey, inert, avatarSize = 10}: Props = $props()
const profileDisplay = $profiles.display(pubkey).$ const profileDisplay = $profiles.display(pubkey, removeUndefined([url])).$
const handle = $handles.forPubkey(pubkey).$ const handle = $handles.forPubkey(pubkey).$
const openProfile = () => { const openProfile = () => {
@ -35,11 +36,11 @@
<div class="flex max-w-full items-start gap-2"> <div class="flex max-w-full items-start gap-2">
{#if inert} {#if inert}
<span class="py-1"> <span class="py-1">
<ProfileCircle {pubkey} size={avatarSize} /> <ProfileCircle {pubkey} {url} size={avatarSize} />
</span> </span>
{:else} {:else}
<Button onclick={openProfile} class="py-1"> <Button onclick={openProfile} class="py-1">
<ProfileCircle {pubkey} size={avatarSize} /> <ProfileCircle {pubkey} {url} size={avatarSize} />
</Button> </Button>
{/if} {/if}
<div class="flex min-w-0 flex-col"> <div class="flex min-w-0 flex-col">

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import {spec} from "@welshman/lib" import {removeUndefined, spec} from "@welshman/lib"
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl" import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
import UserCircle from "@assets/icons/user-circle.svg?dataurl" import UserCircle from "@assets/icons/user-circle.svg?dataurl"
import MinusCircle from "@assets/icons/minus-circle.svg?dataurl" import MinusCircle from "@assets/icons/minus-circle.svg?dataurl"
@ -48,7 +48,7 @@
const banMember = () => const banMember = () =>
pushModal(Confirm, { pushModal(Confirm, {
title: "Ban User", title: "Ban User",
message: `Are you sure you want to ban @${$profiles.display(pubkey).get()} from the space?`, message: `Are you sure you want to ban @${$profiles.display(pubkey, removeUndefined([url])).get()} from the space?`,
confirm: async () => { confirm: async () => {
const {error} = await $relayManagement.forUrl(url!).banPubkey(pubkey) const {error} = await $relayManagement.forUrl(url!).banPubkey(pubkey)

View file

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import type {Snippet} from "svelte" import type {Snippet} from "svelte"
import {removeUndefined} from "@welshman/lib"
import Code2 from "@assets/icons/code-2.svg?dataurl" import Code2 from "@assets/icons/code-2.svg?dataurl"
import ShareCircle from "@assets/icons/share-circle.svg?dataurl" import ShareCircle from "@assets/icons/share-circle.svg?dataurl"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
@ -19,7 +20,7 @@
const {pubkey, url, onClick, customActions}: Props = $props() const {pubkey, url, onClick, customActions}: Props = $props()
const profile = $profiles.one(pubkey) const profile = $profiles.one(pubkey, removeUndefined([url]))
const showInfo = () => pushModal(ProfileInfo, {event: $profile!.event, url}) const showInfo = () => pushModal(ProfileInfo, {event: $profile!.event, url})

View file

@ -59,7 +59,7 @@
event, event,
deleteReaction, deleteReaction,
createReaction, createReaction,
url = "", url,
reactionClass = "", reactionClass = "",
noTooltip = false, noTooltip = false,
innerEvent = undefined, innerEvent = undefined,
@ -196,7 +196,9 @@
{@const amount = fromMsats(sum(zaps.map(zap => zap.invoiceAmount)))} {@const amount = fromMsats(sum(zaps.map(zap => zap.invoiceAmount)))}
{@const pubkeys = uniq(zaps.map(zap => zap.request.pubkey))} {@const pubkeys = uniq(zaps.map(zap => zap.request.pubkey))}
{@const isOwn = pubkeys.includes($user.pubkey)} {@const isOwn = pubkeys.includes($user.pubkey)}
{@const info = displayList(pubkeys.map(pubkey => $profiles.display(pubkey).get()))} {@const info = displayList(
pubkeys.map(pubkey => $profiles.display(pubkey, removeUndefined([url])).get()),
)}
{@const tooltip = `${info} zapped`} {@const tooltip = `${info} zapped`}
{@const onZapClickHandler = () => onZapClick(pubkeys, tooltip)} {@const onZapClickHandler = () => onZapClick(pubkeys, tooltip)}
<Button <Button
@ -218,7 +220,9 @@
{#each groupedReactions.entries() as [key, events]} {#each groupedReactions.entries() as [key, events]}
{@const pubkeys = events.map(e => e.pubkey)} {@const pubkeys = events.map(e => e.pubkey)}
{@const isOwn = pubkeys.includes($user.pubkey)} {@const isOwn = pubkeys.includes($user.pubkey)}
{@const info = displayList(pubkeys.map(pubkey => $profiles.display(pubkey).get()))} {@const info = displayList(
pubkeys.map(pubkey => $profiles.display(pubkey, removeUndefined([url])).get()),
)}
{@const tooltip = `${info} reacted`} {@const tooltip = `${info} reacted`}
{@const onClick = () => onReactionClick(events, pubkeys, info)} {@const onClick = () => onReactionClick(events, pubkeys, info)}
<Button <Button

View file

@ -74,7 +74,7 @@
pushModal(Confirm, { pushModal(Confirm, {
title: "Ban User", title: "Ban User",
message: `Are you sure you want to ban @${$profiles.display(reported).get()} from the space?`, message: `Are you sure you want to ban @${$profiles.display(reported, [url]).get()} from the space?`,
confirm: async () => { confirm: async () => {
const {error} = await $relayManagement.forUrl(url).banPubkey(reported, reason) const {error} = await $relayManagement.forUrl(url).banPubkey(reported, reason)

View file

@ -639,10 +639,10 @@
{:else} {:else}
<div> <div>
{#if parent} {#if parent}
<RoomComposeParent event={parent} clear={clearParent} verb="Replying to" /> <RoomComposeParent {url} event={parent} clear={clearParent} verb="Replying to" />
{/if} {/if}
{#if sharedEvent} {#if sharedEvent}
<RoomComposeParent event={sharedEvent} clear={clearShare} verb="Sharing" /> <RoomComposeParent {url} event={sharedEvent} clear={clearShare} verb="Sharing" />
{/if} {/if}
{#if eventToEdit} {#if eventToEdit}
<RoomComposeEdit clear={clearEventToEdit} /> <RoomComposeEdit clear={clearEventToEdit} />

View file

@ -8,14 +8,15 @@
import {profiles} from "@app/core" import {profiles} from "@app/core"
type Props = { type Props = {
url: string
verb: string verb: string
event: TrustedEvent event: TrustedEvent
clear: () => void clear: () => void
} }
const {verb, event, clear}: Props = $props() const {url, verb, event, clear}: Props = $props()
const display = $profiles.display(event.pubkey).$ const display = $profiles.display(event.pubkey, [url]).$
</script> </script>
<div <div

View file

@ -140,7 +140,7 @@
{#if path && $innerComments.length > 0} {#if path && $innerComments.length > 0}
{@const pubkeys = $innerComments.map(e => e.pubkey)} {@const pubkeys = $innerComments.map(e => e.pubkey)}
{@const isOwn = pubkeys.includes($user.pubkey)} {@const isOwn = pubkeys.includes($user.pubkey)}
{@const info = displayList(pubkeys.map(pk => $profiles.display(pk).get()))} {@const info = displayList(pubkeys.map(pk => $profiles.display(pk, [url]).get()))}
{@const tooltip = `${info} commented`} {@const tooltip = `${info} commented`}
<div data-tip={tooltip} class="tip tip-right flex"> <div data-tip={tooltip} class="tip tip-right flex">
<Link <Link

View file

@ -67,7 +67,7 @@
subtitle: "Automatically add members to space", subtitle: "Automatically add members to space",
message: message:
nonSpaceMembers.length === 1 nonSpaceMembers.length === 1
? `${$profiles.display(nonSpaceMembers[0]).get()} is not a member of this space. Add them?` ? `${$profiles.display(nonSpaceMembers[0], [url]).get()} is not a member of this space. Add them?`
: `${nonSpaceMembers.length} people are not members of this space. Add them?`, : `${nonSpaceMembers.length} people are not members of this space. Add them?`,
confirm: async () => { confirm: async () => {
setKey("RoomMembersAdd.confirm", true) setKey("RoomMembersAdd.confirm", true)

View file

@ -18,7 +18,7 @@
const {url, pubkey, roles = []}: Props = $props() const {url, pubkey, roles = []}: Props = $props()
const profileDisplay = $profiles.display(pubkey).$ const profileDisplay = $profiles.display(pubkey, [url]).$
const supportedMethods = deriveSpaceSupportedMethods(url) const supportedMethods = deriveSpaceSupportedMethods(url)
const canUnallow = $derived($supportedMethods.includes("unallowpubkey")) const canUnallow = $derived($supportedMethods.includes("unallowpubkey"))
const canBan = $derived($supportedMethods.includes("banpubkey")) const canBan = $derived($supportedMethods.includes("banpubkey"))

View file

@ -34,7 +34,7 @@
const removeMember = () => const removeMember = () =>
pushModal(Confirm, { pushModal(Confirm, {
title: "Remove Member", title: "Remove Member",
message: `Remove @${$profiles.display(pubkey).get()} from the space?`, message: `Remove @${$profiles.display(pubkey, [url]).get()} from the space?`,
confirm: async () => { confirm: async () => {
const {error} = await $relayManagement.forUrl(url).unallowPubkey(pubkey) const {error} = await $relayManagement.forUrl(url).unallowPubkey(pubkey)
@ -50,7 +50,7 @@
const banMember = () => const banMember = () =>
pushModal(Confirm, { pushModal(Confirm, {
title: "Ban Member", title: "Ban Member",
message: `Ban @${$profiles.display(pubkey).get()} from the space?`, message: `Ban @${$profiles.display(pubkey, [url]).get()} from the space?`,
confirm: async () => { confirm: async () => {
const {error} = await $relayManagement.forUrl(url).banPubkey(pubkey) const {error} = await $relayManagement.forUrl(url).banPubkey(pubkey)

View file

@ -27,7 +27,7 @@
const relayRoles = $app.use(RelayRoles).forUrl(url).$ const relayRoles = $app.use(RelayRoles).forUrl(url).$
const roles = $derived(sortBy(role => [role.order(), role.label() ?? ""], $relayRoles)) const roles = $derived(sortBy(role => [role.order(), role.label() ?? ""], $relayRoles))
const profileDisplay = $profiles.display(pubkey).$ const profileDisplay = $profiles.display(pubkey, [url]).$
const memberRoles = deriveSpaceMemberRoles(url) const memberRoles = deriveSpaceMemberRoles(url)
const initial = new Set(get(memberRoles).get(pubkey) ?? []) const initial = new Set(get(memberRoles).get(pubkey) ?? [])

View file

@ -172,13 +172,13 @@
$effect(() => { $effect(() => {
for (const t of videoTiles) { for (const t of videoTiles) {
const pk = pubkeyFromLiveKitIdentity(t.liveKitIdentity) const pk = pubkeyFromLiveKitIdentity(t.liveKitIdentity)
if (pk) $profiles.load(pk) if (pk) $profiles.load(pk, [url])
} }
}) })
const labelFor = (liveKitIdentity: string, source: VideoTileData["source"]) => { const labelFor = (liveKitIdentity: string, source: VideoTileData["source"]) => {
const pk = pubkeyFromLiveKitIdentity(liveKitIdentity) const pk = pubkeyFromLiveKitIdentity(liveKitIdentity)
const name = pk ? $profiles.display(pk).get() : "Unknown" const name = pk ? $profiles.display(pk, [url]).get() : "Unknown"
return source === Track.Source.ScreenShare ? `${name} · screen` : name return source === Track.Source.ScreenShare ? `${name} · screen` : name
} }

View file

@ -68,7 +68,7 @@
$effect(() => { $effect(() => {
for (const p of $participants) { for (const p of $participants) {
if (p.pubkey) $profiles.load(p.pubkey) if (p.pubkey) $profiles.load(p.pubkey, [url])
} }
}) })
</script> </script>
@ -102,7 +102,7 @@
<ProfileCircle pubkey={p.pubkey} size={5} class="h-5 w-5" /> <ProfileCircle pubkey={p.pubkey} size={5} class="h-5 w-5" />
</div> </div>
<span class="truncate min-w-0 flex-1 text-xs opacity-70"> <span class="truncate min-w-0 flex-1 text-xs opacity-70">
{p.pubkey ? $profiles.display(p.pubkey).get() : "Unknown"} {p.pubkey ? $profiles.display(p.pubkey, [url]).get() : "Unknown"}
</span> </span>
<VoiceParticipantMediaBadges <VoiceParticipantMediaBadges
muted={media.muted} muted={media.muted}

View file

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import {removeUndefined} from "@welshman/lib"
import {displayHandle} from "@welshman/util" import {displayHandle} from "@welshman/util"
import {displayPubkey} from "@welshman/domain" import {displayPubkey} from "@welshman/domain"
import {handles, profiles} from "@app/core" import {handles, profiles} from "@app/core"
@ -13,7 +14,7 @@
const {value, url}: Props = $props() const {value, url}: Props = $props()
const pubkey = value const pubkey = value
const profileDisplay = $profiles.display(pubkey).$ const profileDisplay = $profiles.display(pubkey, removeUndefined([url])).$
const handle = $handles.forPubkey(pubkey).$ const handle = $handles.forPubkey(pubkey).$
</script> </script>

View file

@ -64,7 +64,8 @@
let term = $state("") let term = $state("")
const matchesTerm = (pubkey: string, t: string) => const matchesTerm = (pubkey: string, t: string) =>
$profiles.display(pubkey).get().toLowerCase().includes(t) || pubkey.toLowerCase().includes(t) $profiles.display(pubkey, [url]).get().toLowerCase().includes(t) ||
pubkey.toLowerCase().includes(t)
// In-place search: match by member info or by the name of any role they hold. // In-place search: match by member info or by the name of any role they hold.
const visibleMembers = $derived.by(() => { const visibleMembers = $derived.by(() => {