Преглед изворни кода

feat(app): review panel reactivity improvements (#37089)

Aarav Sareen пре 1 месец
родитељ
комит
ed926be253

+ 1 - 1
packages/app/src/pages/session/session-side-panel.tsx

@@ -551,7 +551,7 @@ export function SessionSidePanel(props: {
                           >
                             <Show when={props.reviewSidebarToggle}>
                               {(toggle) => (
-                                <div class="h-full shrink-0 flex items-center justify-center">
+                                <div class="session-review-v2-sidebar-toggle-slot h-full shrink-0 sticky left-0 z-10 flex items-center justify-center bg-v2-background-bg-base">
                                   {toggle()(activeTab() === SESSION_OPEN_FILE_TAB)}
                                 </div>
                               )}

+ 3 - 1
packages/session-ui/src/v2/components/session-review-file-preview-v2.tsx

@@ -263,7 +263,9 @@ export function SessionReviewFilePreviewV2(props: SessionReviewFilePreviewV2Prop
             <span data-slot="session-review-v2-file-path">{getDirectory(props.file)}</span>
           </Show>
         </div>
-        <DiffChanges changes={view()} />
+        <div data-slot="session-review-v2-file-diff">
+          <DiffChanges changes={view()} />
+        </div>
       </div>
       <div
         ref={(el) => {

+ 30 - 2
packages/session-ui/src/v2/components/session-review-v2.css

@@ -149,7 +149,7 @@
   align-items: center;
   justify-content: space-between;
   gap: 8px;
-  padding: 8px 12px;
+  padding: 10px 12px;
   padding-left: 8px;
   flex-shrink: 0;
   border-bottom: 1px solid var(--border-weaker-base, var(--v2-border-border-weak));
@@ -273,9 +273,37 @@
   flex: 1;
 }
 
-[data-component="session-review-v2"] [data-slot="session-review-v2-file-header"] [data-component="diff-changes"] {
+[data-component="session-review-v2"] [data-slot="session-review-v2-file-diff"] {
+  position: relative;
   flex-shrink: 0;
   margin-left: auto;
+  background-color: var(--v2-background-bg-base);
+
+  &::before {
+    content: "";
+    position: absolute;
+    top: -8px;
+    bottom: -8px;
+    right: 100%;
+    width: 16px;
+    z-index: 1;
+    pointer-events: none;
+    background: linear-gradient(90deg, transparent, var(--v2-background-bg-base));
+  }
+
+  &::after {
+    content: "";
+    position: absolute;
+    inset: -8px -16px -8px 0;
+    z-index: 0;
+    pointer-events: none;
+    background-color: var(--v2-background-bg-base);
+  }
+
+  [data-component="diff-changes"] {
+    position: relative;
+    z-index: 1;
+  }
 }
 
 [data-component="session-review-v2"] [data-slot="session-review-v2-file-status"] {

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

@@ -139,6 +139,7 @@ export function SessionReviewV2Sidebar(props: SessionReviewV2SidebarProps) {
             min={minWidth()}
             max={maxWidth()}
             onResize={(next) => props.onWidthChange?.(next)}
+            onDblClick={() => props.onWidthChange?.(SESSION_REVIEW_V2_SIDEBAR_WIDTH_DEFAULT)}
           />
         </div>
       </Show>

+ 21 - 5
packages/ui/src/components/resize-handle.tsx

@@ -8,6 +8,8 @@ export interface ResizeHandleProps extends Omit<JSX.HTMLAttributes<HTMLDivElemen
   max: number
   onResize: (size: number) => void
   onCollapse?: () => void
+  /** Called while dragging when size crosses `collapseThreshold`. */
+  onCollapseChange?: (collapsed: boolean) => void
   collapseThreshold?: number
 }
 
@@ -20,17 +22,26 @@ export function ResizeHandle(props: ResizeHandleProps) {
     "max",
     "onResize",
     "onCollapse",
+    "onCollapseChange",
     "collapseThreshold",
     "class",
     "classList",
   ])
 
   const handleMouseDown = (e: MouseEvent) => {
+    if (e.detail > 1) return
     e.preventDefault()
     const edge = local.edge ?? (local.direction === "vertical" ? "start" : "end")
     const start = local.direction === "horizontal" ? e.clientX : e.clientY
     const startSize = local.size
+    const min = local.min
+    const max = local.max
+    const threshold = local.collapseThreshold ?? 0
+    const onResize = local.onResize
+    const onCollapse = local.onCollapse
+    const onCollapseChange = local.onCollapseChange
     let current = startSize
+    let collapsed = false
 
     document.body.style.userSelect = "none"
     document.body.style.overflow = "hidden"
@@ -46,8 +57,12 @@ export function ResizeHandle(props: ResizeHandleProps) {
             ? start - pos
             : pos - start
       current = startSize + delta
-      const clamped = Math.min(local.max, Math.max(local.min, current))
-      local.onResize(clamped)
+      const nextCollapsed = threshold > 0 && current < threshold
+      if (nextCollapsed !== collapsed) {
+        collapsed = nextCollapsed
+        onCollapseChange?.(collapsed)
+      }
+      onResize(Math.min(max, Math.max(min, current)))
     }
 
     const onMouseUp = () => {
@@ -56,10 +71,11 @@ export function ResizeHandle(props: ResizeHandleProps) {
       document.removeEventListener("mousemove", onMouseMove)
       document.removeEventListener("mouseup", onMouseUp)
 
-      const threshold = local.collapseThreshold ?? 0
-      if (local.onCollapse && threshold > 0 && current < threshold) {
-        local.onCollapse()
+      if (collapsed) {
+        onCollapse?.()
+        return
       }
+      onCollapseChange?.(false)
     }
 
     document.addEventListener("mousemove", onMouseMove)

+ 56 - 0
packages/ui/src/components/tabs.css

@@ -793,6 +793,62 @@ body[data-new-layout]
   [data-slot="tabs-list"]
   > .sticky {
   padding-right: 0;
+
+  [data-component="icon-button-v2"] {
+    position: relative;
+
+    &::after {
+      content: "";
+      position: absolute;
+      left: 100%;
+      top: 50%;
+      transform: translateY(-50%);
+      width: 20px;
+      height: 28px;
+      background-color: var(--v2-background-bg-base);
+      pointer-events: none;
+    }
+  }
+}
+
+body[data-new-layout]
+  #review-panel
+  [data-component="tabs"]
+  .session-review-v2-tabs-bar
+  [data-slot="tabs-list"]
+  > .session-review-v2-sidebar-toggle-slot.sticky {
+  padding-right: 0;
+
+  &::before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    bottom: auto;
+    left: auto;
+    right: 100%;
+    transform: translateY(-50%);
+    width: 12px;
+    height: 28px;
+    background-color: var(--v2-background-bg-base);
+    background-image: none;
+    pointer-events: none;
+  }
+
+  &::after {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 100%;
+    transform: translateY(-50%);
+    width: 8px;
+    height: 28px;
+    pointer-events: none;
+    background: linear-gradient(90deg, var(--v2-background-bg-base), transparent);
+  }
+
+  [data-component="icon-button-v2"]::after {
+    display: none;
+  }
 }
 
 body[data-new-layout] #review-panel [data-component="tabs"] .session-review-v2-open-in-app-slot {