diff options
| author | Adam <[email protected]> | 2026-01-15 07:00:53 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-15 07:29:13 -0600 |
| commit | 564d3edfac6e3cc872d35d7b2d1e8bc1ea4b84bd (patch) | |
| tree | 1b012bf5ba4ce00b943c234034d1a4025d7eb0f5 | |
| parent | 679270d9e0731c2b3e2c059d83907cb4086d90e2 (diff) | |
| download | opencode-564d3edfac6e3cc872d35d7b2d1e8bc1ea4b84bd.tar.gz opencode-564d3edfac6e3cc872d35d7b2d1e8bc1ea4b84bd.zip | |
fix(app): new layout issues
| -rw-r--r-- | packages/app/src/context/layout.tsx | 38 | ||||
| -rw-r--r-- | packages/app/src/pages/layout.tsx | 98 | ||||
| -rw-r--r-- | packages/desktop/src-tauri/src/lib.rs | 5 | ||||
| -rw-r--r-- | packages/desktop/src/index.tsx | 3 |
4 files changed, 113 insertions, 31 deletions
diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index ba332be7b..a49e891bf 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -47,13 +47,34 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( const globalSdk = useGlobalSDK() const globalSync = useGlobalSync() const server = useServer() + + const isRecord = (value: unknown): value is Record<string, unknown> => + typeof value === "object" && value !== null && !Array.isArray(value) + + const migrate = (value: unknown) => { + if (!isRecord(value)) return value + const sidebar = value.sidebar + if (!isRecord(sidebar)) return value + if (typeof sidebar.workspaces !== "boolean") return value + return { + ...value, + sidebar: { + ...sidebar, + workspaces: {}, + workspacesDefault: sidebar.workspaces, + }, + } + } + + const target = Persist.global("layout", ["layout.v6"]) const [store, setStore, _, ready] = persisted( - Persist.global("layout", ["layout.v6"]), + { ...target, migrate }, createStore({ sidebar: { opened: false, width: 280, - workspaces: false, + workspaces: {} as Record<string, boolean>, + workspacesDefault: false, }, terminal: { height: 280, @@ -305,12 +326,15 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( resize(width: number) { setStore("sidebar", "width", width) }, - workspaces: createMemo(() => store.sidebar.workspaces ?? false), - setWorkspaces(value: boolean) { - setStore("sidebar", "workspaces", value) + workspaces(directory: string) { + return createMemo(() => store.sidebar.workspaces[directory] ?? store.sidebar.workspacesDefault ?? false) + }, + setWorkspaces(directory: string, value: boolean) { + setStore("sidebar", "workspaces", directory, value) }, - toggleWorkspaces() { - setStore("sidebar", "workspaces", (x) => !x) + toggleWorkspaces(directory: string) { + const current = store.sidebar.workspaces[directory] ?? store.sidebar.workspacesDefault ?? false + setStore("sidebar", "workspaces", directory, !current) }, }, terminal: { diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index cc5396656..b2c617bfa 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -271,6 +271,12 @@ export default function Layout(props: ParentProps) { return layout.projects.list().find((p) => p.worktree === directory || p.sandboxes?.includes(directory)) }) + const workspaceSetting = createMemo(() => { + const project = currentProject() + if (!project) return false + return layout.sidebar.workspaces(project.worktree)() + }) + createEffect(() => { const project = currentProject() if (!project) return @@ -306,7 +312,16 @@ export default function Layout(props: ParentProps) { return sessions.filter((s) => !s.parentID) } - const currentSessions = createMemo(() => projectSessions(currentProject())) + const currentSessions = createMemo(() => { + const project = currentProject() + if (!project) return [] as Session[] + if (workspaceSetting()) return projectSessions(project) + const [projectStore] = globalSync.child(project.worktree) + return projectStore.session + .filter((session) => session.directory === projectStore.path.directory) + .filter((session) => !session.parentID) + .toSorted(sortSessions) + }) type PrefetchQueue = { inflight: Set<string> @@ -730,6 +745,21 @@ export default function Layout(props: ParentProps) { }) createEffect(() => { + const project = currentProject() + if (!project) return + + if (workspaceSetting()) { + const dirs = [project.worktree, ...(project.sandboxes ?? [])] + for (const directory of dirs) { + globalSync.project.loadSessions(directory) + } + return + } + + globalSync.project.loadSessions(project.worktree) + }) + + createEffect(() => { if (isLargeViewport()) { const sidebarWidth = layout.sidebar.opened() ? layout.sidebar.width() : 64 document.documentElement.style.setProperty("--dialog-left-margin", `${sidebarWidth}px`) @@ -943,6 +973,7 @@ export default function Layout(props: ParentProps) { }) const workspaces = createMemo(() => workspaceIds(props.project).slice(0, 2)) + const workspaceEnabled = createMemo(() => layout.sidebar.workspaces(props.project.worktree)()) const label = (directory: string) => { const [data] = globalSync.child(directory) const kind = directory === props.project.worktree ? "local" : "sandbox" @@ -959,6 +990,15 @@ export default function Layout(props: ParentProps) { .slice(0, 2) } + const projectSessions = () => { + const [data] = globalSync.child(props.project.worktree) + return data.session + .filter((session) => session.directory === data.path.directory) + .filter((session) => !session.parentID) + .toSorted(sortSessions) + .slice(0, 2) + } + const trigger = ( <button type="button" @@ -980,23 +1020,39 @@ export default function Layout(props: ParentProps) { <div class="-m-3 flex flex-col w-72"> <div class="px-3 py-2 text-12-medium text-text-strong">Recent sessions</div> <div class="px-2 pb-2 flex flex-col gap-2"> - <For each={workspaces()}> - {(directory) => ( - <div class="flex flex-col gap-1"> - <div class="px-2 py-0.5 flex items-center gap-1 min-w-0"> - <div class="shrink-0 size-6 flex items-center justify-center"> - <Icon name="branch" size="small" class="text-icon-base" /> + <Show + when={workspaceEnabled()} + fallback={ + <For each={projectSessions()}> + {(session) => ( + <SessionItem + session={session} + slug={base64Encode(props.project.worktree)} + dense + mobile={props.mobile} + /> + )} + </For> + } + > + <For each={workspaces()}> + {(directory) => ( + <div class="flex flex-col gap-1"> + <div class="px-2 py-0.5 flex items-center gap-1 min-w-0"> + <div class="shrink-0 size-6 flex items-center justify-center"> + <Icon name="branch" size="small" class="text-icon-base" /> + </div> + <span class="truncate text-14-medium text-text-strong">{label(directory)}</span> </div> - <span class="truncate text-14-medium text-text-strong">{label(directory)}</span> + <For each={sessions(directory)}> + {(session) => ( + <SessionItem session={session} slug={base64Encode(directory)} dense mobile={props.mobile} /> + )} + </For> </div> - <For each={sessions(directory)}> - {(session) => ( - <SessionItem session={session} slug={base64Encode(directory)} dense mobile={props.mobile} /> - )} - </For> - </div> - )} - </For> + )} + </For> + </Show> </div> <div class="px-2 py-2 border-t border-border-weak-base"> <Button @@ -1068,7 +1124,7 @@ export default function Layout(props: ParentProps) { return `${kind} : ${name}` }) const open = createMemo(() => store.workspaceExpanded[props.directory] ?? true) - const hasMore = createMemo(() => local() && workspaceStore.session.length >= workspaceStore.limit) + const hasMore = createMemo(() => local() && workspaceStore.sessionTotal > workspaceStore.session.length) const loadMore = async () => { if (!local()) return setWorkspaceStore("limit", (limit) => limit + 5) @@ -1157,7 +1213,7 @@ export default function Layout(props: ParentProps) { .filter((session) => !session.parentID) .toSorted(sortSessions), ) - const hasMore = createMemo(() => workspaceStore.session.length >= workspaceStore.limit) + const hasMore = createMemo(() => workspaceStore.sessionTotal > workspaceStore.session.length) const loadMore = async () => { setWorkspaceStore("limit", (limit) => limit + 5) await globalSync.project.loadSessions(props.project.worktree) @@ -1324,9 +1380,9 @@ export default function Layout(props: ParentProps) { <DropdownMenu.ItemLabel>Close project</DropdownMenu.ItemLabel> </DropdownMenu.Item> <DropdownMenu.Separator /> - <DropdownMenu.Item onSelect={() => layout.sidebar.toggleWorkspaces()}> + <DropdownMenu.Item onSelect={() => layout.sidebar.toggleWorkspaces(p().worktree)}> <DropdownMenu.ItemLabel> - {layout.sidebar.workspaces() ? "Disable workspaces" : "Enable workspaces"} + {layout.sidebar.workspaces(p().worktree)() ? "Disable workspaces" : "Enable workspaces"} </DropdownMenu.ItemLabel> </DropdownMenu.Item> </DropdownMenu.Content> @@ -1336,7 +1392,7 @@ export default function Layout(props: ParentProps) { </div> <Show - when={layout.sidebar.workspaces()} + when={layout.sidebar.workspaces(p().worktree)()} fallback={ <> <div class="py-4 px-3"> diff --git a/packages/desktop/src-tauri/src/lib.rs b/packages/desktop/src-tauri/src/lib.rs index 15033fd56..484c4a866 100644 --- a/packages/desktop/src-tauri/src/lib.rs +++ b/packages/desktop/src-tauri/src/lib.rs @@ -293,6 +293,11 @@ pub fn run() { "# )); + #[cfg(target_os = "macos")] + let window_builder = window_builder + .title_bar_style(tauri::TitleBarStyle::Overlay) + .hidden_title(true); + let _window = window_builder.build().expect("Failed to create window"); let (tx, rx) = oneshot::channel(); diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index e554f8da0..7a46ba8cd 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -319,9 +319,6 @@ render(() => { return ( <PlatformProvider value={platform}> <AppBaseProviders> - {ostype() === "macos" && ( - <div class="mx-px bg-background-base border-b border-border-weak-base h-8" data-tauri-drag-region /> - )} <ServerGate> {(data) => { setServerPassword(data().password) |
