diff --git a/.changeset/fix-web-session-row-hover.md b/.changeset/fix-web-session-row-hover.md new file mode 100644 index 000000000..f983ec733 --- /dev/null +++ b/.changeset/fix-web-session-row-hover.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Fix the sidebar session row shifting its title and status badges when hovered. diff --git a/apps/kimi-web/design/design-system.html b/apps/kimi-web/design/design-system.html index 3694066d9..d91372e8b 100644 --- a/apps/kimi-web/design/design-system.html +++ b/apps/kimi-web/design/design-system.html @@ -2188,20 +2188,35 @@ export function auth(token: string) {

Session row

-

A session row is an inset rounded pill, structured as: status slot → title → time → attention Badge → kebab.

+

A session row is an inset rounded pill, structured as: status slot → title → attention Badge → trailing action slot.

- - - + +
PartRule
Containermargin: 1px 6px; padding: 7px 10px; radius-md; hover = surface-sunken; active = accent-soft + inset 0 0 0 1px accent-bd
Status slot (lead)fixed --sb-gutter width; running = Spinner sm, otherwise unread = 7px accent dot
Titleflex:1 with truncation; double-click enters inline rename (compact input, not Input)
Timemono xs, fg-faint; yields to the kebab on hover
Attention BadgeBadge sm: info (needs answer) / warning (needs approval) / danger (aborted)
kebabIconButton sm, shown on hover; dropdown uses Menu/MenuItem
Attention BadgeBadge sm: info (needs answer) / warning (needs approval) / danger (aborted); always shown, not toggled on hover
Trailing action slot (trail)fixed slot shared by the time ↔ kebab (see below)
Archive confirmationreplaces the title area, Button sm (danger confirm / secondary cancel)
+

Trailing action slot

+

The session row's rightmost is a fixed-width action slot: at rest it shows the relative time (mono xs, fg-faint); on hover it swaps in place to the kebab (IconButton sm).

+ +
SessionRow.vue
.act { display: inline-grid; flex: none; align-items: center; justify-items: center; }
+.act .ts, .act .kebab { grid-area: 1 / 1; }
+.act .kebab { visibility: hidden; }
+.se:hover .act .kebab, .act:has(.kebab.open) .kebab { visibility: visible; }
+.se:hover .act .ts,   .act:has(.kebab.open) .ts   { visibility: hidden; }
+
i
+ Why the time and kebab share a slot and use visibility rather than display:none: the time is variable-width (2h / 5m / just now …), the kebab a fixed 26px. If hover used display:none to drop the time and append the kebab, the right region would reflow — badges shift and the title's truncation changes, causing visible jitter. Sharing one slot and swapping via visibility keeps the slot width constant; this is a hard rule for sidebar list-row stability. +
+

Workspace group

The group head and session rows share --sb-*: folder icon (open/closed) → name → path subtitle, with the kebab and "+" revealed on hover.