kimi-code/docs/prototypes
qer a818544df0
feat(sidebar): session emoji icon with searchable picker (#97)
* feat(sidebar): session emoji icon with searchable picker

A session's icon is the leading emoji cluster of its title (web-core
splitSessionEmoji/applySessionEmoji) — no icon field, every client renders
the title as-is, and writing reuses the existing rename path.

SessionRow grows a kebab-menu 'Set Emoji…' entry (the touch/keyboard path)
plus a quiet hover wash on the title's emoji; both open SessionEmojiPicker,
a Menu-shelled panel with a bare search row (zh/en keyword dataset, ~400
grouped entries), a Recently-used row (localStorage, cap 8), and
remove/random MenuItems. Inline rename edits only the title text and
re-applies the icon on commit.

DesignSystemView documents the pattern (§07 session row + no-emoji-icon's
user-content scope); the two apps' copies of the row/picker stay in sync.

* fix(sidebar): emoji picker review fixes

- Unchanged text in the inline rename now skips the PATCH entirely, so
  stored titles that don't use the normalized "emoji + space" shape
  (e.g. "🔥bug") are kept byte-for-byte instead of being rewritten.
- The picker's outside-click handler ignores the trigger element, so
  clicking the title emoji / kebab again toggles the picker closed
  instead of close-then-reopen.
- Enter during IME composition no longer picks the first search result
  (useImeComposition guard on the search input).
- Picker paddings/gaps moved onto --space-* tokens.

* fix(sidebar): emoji picker review fixes, round 2

- The picker's Escape listener now runs in the capture phase and consumes
  the key, so dismissing the picker can't reach the conversation pane's
  bubble-phase handler and interrupt / undo the active turn.
- The title emoji trigger is a real <button> (keyboard-focusable, Enter /
  Space operate it, --p-focus-ring on focus-visible).
- "Set Emoji…" invoked from the row's right-click menu anchors the picker
  to the menu's position (captured before closeMenu unmounts it) instead
  of jumping to the hidden kebab.
- Picker grid gap/padding moved onto --space-* (cell size keeps the 26px
  IconButton-sm footprint).
- web-core lib module banners trimmed to local concerns (the storage
  rationale lives in the PR description / design notes).

* fix(sidebar): emoji picker review fixes, round 3

- Picker Escape now registers on window capture: the topmost layer eats
  the key ahead of the side panel (document capture) and the conversation
  interrupt (document bubble), so one press dismisses exactly one layer.
- Menu gains a role prop ('menu' | 'dialog'); the picker uses 'dialog' —
  its content is a search input + button grid, not menuitems.
- Intl.Segmenter is constructed lazily so the web-core root import graph
  stays side-effect-free.
- Emoji cells use --text-lg; module/component comment banners trimmed.

* fix(sidebar): emoji picker review fixes, round 4

- Keydowns inside the picker panel stop at the panel, so global shortcuts
  (session search / new chat) can't fire behind the popover while typing.
- MenuItem gains a role prop; the picker's dialog footer uses 'button'.
- Re-picking the current emoji returns early — no PATCH even for stored
  titles whose prefix isn't in the normalized shape.
- Empty-state padding moved onto --space-*; comments trimmed further.

* fix(sidebar): emoji picker review fixes, round 5

- The row renders the title's stored suffix byte-for-byte (separator
  included) instead of synthesizing one space, matching what chat header /
  search / export show for non-normalized titles.
- Emoji cell drops a redundant line-height (grid centering owns the box).
- The emoji lib moves off the web-core root barrel into the ./lib subpath
  (same pattern as ./api), keeping the root import graph lean.

* fix(sidebar): drop the session emoji hover wash

* fix(sidebar): emoji picker review fixes, round 6

- The picker's Escape consults the search input's shared IME guard (exposed
  by the picker), so cancelling an IME candidate never closes the picker —
  including Safari's isComposing=false case.
- splitSessionEmoji degrades to "no icon" when Intl.Segmenter is missing
  instead of throwing during sidebar rendering (with a fallback test).

* fix(sidebar): emoji picker review fixes, round 7

- Emoji cells get a --p-focus-ring focus-visible state for keyboard users.
- lib/sessionEmoji header comment trimmed to the implementation invariant.

* fix(sidebar): edit the whole title in inline rename, emoji included

The emoji is an ordinary character of the title string — show it in the
input and let the user edit it like any other text. The icon is whatever
the committed title parses to, so the composition gymnastics (rest-only
editing, re-apply on commit, typed-emoji-wins) all go away.

* fix(sidebar): corner-aware emoji picker anchoring

The panel now pops from the corner nearest the trigger: left-side
triggers (the title emoji, the right-click menu's rect) align left and
pop from top-left as before, while the kebab path right-aligns to the
button and pops from top-right — the same pop language as the kebab's
own dropdown. Upward flips swap in the matching bottom corner.

* fix(sidebar): pointer-anchored emoji picker

The panel now anchors to the click point itself, context-menu style:
opens downward from the pointer, flips upward when space below runs out,
and after horizontal clamping the transform origin is recomputed to the
click's position inside the panel, so the pop always grows out of the
pointer. Keyboard-triggered opens (clientX/Y = 0) keep the previous
trigger-rect anchoring.

* fix(sidebar): trim the pointer-anchoring comment to the invariant

* fix(sidebar): drive picker metrics from one --ep-cell variable

The grid columns now size to the cell (IconButton-sm footprint), the input
and scroll heights derive from it, and the panel width follows the content
— no hard-coded dimensions left in the picker.
2026-07-24 13:51:29 +08:00
..
session-emoji-slot.html feat(sidebar): session emoji icon with searchable picker (#97) 2026-07-24 13:51:29 +08:00
task-notification-ui.html feat(chat): mark goal-continuation turns with a provenance line (#96) 2026-07-24 03:14:31 +08:00