Skip to content

Keep the last prompt sticky at the top of the transcript - #12

Draft
felipeorlando wants to merge 1 commit into
mainfrom
issue-9-sticky-prompt
Draft

felipeorlando wants to merge 1 commit into
mainfrom
issue-9-sticky-prompt

Conversation

@felipeorlando

Copy link
Copy Markdown
Owner

Closes #9

The prompt now stays pinned to the top of the transcript while its reply scrolls underneath, until the next prompt takes its place. Extends the existing Anchor prompts to top setting — no new setting.

  1. Unblocked sticky. content-visibility: auto + contain-intrinsic-block-size moved off .transcript-turn onto a new .transcript-turn-body. The paint containment implied by content-visibility was making any sticky descendant stick to the turn's own box — a no-op. The wrapper is now the sticky travel track; virtualization is preserved on the body, so the 0.1.35 transcript fold keeps every tool row mounted — project switching stays laggy on long sessions (still in 0.1.36) hardbeat920/monocode#107 property stays intact.
  2. Sticky positioning. The leading role === "user" item is pulled out as a direct child row of .transcript-turn with sticky top-0, only when the toggle is on.
  3. Collapse while stuck. One IntersectionObserver per user message (root = scrollerEl, rootMargin: "-1px 0px 0px 0px", threshold: 1), matching the existing per-message ResizeObserver cost. Stuck: line-clamp-1, opaque surface, subtle bottom border.

Two deviations from the issue text, both deliberate

  • zIndex moved. zIndex: stickyIndex was applied to the bubble, which is position: static in the document layout — z-index there does nothing for sticky stacking between turns. The same ascending value now sits on the sticky row itself, the element that actually stacks, and the dead stickyIndex prop was dropped from TranscriptBlock/UserMessageBlock.
  • Top-edge guard. "Not intersecting" alone also fires for a prompt entering from the bottom, which rendered unreached prompts pre-collapsed. The callback now also requires entry.boundingClientRect.top <= entry.rootBounds.top.
  • The opaque surface sits on the row rather than swapping the bubble's bg-content/10 — only a full-width bar blocks text scrolling past in the padding gaps. The bubble's tint composites over it and stays right-aligned in chat layout.

Verification

npm run check:web — exit 0, 127 files / 1327 tests. 4 new tests: sticky class present/absent per setting, ascending z-index on consecutive pinned prompts, and content-visibility landing on .transcript-turn-body with no .transcript-turn rule.

NOT verified — needs a run of the app

renderToStaticMarkup runs no effects and has no layout, so everything driven by the IntersectionObserver is untested: whether the prompt actually pins, the stuck→released transition, the one-line opaque bar, the top-edge guard, the handoff where the next prompt pushes the previous one out and the z-index ordering during that overlap, the bar's appearance under native glass, and whether contain-intrinsic-block-size on the body alone causes scroll jumps on long transcripts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keep the last prompt sticky at the top of the transcript

1 participant