Skip to content

fix: remeasure virtualized rows after scroll restore#93

Open
AlejandroAkbal wants to merge 1 commit intomainfrom
auto-triage/178-image-overlapping
Open

fix: remeasure virtualized rows after scroll restore#93
AlejandroAkbal wants to merge 1 commit intomainfrom
auto-triage/178-image-overlapping

Conversation

@AlejandroAkbal
Copy link
Member

@AlejandroAkbal AlejandroAkbal commented Mar 13, 2026

Summary

  • remeasure virtualized rows after restored scroll positions so already-rendered posts recalculate their height instead of stacking on top of each other
  • apply the same recovery path to the premium saved posts page because it shares the same window virtualizer behavior
  • keep the fix scoped to scroll-restored/reloaded sessions by remeasuring on mount, pageshow, and list-length changes while the page is already scrolled

Validation

  • npx prettier --check \"pages/posts/[domain].vue\" \"pages/premium/saved-posts/[domain].vue\"
  • npm run build (fails due to a pre-existing missing file import: /Users/lume/Projects/Rule-34-App-worktree-47344/assets/lib/rule-34-shared-resources/src/util/BooruUtils imported by pages/premium/additional-boorus.vue)

Feedback

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved scroll position restoration and list rendering stability when navigating back to your posts
    • Enhanced visual stability of virtualized post lists during page transitions and data updates
    • Fixed layout flickering that could occur when returning to previously visited pages

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

Walkthrough

Adds client-side scroll restoration and virtualization remeasurement logic to two posts listing pages. Introduces lifecycle hooks and event listeners to detect page visibility changes, then performs staged row measurements (immediate, next animation frame, 250ms timeout) to stabilize virtual scrolling layout after navigation or data updates.

Changes

Cohort / File(s) Summary
Scroll Restoration & Virtualization Remeasurement
pages/posts/[domain].vue, pages/premium/saved-posts/[domain].vue
Both files receive identical enhancements: adds scrollRestoreRemeasureTimeout tracker, clearScrollRestoreRemeasureTimeout helper, and remeasureAfterScrollRestore() function that performs staged measurements. Extends onMounted to initialize parent offset, trigger remeasurement, and register pageshow listener. Adds onBeforeUnmount cleanup for timeouts and listeners. Includes watcher on allRows.length to remeasure on data changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: remeasure virtualized rows after scroll restore' clearly and specifically describes the main change: adding remeasurement logic for virtualized rows after scroll restoration events.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auto-triage/178-image-overlapping
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch auto-triage/178-image-overlapping
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pages/posts/[domain].vue (1)

575-699: 🛠️ Refactor suggestion | 🟠 Major

Extract scroll-restore remeasurement into a shared composable.

Line 575 through Line 699 introduces a full lifecycle/timer/watch flow that is duplicated in the premium page. This should be centralized to prevent behavior drift and simplify future fixes.

Proposed refactor sketch
- let scrollRestoreRemeasureTimeout: ReturnType<typeof setTimeout> | null = null
- function clearScrollRestoreRemeasureTimeout() { ... }
- function remeasureAfterScrollRestore() { ... }
- function onPageShow() { ... }
- onMounted(() => { ... })
- onBeforeUnmount(() => { ... })
- watch(() => allRows.value.length, () => { remeasureAfterScrollRestore() })
+ useVirtualizerScrollRestoreRemeasure({
+   rowVirtualizer,
+   parentRef,
+   parentOffsetRef,
+   rowCount: computed(() => allRows.value.length)
+ })
// composables/useVirtualizerScrollRestoreRemeasure.ts
export function useVirtualizerScrollRestoreRemeasure({ rowVirtualizer, parentRef, parentOffsetRef, rowCount }) {
  // move timeout cleanup, pageshow handler, mount/unmount, and rowCount watch here
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/posts/`[domain].vue around lines 575 - 699, Extract the scroll-restore
remeasurement lifecycle and timer logic into a composable named
useVirtualizerScrollRestoreRemeasure and replace the in-file implementation:
move the scrollRestoreRemeasureTimeout state,
clearScrollRestoreRemeasureTimeout(), remeasureAfterScrollRestore(),
onPageShow(), the pageshow listener setup/teardown in onMounted/onBeforeUnmount,
and the watch that reacts to allRows.length into the composable; accept and use
the passed-in refs rowVirtualizer, parentRef, parentOffsetRef and a reactive
rowCount (or allRows) parameter, expose a measureElement helper (wrapping
rowVirtualizer.value.measureElement) and an init or returned remeasure function
if needed, and update the component to call the composable and set
parentOffsetRef from parentRef as before so behavior remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pages/posts/`[domain].vue:
- Around line 575-699: Extract the scroll-restore remeasurement lifecycle and
timer logic into a composable named useVirtualizerScrollRestoreRemeasure and
replace the in-file implementation: move the scrollRestoreRemeasureTimeout
state, clearScrollRestoreRemeasureTimeout(), remeasureAfterScrollRestore(),
onPageShow(), the pageshow listener setup/teardown in onMounted/onBeforeUnmount,
and the watch that reacts to allRows.length into the composable; accept and use
the passed-in refs rowVirtualizer, parentRef, parentOffsetRef and a reactive
rowCount (or allRows) parameter, expose a measureElement helper (wrapping
rowVirtualizer.value.measureElement) and an init or returned remeasure function
if needed, and update the component to call the composable and set
parentOffsetRef from parentRef as before so behavior remains identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 34354a26-3eaf-43e1-ab8e-707746c236db

📥 Commits

Reviewing files that changed from the base of the PR and between eeee500 and e72fd1a.

📒 Files selected for processing (2)
  • pages/posts/[domain].vue
  • pages/premium/saved-posts/[domain].vue

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.

1 participant