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) {
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.
| Part | Rule |
|---|---|
| Container | margin: 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 |
| Title | flex:1 with truncation; double-click enters inline rename (compact input, not Input) |
| Time | mono xs, fg-faint; yields to the kebab on hover |
| Attention Badge | Badge sm: info (needs answer) / warning (needs approval) / danger (aborted) |
| kebab | IconButton sm, shown on hover; dropdown uses Menu/MenuItem |
| Attention Badge | Badge 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 confirmation | replaces the title area, Button sm (danger confirm / secondary cancel) |
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).
display:inline-grid + grid-area:1/1 and swapped on hover via visibility — never display:none.max(time width, IconButton sm 26px), so the right region's total width is unchanged across hover — badges don't shift, the title's visible character count doesn't change, no jitter..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; }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.
+ The group head and session rows share --sb-*: folder icon (open/closed) → name → path subtitle, with the kebab and "+" revealed on hover.
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.
| Part | Rule |
|---|---|
| Container | margin: 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 |
| Title | flex:1 with truncation; double-click enters inline rename (compact input, not Input) |
| Time | mono xs, fg-faint; yields to the kebab on hover |
| Attention Badge | Badge sm: info (needs answer) / warning (needs approval) / danger (aborted) |
| kebab | IconButton sm, shown on hover; dropdown uses Menu/MenuItem |
| Attention Badge | Badge 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 confirmation | replaces the title area, Button sm (danger confirm / secondary cancel) |
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).
display:inline-grid + grid-area:1/1 and swapped on hover via visibility — never display:none.max(time width, IconButton sm 26px), so the right region's total width is unchanged across hover — badges don't shift, the title's visible character count doesn't change, no jitter..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; }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.
+ The group head and session rows share --sb-*: folder icon (open/closed) → name → path subtitle, with the kebab and "+" revealed on hover.