From e2a464341959799203dbcd1d1069829f24787279 Mon Sep 17 00:00:00 2001 From: Zoe <62722391+juls0730@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:41:57 -0600 Subject: [PATCH] feat: add keyboard shortcut tooltips --- TODO.md | 2 +- app/assets/css/base.css | 4 -- app/components/ChatInput.vue | 3 +- app/components/Dialog/QuickSwitcher.vue | 2 +- app/components/Dialog/Settings.vue | 2 +- app/components/Markdown/ShikiHighlight.vue | 2 +- app/components/Message/index.vue | 44 +++++++----- app/components/ModelSelector.vue | 17 +++-- app/components/Settings/ProviderSettings.vue | 4 +- app/components/Settings/ProviderSidebar.vue | 4 +- app/components/Settings/SystemAssistants.vue | 2 +- app/components/Sidenav/index.vue | 38 +++++----- app/components/Tooltip.vue | 20 ++++++ app/components/TooltipProvider.vue | 74 ++++++++++++++++++++ app/composables/useTooltip.ts | 51 ++++++++++++++ app/layouts/default.vue | 1 + 16 files changed, 217 insertions(+), 53 deletions(-) create mode 100644 app/components/Tooltip.vue create mode 100644 app/components/TooltipProvider.vue create mode 100644 app/composables/useTooltip.ts diff --git a/TODO.md b/TODO.md index f37675b..ca5f120 100644 --- a/TODO.md +++ b/TODO.md @@ -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 diff --git a/app/assets/css/base.css b/app/assets/css/base.css index cd0431a..130bc31 100644 --- a/app/assets/css/base.css +++ b/app/assets/css/base.css @@ -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; } diff --git a/app/components/ChatInput.vue b/app/components/ChatInput.vue index a304eab..594b123 100644 --- a/app/components/ChatInput.vue +++ b/app/components/ChatInput.vue @@ -207,7 +207,8 @@ onUnmounted(() => {
- +
diff --git a/app/components/Dialog/Settings.vue b/app/components/Dialog/Settings.vue index d63eb29..df61418 100644 --- a/app/components/Dialog/Settings.vue +++ b/app/components/Dialog/Settings.vue @@ -89,7 +89,7 @@ const runtimePage = computed(() => {
-

{{ runtimePage.label }}

+

{{ runtimePage.label }}

+ + +
- - - + + + + +
@@ -145,10 +149,12 @@ const navKind = computed(() => {
- + + +
diff --git a/app/components/Tooltip.vue b/app/components/Tooltip.vue new file mode 100644 index 0000000..ab01114 --- /dev/null +++ b/app/components/Tooltip.vue @@ -0,0 +1,20 @@ + + + diff --git a/app/components/TooltipProvider.vue b/app/components/TooltipProvider.vue new file mode 100644 index 0000000..a097669 --- /dev/null +++ b/app/components/TooltipProvider.vue @@ -0,0 +1,74 @@ + + + diff --git a/app/composables/useTooltip.ts b/app/composables/useTooltip.ts new file mode 100644 index 0000000..681265f --- /dev/null +++ b/app/composables/useTooltip.ts @@ -0,0 +1,51 @@ +const dwellTimeout = 400; +const persistTimeout = 150; + +export const useTooltip = () => { + const activeElement = useState('tooltip:activeElement', () => null); + const activeHotkey = useState('tooltip:activeHotkey', () => null); + const isVisible = useState('tooltip:isVisible', () => false); + const dwellTimeoutId = useState('tooltip:dwellTimeoutId', () => null); + const closeTimeoutId = useState('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, + }; +}; diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 51c07c7..97a8bde 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -30,5 +30,6 @@ useHead({
+