2
0
mirror of https://github.com/frappe/books.git synced 2025-02-10 07:59:03 +00:00
books/src/components/SearchBar.vue
2022-02-16 13:15:33 +05:30

137 lines
3.6 KiB
Vue

<template>
<div v-on-outside-click="clearInput" class="relative">
<Dropdown :items="suggestions" class="text-sm h-full">
<template
v-slot="{
toggleDropdown,
highlightItemUp,
highlightItemDown,
selectHighlightedItem,
}"
>
<div
class="rounded-md relative flex items-center overflow-hidden h-full"
>
<div class="absolute flex justify-center w-8">
<feather-icon name="search" class="w-3 h-3 text-gray-800" />
</div>
<input
type="search"
class="bg-gray-200 text-sm pl-8 focus:outline-none h-full w-56"
placeholder="Search..."
autocomplete="off"
spellcheck="false"
v-model="inputValue"
@input="
() => {
search();
toggleDropdown(true);
}
"
ref="input"
@keydown.up="highlightItemUp"
@keydown.down="highlightItemDown"
@keydown.enter="selectHighlightedItem"
@keydown.tab="toggleDropdown(false)"
@keydown.esc="toggleDropdown(false)"
/>
</div>
</template>
</Dropdown>
</div>
</template>
<script>
import frappe from 'frappe';
import reports from '../../reports/view';
import Dropdown from '@/components/Dropdown';
import { routeTo } from '@/utils';
import { t } from 'frappe';
export default {
data() {
return {
inputValue: '',
searchList: [],
suggestions: [],
};
},
components: {
Dropdown,
},
emits: ['change'],
mounted() {
this.makeSearchList();
},
methods: {
async search() {
this.suggestions = this.searchList.filter((d) => {
let key = this.inputValue.toLowerCase();
return d.label.toLowerCase().includes(key);
});
if (this.suggestions.length === 0) {
this.suggestions = [{ label: t`No results found.` }];
}
},
clearInput() {
this.inputValue = '';
this.$emit('change', null);
},
async makeSearchList() {
const doctypes = this.getDoctypes();
const reports = this.getReports();
const views = this.getViews();
let searchList = [...doctypes, ...reports, ...views];
this.searchList = searchList.map((d) => {
if (d.route) {
d.action = () => routeTo(d.route);
this.inputValue = '';
}
return d;
});
},
getDoctypes() {
let doctypes = Object.keys(frappe.models).sort();
let doctypeMetas = doctypes.map((doctype) => frappe.getMeta(doctype));
let searchableDoctypes = doctypeMetas.filter((meta) => {
return !meta.isSingle && !meta.isChild;
});
return searchableDoctypes.map((meta) => {
return {
label: meta.label || meta.name,
route: `/list/${meta.name}`,
group: 'List',
};
});
},
getReports() {
return Object.values(reports).map((report) => {
return {
label: report.title,
route: `/report/${report.method}`,
group: 'Reports',
};
});
},
getViews() {
return [
{
label: t`Chart of Accounts`,
route: '/chartOfAccounts',
group: 'List',
},
];
},
},
};
</script>
<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>