diff options
Diffstat (limited to 'packages/app/src/pages/session')
| -rw-r--r-- | packages/app/src/pages/session/file-tabs.tsx | 63 | ||||
| -rw-r--r-- | packages/app/src/pages/session/review-tab.tsx | 34 | ||||
| -rw-r--r-- | packages/app/src/pages/session/terminal-panel.tsx | 6 | ||||
| -rw-r--r-- | packages/app/src/pages/session/use-session-hash-scroll.ts | 36 |
4 files changed, 60 insertions, 79 deletions
diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx index e92eee670..93264353b 100644 --- a/packages/app/src/pages/session/file-tabs.tsx +++ b/packages/app/src/pages/session/file-tabs.tsx @@ -67,6 +67,7 @@ export function FileTabContent(props: { tab: string }) { let scroll: HTMLDivElement | undefined let scrollFrame: number | undefined + let restoreFrame: number | undefined let pending: { x: number; y: number } | undefined let codeScroll: HTMLElement[] = [] let find: FileSearchHandle | null = null @@ -349,6 +350,15 @@ export function FileTabContent(props: { tab: string }) { if (el.scrollLeft !== s.x) el.scrollLeft = s.x } + const queueRestore = () => { + if (restoreFrame !== undefined) return + + restoreFrame = requestAnimationFrame(() => { + restoreFrame = undefined + restoreScroll() + }) + } + const handleScroll = (event: Event & { currentTarget: HTMLDivElement }) => { if (codeScroll.length === 0) syncCodeScroll() @@ -364,46 +374,29 @@ export function FileTabContent(props: { tab: string }) { setNote("commenting", null) } - createEffect( - on( - () => state()?.loaded, - (loaded) => { - if (!loaded) return - requestAnimationFrame(restoreScroll) - }, - { defer: true }, - ), - ) - - createEffect( - on( - () => file.ready(), - (ready) => { - if (!ready) return - requestAnimationFrame(restoreScroll) - }, - { defer: true }, - ), - ) + let prev = { + loaded: false, + ready: false, + active: false, + } - createEffect( - on( - () => tabs().active() === props.tab, - (active) => { - if (!active) return - if (!state()?.loaded) return - requestAnimationFrame(restoreScroll) - }, - ), - ) + createEffect(() => { + const loaded = !!state()?.loaded + const ready = file.ready() + const active = tabs().active() === props.tab + const restore = (loaded && !prev.loaded) || (ready && !prev.ready) || (active && loaded && !prev.active) + prev = { loaded, ready, active } + if (!restore) return + queueRestore() + }) onCleanup(() => { for (const item of codeScroll) { item.removeEventListener("scroll", handleCodeScroll) } - if (scrollFrame === undefined) return - cancelAnimationFrame(scrollFrame) + if (scrollFrame !== undefined) cancelAnimationFrame(scrollFrame) + if (restoreFrame !== undefined) cancelAnimationFrame(restoreFrame) }) const renderFile = (source: string) => ( @@ -421,7 +414,7 @@ export function FileTabContent(props: { tab: string }) { selectedLines={activeSelection()} commentedLines={commentedLines()} onRendered={() => { - requestAnimationFrame(restoreScroll) + queueRestore() }} annotations={commentsUi.annotations()} renderAnnotation={commentsUi.renderAnnotation} @@ -440,7 +433,7 @@ export function FileTabContent(props: { tab: string }) { mode: "auto", path: path(), current: state()?.content, - onLoad: () => requestAnimationFrame(restoreScroll), + onLoad: queueRestore, onError: (args: { kind: "image" | "audio" | "svg" }) => { if (args.kind !== "svg") return showToast({ diff --git a/packages/app/src/pages/session/review-tab.tsx b/packages/app/src/pages/session/review-tab.tsx index 2b7eba324..142ee7ad9 100644 --- a/packages/app/src/pages/session/review-tab.tsx +++ b/packages/app/src/pages/session/review-tab.tsx @@ -1,4 +1,4 @@ -import { createEffect, on, onCleanup, type JSX } from "solid-js" +import { createEffect, onCleanup, type JSX } from "solid-js" import type { FileDiff } from "@opencode-ai/sdk/v2" import { SessionReview } from "@opencode-ai/ui/session-review" import type { @@ -119,32 +119,12 @@ export function SessionReviewTab(props: SessionReviewTabProps) { }) } - createEffect( - on( - () => props.diffs().length, - () => queueRestore(), - { defer: true }, - ), - ) - - createEffect( - on( - () => props.diffStyle, - () => queueRestore(), - { defer: true }, - ), - ) - - createEffect( - on( - () => layout.ready(), - (ready) => { - if (!ready) return - queueRestore() - }, - { defer: true }, - ), - ) + createEffect(() => { + props.diffs().length + props.diffStyle + if (!layout.ready()) return + queueRestore() + }) onCleanup(() => { if (restoreFrame !== undefined) cancelAnimationFrame(restoreFrame) diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index 27ea4e6f3..49bed9490 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -56,9 +56,9 @@ export function TerminalPanel() { on( () => terminal.all().length, (count, prevCount) => { - if (prevCount !== undefined && prevCount > 0 && count === 0) { - if (opened()) view().terminal.toggle() - } + if (prevCount === undefined || prevCount <= 0 || count !== 0) return + if (!opened()) return + close() }, ), ) diff --git a/packages/app/src/pages/session/use-session-hash-scroll.ts b/packages/app/src/pages/session/use-session-hash-scroll.ts index 235714588..c5a7dde9e 100644 --- a/packages/app/src/pages/session/use-session-hash-scroll.ts +++ b/packages/app/src/pages/session/use-session-hash-scroll.ts @@ -1,4 +1,4 @@ -import { createEffect, createMemo, on, onCleanup } from "solid-js" +import { createEffect, createMemo, onCleanup, onMount } from "solid-js" import { UserMessage } from "@opencode-ai/sdk/v2" export const messageIdFromHash = (hash: string) => { @@ -28,6 +28,7 @@ export const useSessionHashScroll = (input: { const visibleUserMessages = createMemo(() => input.visibleUserMessages()) const messageById = createMemo(() => new Map(visibleUserMessages().map((m) => [m.id, m]))) const messageIndex = createMemo(() => new Map(visibleUserMessages().map((m, i) => [m.id, i]))) + let pendingKey = "" const clearMessageHash = () => { if (!window.location.hash) return @@ -130,15 +131,6 @@ export const useSessionHashScroll = (input: { if (el) input.scheduleScrollState(el) } - createEffect( - on(input.sessionKey, (key) => { - if (!input.sessionID()) return - const messageID = input.consumePendingMessage(key) - if (!messageID) return - input.setPendingMessage(messageID) - }), - ) - createEffect(() => { if (!input.sessionID() || !input.messagesReady()) return requestAnimationFrame(() => applyHash("auto")) @@ -150,7 +142,20 @@ export const useSessionHashScroll = (input: { visibleUserMessages() input.turnStart() - const targetId = input.pendingMessage() ?? messageIdFromHash(window.location.hash) + let targetId = input.pendingMessage() + if (!targetId) { + const key = input.sessionKey() + if (pendingKey !== key) { + pendingKey = key + const next = input.consumePendingMessage(key) + if (next) { + input.setPendingMessage(next) + targetId = next + } + } + } + + if (!targetId) targetId = messageIdFromHash(window.location.hash) if (!targetId) return if (input.currentMessageId() === targetId) return @@ -162,9 +167,12 @@ export const useSessionHashScroll = (input: { requestAnimationFrame(() => scrollToMessage(msg, "auto")) }) - createEffect(() => { - if (!input.sessionID() || !input.messagesReady()) return - const handler = () => requestAnimationFrame(() => applyHash("auto")) + onMount(() => { + const handler = () => { + if (!input.sessionID() || !input.messagesReady()) return + requestAnimationFrame(() => applyHash("auto")) + } + window.addEventListener("hashchange", handler) onCleanup(() => window.removeEventListener("hashchange", handler)) }) |
