moved many compoents to composition API

This commit is contained in:
vabene1111
2024-04-21 15:58:31 +02:00
parent ce6c43fb62
commit e040a10096
13 changed files with 342 additions and 347 deletions

View File

@@ -15,7 +15,7 @@
<v-card-text class="pb-0">
<v-text-field
id="id_global_search_input"
v-model="search_query"
v-model="searchQuery"
autocomplete="off"
clearable
placeholder="Search"
@@ -27,7 +27,7 @@
<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 :variant="cardVariant(index)" v-for="(item, index) in searchResults" hover class="mt-1" @click="selectedResult = index" :key="index">
<v-card-title @click="goToSelectedRecipe()">
<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>
@@ -56,124 +56,120 @@
</v-dialog>
</template>
<script lang="ts">
<script setup lang="ts">
import {defineComponent} from 'vue'
import {computed, defineComponent, onMounted, ref, watch} from 'vue'
import {SearchResult} from "@/types/SearchTypes";
import {ApiApi, Recipe, RecipeFlat} from "@/openapi";
import {useRouter} from "vue-router";
export default defineComponent({
name: "GlobalSearchDialog",
props: {},
watch: {
dialog: function (newValue) {
/**
* since dialog has no opened event watch the variable and focus input after delay (nextTick/directly does not work)
*/
this.search_query = ""
setTimeout(() => {
if (newValue) {
let search = document.getElementById('id_global_search_input')
if (search != null) {
search.focus()
}
}
}, 20)
},
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) {
this.selected_result = this.search_results.length - 1
}
},
},
data() {
return {
dialog: false,
recipes: [] as Recipe[],
flat_recipes: [] as RecipeFlat[],
search_query: null as string|null,
selected_result: 0,
}
},
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 () {
let search_results = [] as Array<SearchResult>
const router = useRouter()
if (this.search_query != '' && this.search_query != null) {
search_results.push({name: this.search_query, icon: 'fas fa-search', suffix: 'Advanced Search'} as SearchResult)
const dialog = ref(false)
const recipes = ref([] as Recipe[])
const flatRecipes = ref([] as RecipeFlat[])
const searchQuery = ref(null as string | null)
const selectedResult = ref(0)
this.flat_recipes.filter(fr => fr.name.toLowerCase().includes(this.search_query.toLowerCase())).slice(0, 10).forEach(r => {
search_results.push({name: r.name, image: r.image, recipe_id: r.id} as SearchResult)
})
} else {
// search_results.push({name: 'Recent 1', icon: 'fas fa-history',} as SearchResult)
// search_results.push({name: 'Recent 2', icon: 'fas fa-history',} as SearchResult)
// search_results.push({name: 'Recent 3', icon: 'fas fa-history',} as SearchResult)
/**
* build array of search results
* uses custom type to be able to incorporate recent items, plans, books, ... at a later stage
*/
const searchResults = computed(() => {
let search_results = [] as Array<SearchResult>
this.flat_recipes.slice(0, 5).forEach(r => {
search_results.push({name: r.name, image: r.image, recipe_id: r.id} as SearchResult)
})
}
if (searchQuery.value != '' && searchQuery.value != null) {
search_results.push({name: searchQuery.value, icon: 'fas fa-search', suffix: 'Advanced Search'} as SearchResult)
return search_results
}
},
mounted() {
// add keyhandlers
window.addEventListener('keydown', (e) => {
if (this.dialog) {
if (e.key == 'ArrowUp') {
this.selected_result = Math.max(0, this.selected_result - 1)
}
if (e.key == 'ArrowDown') {
this.selected_result = Math.min(this.search_results.length, this.selected_result + 1)
}
if (e.key == 'Enter') {
this.goToSelectedRecipe()
}
if (e.key == 'k' && e.ctrlKey) {
this.dialog = true
e.preventDefault()
}
}
flatRecipes.value.filter(fr => fr.name.toLowerCase().includes(searchQuery.value.toLowerCase())).slice(0, 10).forEach(r => {
search_results.push({name: r.name, image: r.image, recipe_id: r.id} as SearchResult)
})
} else {
// search_results.push({name: 'Recent 1', icon: 'fas fa-history',} as SearchResult)
// search_results.push({name: 'Recent 2', icon: 'fas fa-history',} as SearchResult)
// search_results.push({name: 'Recent 3', icon: 'fas fa-history',} as SearchResult)
const api = new ApiApi()
api.apiRecipeFlatList().then(r => {
this.flat_recipes = r
flatRecipes.value.slice(0, 5).forEach(r => {
search_results.push({name: r.name, image: r.image, recipe_id: r.id} as SearchResult)
})
},
methods: {
/**
* determines the style for selected elements
* @param index index of card to determine style for
*/
cardVariant(index: number) {
if (this.selected_result == index) {
return 'tonal'
} else {
return 'elevated'
}
},
/**
* open selected recipe
*/
goToSelectedRecipe() {
this.dialog = false
let searchResult = this.search_results[this.selected_result]
if (searchResult.recipe_id != null) {
this.$router.push({name: 'view_recipe', params: {'id': searchResult.recipe_id}})
}
}
},
}
return search_results
})
watch(dialog, (newValue) => {
/**
* since dialog has no opened event watch the variable and focus input after delay (nextTick/directly does not work)
*/
searchQuery.value = ""
setTimeout(() => {
if (newValue) {
let search = document.getElementById('id_global_search_input')
if (search != null) {
search.focus()
}
}
}, 20)
})
watch(searchQuery, () => {
/**
* update selected result if search result length changes due to search_query changes
*/
if (selectedResult.value >= searchResults.value.length) {
selectedResult.value = searchResults.value.length - 1
}
})
onMounted(() => {
window.addEventListener('keydown', (e) => {
if (dialog.value) {
if (e.key == 'ArrowUp') {
selectedResult.value = Math.max(0, selectedResult.value - 1)
}
if (e.key == 'ArrowDown') {
selectedResult.value = Math.min(searchResults.value.length, selectedResult.value + 1)
}
if (e.key == 'Enter') {
goToSelectedRecipe()
}
} else {
if (e.key == 'k' && e.ctrlKey) {
e.preventDefault();
dialog.value = true
}
}
})
const api = new ApiApi()
api.apiRecipeFlatList().then(r => {
flatRecipes.value = r
})
})
/**
* determines the style for selected elements
* @param index index of card to determine style for
*/
function cardVariant(index: number) {
if (selectedResult.value == index) {
return 'tonal'
} else {
return 'elevated'
}
}
/**
* open selected recipe
*/
function goToSelectedRecipe() {
dialog.value = false
let searchResult = searchResults.value[selectedResult.value]
if (searchResult.recipe_id != null) {
router.push({name: 'view_recipe', params: {'id': searchResult.recipe_id}})
}
}
</script>

View File

@@ -11,7 +11,7 @@
<v-card-text>
<v-number-input v-model="mutable_number" @update:modelValue="updateNumber('set')" control-variant="split" :min="0" >
<v-number-input v-model="mutable_number" @update:modelValue="updateNumber('set')" control-variant="split" :min="0" >
</v-number-input>
<v-btn-group divided class="d-flex">
@@ -53,7 +53,8 @@ export default defineComponent({
data() {
return {
dialog: false,
mutable_number: 0
mutable_number: 0,
someNumber: 12
}
},
watch: {
@@ -82,7 +83,7 @@ export default defineComponent({
if (operation === 'sub') {
this.mutable_number = this.number - 1
}
console.log(operation, this.mutable_number)
this.$emit('change', {number: this.mutable_number})
}
},