diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index e813f9f10b08..a2032e703813 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -10,6 +10,7 @@ import { startTransition, Switch, untrack, + type JSX, } from "solid-js" import { createStore } from "solid-js/store" import { useLocation, useMatch, useNavigate, useParams } from "@solidjs/router" @@ -35,11 +36,22 @@ import { displayName, getProjectAvatarSource, projectForSession } from "@/pages/ import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state" import { makeEventListener } from "@solid-primitives/event-listener" import { createResizeObserver } from "@solid-primitives/resize-observer" +import { + DragDropProvider, + DragDropSensors, + DragOverlay, + SortableProvider, + closestCenter, + createSortable, +} from "@thisbeyond/solid-dnd" +import type { DragEvent } from "@thisbeyond/solid-dnd" import { readSessionTabsRemovedDetail, SESSION_TABS_REMOVED_EVENT } from "@/components/titlebar-session-events" import { useGlobal } from "@/context/global" import { decode64 } from "@/utils/base64" import { ServerConnection, useServer } from "@/context/server" -import { tabHref, useTabs, type Tab } from "@/context/tabs" +import { tabHref, tabKey, useTabs, type Tab } from "@/context/tabs" +import { getDraggableId } from "@/utils/solid-dnd" +import { getTabReorderIndex } from "@/pages/session/helpers" import "./titlebar.css" type TauriDesktopWindow = { @@ -409,12 +421,31 @@ export function Titlebar(props: { update?: TitlebarUpdate }) { }) const [tabsAreOverflowing, setTabsAreOverflowing] = createSignal(false) + const [tabDrag, setTabDrag] = createStore({ activeDraggable: undefined as string | undefined }) let tabScrollRef!: HTMLDivElement function refreshTabsAreOverflowing() { setTabsAreOverflowing(tabScrollRef.scrollWidth > tabScrollRef.clientWidth) } + const tabIds = createMemo(() => tabsStore.map(tabKey)) + const handleTabDragStart = (event: unknown) => setTabDrag("activeDraggable", getDraggableId(event)) + const handleTabDragEnd = () => setTabDrag("activeDraggable", undefined) + const handleTabDragOver = (event: DragEvent) => { + const { draggable, droppable } = event + if (!draggable || !droppable) return + const next = [...tabIds()] + const toIndex = getTabReorderIndex(next, draggable.id.toString(), droppable.id.toString()) + if (toIndex === undefined) return + next.splice(toIndex, 0, ...next.splice(next.indexOf(draggable.id.toString()), 1)) + tabsStoreActions.reorder(next) + } + const draggedTab = createMemo(() => { + const key = tabDrag.activeDraggable + if (!key) return + return tabsStore.find((tab) => tabKey(tab) === key) + }) + return (
-