feat: add modal and drawer components and examples (#4229)

* feat: add modal component

* feat: add drawer component

* feat: apply new modal and drawer components to the layout

* chore: typo

* feat: add some unit tests
This commit is contained in:
Vben
2024-08-25 23:40:52 +08:00
committed by GitHub
parent edb55b1fc0
commit 20a3868594
96 changed files with 2700 additions and 743 deletions

View File

@@ -12,17 +12,9 @@ import {
} from '@vben/icons';
import { $t } from '@vben/locales';
import { isWindowsOs } from '@vben/utils';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@vben-core/shadcn-ui';
import { useVbenModal } from '@vben-core/popup-ui';
import { useMagicKeys, useToggle, whenever } from '@vueuse/core';
import { useMagicKeys, whenever } from '@vueuse/core';
import SearchPanel from './search-panel.vue';
@@ -38,12 +30,18 @@ const props = withDefaults(
},
);
const [open, toggleOpen] = useToggle();
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
});
const open = modalApi.useStore((state) => state.isOpen);
const keyword = ref('');
const searchInputRef = ref<HTMLInputElement>();
function handleClose() {
open.value = false;
modalApi.close();
keyword.value = '';
}
@@ -51,7 +49,7 @@ const keys = useMagicKeys();
const cmd = isWindowsOs() ? keys['ctrl+k'] : keys['cmd+k'];
whenever(cmd!, () => {
if (props.enableShortcutKey) {
open.value = true;
modalApi.open();
}
});
@@ -75,6 +73,10 @@ const toggleKeydownListener = () => {
}
};
const toggleOpen = () => {
open.value ? modalApi.close() : modalApi.open();
};
watch(() => props.enableShortcutKey, toggleKeydownListener);
onMounted(() => {
@@ -88,67 +90,58 @@ onMounted(() => {
<template>
<div>
<Dialog :open="open">
<DialogTrigger as-child>
<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-3 group-hover:opacity-100"
<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"
/>
<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>
</DialogTrigger>
<DialogContent
class="top-0 h-full w-full -translate-y-0 border-none p-0 shadow-xl sm:top-[10%] sm:h-[unset] sm:w-[600px] sm:rounded-2xl"
@close="handleClose"
>
<DialogHeader>
<DialogTitle
class="border-border flex h-12 items-center gap-3 border-b px-5 font-normal"
>
<Search class="text-muted-foreground 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 outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
/>
</DialogTitle>
<DialogDescription />
</DialogHeader>
<SearchPanel :keyword="keyword" :menus="menus" @close="handleClose" />
<DialogFooter
class="text-muted-foreground border-border hidden flex-row rounded-b-2xl border-t px-4 py-2 text-xs sm:flex sm:justify-start sm:gap-x-4"
>
<div class="flex items-center">
</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" />
{{ $t('widgets.search.select') }}
</div>
<div class="flex items-center">
<ArrowUp class="mr-2 size-3" />
<ArrowDown class="mr-2 size-3" />
<div class="mr-2 flex items-center">
<ArrowUp class="mr-1 size-3" />
<ArrowDown class="mr-1 size-3" />
{{ $t('widgets.search.navigate') }}
</div>
<div class="flex items-center">
<MdiKeyboardEsc class="mr-1 size-3" />
{{ $t('widgets.search.close') }}
</div>
</DialogFooter>
</DialogContent>
</Dialog>
</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-3 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>
</div>
</template>