diff options
| author | Brendan Allan <[email protected]> | 2026-03-23 16:58:20 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-23 08:58:20 +0000 |
| commit | 0a7dfc03ee1dbc29d65605e8ca37ed9d137bd2ec (patch) | |
| tree | d3ab35650170465dd4e892290ef908d1c7de7e34 /packages | |
| parent | 4c27e7fc6499dee385e718d523c4f0612bd8a063 (diff) | |
| download | opencode-0a7dfc03ee1dbc29d65605e8ca37ed9d137bd2ec.tar.gz opencode-0a7dfc03ee1dbc29d65605e8ca37ed9d137bd2ec.zip | |
fix(app): lift up project hover state to layout (#18732)
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/app/src/pages/layout.tsx | 4 | ||||
| -rw-r--r-- | packages/app/src/pages/layout/sidebar-project.tsx | 29 |
2 files changed, 12 insertions, 21 deletions
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 88572503f..d8b073258 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -1989,6 +1989,10 @@ export default function Layout(props: ParentProps) { onProjectMouseEnter: (worktree, event) => aim.enter(worktree, event), onProjectMouseLeave: (worktree) => aim.leave(worktree), onProjectFocus: (worktree) => aim.activate(worktree), + onHoverOpenChanged: (worktree, hoverOpen) => { + if (!hoverOpen && state.hoverProject && state.hoverProject !== worktree) return + setState("hoverProject", hoverOpen ? worktree : undefined) + }, navigateToProject, openSidebar: () => layout.sidebar.open(), closeProject, diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx index 99f1edb74..aff0645dd 100644 --- a/packages/app/src/pages/layout/sidebar-project.tsx +++ b/packages/app/src/pages/layout/sidebar-project.tsx @@ -23,6 +23,7 @@ export type ProjectSidebarContext = { onProjectMouseEnter: (worktree: string, event: MouseEvent) => void onProjectMouseLeave: (worktree: string) => void onProjectFocus: (worktree: string) => void + onHoverOpenChanged: (worktree: string, hovered: boolean) => void navigateToProject: (directory: string) => void openSidebar: () => void closeProject: (directory: string) => void @@ -197,7 +198,6 @@ const ProjectPreviewPanel = (props: { projectChildren: Accessor<Map<string, string[]>> workspaceSessions: (directory: string) => ReturnType<typeof sortedRootSessions> workspaceChildren: (directory: string) => Map<string, string[]> - setOpen: (value: boolean) => void ctx: ProjectSidebarContext language: ReturnType<typeof useLanguage> }): JSX.Element => ( @@ -264,7 +264,7 @@ const ProjectPreviewPanel = (props: { class="flex w-full text-left justify-start text-text-base px-2 hover:bg-transparent active:bg-transparent" onClick={() => { props.ctx.openSidebar() - props.setOpen(false) + props.ctx.onHoverOpenChanged(props.project.worktree, false) if (props.selected()) return props.ctx.navigateToProject(props.project.worktree) }} @@ -289,28 +289,16 @@ export const SortableProject = (props: { const workspaceEnabled = createMemo(() => props.ctx.workspacesEnabled(props.project)) const dirs = createMemo(() => props.ctx.workspaceIds(props.project)) const [state, setState] = createStore({ - open: false, menu: false, suppressHover: false, }) + const isHoverProject = () => props.ctx.hoverProject() === props.project.worktree const preview = createMemo(() => !props.mobile && props.ctx.sidebarOpened()) const overlay = createMemo(() => !props.mobile && !props.ctx.sidebarOpened()) - const active = createMemo( - () => state.menu || (preview() ? state.open : overlay() && props.ctx.hoverProject() === props.project.worktree), - ) + const active = createMemo(() => state.menu || (preview() ? isHoverProject() : overlay() && isHoverProject())) - createEffect(() => { - if (preview()) return - if (!state.open) return - setState("open", false) - }) - - createEffect(() => { - if (!selected()) return - if (!state.open) return - setState("open", false) - }) + const hoverOpen = () => isHoverProject() && preview() && !selected() && !state.menu const label = (directory: string) => { const [data] = globalSync.child(directory, { bootstrap: false }) @@ -351,7 +339,7 @@ export const SortableProject = (props: { workspacesEnabled={props.ctx.workspacesEnabled} closeProject={props.ctx.closeProject} setMenu={(value) => setState("menu", value)} - setOpen={(value) => setState("open", value)} + setOpen={(value) => props.ctx.onHoverOpenChanged(props.project.worktree, value)} setSuppressHover={(value) => setState("suppressHover", value)} language={language} /> @@ -362,7 +350,7 @@ export const SortableProject = (props: { <div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}> <Show when={preview() && !selected()} fallback={tile()}> <HoverCard - open={!state.suppressHover && state.open && !state.menu} + open={!state.suppressHover && hoverOpen() && !state.menu} openDelay={0} closeDelay={0} placement="right-start" @@ -371,7 +359,7 @@ export const SortableProject = (props: { onOpenChange={(value) => { if (state.menu) return if (value && state.suppressHover) return - setState("open", value) + props.ctx.onHoverOpenChanged(props.project.worktree, value) if (value) props.ctx.setHoverSession(undefined) }} > @@ -386,7 +374,6 @@ export const SortableProject = (props: { projectChildren={projectChildren} workspaceSessions={workspaceSessions} workspaceChildren={workspaceChildren} - setOpen={(value) => setState("open", value)} ctx={props.ctx} language={language} /> |
