autocomplete styling

This commit is contained in:
2023-05-04 23:48:39 +02:00
parent e606296585
commit 38a6255e77
6 changed files with 84 additions and 28 deletions

View File

@@ -0,0 +1,76 @@
<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import SearchResult from '@/components/Search/SearchResult.vue'
import { notes, findNotes, activeNote } from '@/composables/useNotes'
const active = ref(false)
watch(active, () => {
if (!active.value) {
query.value = ''
activeResult.value = undefined
}
})
const query = ref('')
const results = computed<Note[]>(() => {
return query.value ? findNotes(query.value) : notes.value
})
const goToNote = (note: Note) => {
activeNote.value = note
active.value = false
if (queryElem.value) queryElem.value.blur()
}
const queryElem = ref<HTMLInputElement | null>(null)
const activeResult = ref<Note>()
const handleKeydown = (event: KeyboardEvent) => {
const code = event.code
if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code)) {
let index = results.value.findIndex((note) => note.id === activeResult.value?.id)
if (['ArrowDown', 'Tab'].includes(code)) {
index++
} else if (['ArrowUp'].includes(code)) {
index--
}
if (index + 1 > results.value.length) index = index - results.value.length
if (index < 0) index = results.value.length - 1
activeResult.value = results.value[index]
} else if (code === 'Enter' && activeResult.value) {
goToNote(activeResult.value)
} else if (code === 'Escape' && queryElem.value) {
queryElem.value.blur()
}
}
</script>
<template>
<div id="search-container" class="relative h-full flex-1">
<input
type="text"
placeholder="Search for notes"
class="h-full w-full rounded border-0 bg-[#355fd3] px-2 text-white outline-none placeholder:text-white focus:bg-white focus:text-black"
@focus="active = true"
@mousedown="active = true"
@blur="active = false"
v-model="query"
ref="queryElem"
@keydown="handleKeydown"
/>
<div class="z-1000 dropdown absolute left-0 right-0 top-[100%]" v-if="active">
<ul
tabindex="0"
class="menu mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow"
>
<SearchResult
v-for="result in results"
v-if="results.length > 0"
:result="result"
:active-result="activeResult"
@go-to-note="() => goToNote(result)"
/>
<li v-else><a>No notes found</a></li>
</ul>
</div>
</div>
</template>

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
import { activeNote } from '@/composables/useNotes'
import { formatDate } from '@/utils/helpers'
const props = defineProps<{
result: Note
activeResult?: Note
}>()
const emit = defineEmits<{
(e: 'goToNote'): void
}>()
</script>
<template>
<li class="flex flex-row">
<a
class="flex-1 items-center px-2 py-1"
@click.stop.prevent="() => emit('goToNote')"
@mousedown.prevent
:class="{
disabled: activeNote?.id === result.id,
active: props.activeResult?.id === result.id,
}"
>
<span
class="badge-ghost badge badge-sm mr-0.5"
v-if="activeNote?.id === result.id"
>
current
</span>
<span class="flex-1">{{ result.title }}</span>
<span>{{ formatDate(result.modified) }}</span>
</a>
</li>
</template>