Skip to content

[#2542] Add scroll button component and implement on views#2556

Merged
FisherSkyi merged 30 commits intoreposense:masterfrom
FisherSkyi:roll-back
Apr 16, 2026
Merged

[#2542] Add scroll button component and implement on views#2556
FisherSkyi merged 30 commits intoreposense:masterfrom
FisherSkyi:roll-back

Conversation

@FisherSkyi
Copy link
Copy Markdown
Member

Fixes #2542

Proposed commit message

Add roll back to top button

Currently, users have no quick way to navigate back to the top of the
page after scrolling down.

Let's add a floating button that scrolls the user back to the top of
the page on click.

Other information

N/A

@FisherSkyi FisherSkyi changed the title Feat: scroll button [#2542] Add scroll button component and implement on views Mar 16, 2026
@FisherSkyi FisherSkyi requested review from Airiinnn and removed request for Airiinnn March 16, 2026 10:36
@FisherSkyi FisherSkyi marked this pull request as ready for review March 23, 2026 10:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a “scroll back to top” affordance to the report UI by introducing a reusable scroll-to-top button and wiring it into the main report panes.

Changes:

  • Added a new c-scroll-top-button Vue component that shows/hides based on a scroll container’s scroll position and scrolls back to top on click.
  • Integrated the button into the summary pane and the right-side tab views (authorship + global file browser).
  • Registered the Font Awesome arrow-up icon and added Cypress coverage for the new button behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
frontend/src/views/c-summary.vue Renders the scroll-to-top button for the summary pane (#summary-wrapper).
frontend/src/views/c-scroll-top-button.vue New scroll-to-top button component (scroll listener + UI + styling).
frontend/src/views/c-global-file-browser.vue Renders the scroll-to-top button for the right tab pane (#tabs-wrapper).
frontend/src/views/c-authorship.vue Renders the scroll-to-top button for the right tab pane (#tabs-wrapper).
frontend/src/utils/load-font-awesome-icons.ts Adds faArrowUp to the Font Awesome library.
frontend/cypress/tests/globalBrowserView/globalBrowserView_scrollButton.cy.js Cypress coverage for scroll-to-top button in global file browser view.
frontend/cypress/tests/chartView/chartView_scrollButton.cy.js Cypress coverage for scroll-to-top button in the summary/chart view.

Comment thread frontend/cypress/tests/chartView/chartView_scrollButton.cy.js Outdated
Comment thread frontend/cypress/tests/chartView/chartView_scrollButton.cy.js Outdated
Comment thread frontend/src/views/c-scroll-top-button.vue Outdated
Comment thread frontend/src/views/c-authorship.vue Outdated
Comment thread frontend/src/views/c-scroll-top-button.vue Outdated
Comment thread frontend/src/views/c-scroll-top-button.vue Outdated
Comment thread frontend/src/views/c-scroll-top-button.vue Outdated
Comment thread frontend/src/views/c-scroll-top-button.vue Outdated
Comment thread frontend/src/views/c-scroll-top-button.vue Outdated
Comment thread frontend/src/views/c-global-file-browser.vue Outdated
@FisherSkyi
Copy link
Copy Markdown
Member Author

Update on copilot's review:

  1. Make c-scroll-top-button presentational only.
    In frontend/src/components/c-scroll-top-button.vue:

    • remove scrollContainerId, mounted, beforeUnmount, handleScroll, topFunction
    • add a boolean prop like showBackToTop
    • emit one event like scroll-to-top on click
    • change the root element from a plain div to button type="button"
    • replace the hard-coded id with a class such as .go-back-button
  2. Move scroll ownership to frontend/src/views/c-home.vue.
    c-home already owns both real scroll containers:

    • #summary-wrapper
    • #tabs-wrapper

    Add:

    • showSummaryBackToTop
    • showTabsBackToTop
    • Or to prevent duplicate method, we may use
      c-scroll-top-button(@scroll-to-top="scrollPaneToTop('summary')")
      c-scroll-top-button(@scroll-to-top="scrollPaneToTop('tabs')")
      Then in home.vue:
      methods: {
        scrollPaneToTop(pane: 'summary' | 'tabs') {
          const el = pane === 'summary'
            ? this.$refs.summaryWrapper
            : this.$refs.tabWrapper;
          (el as HTMLElement | undefined)?.scrollTo({ top: 0, behavior: 'smooth' });
        },
      }
    • scroll handlers for each wrapper
    • click handlers that scroll the corresponding wrapper to top
  3. Render the two button instances in c-home.vue, one per pane.
    Example idea:

    • one inside #summary-wrapper, bound to showSummaryBackToTop and scrollSummaryToTop
    • one inside #tabs-wrapper, bound to showTabsBackToTop and scrollTabsToTop
  4. Remove c-scroll-top-button usage from child views.
    Remove it from:

    • frontend/src/views/c-summary.vue
    • frontend/src/views/c-authorship.vue
    • frontend/src/views/c-global-file-browser.vue
  5. Update Cypress selectors.
    Since the button should no longer use #go-back-button, change tests to use something like:

    • #summary-wrapper .go-back-button
    • #tabs-wrapper .go-back-button

Rationale:

  • Keeps the child reusable.
    c-scroll-top-button becomes a generic control that only says “user clicked me” and “show/hide me”.
  • Avoids container binding.
    No scrollContainerId and document.getElementById(...) inside the reusable child.
  • Makes event handling unambiguous.
    Both buttons can emit the same scroll-to-top event, because each instance is wired separately in c-home.vue.

@FisherSkyi FisherSkyi closed this Mar 30, 2026
@github-actions
Copy link
Copy Markdown
Contributor

The following links are for previewing this pull request:

@FisherSkyi FisherSkyi reopened this Mar 30, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

padding: 0;
place-content: center;
place-items: center;
position: sticky;
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

Using position: sticky here keeps the button in normal document flow. Because the button is rendered after all content in each scroll container, it won’t be reachable/visible until the user scrolls near the bottom of the container (defeating the purpose of a “back to top” control for long reports). Consider positioning it out of flow (e.g., position: absolute within a position: relative scroll container, or position: fixed with appropriate container scoping) so it can appear whenever showBackToTop becomes true.

Suggested change
position: sticky;
position: fixed;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

From a practical perspective fixed will cause the left and right buttons overlap as they are both positioned relative to the viewpoint. But help and suggestions are welcome here as I don't really understand the mechanism of css layout.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Regarding this issue, yes, position: fixed won't work here. position: sticky does technically work (the button sticks to the bottom of the visible scroll area since it's the last child in the container), but it stays in document flow and can cause layout shifts.

The cleaner fix might be position: absolute scoped to each panel:

  1. Add position: relative to #summary-wrapper in style.scss).
  2. Change the button to position: absolute; bottom: 20px; right: 20px and remove margin-left: auto.
  3. Make sure c-scroll-top-buttonin the tabs panel out of .tab-pane/.tab-content and make it a direct child of #tabs-wrapper, so it floats over the panel content rather than scrolling with it. The summary panel button is already placed correctly.
    This keeps each button scoped to its own panel, out of document flow, and visible at any scroll depth regardless of content length.

Can try this out though and see if it works!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

agree with ashmita here !

Copy link
Copy Markdown
Member Author

@FisherSkyi FisherSkyi Apr 9, 2026

Choose a reason for hiding this comment

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

The behavior with proposed fix: the button will scroll along with the segment, which is not desirable. Right now I think we can keep the sticky.

Comment thread frontend/src/components/c-scroll-top-button.vue
Comment thread frontend/src/utils/load-font-awesome-icons.ts Outdated
Copy link
Copy Markdown
Contributor

@ashmitahaldar ashmitahaldar left a comment

Choose a reason for hiding this comment

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

Overall great work! Just some questions and inputs on the existing PR comments.

padding: 0;
place-content: center;
place-items: center;
position: sticky;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Regarding this issue, yes, position: fixed won't work here. position: sticky does technically work (the button sticks to the bottom of the visible scroll area since it's the last child in the container), but it stays in document flow and can cause layout shifts.

The cleaner fix might be position: absolute scoped to each panel:

  1. Add position: relative to #summary-wrapper in style.scss).
  2. Change the button to position: absolute; bottom: 20px; right: 20px and remove margin-left: auto.
  3. Make sure c-scroll-top-buttonin the tabs panel out of .tab-pane/.tab-content and make it a direct child of #tabs-wrapper, so it floats over the panel content rather than scrolling with it. The summary panel button is already placed correctly.
    This keeps each button scoped to its own panel, out of document flow, and visible at any scroll depth regardless of content length.

Can try this out though and see if it works!

Comment thread frontend/cypress/tests/chartView/chartView_scrollButton.cy.js
});

it('shows the button when scroll more than 200 pixels', () => {
cy.get('#tabs-wrapper').scrollTo(0, 300).trigger('scroll');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What does this .trigger('scroll') do? Why does test 2 and 3 use it but not test 1? Just a bit confused haha, would be good to understand.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

trigger will emit the event "scroll".

scroll is an event. It's handler is in c-home.vue line 48 #summary-wrapper(ref="summaryWrapper", @scroll="handleSummaryScroll")

trigger is needed, as cy.scrollTo() changes the element's scrollTop property in the DOM. But in test environments (on CI/CD env specifically), the native scroll event does not fire automatically

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@FisherSkyi Thanks for clarifying! Do you need to include it then in the other tests or no need?

Comment thread frontend/src/components/c-scroll-top-button.vue Outdated
Copy link
Copy Markdown
Contributor

@jonasongg jonasongg left a comment

Choose a reason for hiding this comment

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

lgtm other than the small comment!

padding: 0;
place-content: center;
place-items: center;
position: sticky;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

agree with ashmita here !

Copy link
Copy Markdown
Contributor

@ashmitahaldar ashmitahaldar left a comment

Choose a reason for hiding this comment

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

Generally LGTM! Would just like you to check if .trigger() is needed on other tests, otherwise looks good to go.

@FisherSkyi
Copy link
Copy Markdown
Member Author

Generally LGTM! Would just like you to check if .trigger() is needed on other tests, otherwise looks good to go.

I double checked and it seems scrollTo along is enough. Chaining with .trigger() would emit scroll event twice, which is not desirable.

Also while exploring I found another separate issue #2574 but it should be addressed in separate pr.

@FisherSkyi FisherSkyi requested a review from jonasongg April 12, 2026 03:21
Copy link
Copy Markdown
Member

@CYX22222003 CYX22222003 left a comment

Choose a reason for hiding this comment

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

LGTM!

scrollTabsToTop(): void {
const el = this.$refs.tabWrapper as HTMLElement | undefined;
el?.scrollTo({ top: 0, behavior: 'smooth' });
},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Scrolling logic appears to be sound.

@FisherSkyi FisherSkyi merged commit 5f50615 into reposense:master Apr 16, 2026
10 checks passed
FisherSkyi added a commit that referenced this pull request Apr 16, 2026
@github-actions
Copy link
Copy Markdown
Contributor

The following links are for previewing this pull request:

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add roll back to top button

5 participants