Quick Actions & global search #528

Merged
konrad merged 17 commits from feature/quick-action into main 2021-05-30 18:30:08 +00:00
3 changed files with 60 additions and 33 deletions
Showing only changes of commit 98744936aa - Show all commits

View File

@ -34,7 +34,7 @@
</div>
<transition name="fade">
<div class="search-results" v-if="searchResultsVisible">
<div class="search-results" :class="{'search-results-inline': inline}" v-if="searchResultsVisible">
<button
v-if="creatableAvailable"
class="is-fullwidth"
@ -166,6 +166,27 @@ export default {
return false
},
},
// If true, displays the search results inline instead of using a dropdown.
inline: {
type: Boolean,
default() {
return false
},
},
// If true, shows search results when no query is specified.
showEmpty: {
type: Boolean,
default() {
return true
},
},
// The delay in ms after which the search event will be fired. Used to avoid hitting the network on every keystroke.
searchDelay: {
type: Number,
default() {
return 200
},
},
},
mounted() {
document.addEventListener('click', this.hideSearchResultsHandler)
@ -181,10 +202,14 @@ export default {
},
computed: {
searchResultsVisible() {
if(this.query === '' && !this.showEmpty) {
return false
}
return this.showSearchResults && (
(this.filteredSearchResults.length > 0) ||
(this.creatable && this.query !== '')
)
(this.filteredSearchResults.length > 0) ||
(this.creatable && this.query !== '')
)
},
creatableAvailable() {
return this.creatable && this.query !== '' && !this.filteredSearchResults.some(elem => {
@ -211,7 +236,7 @@ export default {
// Updating the query with a binding does not work on mobile for some reason,
// getting the value manual does.
this.query = this.$refs.searchInput.value
if (this.searchTimeout !== null) {
clearTimeout(this.searchTimeout)
this.searchTimeout = null
@ -225,7 +250,7 @@ export default {
this.localLoading = false
}, 100) // The duration of the loading timeout of the services
this.showSearchResults = true
}, 200)
}, this.searchDelay)
},
hideSearchResultsHandler(e) {
closeWhenClickedOutside(e, this.$refs.multiselectRoot, this.closeSearchResults)

View File

@ -1,53 +1,51 @@
<template>
<modal v-if="active">
<div class="card p-4">
<input
type="text"
class="input"
<multiselect
placeholder="What do you want to do?"
v-focus
@keyup="run"
v-model="search"/>
<div v-if="search !== ''">
<ul>
<li v-for="l in lists" :key="l.id">{{ l.title }}</li>
</ul>
<nothing v-if="nothing">
No results found.
</nothing>
</div>
:search-results="results"
label="title"
@search="search"
:inline="true"
:show-empty="false"
@select="select"
:search-delay="0"
/>
</div>
</modal>
</template>
<script>
import Multiselect from '@/components/input/multiselect'
import Nothing from '@/components/misc/nothing'
export default {
name: 'quick-actions',
components: {Nothing},
components: {
Multiselect,
},
data() {
return {
search: '',
results: [],
query: '',
}
},
computed: {
active: () => true, // TODO: use state + keyboard shortcut
lists() {
return Object.fromEntries(Object.entries(this.$store.state.lists).filter(l => {
return l[1].title.toLowerCase().includes(this.search.toLowerCase())
}))
results() {
return Object.values(this.$store.state.lists).filter(l => {
return l.title.toLowerCase().includes(this.query.toLowerCase())
}) ?? []
},
nothing() {
return this.search === '' || Object.keys(this.lists).length === 0
return this.search === '' || Object.keys(this.results).length === 0
},
},
methods: {
run() {
console.log('run', this.search)
}
search(query) {
this.query = query
},
select(e) {
console.log('select', e)
},
},
}
</script>

View File

@ -72,6 +72,10 @@
max-width: 100%;
min-width: 100%;
&-inline {
position: static;
}
button {
background: transparent;
display: block;