From 5322c638895a934c1ce220fefed54f5077d2a49e Mon Sep 17 00:00:00 2001 From: qer Date: Thu, 2 Jul 2026 19:53:01 +0800 Subject: [PATCH] fix(web): trim redundant and incorrect tooltips (#1316) * fix(web): trim redundant and incorrect tooltips Drop hover tooltips that only restated a button's accessible label, and remove the permission-pill tooltip that described cycling modes while the control actually opens a dropdown. Keep tooltips that reveal truncated text or explain status. * fix(web): remove remaining ChatHeader tooltips Drop the session-title, git-branch, and open-PR tooltips in ChatHeader so the header has no hover tooltips. Broaden the changeset wording to cover the wider trim. * fix(web): keep tooltips from getting stuck on unmount Tooltip attached its mouseleave listener to the slotted trigger element once, so if that element was removed (e.g. a v-if toggled while hovering a tool-call path) the open bubble never received mouseleave and stranded on screen. Re-sync the listener to the live slotted element via a MutationObserver and close the tooltip whenever the trigger changes. * chore: add changeset for stuck-tooltip fix * fix(web): restore session title tooltip in ChatHeader The session title is truncated with an ellipsis when it exceeds the header width, so the tooltip was the only way to read the full name from the header. Restoring it keeps the truncation-revealing hint while the redundant git/branch/open-PR tooltips stay removed. --- .changeset/fix-stuck-web-tooltip.md | 5 + .changeset/trim-redundant-web-tooltips.md | 5 + apps/kimi-web/src/App.vue | 17 +-- apps/kimi-web/src/components/FilePreview.vue | 90 +++++------- apps/kimi-web/src/components/Sidebar.vue | 93 ++++++------ .../src/components/WorkspaceGroup.vue | 42 +++--- .../src/components/chat/ApprovalCard.vue | 20 ++- .../src/components/chat/ChatHeader.vue | 90 ++++++------ .../kimi-web/src/components/chat/ChatPane.vue | 72 ++++------ .../kimi-web/src/components/chat/Composer.vue | 132 ++++++++---------- .../kimi-web/src/components/chat/DiffView.vue | 10 +- .../src/components/chat/OpenInMenu.vue | 22 ++- .../src/components/chat/QuestionCard.vue | 21 ++- .../components/mobile/MobileSwitcherSheet.vue | 54 ++++--- .../src/components/ui/PanelHeader.vue | 20 ++- apps/kimi-web/src/components/ui/Tooltip.vue | 60 +++++--- apps/kimi-web/src/i18n/locales/en/status.ts | 3 - apps/kimi-web/src/i18n/locales/zh/status.ts | 3 - 18 files changed, 353 insertions(+), 406 deletions(-) create mode 100644 .changeset/fix-stuck-web-tooltip.md create mode 100644 .changeset/trim-redundant-web-tooltips.md diff --git a/.changeset/fix-stuck-web-tooltip.md b/.changeset/fix-stuck-web-tooltip.md new file mode 100644 index 000000000..9f9fc042b --- /dev/null +++ b/.changeset/fix-stuck-web-tooltip.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Fix web tooltips that could get stuck on screen when their trigger element is removed while open. diff --git a/.changeset/trim-redundant-web-tooltips.md b/.changeset/trim-redundant-web-tooltips.md new file mode 100644 index 000000000..ee1038b2d --- /dev/null +++ b/.changeset/trim-redundant-web-tooltips.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Trim redundant and incorrect tooltips in the web UI. diff --git a/apps/kimi-web/src/App.vue b/apps/kimi-web/src/App.vue index 48224498e..d89debde7 100644 --- a/apps/kimi-web/src/App.vue +++ b/apps/kimi-web/src/App.vue @@ -40,7 +40,6 @@ import type { AppConfig, ThinkingLevel } from './api/types'; import Button from './components/ui/Button.vue'; import IconButton from './components/ui/IconButton.vue'; import Icon from './components/ui/Icon.vue'; -import Tooltip from './components/ui/Tooltip.vue'; // Hydrate the server-transport credential (fragment token or sessionStorage) // BEFORE the client connects, so the first REST/WS calls already carry it. @@ -625,15 +624,13 @@ function openPr(url: string): void { @update:width="sessionColWidth = $event" /> diff --git a/apps/kimi-web/src/components/FilePreview.vue b/apps/kimi-web/src/components/FilePreview.vue index 8b65cf4c8..1888c2127 100644 --- a/apps/kimi-web/src/components/FilePreview.vue +++ b/apps/kimi-web/src/components/FilePreview.vue @@ -482,60 +482,46 @@ function truncatePath(path: string, maxLen = 55): string { {{ searchMatches.length }} - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + default panel width — icon-only buttons keep it single-line. --> + + + + + + + + + + + + + + + + + diff --git a/apps/kimi-web/src/components/Sidebar.vue b/apps/kimi-web/src/components/Sidebar.vue index 4b4911b1a..c8c92ef2b 100644 --- a/apps/kimi-web/src/components/Sidebar.vue +++ b/apps/kimi-web/src/components/Sidebar.vue @@ -23,7 +23,6 @@ import IconButton from './ui/IconButton.vue'; import Icon from './ui/Icon.vue'; import Menu from './ui/Menu.vue'; import MenuItem from './ui/MenuItem.vue'; -import Tooltip from './ui/Tooltip.vue'; import { useConfirmDialog } from '../composables/useConfirmDialog'; const { t } = useI18n(); @@ -553,24 +552,20 @@ onBeforeUnmount(() => { Kimi Code · {{ endpoint }} - - - - - - - - - - + + + + + + @@ -585,16 +580,14 @@ onBeforeUnmount(() => { {{ t('sidebar.newChat') }} - - - - - + + + @@ -609,29 +602,25 @@ onBeforeUnmount(() => {
- - - - - + + + - - - - - + + +
diff --git a/apps/kimi-web/src/components/chat/ApprovalCard.vue b/apps/kimi-web/src/components/chat/ApprovalCard.vue index ee8d47003..0448ff261 100644 --- a/apps/kimi-web/src/components/chat/ApprovalCard.vue +++ b/apps/kimi-web/src/components/chat/ApprovalCard.vue @@ -191,17 +191,15 @@ onUnmounted(() => document.removeEventListener('keydown', handleKeydown)); {{ t('approval.subagentBadge', { name: agentName }) }} {{ t('approval.required') }} - - - - - - + + + + diff --git a/apps/kimi-web/src/components/chat/ChatHeader.vue b/apps/kimi-web/src/components/chat/ChatHeader.vue index 77b89cf5e..66b603bab 100644 --- a/apps/kimi-web/src/components/chat/ChatHeader.vue +++ b/apps/kimi-web/src/components/chat/ChatHeader.vue @@ -222,19 +222,17 @@ async function startArchive(): Promise { - - - - - + + + { - - - + {{ branch || t('header.detached') }} + + + ↑{{ ahead }} + ↓{{ behind }} + + + +{{ adds }} + -{{ dels }} + + - - - + diff --git a/apps/kimi-web/src/components/chat/ChatPane.vue b/apps/kimi-web/src/components/chat/ChatPane.vue index 019bfa6dc..d61495293 100644 --- a/apps/kimi-web/src/components/chat/ChatPane.vue +++ b/apps/kimi-web/src/components/chat/ChatPane.vue @@ -575,31 +575,25 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }):
- - - -
- - +
+ - + + + @@ -733,16 +723,14 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }): {{ t('composer.queueNext') }} #{{ qi + 1 }} - - - + diff --git a/apps/kimi-web/src/components/chat/Composer.vue b/apps/kimi-web/src/components/chat/Composer.vue index f8a8feb7e..9d00f61b6 100644 --- a/apps/kimi-web/src/components/chat/Composer.vue +++ b/apps/kimi-web/src/components/chat/Composer.vue @@ -783,18 +783,16 @@ function selectModel(modelId: string): void { @compositionend="handleCompositionEnd" @input="handleInput" /> - - - + @@ -813,30 +811,26 @@ function selectModel(modelId: string): void {
- - - - - + + + - - {{ permLabel }} - + {{ permLabel }} {{ attentionBySession[s.id] }} - - - - - + + + diff --git a/apps/kimi-web/src/components/ui/PanelHeader.vue b/apps/kimi-web/src/components/ui/PanelHeader.vue index fbd276b9b..930ba5179 100644 --- a/apps/kimi-web/src/components/ui/PanelHeader.vue +++ b/apps/kimi-web/src/components/ui/PanelHeader.vue @@ -30,17 +30,15 @@ defineEmits<{ close: [] }>(); {{ subtitle }} - - - - - + + +
diff --git a/apps/kimi-web/src/components/ui/Tooltip.vue b/apps/kimi-web/src/components/ui/Tooltip.vue index 8d097e44d..a120cbff3 100644 --- a/apps/kimi-web/src/components/ui/Tooltip.vue +++ b/apps/kimi-web/src/components/ui/Tooltip.vue @@ -2,11 +2,12 @@ + the real trigger element, which also anchors the bubble, and re-attached if that + element is removed or replaced (so an open tooltip can never strand on screen). + The bubble is rendered through a body teleport so it escapes ancestor overflow + clipping, and positioned with flip + viewport clamping. Short text stays on one + line; long text wraps within `maxWidth` and is clamped to `maxLines` lines with + an ellipsis so the bubble never grows too tall. -->