2022-04-29 18:30:24 +05:30
|
|
|
<script setup>
|
|
|
|
const keys = useKeys();
|
|
|
|
</script>
|
2019-08-01 17:22:58 +05:30
|
|
|
<template>
|
2019-10-04 23:51:26 +05:30
|
|
|
<div v-on-outside-click="clearInput" class="relative">
|
2019-11-20 01:59:44 +05:30
|
|
|
<Dropdown :items="suggestions" class="text-sm h-full">
|
|
|
|
<template
|
|
|
|
v-slot="{
|
|
|
|
toggleDropdown,
|
|
|
|
highlightItemUp,
|
|
|
|
highlightItemDown,
|
2022-02-10 17:27:31 +05:30
|
|
|
selectHighlightedItem,
|
2019-11-20 01:59:44 +05:30
|
|
|
}"
|
2019-08-01 17:22:58 +05:30
|
|
|
>
|
2019-11-20 01:59:44 +05:30
|
|
|
<div
|
2019-12-11 15:08:20 +05:30
|
|
|
class="rounded-md relative flex items-center overflow-hidden h-full"
|
2019-11-20 01:59:44 +05:30
|
|
|
>
|
|
|
|
<div class="absolute flex justify-center w-8">
|
2022-04-29 18:30:24 +05:30
|
|
|
<feather-icon name="search" class="w-3 h-3 text-gray-800" />
|
2019-11-20 01:59:44 +05:30
|
|
|
</div>
|
|
|
|
<input
|
|
|
|
type="search"
|
2022-04-29 18:30:24 +05:30
|
|
|
class="
|
|
|
|
bg-gray-100
|
|
|
|
text-sm
|
|
|
|
pl-7
|
|
|
|
focus:outline-none
|
|
|
|
h-full
|
|
|
|
w-56
|
|
|
|
placeholder-gray-800
|
|
|
|
"
|
2022-03-30 16:27:45 +05:30
|
|
|
:placeholder="t`Search...`"
|
2019-11-20 01:59:44 +05:30
|
|
|
autocomplete="off"
|
|
|
|
spellcheck="false"
|
|
|
|
v-model="inputValue"
|
2022-04-29 18:30:24 +05:30
|
|
|
@focus="
|
2022-02-11 11:25:07 +05:30
|
|
|
() => {
|
|
|
|
search();
|
|
|
|
toggleDropdown(true);
|
|
|
|
}
|
|
|
|
"
|
2022-04-29 18:30:24 +05:30
|
|
|
@input="search"
|
2019-11-20 01:59:44 +05:30
|
|
|
ref="input"
|
|
|
|
@keydown.up="highlightItemUp"
|
|
|
|
@keydown.down="highlightItemDown"
|
|
|
|
@keydown.enter="selectHighlightedItem"
|
|
|
|
@keydown.tab="toggleDropdown(false)"
|
|
|
|
@keydown.esc="toggleDropdown(false)"
|
|
|
|
/>
|
2022-04-29 18:30:24 +05:30
|
|
|
<div
|
|
|
|
v-if="!inputValue"
|
|
|
|
class="absolute justify-center right-1.5 text-gray-500 px-1.5"
|
|
|
|
>
|
|
|
|
{{ platform === 'Mac' ? '⌘ K' : 'Ctrl K' }}
|
|
|
|
</div>
|
2019-11-20 01:59:44 +05:30
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</Dropdown>
|
2019-08-01 17:22:58 +05:30
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<script>
|
2022-04-21 18:38:36 +05:30
|
|
|
import { t } from 'fyo';
|
2022-04-20 12:08:47 +05:30
|
|
|
import Dropdown from 'src/components/Dropdown';
|
2022-04-29 18:30:24 +05:30
|
|
|
import { getSearchList } from 'src/utils/search';
|
2022-04-23 14:53:44 +05:30
|
|
|
import { routeTo } from 'src/utils/ui';
|
2022-04-29 18:30:24 +05:30
|
|
|
import { useKeys } from 'src/utils/vueUtils';
|
|
|
|
import { watch } from 'vue';
|
2022-04-21 18:38:36 +05:30
|
|
|
|
2019-08-01 17:22:58 +05:30
|
|
|
export default {
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
inputValue: '',
|
2019-11-20 01:59:44 +05:30
|
|
|
searchList: [],
|
|
|
|
suggestions: [],
|
2019-08-01 17:22:58 +05:30
|
|
|
};
|
|
|
|
},
|
|
|
|
components: {
|
2022-02-10 17:27:31 +05:30
|
|
|
Dropdown,
|
2019-11-20 01:59:44 +05:30
|
|
|
},
|
2022-02-10 17:27:31 +05:30
|
|
|
emits: ['change'],
|
2019-11-20 01:59:44 +05:30
|
|
|
mounted() {
|
|
|
|
this.makeSearchList();
|
2022-04-29 18:30:24 +05:30
|
|
|
watch(this.keys, (keys) => {
|
|
|
|
if (
|
|
|
|
keys.size === 2 &&
|
|
|
|
keys.has('KeyK') &&
|
|
|
|
(keys.has('MetaLeft') || keys.has('ControlLeft'))
|
|
|
|
) {
|
|
|
|
this.$refs.input.focus();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keys.size === 1 && keys.has('Escape')) {
|
|
|
|
this.$refs.input.blur();
|
|
|
|
}
|
|
|
|
});
|
2019-08-01 17:22:58 +05:30
|
|
|
},
|
|
|
|
methods: {
|
2019-11-20 01:59:44 +05:30
|
|
|
async search() {
|
2022-02-10 17:27:31 +05:30
|
|
|
this.suggestions = this.searchList.filter((d) => {
|
2019-11-20 01:59:44 +05:30
|
|
|
let key = this.inputValue.toLowerCase();
|
|
|
|
return d.label.toLowerCase().includes(key);
|
2019-08-01 17:22:58 +05:30
|
|
|
});
|
2019-11-20 01:59:44 +05:30
|
|
|
|
|
|
|
if (this.suggestions.length === 0) {
|
2022-02-16 11:49:16 +05:30
|
|
|
this.suggestions = [{ label: t`No results found.` }];
|
2019-11-20 01:59:44 +05:30
|
|
|
}
|
2019-08-01 17:22:58 +05:30
|
|
|
},
|
2019-12-16 17:04:22 +05:30
|
|
|
clearInput() {
|
2019-08-01 17:22:58 +05:30
|
|
|
this.inputValue = '';
|
|
|
|
this.$emit('change', null);
|
|
|
|
},
|
2021-11-04 16:01:26 +05:30
|
|
|
async makeSearchList() {
|
2022-04-29 18:30:24 +05:30
|
|
|
const searchList = getSearchList();
|
2022-02-10 17:27:31 +05:30
|
|
|
this.searchList = searchList.map((d) => {
|
2022-04-29 18:30:24 +05:30
|
|
|
if (d.route && !d.action) {
|
|
|
|
d.action = () => {
|
|
|
|
routeTo(d.route);
|
|
|
|
this.inputValue = '';
|
|
|
|
};
|
2019-08-01 17:22:58 +05:30
|
|
|
}
|
2019-11-20 01:59:44 +05:30
|
|
|
return d;
|
|
|
|
});
|
2019-08-01 17:22:58 +05:30
|
|
|
},
|
2022-02-10 17:27:31 +05:30
|
|
|
},
|
2019-08-01 17:22:58 +05:30
|
|
|
};
|
|
|
|
</script>
|
2022-02-11 11:25:07 +05:30
|
|
|
<style scoped>
|
|
|
|
input[type='search']::-webkit-search-decoration,
|
|
|
|
input[type='search']::-webkit-search-cancel-button,
|
|
|
|
input[type='search']::-webkit-search-results-button,
|
|
|
|
input[type='search']::-webkit-search-results-decoration {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
</style>
|