@@ -37,7 +37,6 @@ import { createOpenReviewFile, createSizing } from "@/pages/session/helpers"
3737import { MessageTimeline } from "@/pages/session/message-timeline"
3838import { type DiffStyle , SessionReviewTab , type SessionReviewTabProps } from "@/pages/session/review-tab"
3939import { resetSessionModel , syncSessionModel } from "@/pages/session/session-model-helpers"
40- import { createScrollSpy } from "@/pages/session/scroll-spy"
4140import { SessionMobileTabs } from "@/pages/session/session-mobile-tabs"
4241import { SessionSidePanel } from "@/pages/session/session-side-panel"
4342import { TerminalPanel } from "@/pages/session/terminal-panel"
@@ -486,20 +485,49 @@ export default function Page() {
486485 return "main"
487486 } )
488487
489- const activeMessage = createMemo ( ( ) => {
490- if ( ! store . messageId ) return lastUserMessage ( )
491- const found = visibleUserMessages ( ) ?. find ( ( m ) => m . id === store . messageId )
492- return found ?? lastUserMessage ( )
493- } )
494488 const setActiveMessage = ( message : UserMessage | undefined ) => {
489+ messageMark = scrollMark
495490 setStore ( "messageId" , message ?. id )
496491 }
497492
493+ const anchor = ( id : string ) => `message-${ id } `
494+
495+ const cursor = ( ) => {
496+ const root = scroller
497+ if ( ! root ) return store . messageId
498+
499+ const box = root . getBoundingClientRect ( )
500+ const line = box . top + 100
501+ const list = [ ...root . querySelectorAll < HTMLElement > ( "[data-message-id]" ) ]
502+ . map ( ( el ) => {
503+ const id = el . dataset . messageId
504+ if ( ! id ) return
505+
506+ const rect = el . getBoundingClientRect ( )
507+ return { id, top : rect . top , bottom : rect . bottom }
508+ } )
509+ . filter ( ( item ) : item is { id : string ; top : number ; bottom : number } => ! ! item )
510+
511+ const shown = list . filter ( ( item ) => item . bottom > box . top && item . top < box . bottom )
512+ const hit = shown . find ( ( item ) => item . top <= line && item . bottom >= line )
513+ if ( hit ) return hit . id
514+
515+ const near = [ ...shown ] . sort ( ( a , b ) => {
516+ const da = Math . abs ( a . top - line )
517+ const db = Math . abs ( b . top - line )
518+ if ( da !== db ) return da - db
519+ return a . top - b . top
520+ } ) [ 0 ]
521+ if ( near ) return near . id
522+
523+ return list . filter ( ( item ) => item . top <= line ) . at ( - 1 ) ?. id ?? list [ 0 ] ?. id ?? store . messageId
524+ }
525+
498526 function navigateMessageByOffset ( offset : number ) {
499527 const msgs = visibleUserMessages ( )
500528 if ( msgs . length === 0 ) return
501529
502- const current = store . messageId
530+ const current = store . messageId && messageMark === scrollMark ? store . messageId : cursor ( )
503531 const base = current ? msgs . findIndex ( ( m ) => m . id === current ) : msgs . length
504532 const currentIndex = base === - 1 ? msgs . length : base
505533 const targetIndex = currentIndex + offset
@@ -572,6 +600,8 @@ export default function Page() {
572600 let dockHeight = 0
573601 let scroller : HTMLDivElement | undefined
574602 let content : HTMLDivElement | undefined
603+ let scrollMark = 0
604+ let messageMark = 0
575605
576606 const scrollGestureWindowMs = 250
577607
@@ -616,6 +646,7 @@ export default function Page() {
616646 ( ) => {
617647 setStore ( "messageId" , undefined )
618648 setStore ( "changes" , "session" )
649+ setUi ( "pendingMessage" , undefined )
619650 } ,
620651 { defer : true } ,
621652 ) ,
@@ -1110,12 +1141,6 @@ export default function Page() {
11101141
11111142 let scrollStateFrame : number | undefined
11121143 let scrollStateTarget : HTMLDivElement | undefined
1113- const scrollSpy = createScrollSpy ( {
1114- onActive : ( id ) => {
1115- if ( id === store . messageId ) return
1116- setStore ( "messageId" , id )
1117- } ,
1118- } )
11191144
11201145 const updateScrollState = ( el : HTMLDivElement ) => {
11211146 const max = el . scrollHeight - el . clientHeight
@@ -1163,31 +1188,21 @@ export default function Page() {
11631188 ) ,
11641189 )
11651190
1166- createEffect (
1167- on (
1168- sessionKey ,
1169- ( ) => {
1170- scrollSpy . clear ( )
1171- } ,
1172- { defer : true } ,
1173- ) ,
1174- )
1175-
1176- const anchor = ( id : string ) => `message-${ id } `
1177-
11781191 const setScrollRef = ( el : HTMLDivElement | undefined ) => {
11791192 scroller = el
11801193 autoScroll . scrollRef ( el )
1181- scrollSpy . setContainer ( el )
11821194 if ( el ) scheduleScrollState ( el )
11831195 }
11841196
1197+ const markUserScroll = ( ) => {
1198+ scrollMark += 1
1199+ }
1200+
11851201 createResizeObserver (
11861202 ( ) => content ,
11871203 ( ) => {
11881204 const el = scroller
11891205 if ( el ) scheduleScrollState ( el )
1190- scrollSpy . markDirty ( )
11911206 } ,
11921207 )
11931208
@@ -1220,7 +1235,6 @@ export default function Page() {
12201235 if ( stick ) autoScroll . forceScrollToBottom ( )
12211236
12221237 if ( el ) scheduleScrollState ( el )
1223- scrollSpy . markDirty ( )
12241238 } ,
12251239 )
12261240
@@ -1248,7 +1262,6 @@ export default function Page() {
12481262
12491263 onCleanup ( ( ) => {
12501264 document . removeEventListener ( "keydown" , handleKeyDown )
1251- scrollSpy . destroy ( )
12521265 if ( reviewFrame !== undefined ) cancelAnimationFrame ( reviewFrame )
12531266 if ( scrollStateFrame !== undefined ) cancelAnimationFrame ( scrollStateFrame )
12541267 } )
@@ -1280,7 +1293,7 @@ export default function Page() {
12801293 < div class = "flex-1 min-h-0 overflow-hidden" >
12811294 < Switch >
12821295 < Match when = { params . id } >
1283- < Show when = { activeMessage ( ) } >
1296+ < Show when = { lastUserMessage ( ) } >
12841297 < MessageTimeline
12851298 mobileChanges = { mobileChanges ( ) }
12861299 mobileFallback = { reviewContent ( {
@@ -1300,8 +1313,7 @@ export default function Page() {
13001313 onAutoScrollHandleScroll = { autoScroll . handleScroll }
13011314 onMarkScrollGesture = { markScrollGesture }
13021315 hasScrollGesture = { hasScrollGesture }
1303- isDesktop = { isDesktop ( ) }
1304- onScrollSpyScroll = { scrollSpy . onScroll }
1316+ onUserScroll = { markUserScroll }
13051317 onTurnBackfillScroll = { historyWindow . onScrollerScroll }
13061318 onAutoScrollInteraction = { autoScroll . handleInteraction }
13071319 centered = { centered ( ) }
@@ -1320,8 +1332,6 @@ export default function Page() {
13201332 } }
13211333 renderedUserMessages = { historyWindow . renderedUserMessages ( ) }
13221334 anchor = { anchor }
1323- onRegisterMessage = { scrollSpy . register }
1324- onUnregisterMessage = { scrollSpy . unregister }
13251335 />
13261336 </ Show >
13271337 </ Match >
0 commit comments