Просмотр исходного кода

fix(app): store terminal and review pane visibility per session

adamelmore 1 месяц назад
Родитель
Сommit
0433d4d064

+ 2 - 1
packages/app/src/components/dialog-select-file.tsx

@@ -15,6 +15,7 @@ export function DialogSelectFile() {
   const params = useParams()
   const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
   const tabs = createMemo(() => layout.tabs(sessionKey()))
+  const view = createMemo(() => layout.view(sessionKey()))
   return (
     <Dialog title="Select file">
       <List
@@ -27,7 +28,7 @@ export function DialogSelectFile() {
             const value = file.tab(path)
             tabs().open(value)
             file.load(path)
-            layout.review.open()
+            view().reviewPanel.open()
           }
           dialog.close()
         }}

+ 2 - 1
packages/app/src/components/session-context-usage.tsx

@@ -20,6 +20,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
   const variant = createMemo(() => props.variant ?? "button")
   const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
   const tabs = createMemo(() => layout.tabs(sessionKey()))
+  const view = createMemo(() => layout.view(sessionKey()))
   const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : []))
 
   const cost = createMemo(() => {
@@ -48,7 +49,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
 
   const openContext = () => {
     if (!params.id) return
-    layout.review.open()
+    view().reviewPanel.open()
     tabs().open("context")
     tabs().setActive("context")
   }

+ 13 - 7
packages/app/src/components/session/session-header.tsx

@@ -43,6 +43,8 @@ export function SessionHeader() {
   })
   const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")
   const worktrees = createMemo(() => layout.projects.list().map((p) => p.worktree), [], { equals: same })
+  const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
+  const view = createMemo(() => layout.view(sessionKey()))
 
   function navigateToProject(directory: string) {
     navigate(`/${base64Encode(directory)}`)
@@ -171,20 +173,24 @@ export function SessionHeader() {
                 title="Toggle review"
                 keybind={command.keybind("review.toggle")}
               >
-                <Button variant="ghost" class="group/review-toggle size-6 p-0" onClick={layout.review.toggle}>
+                <Button
+                  variant="ghost"
+                  class="group/review-toggle size-6 p-0"
+                  onClick={() => view().reviewPanel.toggle()}
+                >
                   <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
                     <Icon
-                      name={layout.review.opened() ? "layout-right" : "layout-left"}
+                      name={view().reviewPanel.opened() ? "layout-right" : "layout-left"}
                       size="small"
                       class="group-hover/review-toggle:hidden"
                     />
                     <Icon
-                      name={layout.review.opened() ? "layout-right-partial" : "layout-left-partial"}
+                      name={view().reviewPanel.opened() ? "layout-right-partial" : "layout-left-partial"}
                       size="small"
                       class="hidden group-hover/review-toggle:inline-block"
                     />
                     <Icon
-                      name={layout.review.opened() ? "layout-right-full" : "layout-left-full"}
+                      name={view().reviewPanel.opened() ? "layout-right-full" : "layout-left-full"}
                       size="small"
                       class="hidden group-active/review-toggle:inline-block"
                     />
@@ -197,11 +203,11 @@ export function SessionHeader() {
               title="Toggle terminal"
               keybind={command.keybind("terminal.toggle")}
             >
-              <Button variant="ghost" class="group/terminal-toggle size-6 p-0" onClick={layout.terminal.toggle}>
+              <Button variant="ghost" class="group/terminal-toggle size-6 p-0" onClick={() => view().terminal.toggle()}>
                 <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
                   <Icon
                     size="small"
-                    name={layout.terminal.opened() ? "layout-bottom-full" : "layout-bottom"}
+                    name={view().terminal.opened() ? "layout-bottom-full" : "layout-bottom"}
                     class="group-hover/terminal-toggle:hidden"
                   />
                   <Icon
@@ -211,7 +217,7 @@ export function SessionHeader() {
                   />
                   <Icon
                     size="small"
-                    name={layout.terminal.opened() ? "layout-bottom" : "layout-bottom-full"}
+                    name={view().terminal.opened() ? "layout-bottom" : "layout-bottom-full"}
                     class="hidden group-active/terminal-toggle:inline-block"
                   />
                 </div>

+ 61 - 25
packages/app/src/context/layout.tsx

@@ -33,6 +33,8 @@ type SessionTabs = {
 type SessionView = {
   scroll: Record<string, SessionScroll>
   reviewOpen?: string[]
+  terminalOpened?: boolean
+  reviewPanelOpened?: boolean
 }
 
 export type LocalProject = Partial<Project> & { worktree: string; expanded: boolean }
@@ -53,11 +55,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
           width: 280,
         },
         terminal: {
-          opened: false,
           height: 280,
         },
         review: {
-          opened: true,
           diffStyle: "split" as ReviewDiffStyle,
         },
         session: {
@@ -150,7 +150,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         const current = store.sessionView[sessionKey]
         const keep = meta.active ?? sessionKey
         if (!current) {
-          setStore("sessionView", sessionKey, { scroll: next })
+          setStore("sessionView", sessionKey, { scroll: next, terminalOpened: false, reviewPanelOpened: true })
           prune(keep)
           return
         }
@@ -306,40 +306,20 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         },
       },
       terminal: {
-        opened: createMemo(() => store.terminal.opened),
-        open() {
-          setStore("terminal", "opened", true)
-        },
-        close() {
-          setStore("terminal", "opened", false)
-        },
-        toggle() {
-          setStore("terminal", "opened", (x) => !x)
-        },
         height: createMemo(() => store.terminal.height),
         resize(height: number) {
           setStore("terminal", "height", height)
         },
       },
       review: {
-        opened: createMemo(() => store.review?.opened ?? true),
         diffStyle: createMemo(() => store.review?.diffStyle ?? "split"),
         setDiffStyle(diffStyle: ReviewDiffStyle) {
           if (!store.review) {
-            setStore("review", { opened: true, diffStyle })
+            setStore("review", { diffStyle })
             return
           }
           setStore("review", "diffStyle", diffStyle)
         },
-        open() {
-          setStore("review", "opened", true)
-        },
-        close() {
-          setStore("review", "opened", false)
-        },
-        toggle() {
-          setStore("review", "opened", (x) => !x)
-        },
       },
       session: {
         width: createMemo(() => store.session?.width ?? 600),
@@ -367,6 +347,33 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         touch(sessionKey)
         scroll.seed(sessionKey)
         const s = createMemo(() => store.sessionView[sessionKey] ?? { scroll: {} })
+        const terminalOpened = createMemo(() => s().terminalOpened ?? false)
+        const reviewPanelOpened = createMemo(() => s().reviewPanelOpened ?? true)
+
+        function setTerminalOpened(next: boolean) {
+          const current = store.sessionView[sessionKey]
+          if (!current) {
+            setStore("sessionView", sessionKey, { scroll: {}, terminalOpened: next, reviewPanelOpened: true })
+            return
+          }
+
+          const value = current.terminalOpened ?? false
+          if (value === next) return
+          setStore("sessionView", sessionKey, "terminalOpened", next)
+        }
+
+        function setReviewPanelOpened(next: boolean) {
+          const current = store.sessionView[sessionKey]
+          if (!current) {
+            setStore("sessionView", sessionKey, { scroll: {}, terminalOpened: false, reviewPanelOpened: next })
+            return
+          }
+
+          const value = current.reviewPanelOpened ?? true
+          if (value === next) return
+          setStore("sessionView", sessionKey, "reviewPanelOpened", next)
+        }
+
         return {
           scroll(tab: string) {
             return scroll.scroll(sessionKey, tab)
@@ -374,12 +381,41 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
           setScroll(tab: string, pos: SessionScroll) {
             scroll.setScroll(sessionKey, tab, pos)
           },
+          terminal: {
+            opened: terminalOpened,
+            open() {
+              setTerminalOpened(true)
+            },
+            close() {
+              setTerminalOpened(false)
+            },
+            toggle() {
+              setTerminalOpened(!terminalOpened())
+            },
+          },
+          reviewPanel: {
+            opened: reviewPanelOpened,
+            open() {
+              setReviewPanelOpened(true)
+            },
+            close() {
+              setReviewPanelOpened(false)
+            },
+            toggle() {
+              setReviewPanelOpened(!reviewPanelOpened())
+            },
+          },
           review: {
             open: createMemo(() => s().reviewOpen),
             setOpen(open: string[]) {
               const current = store.sessionView[sessionKey]
               if (!current) {
-                setStore("sessionView", sessionKey, { scroll: {}, reviewOpen: open })
+                setStore("sessionView", sessionKey, {
+                  scroll: {},
+                  terminalOpened: false,
+                  reviewPanelOpened: true,
+                  reviewOpen: open,
+                })
                 return
               }
 

+ 9 - 7
packages/app/src/pages/session.tsx

@@ -377,7 +377,7 @@ export default function Page() {
   })
 
   createEffect(() => {
-    if (!layout.terminal.opened()) return
+    if (!view().terminal.opened()) return
     if (!terminal.ready()) return
     if (terminal.all().length !== 0) return
     terminal.new()
@@ -440,7 +440,7 @@ export default function Page() {
       category: "View",
       keybind: "ctrl+`",
       slash: "terminal",
-      onSelect: () => layout.terminal.toggle(),
+      onSelect: () => view().terminal.toggle(),
     },
     {
       id: "review.toggle",
@@ -448,7 +448,7 @@ export default function Page() {
       description: "Show or hide the review panel",
       category: "View",
       keybind: "mod+shift+r",
-      onSelect: () => layout.review.toggle(),
+      onSelect: () => view().reviewPanel.toggle(),
     },
     {
       id: "terminal.new",
@@ -720,7 +720,9 @@ export default function Page() {
   const reviewTab = createMemo(() => hasReview() || tabs().active() === "review")
   const mobileReview = createMemo(() => !isDesktop() && hasReview() && store.mobileTab === "review")
 
-  const showTabs = createMemo(() => layout.review.opened() && (hasReview() || tabs().all().length > 0 || contextOpen()))
+  const showTabs = createMemo(
+    () => view().reviewPanel.opened() && (hasReview() || tabs().all().length > 0 || contextOpen()),
+  )
 
   const activeTab = createMemo(() => {
     const active = tabs().active()
@@ -745,7 +747,7 @@ export default function Page() {
     if (!id) return
     if (!hasReview()) return
 
-    const wants = isDesktop() ? layout.review.opened() && activeTab() === "review" : store.mobileTab === "review"
+    const wants = isDesktop() ? view().reviewPanel.opened() && activeTab() === "review" : store.mobileTab === "review"
     if (!wants) return
     if (diffsReady()) return
 
@@ -1600,7 +1602,7 @@ export default function Page() {
         </Show>
       </div>
 
-      <Show when={isDesktop() && layout.terminal.opened()}>
+      <Show when={isDesktop() && view().terminal.opened()}>
         <div
           class="relative w-full flex-col shrink-0 border-t border-border-weak-base"
           style={{ height: `${layout.terminal.height()}px` }}
@@ -1612,7 +1614,7 @@ export default function Page() {
             max={window.innerHeight * 0.6}
             collapseThreshold={50}
             onResize={layout.terminal.resize}
-            onCollapse={layout.terminal.close}
+            onCollapse={view().terminal.close}
           />
           <Show
             when={terminal.ready()}