Browse Source

fix(app): new layout issues

Adam 2 months ago
parent
commit
564d3edfac

+ 31 - 7
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: {

+ 77 - 21
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>
@@ -729,6 +744,21 @@ export default function Layout(props: ParentProps) {
     requestAnimationFrame(() => scrollToSession(id))
   })
 
+  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
@@ -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">

+ 5 - 0
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();

+ 0 - 3
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)