feat: use NIP-50 relay-side search with scope selection #114

Merged
hodlbod merged 4 commits from :dev into dev 2026-04-02 18:49:18 +00:00
Showing only changes of commit 63b1cd125e - Show all commits
+7 -33
View File
@@ -20,22 +20,15 @@
const {url, h}: Props = $props()
type SearchScope = "room" | "space"
const scopes: SearchScope[] = h ? ["room", "space"] : ["space"]
let term = $state("")
let show = $state(false)
hodlbod marked this conversation as resolved Outdated
Outdated
Review

Let's just stick to room/space, it probably doesn't make sense to add the everything category until we've integrated social media features (and it should probably go on the global search page).

Let's just stick to room/space, it probably doesn't make sense to add the everything category until we've integrated social media features (and it should probably go on the global search page).
Outdated
Review

Sure. I've removed the everything scope and kept the search UI limited to room and space only.

Sure. I've removed the `everything` scope and kept the search UI limited to room and space only.
let scope = $state<SearchScope>(h ? "room" : "space")
let results = $state<TrustedEvent[]>([])
let loading = $state(false)
let input: HTMLInputElement | undefined = $state()
let controller: AbortController | undefined
const relayStatus = $derived(
scope === "room"
? `Using space relay: ${url} (room filter applied).`
: `Using space relay: ${url}.`,
h ? `Searching this room on relay: ${url}.` : `Searching this space on relay: ${url}.`,
)
const open = () => {
2
@@ -58,13 +51,10 @@
const getRelayUrls = () => [url]
const getFilter = (searchTerm: string): Filter => {
if (scope === "room" && h) {
return {kinds: CONTENT_KINDS, "#h": [h], search: searchTerm}
}
return {kinds: CONTENT_KINDS, search: searchTerm}
}
const getFilter = (searchTerm: string): Filter =>
h
? {kinds: CONTENT_KINDS, "#h": [h], search: searchTerm}
: {kinds: CONTENT_KINDS, search: searchTerm}
const search = debounce(300, async (searchTerm: string) => {
controller?.abort()
2
@@ -100,11 +90,6 @@
void search(term)
}
const setScope = (value: SearchScope) => {
scope = value
void search(term)
}
const eventsByAge = $derived(groupBy(e => getAgeSection(e.created_at), results))
const getAgeSection = (createdAt: number) => {
2
@@ -168,25 +153,14 @@
bind:value={term}
class="min-w-0 grow"
type="text"
placeholder={scope === "room" ? "Search this room..." : "Search this space..."}
placeholder={h ? "Search this room..." : "Search this space..."}
oninput={onInput} />
</label>
<div class="flex flex-wrap gap-1">
{#each scopes as value (value)}
<Button
class={value === scope ? "btn btn-neutral btn-xs" : "btn btn-ghost btn-xs"}
onclick={() => setScope(value)}>
{value === "room" ? "Room" : "Space"}
</Button>
{/each}
</div>
<div class="max-h-[65vh] overflow-y-auto">
<p class="mb-2 text-xs opacity-70">{relayStatus}</p>
{#if !term}
<p class="text-sm opacity-70">
{scope === "room"
? "Search for content in this room."
: "Search for content in this space."}
{h ? "Search for content in this room." : "Search for content in this space."}
</p>
{:else if loading}
<p class="text-sm opacity-70">Searching...</p>