From 307af10c8bad1eb90288df5447275bb1b65cebc7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Sat, 13 Dec 2025 06:15:11 -0600 Subject: [PATCH] fix: session turn scroll --- packages/ui/src/components/session-turn.css | 29 ++++--- packages/ui/src/components/session-turn.tsx | 87 +++++++++++---------- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css index c4dd2b839..24eb1563b 100644 --- a/packages/ui/src/components/session-turn.css +++ b/packages/ui/src/components/session-turn.css @@ -1,5 +1,6 @@ [data-component="session-turn"] { /* flex: 1; */ + --scroll-y: 0px; height: 100%; min-height: 0; min-width: 0; @@ -26,18 +27,26 @@ align-items: flex-start; align-self: stretch; min-width: 0; - gap: 32px; + gap: clamp(8px, calc(42px - var(--scroll-y) * 0.48), 42px); } - [data-slot="session-turn-sticky-header"] { + [data-slot="session-turn-sticky-title"] { width: 100%; position: sticky; top: 0; background-color: var(--background-stronger); + z-index: 21; + /* padding-bottom: clamp(0px, calc(8px - var(--scroll-y) * 0.16), 8px); */ + } + + [data-slot="session-turn-response-trigger"] { + position: sticky; + top: 32px; + background-color: var(--background-stronger); z-index: 20; - display: flex; - flex-direction: column; - gap: 8px; + width: calc(100% + 9px); + margin-left: -9px; + padding-left: 9px; padding-bottom: 8px; } @@ -49,13 +58,8 @@ height: 32px; } - /* [data-slot="session-turn-message-content"] { */ - /* } */ - - [data-slot="session-turn-response-trigger"] { - width: calc(100% + 9px); - margin-left: -9px; - padding-left: 9px; + [data-slot="session-turn-message-content"] { + margin-top: -24px; } [data-slot="session-turn-message-title"] { @@ -292,6 +296,7 @@ [data-slot="session-turn-collapsible"] { gap: 32px; overflow: visible; + /* margin-top: clamp(8px, calc(24px - var(--scroll-y) * 0.32), 24px); */ } [data-slot="session-turn-collapsible-trigger-content"] { diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 708ac5b83..361a5cac0 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -3,18 +3,7 @@ import { useData } from "../context" import { useDiffComponent } from "../context/diff" import { getDirectory, getFilename } from "@opencode-ai/util/path" import { checksum } from "@opencode-ai/util/encode" -import { - createEffect, - createMemo, - createSignal, - For, - Match, - onCleanup, - onMount, - ParentProps, - Show, - Switch, -} from "solid-js" +import { createEffect, createMemo, createSignal, For, Match, onCleanup, ParentProps, Show, Switch } from "solid-js" import { createResizeObserver } from "@solid-primitives/resize-observer" import { DiffChanges } from "./diff-changes" import { Typewriter } from "./typewriter" @@ -61,12 +50,15 @@ export function SessionTurn( let scrollRef: HTMLDivElement | undefined const [contentRef, setContentRef] = createSignal() - const [stickyHeaderRef, setStickyHeaderRef] = createSignal() + const [stickyTitleRef, setStickyTitleRef] = createSignal() + const [stickyTriggerRef, setStickyTriggerRef] = createSignal() const [userScrolled, setUserScrolled] = createSignal(false) const [stickyHeaderHeight, setStickyHeaderHeight] = createSignal(0) + const [scrollY, setScrollY] = createSignal(0) function handleScroll() { if (!scrollRef) return + setScrollY(scrollRef.scrollTop) const { scrollTop, scrollHeight, clientHeight } = scrollRef const atBottom = scrollHeight - scrollTop - clientHeight < 50 if (!atBottom && working()) { @@ -88,15 +80,24 @@ export function SessionTurn( createResizeObserver(contentRef, () => { if (!scrollRef || userScrolled() || !working()) return - scrollRef.scrollTop = scrollRef.scrollHeight + requestAnimationFrame(() => { + if (!scrollRef) return + scrollRef.scrollTop = scrollRef.scrollHeight + }) }) - createResizeObserver(stickyHeaderRef, ({ height }) => { - setStickyHeaderHeight(height + 8) + createResizeObserver(stickyTitleRef, ({ height }) => { + const triggerHeight = stickyTriggerRef()?.offsetHeight ?? 0 + setStickyHeaderHeight(height + triggerHeight + 8) + }) + + createResizeObserver(stickyTriggerRef, ({ height }) => { + const titleHeight = stickyTitleRef()?.offsetHeight ?? 0 + setStickyHeaderHeight(titleHeight + height + 8) }) return ( -
+
@@ -250,8 +251,8 @@ export function SessionTurn( class={props.classes?.container} style={{ "--sticky-header-height": `${stickyHeaderHeight()}px` }} > - {/* Sticky Header */} -
+ {/* Title (sticky) */} +
@@ -264,29 +265,31 @@ export function SessionTurn(
-
- -
-
- -
+
+ {/* User Message (non-sticky, scrolls under sticky header) */} +
+ +
+ {/* Trigger (sticky) */} +
+
{/* Response */}