ruoyi-plus-vben5/packages/effects/layouts/src/widgets/global-search/global-search.vue

148 lines
4.1 KiB
Vue
Raw Normal View History

2024-05-19 21:20:42 +08:00
<script setup lang="ts">
import type { MenuRecordRaw } from '@vben/types';
2024-05-19 21:20:42 +08:00
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
2024-06-08 19:49:06 +08:00
2024-05-19 21:20:42 +08:00
import {
ArrowDown,
ArrowUp,
CornerDownLeft,
2024-05-19 21:20:42 +08:00
MdiKeyboardEsc,
Search,
} from '@vben/icons';
import { $t } from '@vben/locales';
import { isWindowsOs } from '@vben/utils';
import { useVbenModal } from '@vben-core/popup-ui';
2024-05-19 21:20:42 +08:00
import { useMagicKeys, whenever } from '@vueuse/core';
2024-05-19 21:20:42 +08:00
import SearchPanel from './search-panel.vue';
defineOptions({
name: 'GlobalSearch',
});
2024-05-25 20:02:21 +08:00
const props = withDefaults(
defineProps<{ enableShortcutKey?: boolean; menus: MenuRecordRaw[] }>(),
{
enableShortcutKey: true,
menus: () => [],
},
);
2024-05-19 21:20:42 +08:00
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
});
const open = modalApi.useStore((state) => state.isOpen);
2024-05-19 21:20:42 +08:00
const keyword = ref('');
const searchInputRef = ref<HTMLInputElement>();
2024-05-19 21:20:42 +08:00
function handleClose() {
modalApi.close();
2024-05-19 21:20:42 +08:00
keyword.value = '';
}
const keys = useMagicKeys();
const cmd = isWindowsOs() ? keys['ctrl+k'] : keys['cmd+k'];
whenever(cmd!, () => {
if (props.enableShortcutKey) {
modalApi.open();
}
});
whenever(open, () => {
nextTick(() => {
searchInputRef.value?.focus();
});
});
const preventDefaultBrowserSearchHotKey = (event: KeyboardEvent) => {
if (event.key.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
}
};
const toggleKeydownListener = () => {
if (props.enableShortcutKey) {
window.addEventListener('keydown', preventDefaultBrowserSearchHotKey);
} else {
window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);
}
};
const toggleOpen = () => {
open.value ? modalApi.close() : modalApi.open();
};
watch(() => props.enableShortcutKey, toggleKeydownListener);
onMounted(() => {
toggleKeydownListener();
onUnmounted(() => {
window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);
2024-05-19 21:20:42 +08:00
});
});
2024-05-19 21:20:42 +08:00
</script>
<template>
<div>
<Modal :fullscreen-button="false" class="w-[600px]" header-class="py-2">
<template #title>
<div class="flex items-center">
<Search class="text-muted-foreground mr-2 size-4" />
<input
ref="searchInputRef"
v-model="keyword"
:placeholder="$t('widgets.search.searchNavigate')"
class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm font-normal outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
2024-05-19 21:20:42 +08:00
/>
</div>
</template>
<SearchPanel :keyword="keyword" :menus="menus" @close="handleClose" />
<template #footer>
<div class="flex w-full justify-start text-xs">
<div class="mr-2 flex items-center">
<CornerDownLeft class="mr-1 size-3" />
2024-06-29 15:41:10 +08:00
{{ $t('widgets.search.select') }}
2024-05-19 21:20:42 +08:00
</div>
<div class="mr-2 flex items-center">
<ArrowUp class="mr-1 size-3" />
<ArrowDown class="mr-1 size-3" />
2024-06-29 15:41:10 +08:00
{{ $t('widgets.search.navigate') }}
2024-05-19 21:20:42 +08:00
</div>
<div class="flex items-center">
<MdiKeyboardEsc class="mr-1 size-3" />
2024-06-29 15:41:10 +08:00
{{ $t('widgets.search.close') }}
2024-05-19 21:20:42 +08:00
</div>
</div>
</template>
</Modal>
<div
class="md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none"
@click="toggleOpen()"
>
<Search
class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100"
/>
<span
class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
>
{{ $t('widgets.search.title') }}
</span>
<span
v-if="enableShortcutKey"
class="bg-background border-foreground/60 text-muted-foreground group-hover:text-foreground relative hidden rounded-sm rounded-r-xl px-1.5 py-1 text-xs leading-none group-hover:opacity-100 md:block"
>
{{ isWindowsOs() ? 'Ctrl' : '⌘' }}
<kbd>K</kbd>
</span>
<span v-else></span>
</div>
2024-05-19 21:20:42 +08:00
</div>
</template>