an atproto based link aggregator
1<script lang="ts">
2 import { goto } from '$app/navigation';
3
4 interface Props {
5 compact?: boolean;
6 }
7
8 let { compact = false }: Props = $props();
9
10 let query = $state('');
11 let inputEl: HTMLInputElement;
12
13 function handleSubmit(e: Event) {
14 e.preventDefault();
15 if (query.trim().length >= 2) {
16 goto(`/search?q=${encodeURIComponent(query.trim())}`);
17 query = '';
18 inputEl?.blur();
19 }
20 }
21
22 function handleKeydown(e: KeyboardEvent) {
23 // Allow Escape to blur
24 if (e.key === 'Escape') {
25 query = '';
26 inputEl?.blur();
27 }
28 }
29</script>
30
31<form onsubmit={handleSubmit} class="relative">
32 <input
33 bind:this={inputEl}
34 bind:value={query}
35 onkeydown={handleKeydown}
36 type="search"
37 placeholder={compact ? 'Search...' : 'Search posts...'}
38 class="w-full pl-8 pr-3 py-1.5 text-sm rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent {compact
39 ? 'w-32 focus:w-48 transition-all'
40 : ''}"
41 />
42 <svg
43 class="absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 dark:text-gray-500"
44 fill="none"
45 stroke="currentColor"
46 viewBox="0 0 24 24"
47 >
48 <path
49 stroke-linecap="round"
50 stroke-linejoin="round"
51 stroke-width="2"
52 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
53 />
54 </svg>
55</form>