Adam преди 1 месец
родител
ревизия
56dda4c98c

+ 1 - 1
packages/app/src/pages/session/message-timeline.tsx

@@ -368,7 +368,7 @@ export function MessageTimeline(props: {
           class="relative min-w-0 w-full h-full overflow-y-auto session-scroller"
           style={{
             "--session-title-height": showHeader() ? "40px" : "0px",
-            "--sticky-accordion-top": showHeader() ? "64px" : "0px",
+            "--sticky-accordion-top": showHeader() ? "48px" : "0px",
           }}
         >
           <Show when={showHeader()}>

+ 15 - 0
packages/ui/src/components/message-part.css

@@ -1219,6 +1219,21 @@
   }
 }
 
+[data-component="apply-patch-tool"] {
+  > [data-component="collapsible"].tool-collapsible {
+    gap: 0px;
+  }
+
+  > [data-component="collapsible"] > [data-slot="collapsible-trigger"][aria-expanded="true"] {
+    position: sticky;
+    top: var(--sticky-accordion-top, 0px);
+    z-index: 20;
+    height: 40px;
+    padding-bottom: 8px;
+    background-color: var(--background-stronger);
+  }
+}
+
 [data-component="accordion"][data-scope="apply-patch"] {
   [data-slot="accordion-trigger"] {
     background-color: var(--background-stronger) !important;

+ 89 - 86
packages/ui/src/components/message-part.tsx

@@ -1611,97 +1611,100 @@ ToolRegistry.register({
     })
 
     return (
-      <BasicTool
-        {...props}
-        icon="code-lines"
-        defer
-        trigger={{
-          title: i18n.t("ui.tool.patch"),
-          subtitle: subtitle(),
-        }}
-      >
-        <Show when={files().length > 0}>
-          <Accordion
-            multiple
-            data-scope="apply-patch"
-            value={expanded()}
-            onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
-          >
-            <For each={files()}>
-              {(file) => {
-                const active = createMemo(() => expanded().includes(file.filePath))
-                const [visible, setVisible] = createSignal(false)
-
-                createEffect(() => {
-                  if (!active()) {
-                    setVisible(false)
-                    return
-                  }
-
-                  requestAnimationFrame(() => {
-                    if (!active()) return
-                    setVisible(true)
+      <div data-component="apply-patch-tool">
+        <BasicTool
+          {...props}
+          icon="code-lines"
+          defer
+          trigger={{
+            title: i18n.t("ui.tool.patch"),
+            subtitle: subtitle(),
+          }}
+        >
+          <Show when={files().length > 0}>
+            <Accordion
+              multiple
+              data-scope="apply-patch"
+              style={{ "--sticky-accordion-offset": "40px" }}
+              value={expanded()}
+              onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
+            >
+              <For each={files()}>
+                {(file) => {
+                  const active = createMemo(() => expanded().includes(file.filePath))
+                  const [visible, setVisible] = createSignal(false)
+
+                  createEffect(() => {
+                    if (!active()) {
+                      setVisible(false)
+                      return
+                    }
+
+                    requestAnimationFrame(() => {
+                      if (!active()) return
+                      setVisible(true)
+                    })
                   })
-                })
 
-                return (
-                  <Accordion.Item value={file.filePath} data-type={file.type}>
-                    <StickyAccordionHeader>
-                      <Accordion.Trigger>
-                        <div data-slot="apply-patch-trigger-content">
-                          <div data-slot="apply-patch-file-info">
-                            <FileIcon node={{ path: file.relativePath, type: "file" }} />
-                            <div data-slot="apply-patch-file-name-container">
-                              <Show when={file.relativePath.includes("/")}>
-                                <span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span>
-                              </Show>
-                              <span data-slot="apply-patch-filename">{getFilename(file.relativePath)}</span>
+                  return (
+                    <Accordion.Item value={file.filePath} data-type={file.type}>
+                      <StickyAccordionHeader>
+                        <Accordion.Trigger>
+                          <div data-slot="apply-patch-trigger-content">
+                            <div data-slot="apply-patch-file-info">
+                              <FileIcon node={{ path: file.relativePath, type: "file" }} />
+                              <div data-slot="apply-patch-file-name-container">
+                                <Show when={file.relativePath.includes("/")}>
+                                  <span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span>
+                                </Show>
+                                <span data-slot="apply-patch-filename">{getFilename(file.relativePath)}</span>
+                              </div>
+                            </div>
+                            <div data-slot="apply-patch-trigger-actions">
+                              <Switch>
+                                <Match when={file.type === "add"}>
+                                  <span data-slot="apply-patch-change" data-type="added">
+                                    {i18n.t("ui.patch.action.created")}
+                                  </span>
+                                </Match>
+                                <Match when={file.type === "delete"}>
+                                  <span data-slot="apply-patch-change" data-type="removed">
+                                    {i18n.t("ui.patch.action.deleted")}
+                                  </span>
+                                </Match>
+                                <Match when={file.type === "move"}>
+                                  <span data-slot="apply-patch-change" data-type="modified">
+                                    {i18n.t("ui.patch.action.moved")}
+                                  </span>
+                                </Match>
+                                <Match when={true}>
+                                  <DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} />
+                                </Match>
+                              </Switch>
+                              <Icon name="chevron-grabber-vertical" size="small" />
                             </div>
                           </div>
-                          <div data-slot="apply-patch-trigger-actions">
-                            <Switch>
-                              <Match when={file.type === "add"}>
-                                <span data-slot="apply-patch-change" data-type="added">
-                                  {i18n.t("ui.patch.action.created")}
-                                </span>
-                              </Match>
-                              <Match when={file.type === "delete"}>
-                                <span data-slot="apply-patch-change" data-type="removed">
-                                  {i18n.t("ui.patch.action.deleted")}
-                                </span>
-                              </Match>
-                              <Match when={file.type === "move"}>
-                                <span data-slot="apply-patch-change" data-type="modified">
-                                  {i18n.t("ui.patch.action.moved")}
-                                </span>
-                              </Match>
-                              <Match when={true}>
-                                <DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} />
-                              </Match>
-                            </Switch>
-                            <Icon name="chevron-grabber-vertical" size="small" />
+                        </Accordion.Trigger>
+                      </StickyAccordionHeader>
+                      <Accordion.Content>
+                        <Show when={visible()}>
+                          <div data-component="apply-patch-file-diff">
+                            <Dynamic
+                              component={diffComponent}
+                              before={{ name: file.filePath, contents: file.before }}
+                              after={{ name: file.movePath ?? file.filePath, contents: file.after }}
+                            />
                           </div>
-                        </div>
-                      </Accordion.Trigger>
-                    </StickyAccordionHeader>
-                    <Accordion.Content>
-                      <Show when={visible()}>
-                        <div data-component="apply-patch-file-diff">
-                          <Dynamic
-                            component={diffComponent}
-                            before={{ name: file.filePath, contents: file.before }}
-                            after={{ name: file.movePath ?? file.filePath, contents: file.after }}
-                          />
-                        </div>
-                      </Show>
-                    </Accordion.Content>
-                  </Accordion.Item>
-                )
-              }}
-            </For>
-          </Accordion>
-        </Show>
-      </BasicTool>
+                        </Show>
+                      </Accordion.Content>
+                    </Accordion.Item>
+                  )
+                }}
+              </For>
+            </Accordion>
+          </Show>
+        </BasicTool>
+      </div>
     )
   },
 })

+ 12 - 1
packages/ui/src/components/session-turn.css

@@ -81,6 +81,17 @@
     min-width: 0;
   }
 
+  [data-slot="session-turn-diffs"]
+    > [data-component="collapsible"]
+    > [data-slot="collapsible-trigger"][aria-expanded="true"] {
+    position: sticky;
+    top: var(--sticky-accordion-top, 0px);
+    z-index: 20;
+    height: 40px;
+    padding-bottom: 8px;
+    background-color: var(--background-stronger);
+  }
+
   [data-component="session-turn-diffs-trigger"] {
     width: 100%;
     display: flex;
@@ -124,7 +135,7 @@
   }
 
   [data-component="session-turn-diffs-content"] {
-    padding-top: 8px;
+    padding-top: 0px;
     display: flex;
     flex-direction: column;
   }

+ 1 - 0
packages/ui/src/components/session-turn.tsx

@@ -318,6 +318,7 @@ export function SessionTurn(
                           <div data-component="session-turn-diffs-content">
                             <Accordion
                               multiple
+                              style={{ "--sticky-accordion-offset": "40px" }}
                               value={expanded()}
                               onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
                             >

+ 2 - 10
packages/ui/src/components/sticky-accordion-header.css

@@ -1,14 +1,6 @@
 [data-component="sticky-accordion-header"] {
-  --sticky-accordion-top: 0px;
   position: sticky;
-  top: var(--sticky-accordion-top);
-}
-
-[data-slot="accordion-item"]:first-child [data-component="sticky-accordion-header"] {
-  background-color: var(--background-stronger);
-}
-
-[data-component="sticky-accordion-header"][data-expanded],
-[data-slot="accordion-item"][data-expanded] [data-component="sticky-accordion-header"] {
+  top: calc(var(--sticky-accordion-top, 0px) + var(--sticky-accordion-offset, 0px));
   z-index: 10;
+  background-color: var(--background-stronger);
 }