Coves frontend - a photon fork
1<script lang="ts">
2 // @ts-nocheck TODO(coves-migration): Needs Coves user search API
3 import { getClient } from '$lib/api/client.svelte'
4 import type { ListingType, Person } from '$lib/api/types'
5 import Avatar from '$lib/ui/generic/Avatar.svelte'
6 import { MenuButton, Search } from 'mono-svelte'
7 import { createEventDispatcher } from 'svelte'
8 import { Icon, XCircle } from 'svelte-hero-icons/dist'
9 import { fly } from 'svelte/transition'
10
11 interface Props {
12 q?: string
13 instance?: string | undefined
14 listing_type?: ListingType
15 showWhenEmpty?: boolean
16 /** @deprecated No longer functional - will filter users when Coves API provides DID */
17 hideOwnUser?: boolean
18 placeholder?: string
19 onselect?: (e?: Person) => void
20 }
21
22 let {
23 q = $bindable(''),
24 instance = undefined,
25 listing_type = 'Subscribed',
26 showWhenEmpty = false,
27 // eslint-disable-next-line @typescript-eslint/no-unused-vars
28 hideOwnUser = false,
29 ...rest
30 }: Props = $props()
31
32 const dispatcher = createEventDispatcher<{ select: Person | undefined }>()
33</script>
34
35<Search
36 search={async (q) => {
37 const users = (
38 await getClient(instance).search({
39 q: q || ' ',
40 type_: 'Users',
41 limit: 20,
42 listing_type: listing_type,
43 sort: 'TopAll',
44 })
45 ).users.map((c) => c.person)
46
47 // TODO: Filter out own user when DID comparison is available
48 return users
49 }}
50 extractName={(c) => `${c.name}@${new URL(c.actor_id).hostname}`}
51 bind:query={q}
52 {...rest}
53>
54 {#snippet noresults()}
55 <div class="w-full h-full">
56 {#if showWhenEmpty}
57 <MenuButton onclick={() => dispatcher('select', undefined)}>
58 <Icon src={XCircle} size="16" mini />
59 <div class="flex flex-col text-left">
60 <span>None</span>
61 </div>
62 </MenuButton>
63 {:else}
64 <span class="mx-auto my-auto">No results.</span>
65 {/if}
66 </div>
67 {/snippet}
68 {#snippet children({ item, select })}
69 <div in:fly|global={{ y: -4, opacity: 0 }}>
70 <MenuButton onclick={() => select(item)}>
71 <Avatar url={item.avatar} alt={item.name} width={24} />
72 <div class="flex flex-col text-left">
73 <span>{item.name}</span>
74 <span class="text-xs opacity-80">
75 {new URL(item.actor_id).hostname}
76 </span>
77 </div>
78 </MenuButton>
79 </div>
80 {/snippet}
81</Search>