summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages/layout
diff options
context:
space:
mode:
authorOpeOginni <[email protected]>2026-02-26 18:00:11 +0100
committerGitHub <[email protected]>2026-02-26 11:00:11 -0600
commit5745ee87ba9847e32c07fd364c52a6fad23bb55e (patch)
tree6d0f803653c276411c6c432638ec4e20d8fe001f /packages/app/src/pages/layout
parent08f056d412e424eb48842dc99d0955be4e9874ae (diff)
downloadopencode-5745ee87ba9847e32c07fd364c52a6fad23bb55e.tar.gz
opencode-5745ee87ba9847e32c07fd364c52a6fad23bb55e.zip
refactor(desktop): enhance project tile interaction with suppress hover functionality (#15214)
Diffstat (limited to 'packages/app/src/pages/layout')
-rw-r--r--packages/app/src/pages/layout/sidebar-project.tsx59
1 files changed, 43 insertions, 16 deletions
diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx
index e19e6f430..3c3652e38 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<boolean>
active: Accessor<boolean>
overlay: Accessor<boolean>
+ suppressHover: Accessor<boolean>
dirs: Accessor<string[]>
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<typeof useLanguage>
}): 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)}
>
<ProjectIcon project={props.project} notify />
@@ -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
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
- <Show when={preview()} fallback={tile()}>
+ <Show when={preview() && !selected()} fallback={tile()}>
<HoverCard
- open={open() && !menu()}
+ open={!state.suppressHover && state.open && !state.menu}
openDelay={0}
closeDelay={0}
placement="right-start"
gutter={6}
trigger={tile()}
onOpenChange={(value) => {
- 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}
/>