feat(ui): add interface to manage message swipe history (#5304)

* feat(ui): add popup to jump to a specific swipe

Adds a new "Jump to swipe history" button to message actions and makes
the swipe counter clickable on the latest message. This opens a
searchable popup allowing users to quickly find and jump to a
specific alternate swipe without having to click through them
sequentially.

- Adds a searchable swipe picker popup menu
- Makes the swipe counter interactive when multiple swipes exist
- Adds a dedicated swipe picker button to message controls

* fix(ui): hide swipe picker when there are no swipes

Ensures the newly added swipe picker button is only shown when a
message has multiple swipes available. It explicitly hides the
button for non-swipeable messages or messages with a single swipe.

* feat(ui): redesign swipe picker with direct id input

Replace text-based search with a numeric input for direct swipe navigation.
Update popup layout with a sticky header and improved scrolling behavior.
Sync input value with the currently selected swipe in the list.
Refactor styling to align with chat selection components.

* feat(ui): allow branching from specific swipes via picker

- Enable swipe picker for historical messages to inspect alternate swipes
- Add branch button to picker entries to create new chats from specific swipes
- Update saveChat and createBranch to accept chat snapshots
- Restrict swipe jumping to the active message only

* refactor(logic): consolidate swipe sync logic and simplify helpers

Update `syncSwipeToMes` to accept a target message object, enabling its
use in the bookmarks module and removing the duplicate
`applySwipeToSnapshot` function.

Also simplify `canOpenSwipePickerForMessage` and
`canJumpToSwipeForMessage` signatures by removing the redundant message
parameter.

* refactor(a11y): support dynamic roles via classes

Introduce a managed role system in the accessibility script to handle
elements that dynamically gain or lose interactive states. The mutation
observer now watches for class attribute changes and automatically
applies or clears roles (e.g., `role="button"`) using active selectors.

Updated the swipe counter to rely on this centralized system by toggling
an `.interactable` class instead of manually modifying tabindex and role
attributes. Removed the redundant 'Enter' keydown handler for the swipe
counter to prevent duplicate trigger events.

* fix(ui): compute missing token counts in swipe picker

Update renderSwipeList to asynchronously calculate token counts when
missing from swipe metadata. Introduce SWIPE_SOURCE.SWIPE_PICKER to
correctly identify swipes triggered from the picker and bypass
generation checks.

* feat(ui): enable deleting specific swipes via swipe picker

- Adds a delete button to swipe picker entries, allowing removal of specific message versions.
- Refactors deletion logic to handle removing non-current swipes without triggering animations and correctly updates indices.
- Includes confirmation dialogs and improves input focus behavior.

* refactor:Delete process inline to button click processor

* feat: universal swipe inspection and picker improvements

- Permit opening the swipe browser on any chat entry to review past generations.
- Parallelize the retrieval of token statistics to speed up list rendering.
- Format message metrics (length and tokens) into a single, concise string.
- Update the `getBranchChatSnapshot` API to accept an options object.
- Register swipe list items as interactable elements for keyboard control.
- Apply styling to prevent text highlighting on picker entries.

* fix:remove unused CSS

* fix: fix disabled styling for swipe delete button

Remove tooltips and prevent hover animations or glow effects when the
delete button is disabled in the swipe picker. Update CSS to enforce
default cursor and fixed opacity on hover for the disabled state.

* remove: Unused CSS

* Extract swipe-picker.js module

* Revert to manual ARIA role management

* Avoid scrollIntoView and scroll on open

* Fix keyboard interaction in past chats menu

* Fix a11y attribute

* fix: call refreshSwipeButtons when deleting not selected swipe

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
awaae
2026-03-26 09:28:48 +09:00
committed by GitHub
parent 94139f465e
commit b04c974407
8 changed files with 590 additions and 40 deletions
+1
View File
@@ -7365,6 +7365,7 @@
<div title="Toggle media display style" class="mes_button mes_media_gallery fa-solid fa-photo-film" data-i18n="[title]Toggle media display style"></div>
<div title="Toggle media display style" class="mes_button mes_media_list fa-solid fa-table-cells-large" data-i18n="[title]Toggle media display style"></div>
<div title="Embed file or image" class="mes_button mes_embed fa-solid fa-paperclip" data-i18n="[title]Embed file or image"></div>
<div title="Jump to swipe history" class="mes_button mes_swipe_picker fa-solid fa-bookmark" data-i18n="[title]Jump to swipe history" style="display: none;"></div>
<div title="Create checkpoint" class="mes_button mes_create_bookmark fa-regular fa-solid fa-flag-checkered" data-i18n="[title]Create checkpoint"></div>
<div title="Create branch" class="mes_button mes_create_branch fa-regular fa-code-branch" data-i18n="[title]Create Branch"></div>
<div title="Copy" class="mes_button mes_copy fa-solid fa-copy " data-i18n="[title]Copy"></div>