mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 12:18:45 -05:00
improved global search dialog
This commit is contained in:
@@ -1,12 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<slot name="activator">
|
<slot name="activator">
|
||||||
<v-btn @click="dialog = true"><i class="fas fa-search mr-1"></i> Search</v-btn>
|
<v-btn @click="dialog = true" variant="plain" density="default">
|
||||||
|
<i class="fas fa-search mr-1"></i>
|
||||||
|
<span class="d-none d-sm-block">Search</span>
|
||||||
|
<v-chip size="x-small" variant="tonal" class="d-none d-md-flex ml-1" label>Ctrl+K</v-chip>
|
||||||
|
</v-btn>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<v-dialog width="90%" max-width="800px" v-model="dialog" location="id_dialog_anchor"
|
<v-dialog width="90%" max-width="800px" v-model="dialog" location="id_dialog_anchor"
|
||||||
location-strategy="connected">
|
location-strategy="connected">
|
||||||
|
|
||||||
<v-card>
|
<v-card>
|
||||||
|
<!-- search input -->
|
||||||
<v-card-text class="pb-0">
|
<v-card-text class="pb-0">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
id="id_global_search_input"
|
id="id_global_search_input"
|
||||||
@@ -18,17 +23,33 @@
|
|||||||
variant="solo"
|
variant="solo"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-divider></v-divider>
|
|
||||||
<v-card-text>
|
|
||||||
|
|
||||||
<v-card :variant="cardVariant(index)" v-for="(item, index) in search_results" hover class="mt-1" @click="selected_result = index">
|
<v-divider></v-divider>
|
||||||
|
<!-- search results -->
|
||||||
|
<v-card-text>
|
||||||
|
<v-card :variant="cardVariant(index)" v-for="(item, index) in search_results" hover class="mt-1" @click="selected_result = index" :key="index">
|
||||||
<v-card-title @click="goToSelectedRecipe()">
|
<v-card-title @click="goToSelectedRecipe()">
|
||||||
<v-avatar v-if="item.image" :image="item.image"></v-avatar>
|
<v-avatar v-if="item.image" :image="item.image"></v-avatar>
|
||||||
|
<v-avatar v-else-if="item.recipe_id !== undefined" color="tandoor">{{ item.name.charAt(0) }}</v-avatar>
|
||||||
<v-icon :icon="item.icon" v-if="item.icon"></v-icon>
|
<v-icon :icon="item.icon" v-if="item.icon"></v-icon>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-divider class="d-none d-sm-block"></v-divider>
|
||||||
|
<!-- keybind info shown on screens at least sm -->
|
||||||
|
<v-card-text class="d-none d-sm-block pt-2">
|
||||||
|
<v-chip size="x-small" class="mr-1" label><i class="fas fa-arrow-up"></i></v-chip>
|
||||||
|
<v-chip size="x-small" class="mr-1" label><i class="fas fa-arrow-down"></i></v-chip>
|
||||||
|
<small class="mr-2">to navigate</small>
|
||||||
|
<v-chip size="x-small" class="mr-1" label><i class="fas fa-level-down-alt fa-rotate-90"></i></v-chip>
|
||||||
|
<small class="mr-2">to select</small>
|
||||||
|
<v-chip size="x-small" class="mr-1" label> esc</v-chip>
|
||||||
|
<small>to close</small>
|
||||||
|
|
||||||
|
|
||||||
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
|
||||||
@@ -49,6 +70,7 @@ export default defineComponent({
|
|||||||
/**
|
/**
|
||||||
* since dialog has no opened event watch the variable and focus input after delay (nextTick/directly does not work)
|
* since dialog has no opened event watch the variable and focus input after delay (nextTick/directly does not work)
|
||||||
*/
|
*/
|
||||||
|
this.search_query = ""
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
let search = document.getElementById('id_global_search_input')
|
let search = document.getElementById('id_global_search_input')
|
||||||
@@ -59,6 +81,9 @@ export default defineComponent({
|
|||||||
}, 20)
|
}, 20)
|
||||||
},
|
},
|
||||||
search_query: function (newValue) {
|
search_query: function (newValue) {
|
||||||
|
/**
|
||||||
|
* update selected result if search result length changes due to search_query changes
|
||||||
|
*/
|
||||||
if (this.selected_result >= this.search_results.length) {
|
if (this.selected_result >= this.search_results.length) {
|
||||||
this.selected_result = this.search_results.length - 1
|
this.selected_result = this.search_results.length - 1
|
||||||
}
|
}
|
||||||
@@ -74,6 +99,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
/**
|
||||||
|
* build array of search results
|
||||||
|
* uses custom type to be able to incorporate recent items, plans, books, ... at a later stage
|
||||||
|
*/
|
||||||
search_results: function () {
|
search_results: function () {
|
||||||
let search_results = [] as Array<SearchResult>
|
let search_results = [] as Array<SearchResult>
|
||||||
|
|
||||||
@@ -97,6 +126,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
// add keyhandlers
|
||||||
window.addEventListener('keydown', (e) => {
|
window.addEventListener('keydown', (e) => {
|
||||||
if (e.key == 'ArrowUp') {
|
if (e.key == 'ArrowUp') {
|
||||||
this.selected_result = Math.max(0, this.selected_result - 1)
|
this.selected_result = Math.max(0, this.selected_result - 1)
|
||||||
@@ -107,6 +137,10 @@ export default defineComponent({
|
|||||||
if (e.key == 'Enter') {
|
if (e.key == 'Enter') {
|
||||||
this.goToSelectedRecipe()
|
this.goToSelectedRecipe()
|
||||||
}
|
}
|
||||||
|
if (e.key == 'k' && e.ctrlKey) {
|
||||||
|
this.dialog = true
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const api = new ApiApi()
|
const api = new ApiApi()
|
||||||
@@ -115,6 +149,10 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* determines the style for selected elements
|
||||||
|
* @param index index of card to determine style for
|
||||||
|
*/
|
||||||
cardVariant(index: number) {
|
cardVariant(index: number) {
|
||||||
if (this.selected_result == index) {
|
if (this.selected_result == index) {
|
||||||
return 'tonal'
|
return 'tonal'
|
||||||
@@ -122,6 +160,9 @@ export default defineComponent({
|
|||||||
return 'elevated'
|
return 'elevated'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* open selected recipe
|
||||||
|
*/
|
||||||
goToSelectedRecipe() {
|
goToSelectedRecipe() {
|
||||||
this.dialog = false
|
this.dialog = false
|
||||||
let searchResult = this.search_results[this.selected_result]
|
let searchResult = this.search_results[this.selected_result]
|
||||||
|
|||||||
Reference in New Issue
Block a user