feat: implement autocomplete functionality for park search with keyboard navigation

This commit is contained in:
pacnpal
2025-02-26 13:00:42 -05:00
parent 82d99a8161
commit 1a88c35fa8
8 changed files with 443 additions and 342 deletions

View File

@@ -0,0 +1,104 @@
<div
x-data="{
open: false,
selected: null,
selectedIndex: -1,
init() {
this.$watch('open', value => {
if (value === false) {
this.selectedIndex = -1;
}
});
this.$watch('selectedIndex', value => {
if (!this.open) {
return;
}
if (value === -1) {
this.selected = null;
return;
}
this.selected = this.$refs.results.children[value];
});
},
onKeyDown($event) {
if (!this.open) {
return;
}
switch ($event.key) {
case 'ArrowDown':
$event.preventDefault();
if (this.selectedIndex === -1) {
this.selectedIndex = 0;
return;
}
if (this.selectedIndex === this.$refs.results.children.length - 1) {
return;
}
this.selectedIndex++;
break;
case 'ArrowUp':
$event.preventDefault();
if (this.selectedIndex === -1 || this.selectedIndex === 0) {
return;
}
this.selectedIndex--;
break;
case 'Enter':
$event.preventDefault();
if (this.selectedIndex === -1) {
return;
}
this.selected = this.$refs.results.children[this.selectedIndex];
window.location.href = this.selected.dataset.url;
break;
case 'Escape':
this.open = false;
break;
}
}
}"
class="relative"
@click.away="open = false"
>
<input
type="text"
wire:model.live.debounce.300ms="query"
@focus="open = true"
@keydown="onKeyDown($event)"
placeholder="Search..."
class="w-full px-4 py-2 border rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-800 dark:border-gray-700 dark:text-white"
>
<div
x-show="open"
x-ref="results"
class="absolute z-50 w-full mt-1 bg-white rounded-md shadow-lg dark:bg-gray-800"
x-cloak
>
@if(count($suggestions) > 0)
@foreach($suggestions as $suggestion)
<a
href="{{ $suggestion['url'] }}"
class="block px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-gray-200"
:class="{ 'bg-gray-100 dark:bg-gray-700': selectedIndex === {{ $loop->index }} }"
data-url="{{ $suggestion['url'] }}"
wire:key="{{ $suggestion['id'] }}"
>
{{ $suggestion['text'] }}
</a>
@endforeach
@else
@if(strlen($query) >= 2)
<div class="px-4 py-2 text-sm text-gray-500 dark:text-gray-400">
No results found
</div>
@endif
@endif
</div>
</div>