diff options
| author | Adam <[email protected]> | 2026-02-04 13:25:55 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-02-04 19:25:55 +0000 |
| commit | 9436cb575bf64ba5867511c998d1e1c51782173c (patch) | |
| tree | 4856b18f71241f0f559470e5be0a6566485a0da1 /packages/app/src/pages/layout.tsx | |
| parent | d1686661c0d42edb8e9e6576fb12cfdfc4ee2142 (diff) | |
| download | opencode-9436cb575bf64ba5867511c998d1e1c51782173c.tar.gz opencode-9436cb575bf64ba5867511c998d1e1c51782173c.zip | |
fix(app): safety triangle for sidebar hover (#12179)
Diffstat (limited to 'packages/app/src/pages/layout.tsx')
| -rw-r--r-- | packages/app/src/pages/layout.tsx | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 1c5edbf2b..4ee54d306 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -58,6 +58,7 @@ import { usePermission } from "@/context/permission" import { Binary } from "@opencode-ai/util/binary" import { retry } from "@opencode-ai/util/retry" import { playSound, soundSrc } from "@/utils/sound" +import { createAim } from "@/utils/aim" import { Worktree as WorktreeState } from "@/utils/worktree" import { agentColor } from "@/utils/agent" @@ -146,9 +147,20 @@ export default function Layout(props: ParentProps) { const navLeave = { current: undefined as number | undefined } + const aim = createAim({ + enabled: () => !layout.sidebar.opened(), + active: () => state.hoverProject, + el: () => state.nav, + onActivate: (directory) => { + globalSync.child(directory) + setState("hoverProject", directory) + setState("hoverSession", undefined) + }, + }) + onCleanup(() => { - if (navLeave.current === undefined) return - clearTimeout(navLeave.current) + if (navLeave.current !== undefined) clearTimeout(navLeave.current) + aim.reset() }) const sidebarHovering = createMemo(() => !layout.sidebar.opened() && state.hoverProject !== undefined) @@ -162,15 +174,22 @@ export default function Layout(props: ParentProps) { createEffect(() => { if (!layout.sidebar.opened()) return + aim.reset() setState("hoverProject", undefined) }) + createEffect(() => { + if (state.hoverProject !== undefined) return + aim.reset() + }) + createEffect( on( () => ({ dir: params.dir, id: params.id }), () => { if (layout.sidebar.opened()) return if (!state.hoverProject) return + aim.reset() setState("hoverSession", undefined) setState("hoverProject", undefined) }, @@ -2311,17 +2330,17 @@ export default function Layout(props: ParentProps) { !selected() && !active(), "bg-surface-base-hover border border-border-weak-base": !selected() && active(), }} - onMouseEnter={() => { + onMouseEnter={(event: MouseEvent) => { + if (!overlay()) return + aim.enter(props.project.worktree, event) + }} + onMouseLeave={() => { if (!overlay()) return - globalSync.child(props.project.worktree) - setState("hoverProject", props.project.worktree) - setState("hoverSession", undefined) + aim.leave(props.project.worktree) }} onFocus={() => { if (!overlay()) return - globalSync.child(props.project.worktree) - setState("hoverProject", props.project.worktree) - setState("hoverSession", undefined) + aim.activate(props.project.worktree) }} onClick={() => navigateToProject(props.project.worktree)} onBlur={() => setOpen(false)} @@ -2806,7 +2825,7 @@ export default function Layout(props: ParentProps) { return ( <div class="flex h-full w-full overflow-hidden"> - <div class="w-16 shrink-0 bg-background-base flex flex-col items-center overflow-hidden"> + <div class="w-16 shrink-0 bg-background-base flex flex-col items-center overflow-hidden" onMouseMove={aim.move}> <div class="flex-1 min-h-0 w-full"> <DragDropProvider onDragStart={handleDragStart} @@ -2901,6 +2920,7 @@ export default function Layout(props: ParentProps) { navLeave.current = undefined }} onMouseLeave={() => { + aim.reset() if (!sidebarHovering()) return if (navLeave.current !== undefined) clearTimeout(navLeave.current) @@ -2916,7 +2936,7 @@ export default function Layout(props: ParentProps) { </div> <Show when={!layout.sidebar.opened() ? hoverProjectData() : undefined} keyed> {(project) => ( - <div class="absolute inset-y-0 left-16 z-50 flex"> + <div class="absolute inset-y-0 left-16 z-50 flex" onMouseEnter={aim.reset}> <SidebarPanel project={project} /> </div> )} |
