summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages/session
diff options
context:
space:
mode:
Diffstat (limited to 'packages/app/src/pages/session')
-rw-r--r--packages/app/src/pages/session/file-tabs.tsx63
-rw-r--r--packages/app/src/pages/session/review-tab.tsx34
-rw-r--r--packages/app/src/pages/session/terminal-panel.tsx6
-rw-r--r--packages/app/src/pages/session/use-session-hash-scroll.ts36
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))
})