diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx index e19e6f430f0..3c3652e38f3 100644 --- a/packages/app/src/pages/layout/sidebar-project.tsx +++ b/packages/app/src/pages/layout/sidebar-project.tsx @@ -1,4 +1,5 @@ -import { createEffect, createMemo, createSignal, For, Show, type Accessor, type JSX } from "solid-js" +import { createEffect, createMemo, For, Show, type Accessor, type JSX } from "solid-js" +import { createStore } from "solid-js/store" import { base64Encode } from "@opencode-ai/util/encode" import { Button } from "@opencode-ai/ui/button" import { ContextMenu } from "@opencode-ai/ui/context-menu" @@ -7,7 +8,7 @@ import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { Tooltip } from "@opencode-ai/ui/tooltip" import { createSortable } from "@thisbeyond/solid-dnd" -import { type LocalProject } from "@/context/layout" +import { useLayout, type LocalProject } from "@/context/layout" import { useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" import { useNotification } from "@/context/notification" @@ -60,6 +61,7 @@ const ProjectTile = (props: { selected: Accessor active: Accessor overlay: Accessor + suppressHover: Accessor dirs: Accessor onProjectMouseEnter: (worktree: string, event: MouseEvent) => void onProjectMouseLeave: (worktree: string) => void @@ -71,9 +73,11 @@ const ProjectTile = (props: { closeProject: (directory: string) => void setMenu: (value: boolean) => void setOpen: (value: boolean) => void + setSuppressHover: (value: boolean) => void language: ReturnType }): JSX.Element => { const notification = useNotification() + const layout = useLayout() const unseenCount = createMemo(() => props.dirs().reduce((total, directory) => total + notification.project.unseenCount(directory), 0), ) @@ -107,17 +111,28 @@ const ProjectTile = (props: { }} onMouseEnter={(event: MouseEvent) => { if (!props.overlay()) return + if (props.suppressHover()) return props.onProjectMouseEnter(props.project.worktree, event) }} onMouseLeave={() => { + if (props.suppressHover()) props.setSuppressHover(false) if (!props.overlay()) return props.onProjectMouseLeave(props.project.worktree) }} onFocus={() => { if (!props.overlay()) return + if (props.suppressHover()) return props.onProjectFocus(props.project.worktree) }} - onClick={() => props.navigateToProject(props.project.worktree)} + onClick={() => { + if (props.selected()) { + props.setSuppressHover(true) + layout.sidebar.toggle() + return + } + props.setSuppressHover(false) + props.navigateToProject(props.project.worktree) + }} onBlur={() => props.setOpen(false)} > @@ -278,16 +293,19 @@ export const SortableProject = (props: { const workspaces = createMemo(() => props.ctx.workspaceIds(props.project).slice(0, 2)) const workspaceEnabled = createMemo(() => props.ctx.workspacesEnabled(props.project)) const dirs = createMemo(() => props.ctx.workspaceIds(props.project)) - const [open, setOpen] = createSignal(false) - const [menu, setMenu] = createSignal(false) + const [state, setState] = createStore({ + open: false, + menu: false, + suppressHover: false, + }) const preview = createMemo(() => !props.mobile && props.ctx.sidebarOpened()) const overlay = createMemo(() => !props.mobile && !props.ctx.sidebarOpened()) const active = createMemo(() => projectTileActive({ - menu: menu(), + menu: state.menu, preview: preview(), - open: open(), + open: state.open, overlay: overlay(), hoverProject: props.ctx.hoverProject(), worktree: props.project.worktree, @@ -296,8 +314,14 @@ export const SortableProject = (props: { createEffect(() => { if (preview()) return - if (!open()) return - setOpen(false) + if (!state.open) return + setState("open", false) + }) + + createEffect(() => { + if (!selected()) return + if (!state.open) return + setState("open", false) }) const label = (directory: string) => { @@ -328,6 +352,7 @@ export const SortableProject = (props: { selected={selected} active={active} overlay={overlay} + suppressHover={() => state.suppressHover} dirs={dirs} onProjectMouseEnter={props.ctx.onProjectMouseEnter} onProjectMouseLeave={props.ctx.onProjectMouseLeave} @@ -337,8 +362,9 @@ export const SortableProject = (props: { toggleProjectWorkspaces={props.ctx.toggleProjectWorkspaces} workspacesEnabled={props.ctx.workspacesEnabled} closeProject={props.ctx.closeProject} - setMenu={setMenu} - setOpen={setOpen} + setMenu={(value) => setState("menu", value)} + setOpen={(value) => setState("open", value)} + setSuppressHover={(value) => setState("suppressHover", value)} language={language} /> ) @@ -346,17 +372,18 @@ export const SortableProject = (props: { return ( // @ts-ignore
- + { - if (menu()) return - setOpen(value) + if (state.menu) return + if (value && state.suppressHover) return + setState("open", value) if (value) props.ctx.setHoverSession(undefined) }} > @@ -371,7 +398,7 @@ export const SortableProject = (props: { projectChildren={projectChildren} workspaceSessions={workspaceSessions} workspaceChildren={workspaceChildren} - setOpen={setOpen} + setOpen={(value) => setState("open", value)} ctx={props.ctx} language={language} />