OmniboxFind.svelte RawHistoryFolder
1<!--
2 Omnibox Find Component
3
4 Displays find results and match navigation
5-->
6<script lang="ts">
7 import { omniboxStore } from './stores.svelte.ts';
8 import { revealMatch } from './find';
9
10 // Reactive state
11 let matches = $derived(omniboxStore.matches);
12 let selectedIndex = $derived(omniboxStore.selectedIndex);
13 let hasContent = $state(false);
14
15 // Update hasContent when matches change
16 $effect(() => {
17 hasContent = omniboxStore.mode === 'find' && matches.length > 0;
18 });
19
20 // Computed total count
21 let totalMatches = $derived(matches.length);
22
23 // Handle match item mouse enter
24 function handleItemMouseEnter(index: number) {
25 omniboxStore.setSelectedIndex(index);
26 omniboxStore.setFaded(true);
27 scrollToSelection();
28 }
29
30 // Handle match item click
31 function handleItemClick(index: number) {
32 omniboxStore.setSelectedIndex(index);
33 revealMatch(index);
34 omniboxStore.close();
35 }
36
37 // Scroll list to show selected item
38 function scrollToSelection() {
39 const selectedItem = document.getElementById(`find-item-${selectedIndex}`);
40 if (selectedItem && selectedItem.scrollIntoView) {
41 try {
42 selectedItem.scrollIntoView({ block: 'nearest' });
43 } catch {
44 selectedItem.scrollIntoView();
45 }
46 }
47 }
48
49 // Watch for selection changes to scroll
50 $effect(() => {
51 if (selectedIndex >= 0) {
52 scrollToSelection();
53 }
54 });
55</script>
56
57<div
58 id="find-list"
59 class="mt-2 max-h-[50vh] overflow-auto border-t border-[#333]"
60 role="listbox"
61 aria-label="Find results"
62>
63 <!-- Header with match count -->
64 <div
65 class="px-2.5 py-1.5 text-xs text-[#bbb]
66 border-b border-[#2a2a2a]"
67 >
68 {#if totalMatches > 0}
69 {totalMatches} match{totalMatches === 1 ? '' : 'es'}
70 {:else}
71 No matches
72 {/if}
73 </div>
74
75 <!-- Match results -->
76 {#if hasContent}
77 {#each matches as match, index (index)}
78 {@const isSelected = index === selectedIndex}
79
80 <div
81 id="find-item-{index}"
82 class="px-2.5 py-2 cursor-pointer
83 border-b border-[#2a2a2a] last:border-b-0
84 {isSelected ? 'bg-[#0a0a0a]' : ''}"
85 role="option"
86 tabindex="-1"
87 aria-selected={isSelected}
88 onmouseenter={() => handleItemMouseEnter(index)}
89 onclick={() => handleItemClick(index)}
90 onkeydown={(e) => e.key === 'Enter' && handleItemClick(index)}
91 >
92 <!-- Match context -->
93 <div
94 class="text-[#ddd] text-sm
95 whitespace-nowrap overflow-hidden text-ellipsis"
96 >
97 {match.context || ''}
98 </div>
99 </div>
100 {/each}
101 {/if}
102</div>
103