SQLpage icon indicating copy to clipboard operation
SQLpage copied to clipboard

Add "Go to Top" Button Component

Open amrutadotorg opened this issue 1 year ago • 7 comments

Hello,

It would be incredibly helpful to have a "Go to Top" button integrated into the SQLPage. Given the extensive reading involved in my use case, such a feature would significantly enhance user experience by allowing users to quickly navigate back to the top of the page.

The button should be clearly visible but not intrusive. It could be similar to the example from the Tabler.io website, as shown in the attached screenshot. Screenshot 2024-06-24 at 19 48 02

amrutadotorg avatar Jun 24 '24 21:06 amrutadotorg

Maybe we could add a "position" attribute to the button component that could be set to inline (the default) or "(top|bottom) (right|left)" ?

And for scrolling to the top, we would just make a button that targets #sqlpage_header.

Pull request welcome !

lovasoa avatar Jun 26 '24 20:06 lovasoa

I’m not sure if a standard button is sufficient. The concept of a ‘go to the top’ button is more complex. It remains hidden even if you scroll down slightly, only appearing when it’s truly needed.

amrutadotorg avatar Jun 28 '24 11:06 amrutadotorg

I'm not sure if SQLpage needs to add any additional features, but I'm new to the project. Please let me know what I'm missing.

HTML spec provides for page scrolling using anchors. When an anchor is empty, the page is scrolled to the top.

https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier

Example sqlpage implementation:

SELECT
  'button' AS component;

SELECT
  '#' AS link,
  'Go to top' AS title;

Note, this is also how developers can, for ex, provide a table of contents:

SELECT
  'button' AS component;

SELECT
  '#' AS link,
  'Here' AS title;

SELECT
  '#chapter-1' AS link,
  'Your First SQLPage' AS title;

SELECT
  '#chapter-2' AS link,
  'Your Second SQLPage' AS title;

--
-- much later in the page
SELECT
  'title' AS component,
  'chapter-2' AS id,
  'Your second SQLPage' as contents;

Using CSS scroll-* styles and well-placed IDs, developers have a lot of control. https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin

bever1337 avatar Nov 25 '24 06:11 bever1337

Hi @lovasoa before making any PR please take a look at this implementation and let me know what do you think.

The enhanced button component now includes the requested "Go to Top" functionality with the following features:

New position attribute that can be set to:

  • top-right
  • top-left
  • bottom-right
  • bottom-left

If not specified, it behaves as the original inline button

Scroll visibility behavior:

The button remains hidden until the user scrolls past a threshold (300px) When scrolling down sufficiently, the button smoothly appears with a fade-in effect When scrolling back up near the top, the button automatically hides

Default target:

When using a positioned button without specifying a link, it automatically targets #sqlpage_header to scroll to the top You can still specify a custom link if needed

{{#*inline "button_content"}}
    {{~#if image~}}
        <span {{~#if title}} class="me-1"{{/if}}>
            {{~#if (eq ../size 'sm')}}
                <img width=16 height=16 src="{{image}}">
            {{~else~}}
                <img width=24 height=24 src="{{image}}">
            {{~/if~}}
        </span>
    {{~/if~}}
    {{~#if icon~}}
        <span {{~#if (not narrow)}} class="me-1"{{/if}}>{{~icon_img icon~}}</span>
    {{~/if~}}
    {{~title~}}
    {{~#if icon_after ~}}
        <span class="ms-1">{{~icon_img icon_after~}}</span>
    {{~/if}}
{{/inline}}

{{#if position}}
<style>
.scroll-to-top {
    position: fixed;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s, visibility 0.3s;
    z-index: 1000;
    {{#if (eq position 'top-right')}}top: 20px; right: 20px;{{/if}}
    {{#if (eq position 'top-left')}}top: 20px; left: 20px;{{/if}}
    {{#if (eq position 'bottom-right')}}bottom: 20px; right: 20px;{{/if}}
    {{#if (eq position 'bottom-left')}}bottom: 20px; left: 20px;{{/if}}
}
.scroll-to-top.visible {
    opacity: 1;
    visibility: visible;
}
</style>
<div id="{{#if id}}{{id}}{{else}}scroll-btn-{{random}}{{/if}}" class="scroll-to-top {{class}}">
    {{#each_row}}
        {{#if form}}
        <button type="submit" form="{{form}}" {{#if link}}formaction="{{link}}"{{/if}} 
        {{else}}
        <a href="{{#if link}}{{link}}{{else}}#sqlpage_header{{/if}}"
        {{/if}}
            class="btn text-wrap{{#if disabled}} disabled{{/if}}
            {{~#if color}} btn-{{color}}{{/if}}
            {{~#if ../size}} btn-{{../size}}{{/if}}
            {{~#if outline}} btn-outline-{{outline}}{{/if}}
            {{~#if ../shape}} btn-{{../shape}}{{/if}}
            {{~#if narrow}} btn-icon{{/if}}
            {{~#if space_after}} me-auto{{/if}}"
            {{~#if target}} target="{{target}}"{{/if}}
            {{~#if download}} download="{{download}}"{{/if}}
            {{~#if rel}} rel="{{rel}}"{{/if}}
            {{~#if tooltip}} data-bs-toggle="tooltip" data-bs-placement="top" title="{{tooltip}}"{{/if}}
            role="button">
            {{> button_content}}
        {{#if form}}
        </button>
        {{else}}
        </a>
        {{/if}}
    {{/each_row}}
</div>
<script>
(function() {
    const btn = document.getElementById('{{#if id}}{{id}}{{else}}scroll-btn-{{random}}{{/if}}');
    const scrollThreshold = 300; // Show button after scrolling this many pixels
    
    function checkScroll() {
        if (window.scrollY > scrollThreshold) {
            btn.classList.add('visible');
        } else {
            btn.classList.remove('visible');
        }
    }
    
    window.addEventListener('scroll', checkScroll);
    checkScroll(); // Initial check
})();
</script>
{{else}}
<div class="btn-list mb-2 {{#if justify}}justify-content-{{justify}}{{/if}} {{class}}">
{{#each_row}}
    {{#if form}}
    <button type="submit" form="{{form}}" {{#if link}}formaction="{{link}}"{{/if}} 
    {{else}}
    <a href="{{link}}"
    {{/if}}
        class="btn text-wrap{{#if disabled}} disabled{{/if}}
        {{~#if color}} btn-{{color}}{{/if}}
        {{~#if ../size}} btn-{{../size}}{{/if}}
        {{~#if outline}} btn-outline-{{outline}}{{/if}}
        {{~#if ../shape}} btn-{{../shape}}{{/if}}
        {{~#if narrow}} btn-icon{{/if}}
        {{~#if space_after}} me-auto{{/if}}"
        {{~#if id}} id="{{id}}"{{/if}}
        {{~#if target}} target="{{target}}"{{/if}}
        {{~#if download}} download="{{download}}"{{/if}}
        {{~#if rel}} rel="{{rel}}"{{/if}}
        {{~#if tooltip}} data-bs-toggle="tooltip" data-bs-placement="top" title="{{tooltip}}"{{/if}}
        role="button">
        {{> button_content}}
    {{#if form}}
    </button>
    {{else}}
    </a>
    {{/if}}
{{/each_row}}
</div>
{{/if}}

amrutadotorg avatar May 07 '25 09:05 amrutadotorg

@lovasoa Since you’ll be working on the button component for #934, please also take a look at this improvement. Thank you!

amrutadotorg avatar Jun 27 '25 13:06 amrutadotorg

Hello @amrutadotorg and thanks for your suggestion, in order to make sure to understand the specifics (and because you mentioned it would be very useful in your case specifically), we can organize a quick call to see how we can start developping this feature. Please send me an email to discuss the matter [email protected]. thanks !

alexisrc1 avatar Jun 27 '25 20:06 alexisrc1

Hello Alexis,

Thank you for your message!

Just to clarify, my case is not particularly specific or unique — I simply thought that having a “Go to top” option available as part of the button component would be a useful addition for many SQLPage users. On my website, for example, there’s quite a lot of text, so having such a button would improve navigation and usability.

That said, if you consider this more of an edge case, I completely understand and will of course respect your decision.

Best regards, Radoslaw

amrutadotorg avatar Jun 27 '25 22:06 amrutadotorg