fix(tui): persist tab reorder once per drag (#39942)
This commit is contained in:
parent
47c6840752
commit
6a543791b6
1 changed files with 21 additions and 2 deletions
|
|
@ -6,6 +6,7 @@ import { useSessionTabs } from "../context/session-tabs"
|
||||||
import { useTheme, useThemes } from "../context/theme"
|
import { useTheme, useThemes } from "../context/theme"
|
||||||
import {
|
import {
|
||||||
adaptiveSessionTabLayout,
|
adaptiveSessionTabLayout,
|
||||||
|
moveSessionTab,
|
||||||
NEW_SESSION_TAB_TITLE,
|
NEW_SESSION_TAB_TITLE,
|
||||||
sessionTabComplete,
|
sessionTabComplete,
|
||||||
seedSessionTabMotion,
|
seedSessionTabMotion,
|
||||||
|
|
@ -48,6 +49,10 @@ export function SessionTabs(props: { controller?: SessionTabsController; animati
|
||||||
const animations = () => props.animations ?? config.animations ?? true
|
const animations = () => props.animations ?? config.animations ?? true
|
||||||
const [hovered, setHovered] = createSignal<string>()
|
const [hovered, setHovered] = createSignal<string>()
|
||||||
const [dragging, setDragging] = createSignal<string>()
|
const [dragging, setDragging] = createSignal<string>()
|
||||||
|
// A drag reorders a local preview and persists one move on release instead of writing
|
||||||
|
// per slot crossing; the preview holds after release until the store reflects the move,
|
||||||
|
// so the strip never flashes the pre-drag order while the write is in flight.
|
||||||
|
const [preview, setPreview] = createSignal<{ sessionID: string; index: number }>()
|
||||||
let strip: { screenX: number } | undefined
|
let strip: { screenX: number } | undefined
|
||||||
const hueStep = () => (mode() === "light" ? 800 : 200)
|
const hueStep = () => (mode() === "light" ? 800 : 200)
|
||||||
const accent = () => theme.hue.accent[hueStep()]
|
const accent = () => theme.hue.accent[hueStep()]
|
||||||
|
|
@ -55,7 +60,18 @@ export function SessionTabs(props: { controller?: SessionTabsController; animati
|
||||||
const idleNumber = () => tint(theme.text.subdued, theme.background.default, 0.35)
|
const idleNumber = () => tint(theme.text.subdued, theme.background.default, 0.35)
|
||||||
const newTab = () => tabs.newTab?.() ?? false
|
const newTab = () => tabs.newTab?.() ?? false
|
||||||
const activeID = createMemo(() => (newTab() ? NEW_SESSION_TAB.sessionID : tabs.current()))
|
const activeID = createMemo(() => (newTab() ? NEW_SESSION_TAB.sessionID : tabs.current()))
|
||||||
const items = createMemo(() => (newTab() ? [...tabs.tabs(), NEW_SESSION_TAB] : tabs.tabs()))
|
const ordered = createMemo(() => {
|
||||||
|
const pending = preview()
|
||||||
|
if (!pending) return tabs.tabs()
|
||||||
|
return moveSessionTab(tabs.tabs(), pending.sessionID, pending.index)
|
||||||
|
})
|
||||||
|
const items = createMemo(() => (newTab() ? [...ordered(), NEW_SESSION_TAB] : ordered()))
|
||||||
|
createEffect(() => {
|
||||||
|
const pending = preview()
|
||||||
|
if (!pending || dragging()) return
|
||||||
|
const index = tabs.tabs().findIndex((tab) => tab.sessionID === pending.sessionID)
|
||||||
|
if (index === -1 || index === Math.min(pending.index, tabs.tabs().length - 1)) setPreview(undefined)
|
||||||
|
})
|
||||||
const layout = createMemo((previous: ReturnType<typeof adaptiveSessionTabLayout> | undefined) =>
|
const layout = createMemo((previous: ReturnType<typeof adaptiveSessionTabLayout> | undefined) =>
|
||||||
adaptiveSessionTabLayout(items(), activeID(), dimensions().width, previous?.start),
|
adaptiveSessionTabLayout(items(), activeID(), dimensions().width, previous?.start),
|
||||||
)
|
)
|
||||||
|
|
@ -279,6 +295,8 @@ export function SessionTabs(props: { controller?: SessionTabsController; animati
|
||||||
// keeping sloppy clicks indistinguishable from clean ones.
|
// keeping sloppy clicks indistinguishable from clean ones.
|
||||||
const release = () => {
|
const release = () => {
|
||||||
setDragging(undefined)
|
setDragging(undefined)
|
||||||
|
const pending = preview()
|
||||||
|
if (pending?.sessionID === tab.sessionID) tabs.move(pending.sessionID, pending.index)
|
||||||
if (tab === NEW_SESSION_TAB) return
|
if (tab === NEW_SESSION_TAB) return
|
||||||
tabs.select(tab.sessionID)
|
tabs.select(tab.sessionID)
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +313,8 @@ export function SessionTabs(props: { controller?: SessionTabsController; animati
|
||||||
onMouseDrag={(event) => {
|
onMouseDrag={(event) => {
|
||||||
if (tab === NEW_SESSION_TAB) return
|
if (tab === NEW_SESSION_TAB) return
|
||||||
const slot = slotAt(event.x)
|
const slot = slotAt(event.x)
|
||||||
if (slot !== undefined && slot !== tabNumber() - 1) tabs.move(tab.sessionID, slot)
|
if (slot !== undefined && slot !== tabNumber() - 1)
|
||||||
|
setPreview({ sessionID: tab.sessionID, index: slot })
|
||||||
}}
|
}}
|
||||||
onMouseDragEnd={release}
|
onMouseDragEnd={release}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue