fix: scroll gutter

This commit is contained in:
Adam 2025-11-25 13:49:43 -06:00
parent 4a95db6013
commit cd67804412
No known key found for this signature in database
GPG key ID: 9CB48779AF150E75
4 changed files with 96 additions and 54 deletions

View file

@ -401,10 +401,15 @@ export default function Page() {
<Show when={layout.review.state() === "pane" && session.diffs().length}>
<div
classList={{
"relative grow px-6 py-3 flex-1 min-h-0 border-l border-border-weak-base": true,
"relative grow pt-3 flex-1 min-h-0 border-l border-border-weak-base": true,
}}
>
<SessionReview
classes={{
root: "pb-20",
header: "px-6",
container: "px-6",
}}
diffs={session.diffs()}
actions={
<Tooltip value="Open in tab">
@ -427,10 +432,18 @@ export default function Page() {
<Tabs.Content value="review" class="select-text flex flex-col h-full overflow-hidden">
<div
classList={{
"relative px-6 py-3 flex-1 min-h-0 overflow-hidden": true,
"relative pt-3 flex-1 min-h-0 overflow-hidden": true,
}}
>
<SessionReview diffs={session.diffs()} split class="pb-40" />
<SessionReview
classes={{
root: "pb-40",
header: "px-6",
container: "px-6",
}}
diffs={session.diffs()}
split
/>
</div>
</Tabs.Content>
</Show>

View file

@ -16,7 +16,7 @@ import { createStore } from "solid-js/store"
import z from "zod"
import NotFound from "../[...404]"
import { Tabs } from "@opencode-ai/ui/tabs"
import { HunkData, preloadMultiFileDiff, PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
import { preloadMultiFileDiff, PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
const SessionDataMissingError = NamedError.create(
"SessionDataMissingError",
@ -304,8 +304,15 @@ export default function () {
</div>
</div>
<Show when={diffs().length > 0}>
<div class="relative grow px-6 pt-14 flex-1 min-h-0 border-l border-border-weak-base">
<SessionReview diffs={diffs()} class="pb-20" />
<div class="relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base">
<SessionReview
diffs={diffs()}
classes={{
root: "pb-20",
header: "px-6",
container: "px-6",
}}
/>
</div>
</Show>
</div>
@ -324,8 +331,15 @@ export default function () {
{turns()}
</Tabs.Content>
<Tabs.Content forceMount value="review" class="!overflow-hidden hidden data-[selected]:block">
<div class="relative px-4 pt-8 h-full overflow-y-auto no-scrollbar">
<SessionReview diffs={diffs()} class="pb-20" />
<div class="relative h-full pt-8 overflow-y-auto no-scrollbar">
<SessionReview
diffs={diffs()}
classes={{
root: "pb-20",
header: "px-4",
container: "px-4",
}}
/>
</div>
</Tabs.Content>
</Tabs>

View file

@ -5,11 +5,14 @@
height: 100%;
overflow-y: auto;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
/* [data-slot="session-review-container"] { */
/* height: 100%; */
/* } */
[data-slot="session-review-header"] {
position: sticky;
top: 0;

View file

@ -6,7 +6,7 @@ import { FileIcon } from "./file-icon"
import { Icon } from "./icon"
import { StickyAccordionHeader } from "./sticky-accordion-header"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
import { For, Match, Show, Switch, type JSX, splitProps } from "solid-js"
import { For, Match, Show, Switch, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { type FileDiff } from "@opencode-ai/sdk"
import { PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
@ -15,6 +15,7 @@ export interface SessionReviewProps {
split?: boolean
class?: string
classList?: Record<string, boolean | undefined>
classes?: { root?: string; header?: string; container?: string }
actions?: JSX.Element
diffs: (FileDiff & { preloaded?: PreloadMultiFileDiffResult<any> })[]
}
@ -39,17 +40,21 @@ export const SessionReview = (props: SessionReviewProps) => {
}
}
const [split] = splitProps(props, ["class", "classList"])
return (
<div
data-component="session-review"
classList={{
...(split.classList ?? {}),
[split.class ?? ""]: !!split.class,
...(props.classList ?? {}),
[props.classes?.root ?? ""]: !!props.classes?.root,
[props.class ?? ""]: !!props.class,
}}
>
<div data-slot="session-review-header">
<div
data-slot="session-review-header"
classList={{
[props.classes?.header ?? ""]: !!props.classes?.header,
}}
>
<div data-slot="session-review-title">Session changes</div>
<div data-slot="session-review-actions">
<Button size="normal" icon="chevron-grabber-vertical" onClick={handleExpandOrCollapseAll}>
@ -61,47 +66,54 @@ export const SessionReview = (props: SessionReviewProps) => {
{props.actions}
</div>
</div>
<Accordion multiple value={store.open} onChange={handleChange}>
<For each={props.diffs}>
{(diff) => (
<Accordion.Item forceMount value={diff.file} data-slot="session-review-accordion-item">
<StickyAccordionHeader>
<Accordion.Trigger>
<div data-slot="session-review-trigger-content">
<div data-slot="session-review-file-info">
<FileIcon node={{ path: diff.file, type: "file" }} />
<div data-slot="session-review-file-name-container">
<Show when={diff.file.includes("/")}>
<span data-slot="session-review-directory">{getDirectory(diff.file)}&lrm;</span>
</Show>
<span data-slot="session-review-filename">{getFilename(diff.file)}</span>
<div
data-slot="session-review-container"
classList={{
[props.classes?.container ?? ""]: !!props.classes?.container,
}}
>
<Accordion multiple value={store.open} onChange={handleChange}>
<For each={props.diffs}>
{(diff) => (
<Accordion.Item forceMount value={diff.file} data-slot="session-review-accordion-item">
<StickyAccordionHeader>
<Accordion.Trigger>
<div data-slot="session-review-trigger-content">
<div data-slot="session-review-file-info">
<FileIcon node={{ path: diff.file, type: "file" }} />
<div data-slot="session-review-file-name-container">
<Show when={diff.file.includes("/")}>
<span data-slot="session-review-directory">{getDirectory(diff.file)}&lrm;</span>
</Show>
<span data-slot="session-review-filename">{getFilename(diff.file)}</span>
</div>
</div>
<div data-slot="session-review-trigger-actions">
<DiffChanges changes={diff} />
<Icon name="chevron-grabber-vertical" size="small" />
</div>
</div>
<div data-slot="session-review-trigger-actions">
<DiffChanges changes={diff} />
<Icon name="chevron-grabber-vertical" size="small" />
</div>
</div>
</Accordion.Trigger>
</StickyAccordionHeader>
<Accordion.Content data-slot="session-review-accordion-content">
<Diff
preloadedDiff={diff.preloaded}
diffStyle={props.split ? "split" : "unified"}
before={{
name: diff.file!,
contents: diff.before!,
}}
after={{
name: diff.file!,
contents: diff.after!,
}}
/>
</Accordion.Content>
</Accordion.Item>
)}
</For>
</Accordion>
</Accordion.Trigger>
</StickyAccordionHeader>
<Accordion.Content data-slot="session-review-accordion-content">
<Diff
preloadedDiff={diff.preloaded}
diffStyle={props.split ? "split" : "unified"}
before={{
name: diff.file!,
contents: diff.before!,
}}
after={{
name: diff.file!,
contents: diff.after!,
}}
/>
</Accordion.Content>
</Accordion.Item>
)}
</For>
</Accordion>
</div>
</div>
)
}