mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 06:40:51 +08:00
feat: user-dropdown support hover
trigger (#5143)
* feat: user-dropdown support `hover` trigger * fix: modified type declaration
This commit is contained in:
@@ -2,8 +2,9 @@
|
||||
import type { AnyFunction } from '@vben/types';
|
||||
|
||||
import type { Component } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, useTemplateRef, watch } from 'vue';
|
||||
|
||||
import { useHoverToggle } from '@vben/hooks';
|
||||
import { LockKeyhole, LogOut } from '@vben/icons';
|
||||
import { $t } from '@vben/locales';
|
||||
import { preferences, usePreferences } from '@vben/preferences';
|
||||
@@ -53,6 +54,10 @@ interface Props {
|
||||
* 文本
|
||||
*/
|
||||
text?: string;
|
||||
/** 触发方式 */
|
||||
trigger?: 'both' | 'click' | 'hover';
|
||||
/** hover触发时,延迟响应的时间 */
|
||||
hoverDelay?: number;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
@@ -67,10 +72,11 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
showShortcutKey: true,
|
||||
tagText: '',
|
||||
text: '',
|
||||
trigger: 'click',
|
||||
hoverDelay: 500,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{ logout: [] }>();
|
||||
const openPopover = ref(false);
|
||||
|
||||
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } =
|
||||
usePreferences();
|
||||
@@ -84,6 +90,27 @@ const [LogoutModal, logoutModalApi] = useVbenModal({
|
||||
},
|
||||
});
|
||||
|
||||
const refTrigger = useTemplateRef('refTrigger');
|
||||
const refContent = useTemplateRef('refContent');
|
||||
const [openPopover, hoverWatcher] = useHoverToggle(
|
||||
[refTrigger, refContent],
|
||||
() => props.hoverDelay,
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.trigger === 'hover' || props.trigger === 'both',
|
||||
(val) => {
|
||||
if (val) {
|
||||
hoverWatcher.enable();
|
||||
} else {
|
||||
hoverWatcher.disable();
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
|
||||
|
||||
const enableLogoutShortcutKey = computed(() => {
|
||||
@@ -155,8 +182,8 @@ if (enableShortcutKey.value) {
|
||||
{{ $t('ui.widgets.logoutTip') }}
|
||||
</LogoutModal>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<DropdownMenu v-model:open="openPopover">
|
||||
<DropdownMenuTrigger ref="refTrigger" :disabled="props.trigger === 'hover'">
|
||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5">
|
||||
<div class="hover:text-accent-foreground flex-center">
|
||||
<VbenAvatar :alt="text" :src="avatar" class="size-8" dot />
|
||||
@@ -164,64 +191,66 @@ if (enableShortcutKey.value) {
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
|
||||
<DropdownMenuLabel class="flex items-center p-3">
|
||||
<VbenAvatar
|
||||
:alt="text"
|
||||
:src="avatar"
|
||||
class="size-12"
|
||||
dot
|
||||
dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
|
||||
/>
|
||||
<div class="ml-2 w-full">
|
||||
<div
|
||||
v-if="tagText || text || $slots.tagText"
|
||||
class="text-foreground mb-1 flex items-center text-sm font-medium"
|
||||
>
|
||||
{{ text }}
|
||||
<slot name="tagText">
|
||||
<Badge v-if="tagText" class="ml-2 text-green-400">
|
||||
{{ tagText }}
|
||||
</Badge>
|
||||
</slot>
|
||||
<div ref="refContent">
|
||||
<DropdownMenuLabel class="flex items-center p-3">
|
||||
<VbenAvatar
|
||||
:alt="text"
|
||||
:src="avatar"
|
||||
class="size-12"
|
||||
dot
|
||||
dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
|
||||
/>
|
||||
<div class="ml-2 w-full">
|
||||
<div
|
||||
v-if="tagText || text || $slots.tagText"
|
||||
class="text-foreground mb-1 flex items-center text-sm font-medium"
|
||||
>
|
||||
{{ text }}
|
||||
<slot name="tagText">
|
||||
<Badge v-if="tagText" class="ml-2 text-green-400">
|
||||
{{ tagText }}
|
||||
</Badge>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="text-muted-foreground text-xs font-normal">
|
||||
{{ description }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-muted-foreground text-xs font-normal">
|
||||
{{ description }}
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator v-if="menus?.length" />
|
||||
<DropdownMenuItem
|
||||
v-for="menu in menus"
|
||||
:key="menu.text"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="menu.handler"
|
||||
>
|
||||
<VbenIcon :icon="menu.icon" class="mr-2 size-4" />
|
||||
{{ menu.text }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
v-if="preferences.widget.lockScreen"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleOpenLock"
|
||||
>
|
||||
<LockKeyhole class="mr-2 size-4" />
|
||||
{{ $t('ui.widgets.lockScreen.title') }}
|
||||
<DropdownMenuShortcut v-if="enableLockScreenShortcutKey">
|
||||
{{ altView }} L
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator v-if="preferences.widget.lockScreen" />
|
||||
<DropdownMenuItem
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<LogOut class="mr-2 size-4" />
|
||||
{{ $t('common.logout') }}
|
||||
<DropdownMenuShortcut v-if="enableLogoutShortcutKey">
|
||||
{{ altView }} Q
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator v-if="menus?.length" />
|
||||
<DropdownMenuItem
|
||||
v-for="menu in menus"
|
||||
:key="menu.text"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="menu.handler"
|
||||
>
|
||||
<VbenIcon :icon="menu.icon" class="mr-2 size-4" />
|
||||
{{ menu.text }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
v-if="preferences.widget.lockScreen"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleOpenLock"
|
||||
>
|
||||
<LockKeyhole class="mr-2 size-4" />
|
||||
{{ $t('ui.widgets.lockScreen.title') }}
|
||||
<DropdownMenuShortcut v-if="enableLockScreenShortcutKey">
|
||||
{{ altView }} L
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator v-if="preferences.widget.lockScreen" />
|
||||
<DropdownMenuItem
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<LogOut class="mr-2 size-4" />
|
||||
{{ $t('common.logout') }}
|
||||
<DropdownMenuShortcut v-if="enableLogoutShortcutKey">
|
||||
{{ altView }} Q
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</div>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
|
Reference in New Issue
Block a user