feat: add keyboard shortcut tooltips
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
- [ ] Fix custom longcat tool call
|
||||
- [ ] add the ability to make a custom provider
|
||||
- [ ] add browser testing (maybe https://vitest.dev/guide/browser/)
|
||||
- [ ] Add a dropdown to the output token count on agent messages that shows you all the token info
|
||||
- [x] Add a dropdown to the output token count on agent messages that shows you all the token info
|
||||
- [ ] Add the ability to configure UI scale and font size
|
||||
- [ ] Write good docs
|
||||
- [ ] Custom theme colors
|
||||
|
||||
@@ -207,10 +207,6 @@ button.accent:hover {
|
||||
background-color: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.has-obtrusive-scrollbars .chat-scroll-container {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,8 @@ onUnmounted(() => {
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<!-- TODO: since we dont want to model selector dropdown to potentially overflow, it has max-width: 100%, so, we need to maake the trigger large enough to fit the entire width of the dropdown -->
|
||||
<div class="flex flex-1 gap-1">
|
||||
<ModelSelector v-if="providers !== undefined" v-model="selectedModel" :providers="providers" />
|
||||
<ModelSelector v-if="providers !== undefined" :add-hotkey="true" v-model="selectedModel"
|
||||
:providers="providers" />
|
||||
<FileSelector :selected-model="selectedModel" v-model="files" />
|
||||
</div>
|
||||
<button aria-label="Send message" @click="handleSubmit"
|
||||
|
||||
@@ -122,7 +122,7 @@ onMounted(() => { inputRef.value?.focus(); });
|
||||
<input ref="inputRef" v-model="query" type="text" role="combobox" aria-autocomplete="list"
|
||||
aria-haspopup="listbox" :aria-expanded="flattenedResults.length > 0" :aria-controls="listboxId"
|
||||
:aria-activedescendant="flattenedResults[selectedIndex]?.uiId" placeholder="Search agents and topics..."
|
||||
class="w-full bg-transparent border-none outline-none text-lg text-[var(--text-primary)]"
|
||||
class="placeholder:text-[var(--text-tertiary)] w-full bg-transparent border-none outline-none text-lg text-[var(--text-primary)]"
|
||||
@keydown="handleKeyDown" />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ const runtimePage = computed(() => {
|
||||
<main
|
||||
class="flex-1 flex flex-col overflow-y-hidden max-h-full h-full px-3 bg-[var(--bg-surface)] border rounded-lg border-[var(--color-border)]">
|
||||
<header class="flex items-center justify-between pl-2 pb-2 pt-2 ">
|
||||
<h2 class="text-lg font-semibold m-0 capitalize">{{ runtimePage.label }}</h2>
|
||||
<h2 class="text-lg font-semibold m-0 case-capital">{{ runtimePage.label }}</h2>
|
||||
<button
|
||||
class="hover:bg-[var(--color-hover)] p-1.5 rounded-md transition-colors duration-200 ease-[cubic-bezier(0,0.55,0.45,1)]"
|
||||
@click="close">
|
||||
|
||||
@@ -68,7 +68,7 @@ console.log("shiki codeblock rendered in", Date.now() - start);
|
||||
<template>
|
||||
<div class="flex flex-col my-2 rounded-xl overflow-hidden">
|
||||
<div class="flex items-center pl-3 pr-1.5 py-1.5 text-sm font-sans bg-[var(--color-hover)] justify-between">
|
||||
<div class="capitalize">
|
||||
<div class="case-capital">
|
||||
{{ parsed?.displayLang }}
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
|
||||
@@ -138,26 +138,34 @@ const messageCount = computed(() => {
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<div v-if="messageCount > 1" class="flex gap-1">
|
||||
<button :inert="focusedIndex === 0" @click="focusedIndex = focusedIndex! - 1">
|
||||
<span class="i-mynaui-chevron-left w-4 h-4 text-[var(--text-secondary)]"
|
||||
:class="focusedIndex === 0 ? 'opacity-0' : ''"></span>
|
||||
</button>
|
||||
<Tooltip :inert="focusedIndex === 0" :hotkey="['alt', '[']">
|
||||
<button @click="focusedIndex = focusedIndex! - 1"
|
||||
class="hover:bg-[var(--color-hover)] rounded transition duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
||||
<span class="i-mynaui-chevron-left w-4 h-4 text-[var(--text-secondary)]"
|
||||
:class="focusedIndex === 0 ? 'opacity-0' : ''"></span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span class="text-xs text-[var(--text-secondary)]">
|
||||
{{ focusedIndex + 1 }} / {{ messageCount }}
|
||||
</span>
|
||||
<button :inert="focusedIndex + 1 === messageCount" @click="focusedIndex = focusedIndex + 1">
|
||||
<span class="i-mynaui-chevron-right w-4 h-4 text-[var(--text-secondary)]"
|
||||
:class="focusedIndex + 1 === messageCount ? 'opacity-0' : ''"></span>
|
||||
</button>
|
||||
<Tooltip :inert="focusedIndex + 1 === messageCount" :hotkey="['alt', ']']">
|
||||
<button @click="focusedIndex = focusedIndex + 1"
|
||||
class="hover:bg-[var(--color-hover)] rounded transition duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
||||
<span class="i-mynaui-chevron-right w-4 h-4 text-[var(--text-secondary)]"
|
||||
:class="focusedIndex + 1 === messageCount ? 'opacity-0' : ''"></span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="activeMessage.generation?.status !== 'pending'"
|
||||
class="self-end mt-1 w-fit bg-[var(--bg-container)] text-[var(--text-secondary)] gap-px flex items-center rounded-md overflow-hidden opacity-0 group-hover:opacity-100 transition-opacity duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
||||
<button @click="regenerateMessage"
|
||||
class="flex justify-center items-center w-7 h-6 hover:bg-[var(--color-hover)]">
|
||||
<span class="i-mynaui-refresh text-4.5"></span>
|
||||
</button>
|
||||
<Tooltip :hotkey="['ctrl', 'shift', 'enter']">
|
||||
<button @click="regenerateMessage"
|
||||
class="flex justify-center items-center w-7 h-6 hover:bg-[var(--color-hover)]">
|
||||
<span class="i-mynaui-refresh text-4.5"></span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
<button v-if="message.role === 'user'" @click="handleEdit"
|
||||
class="flex justify-center items-center w-7 h-6 hover:bg-[var(--color-hover)]">
|
||||
<span class="i-mynaui-pencil text-4.5"></span>
|
||||
@@ -166,10 +174,12 @@ const messageCount = computed(() => {
|
||||
class="flex justify-center items-center w-7 h-6 hover:bg-[var(--color-hover)]">
|
||||
<span :class="copied ? 'i-mynaui-check text-emerald-500' : 'i-mynaui-copy text-4.5'"></span>
|
||||
</button>
|
||||
<button @click="deleteMessage"
|
||||
class="flex justify-center items-center w-7 h-6 text-red-500 hover:bg-[var(--color-hover)]">
|
||||
<span class="i-mynaui-trash text-5"></span>
|
||||
</button>
|
||||
<Tooltip :hotkey="['ctrl', 'shift', 'backspace']">
|
||||
<button @click="deleteMessage"
|
||||
class="flex justify-center items-center w-7 h-6 text-red-500 hover:bg-[var(--color-hover)]">
|
||||
<span class="i-mynaui-trash text-5"></span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ const { addShortcut } = useKeyboardShortcuts();
|
||||
|
||||
const props = defineProps<{
|
||||
providers: ProviderWithModels[];
|
||||
addHotkey?: boolean;
|
||||
}>();
|
||||
|
||||
const selectedModel = defineModel<ModelWithProvider | null>();
|
||||
@@ -182,11 +183,15 @@ const handleSearchKeyDown = (event: KeyboardEvent) => {
|
||||
}
|
||||
};
|
||||
|
||||
const unbindShortcut = addShortcut(['ctrl', 'shift', 'm'], (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
toggleDropdown();
|
||||
});
|
||||
let unbindShortcut: () => void = () => { };
|
||||
|
||||
if (props.addHotkey) {
|
||||
unbindShortcut = addShortcut(['ctrl', 'shift', 'm'], (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
toggleDropdown();
|
||||
});
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
unbindShortcut();
|
||||
@@ -240,7 +245,7 @@ onUnmounted(() => {
|
||||
|
||||
<div v-for="provider in filteredProviders" :key="provider.id" class="mb-2">
|
||||
<div v-if="provider.models.filter(m => m.enabled).length > 0"
|
||||
class="px-4 py-1.5 text-[13px] font-medium text-[var(--text-secondary)] capitalize tracking-wider flex justify-between">
|
||||
class="px-4 py-1.5 text-[13px] font-medium text-[var(--text-secondary)] case-capital tracking-wider flex justify-between">
|
||||
{{ provider.name }}
|
||||
<button
|
||||
@click="closeDropdown(); openDialog(DialogType.Settings, undefined, { page: 'providers', params: provider.id })"
|
||||
|
||||
@@ -61,7 +61,7 @@ defineEmits(['navigate']);
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<component v-if="providerIcons[p.type]" :color="true" :is="providerIcons[p.type]"
|
||||
class="w-8 h-8 text-[var(--text-primary)]" />
|
||||
<h3 class="text-md font-semibold text-start capitalize">{{ p.name }}</h3>
|
||||
<h3 class="text-md font-semibold text-start case-capital">{{ p.name }}</h3>
|
||||
</div>
|
||||
<hr class="border-t border-[var(--color-border)]" />
|
||||
</div>
|
||||
@@ -87,7 +87,7 @@ defineEmits(['navigate']);
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<component v-if="providerIcons[p.type]" :color="true" :is="providerIcons[p.type]"
|
||||
class="w-8 h-8 text-[var(--text-primary)]" />
|
||||
<h3 class="text-md font-semibold text-start capitalize">{{ p.name }}</h3>
|
||||
<h3 class="text-md font-semibold text-start case-capital">{{ p.name }}</h3>
|
||||
</div>
|
||||
<hr class="border-t border-[var(--color-border)]" />
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ defineEmits(['navigate']);
|
||||
<div class="px-2 py-4 font-bold text-xs uppercase opacity-50">Enabled Providers</div>
|
||||
|
||||
<button v-for="p in providers?.filter(p => p.enabled)" :key="p.id" @click="$emit('navigate', 'providers', p.id)"
|
||||
:class="['capitalize flex items-center justify-between p-2 hover:bg-[var(--color-hover)] transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)] rounded-lg', p.id === params ? 'bg-[var(--color-hover)]' : '']">
|
||||
:class="['case-capital flex items-center justify-between p-2 hover:bg-[var(--color-hover)] transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)] rounded-lg', p.id === params ? 'bg-[var(--color-hover)]' : '']">
|
||||
<div class="flex items-center gap-2">
|
||||
<component v-if="providerIcons[p.type]" :color="true" :is="providerIcons[p.type]"
|
||||
class="w-4 h-4 text-[var(--text-primary)]" />
|
||||
@@ -36,7 +36,7 @@ defineEmits(['navigate']);
|
||||
|
||||
<button v-for="p in providers?.filter(p => !p.enabled)" :key="p.id"
|
||||
@click="$emit('navigate', 'providers', p.id)"
|
||||
:class="['capitalize flex items-center justify-between p-2 hover:bg-[var(--color-hover)] transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)] rounded-lg', p.id === params ? 'bg-[var(--color-hover)]' : '']">
|
||||
:class="['case-capital flex items-center justify-between p-2 hover:bg-[var(--color-hover)] transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)] rounded-lg', p.id === params ? 'bg-[var(--color-hover)]' : '']">
|
||||
<div class="flex items-center gap-2">
|
||||
<component v-if="providerIcons[p.type]" :color="true" :is="providerIcons[p.type]"
|
||||
class="w-4 h-4 text-[var(--text-primary)]" />
|
||||
|
||||
@@ -47,7 +47,7 @@ defineEmits(['navigate']);
|
||||
class="flex flex-col gap-4 py-4 flex-grow overflow-auto [scrollbar-width:thin] [scrollbar-color:#888_transparent] [scrollbar-gutter:stable]">
|
||||
<div class="flex flex-col" v-for="(systemAssistant, key) in settings.systemAssistants" :key="key">
|
||||
<label :for="`slider-${key}`" class="flex justify-between gap-4 items-center">
|
||||
<h4 class="capitalize">{{ key }}</h4>
|
||||
<h4 class="case-capital">{{ key }}</h4>
|
||||
<Slider :id="`slider-${key}`" :checked="systemAssistant.enabled" @click="toggle(String(key))" />
|
||||
</label>
|
||||
<div class="flex-1 justify-between gap-4 items-center">
|
||||
|
||||
@@ -120,20 +120,24 @@ const navKind = computed(() => {
|
||||
<div class="flex items-center justify-end text-[var(--text-secondary)] gap-0.5">
|
||||
<div :style="isHovering ? 'width: 32px;' : 'width: 0px;'"
|
||||
:class="['flex-shrink-0 overflow-hidden rounded-lg transition-all duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)] transform-origin-center-right']">
|
||||
<button aria-label="close sidebar" @click="closeSidebar" :class="[
|
||||
'flex text-5 h-8 w-8 items-center justify-center hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] bg-transparent transition-inherit',
|
||||
]">
|
||||
<span
|
||||
class="i-mynaui-panel-left-close text-5 transition-inherit transform-origin-right-center"
|
||||
:class="isHovering ? 'opacity-100 scale-100' : 'opacity-0 scale-95'"></span>
|
||||
</button>
|
||||
<Tooltip :hotkey="['ctrl', '[']">
|
||||
<button aria-label="close sidebar" @click="closeSidebar" :class="[
|
||||
'flex text-5 h-8 w-8 items-center justify-center hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] bg-transparent transition-inherit',
|
||||
]">
|
||||
<span
|
||||
class="i-mynaui-panel-left-close text-5 transition-inherit transform-origin-right-center"
|
||||
:class="isHovering ? 'opacity-100 scale-100' : 'opacity-0 scale-95'"></span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div v-if="navKind === 'agent'" class="flex-shrink-0 overflow-hidden rounded-lg">
|
||||
<NuxtLink aria-label="Start a new topic" :to="`/agent/${route.params.id}`" :class="[
|
||||
'flex text-5 h-8 w-8 items-center justify-center hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] bg-transparent text-inherit',
|
||||
]">
|
||||
<span class="i-mynaui-book-plus text-5"></span>
|
||||
</NuxtLink>
|
||||
<Tooltip :hotkey="['ctrl', 'alt', 'n']">
|
||||
<NuxtLink aria-label="Start a new topic" :to="`/agent/${route.params.id}`" :class="[
|
||||
'flex text-5 h-8 w-8 items-center justify-center hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] bg-transparent text-inherit',
|
||||
]">
|
||||
<span class="i-mynaui-book-plus text-5"></span>
|
||||
</NuxtLink>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -145,10 +149,12 @@ const navKind = computed(() => {
|
||||
|
||||
<div class="flex justify-between pt-2 z-25 bg-[var(--bg-base)] pb-2">
|
||||
<div class="flex">
|
||||
<button @click="openDialog(DialogType.Settings)"
|
||||
class="flex items-center justify-center h-7 w-7 cursor-pointer hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] rounded-lg transition-colors text-[var(--text-secondary)] active:text-[var(--text-primary)]">
|
||||
<span class="i-mynaui-cog-four text-5"></span>
|
||||
</button>
|
||||
<Tooltip :hotkey="['ctrl', ',']">
|
||||
<button @click="openDialog(DialogType.Settings)"
|
||||
class="flex items-center justify-center h-7 w-7 cursor-pointer hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] rounded-lg transition-colors text-[var(--text-secondary)] active:text-[var(--text-primary)]">
|
||||
<span class="i-mynaui-cog-four text-5"></span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-1">
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
hotkey?: string[];
|
||||
}>();
|
||||
|
||||
const { show, hide } = useTooltip();
|
||||
const triggerRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const onMouseEnter = () => {
|
||||
if (triggerRef.value) {
|
||||
show(triggerRef.value, props.hotkey);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="triggerRef" @mouseenter="onMouseEnter" @mouseleave="hide" :class="$attrs.class" v-bind="$attrs">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { useFloating, offset, flip, shift, autoUpdate } from '@floating-ui/vue';
|
||||
|
||||
const { activeElement, activeHotkey, isVisible } = useTooltip();
|
||||
|
||||
watch(activeElement, () => {
|
||||
console.log('activeElement', activeElement.value);
|
||||
});
|
||||
|
||||
const tooltipRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const { floatingStyles, placement } = useFloating(activeElement, tooltipRef, {
|
||||
placement: 'top',
|
||||
whileElementsMounted: autoUpdate,
|
||||
middleware: [offset(6), flip(), shift({ padding: 8 })],
|
||||
transform: false,
|
||||
});
|
||||
|
||||
const isMoving = ref(false);
|
||||
|
||||
watch(activeElement, (newEl, oldEl) => {
|
||||
// If we have both a new and old element, and we're currently visible,
|
||||
// then we are "moving" and should animate the transform.
|
||||
if (newEl && oldEl && isVisible.value) {
|
||||
isMoving.value = true;
|
||||
} else {
|
||||
isMoving.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Also reset isMoving when the tooltip fully closes
|
||||
watch(isVisible, (visible) => {
|
||||
if (!visible) isMoving.value = false;
|
||||
});
|
||||
|
||||
const isMac = import.meta.client ? navigator.userAgent.toUpperCase().indexOf('MAC') >= 0 : false;
|
||||
|
||||
const displayHotkey = computed(() =>
|
||||
activeHotkey.value?.map((key: string) =>
|
||||
isMac ? key.toLowerCase().replace('ctrl', '⌘') : key.toLowerCase())
|
||||
);
|
||||
|
||||
const transformOrigin = computed(() => placement.value.includes('top') ? 'transform-origin-bottom-center' : 'transform-origin-top-center');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<Transition
|
||||
enter-active-class="transition-[opacity,transform] duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)]"
|
||||
enter-from-class="opacity-0 scale-95" enter-to-class="opacity-100 scale-100"
|
||||
leave-active-class="transition-[opacity,transform] duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)]"
|
||||
leave-from-class="opacity-100 scale-100" leave-to-class="opacity-0 scale-95">
|
||||
<div v-if="isVisible && activeElement" ref="tooltipRef" :style="[
|
||||
floatingStyles,
|
||||
{
|
||||
// Only apply the transform transition when moving between elements
|
||||
transitionProperty: isMoving
|
||||
? 'top, left, right, bottom, opacity, transform'
|
||||
: 'opacity, transform',
|
||||
transitionDuration: '150ms',
|
||||
transitionTimingFunction: 'cubic-bezier(0.5, 1, 0.89, 1)'
|
||||
}
|
||||
]" :class="transformOrigin"
|
||||
class="pointer-events-none fixed z-35 flex flex-col bg-[var(--bg-surface)] rounded-lg shadow-xl px-1.5 py-1 text-xs">
|
||||
<div class="flex gap-1 items-center">
|
||||
<span v-for="key in displayHotkey" :key="key"
|
||||
class="bg-[var(--bg-container)] px-1 rounded border border-[var(--color-border)]">
|
||||
<kbd class="font-mono text-[10px] case-capital">{{ key }}</kbd>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
@@ -0,0 +1,51 @@
|
||||
const dwellTimeout = 400;
|
||||
const persistTimeout = 150;
|
||||
|
||||
export const useTooltip = () => {
|
||||
const activeElement = useState<HTMLElement | null>('tooltip:activeElement', () => null);
|
||||
const activeHotkey = useState<string[] | null>('tooltip:activeHotkey', () => null);
|
||||
const isVisible = useState<boolean>('tooltip:isVisible', () => false);
|
||||
const dwellTimeoutId = useState<NodeJS.Timeout | null>('tooltip:dwellTimeoutId', () => null);
|
||||
const closeTimeoutId = useState<NodeJS.Timeout | null>('tooltip:closeTimeout', () => null);
|
||||
|
||||
const show = (el: HTMLElement, hotkey?: string[]) => {
|
||||
if (closeTimeoutId.value) {
|
||||
clearTimeout(closeTimeoutId.value);
|
||||
}
|
||||
|
||||
if (isVisible.value) {
|
||||
activeElement.value = el;
|
||||
activeHotkey.value = hotkey || null;
|
||||
} else {
|
||||
dwellTimeoutId.value = setTimeout(() => {
|
||||
activeElement.value = el;
|
||||
activeHotkey.value = hotkey || null;
|
||||
isVisible.value = true;
|
||||
}, dwellTimeout);
|
||||
}
|
||||
};
|
||||
|
||||
const hide = () => {
|
||||
if (dwellTimeoutId.value) {
|
||||
clearTimeout(dwellTimeoutId.value);
|
||||
}
|
||||
|
||||
if (closeTimeoutId.value) {
|
||||
clearTimeout(closeTimeoutId.value);
|
||||
}
|
||||
|
||||
closeTimeoutId.value = setTimeout(() => {
|
||||
isVisible.value = false;
|
||||
activeElement.value = null;
|
||||
closeTimeoutId.value = null;
|
||||
}, persistTimeout);
|
||||
};
|
||||
|
||||
return {
|
||||
activeElement: readonly(activeElement),
|
||||
activeHotkey: readonly(activeHotkey),
|
||||
isVisible: readonly(isVisible),
|
||||
show,
|
||||
hide,
|
||||
};
|
||||
};
|
||||
@@ -30,5 +30,6 @@ useHead({
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<Dialog />
|
||||
<TooltipProvider />
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user