Coves frontend - a photon fork
at main 98 lines 2.5 kB view raw
1<script lang="ts"> 2 import { coves } from '$lib/api/client.svelte' 3 import type { CommunityView } from '$lib/api/coves/types' 4 import { MenuButton, Search, toast } from 'mono-svelte' 5 import { Icon, XCircle } from 'svelte-hero-icons/dist' 6 import { fly } from 'svelte/transition' 7 import Avatar from '../generic/Avatar.svelte' 8 9 interface Props { 10 q?: string 11 showWhenEmpty?: boolean 12 placeholder?: string 13 onselect?: (item: CommunityView | undefined) => void 14 label?: string 15 required?: boolean 16 } 17 18 let { 19 q = $bindable(''), 20 showWhenEmpty = false, 21 required, 22 onselect, 23 ...rest 24 }: Props = $props() 25 26 let searchError = $state(false) 27</script> 28 29<Search 30 search={async (q) => { 31 searchError = false 32 try { 33 const api = coves() 34 35 if (q.trim()) { 36 const results = await api.searchCommunities({ 37 query: q, 38 limit: 20, 39 }) 40 return results.communities 41 } else { 42 const results = await api.listCommunities({ 43 limit: 20, 44 }) 45 return results.communities 46 } 47 } catch (err) { 48 console.error('[ObjectAutocomplete] search failed:', err) 49 searchError = true 50 toast({ 51 content: 'Failed to search communities', 52 type: 'error', 53 }) 54 return [] 55 } 56 }} 57 extractName={(c) => c.name} 58 bind:query={q} 59 {required} 60 {...rest} 61> 62 {#snippet noresults()} 63 <div class="w-full h-full"> 64 {#if q == '' && showWhenEmpty} 65 <MenuButton onclick={() => onselect?.(undefined)}> 66 <Icon src={XCircle} size="16" mini /> 67 <div class="flex flex-col text-left"> 68 <span>None</span> 69 </div> 70 </MenuButton> 71 {:else if searchError} 72 <span class="mx-auto my-auto text-red-500 dark:text-red-400"> 73 Search failed. 74 </span> 75 {:else} 76 <span class="mx-auto my-auto">No results.</span> 77 {/if} 78 </div> 79 {/snippet} 80 {#snippet children({ item, select })} 81 <div in:fly|global={{ y: -4, opacity: 0 }}> 82 <MenuButton 83 onclick={() => { 84 select(item) 85 onselect?.(item) 86 }} 87 > 88 <Avatar url={item.avatar} alt={item.name} width={24} /> 89 <div class="flex flex-col text-left"> 90 <span>{item.displayName ?? item.name}</span> 91 <span class="text-xs opacity-80"> 92 {item.handle ?? item.did} 93 </span> 94 </div> 95 </MenuButton> 96 </div> 97 {/snippet} 98</Search>