[object Object]

← back to Wallco Ai

feat(/designs): floating scroll-to-top button (↑) appears after 2 viewports of scroll; respects prefers-reduced-motion; refocuses search on return so / shortcut feels natural

5733155b0f9634bc709ea875c5f07fafe6db35ec · 2026-05-14 10:38:16 -0700 · SteveStudio2

Files touched

Diff

commit 5733155b0f9634bc709ea875c5f07fafe6db35ec
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Thu May 14 10:38:16 2026 -0700

    feat(/designs): floating scroll-to-top button (↑) appears after 2 viewports of scroll; respects prefers-reduced-motion; refocuses search on return so / shortcut feels natural
---
 server.js | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/server.js b/server.js
index 41132d3..f2e39e1 100644
--- a/server.js
+++ b/server.js
@@ -3876,6 +3876,32 @@ ${cat === 'mural-scenic' ? `
   <div id="infinite-status" style="text-align:center;padding:24px 0;font:11px/1 var(--sans,system-ui);letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint,#888)">${page < pages ? `loading more · page ${page} of ${pages}` : `all ${total} designs loaded`}</div>
   <noscript><div class="pager">${pagerLinks}</div></noscript>
   ` : ''}
+
+  <!-- Floating scroll-to-top button — appears after the user has scrolled past two viewport heights. -->
+  <button type="button" id="scroll-top-btn" aria-label="Back to top of catalog" title="Back to top"
+    style="position:fixed;right:18px;bottom:18px;z-index:80;width:42px;height:42px;border-radius:50%;border:1px solid var(--line,#e0d9cd);background:var(--bg,#fff);color:var(--ink,#111);box-shadow:0 4px 12px rgba(0,0,0,.12);cursor:pointer;display:none;align-items:center;justify-content:center;font:600 18px/1 var(--sans,system-ui);transition:opacity .18s ease,transform .12s ease">↑</button>
+  <script>
+  (function(){
+    var btn = document.getElementById('scroll-top-btn');
+    if (!btn) return;
+    var threshold = window.innerHeight * 2;
+    function onScroll(){
+      var show = window.scrollY > threshold;
+      btn.style.display = show ? 'inline-flex' : 'none';
+    }
+    window.addEventListener('scroll', onScroll, { passive: true });
+    window.addEventListener('resize', function(){ threshold = window.innerHeight * 2; onScroll(); });
+    btn.addEventListener('click', function(){
+      // Respect prefers-reduced-motion: instant jump for those users.
+      var rm = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
+      window.scrollTo({ top: 0, behavior: rm ? 'auto' : 'smooth' });
+      // Also focus the search input on return so /-shortcut feels natural after.
+      var s = document.getElementById('catalog-search-input');
+      if (s) setTimeout(function(){ s.focus(); }, rm ? 0 : 320);
+    });
+    onScroll();
+  })();
+  </script>
 </section>
 </main>
 ${FOOTER}

← 7a4ab66 feat(/designs): clear-X button when search query non-empty;  ·  back to Wallco Ai  ·  feat(/designs): hue swatches 14px → 20px for tap-friendly mo f757e73 →