diff --git a/static/Back-to-top.png b/static/Back-to-top.png new file mode 100644 index 00000000..b44e336a Binary files /dev/null and b/static/Back-to-top.png differ diff --git a/static/script.js b/static/script.js index 8123c424..876e3b30 100644 --- a/static/script.js +++ b/static/script.js @@ -188,6 +188,35 @@ var githubInput = document.getElementById('github-username'); var errorMsg = document.getElementById('github-modal-error'); +/* ---- Scroll-to-top button ---- */ + +var scrollBtn = document.querySelector(".back-to-top"); + +if (scrollBtn) { + + // Show the button after scrolling down 300px + window.addEventListener("scroll", function () { + + if (window.scrollY > 300) { + scrollBtn.style.display = "block"; + } else { + scrollBtn.style.display = "none"; + } + + }); + + scrollBtn.addEventListener("click", function () { + + window.scrollTo({ + top: 0, + behavior: "smooth" + }); + + }); + +} + + // ============================================================ // Mobile navigation toggle (runs on all pages) // ============================================================ @@ -705,53 +734,23 @@ if (isIndexPage) { setLoadingState(true); - requestAnimationFrame(function () { + renderResults(data.projects || [], data.message); + }) + .catch(function () { - var payload = { - skills: skillsHidden.value.trim() || skillsTextInput.value.trim(), - level: document.getElementById("level").value, - interest: document.getElementById("interest").value, - time: document.getElementById("time").value - }; + setLoadingState(false); - fetch("/api/recommend", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(payload) - }) - .then(function (res) { - return res.json(); - }) - .then(function (data) { - - setLoadingState(false); - - if (data.error) { var generalErr = document.getElementById("form-error-general"); + if (generalErr) { - generalErr.textContent = data.error; + generalErr.textContent = + "Something went wrong. Please try again."; } - return; - } - - renderResults(data.projects || [], data.message); - }) - .catch(function (err) { - - setLoadingState(false); - - var generalErr = document.getElementById("form-error-general"); + }); - if (generalErr) { - generalErr.textContent = - "Something went wrong. Please try again."; - } + }); - console.error("API request failed:", err); - }); }); }); @@ -802,8 +801,9 @@ if (isIndexPage) { // Clear out any cards from a previous search before showing new ones resultsGrid.innerHTML = ""; - if (!projects || projects.length === 0) { - resultsGrid.style.display = "none"; + + if (!projects || projects.length === 0) { //if no projects returned from api, show the "no results" message and hide the grid + resultsGrid.style.display = "none"; resultsEmptyEl.style.display = "block"; // Show a friendly custom message when the user selected an interest @@ -1396,60 +1396,3 @@ updateRoadmapProgress(); }); } // end github modal handlers - -// ============================================================ -// SCROLL NAVIGATION BUTTON (runs on all pages) -// ============================================================ -(function () { - var SCROLL_THRESHOLD = 200; - var scrollTopBtn = document.getElementById('scroll-top-btn'); - var scrollBtnIcon = document.getElementById('scroll-btn-icon'); - var atBottom = false; - - var ARROW_UP = ''; - var ARROW_DOWN = ''; - - function isNearBottom() { - return (window.innerHeight + window.pageYOffset) >= document.body.scrollHeight - 40; - } - - function handleScroll() { - if (!scrollTopBtn) return; - if (window.pageYOffset > SCROLL_THRESHOLD) { - scrollTopBtn.classList.add('visible'); - } else { - scrollTopBtn.classList.remove('visible'); - } - if (isNearBottom()) { - atBottom = true; - scrollTopBtn.setAttribute('aria-label', 'Scroll to top'); - scrollTopBtn.title = 'Scroll to top'; - if (scrollBtnIcon) scrollBtnIcon.innerHTML = ARROW_UP; - } else { - atBottom = false; - scrollTopBtn.setAttribute('aria-label', 'Scroll to bottom'); - scrollTopBtn.title = 'Scroll to bottom'; - if (scrollBtnIcon) scrollBtnIcon.innerHTML = ARROW_DOWN; - } - } - - main - if (scrollTopBtn) { - window.addEventListener('scroll', handleScroll, { passive: true }); - scrollTopBtn.addEventListener('click', function () { - if (atBottom) { - window.scrollTo({ top: 0, behavior: 'smooth' }); - } else { - window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); - } - }); - handleScroll(); - } -}()); - -/* Only wire up listeners if the button exists on this page */ -if (scrollTopBtn) { - window.addEventListener('scroll', handleScroll); - scrollTopBtn.addEventListener('click', scrollToTop); -} - main diff --git a/static/style.css b/static/style.css index 2bb0431c..eb1e6807 100644 --- a/static/style.css +++ b/static/style.css @@ -3529,37 +3529,27 @@ html[data-theme="dark"] .btn-view-code-sm { white-space: pre; color: #e6edf3; } - -@media (prefers-reduced-motion: reduce) { - html:focus-within { - scroll-behavior: auto; - } - - *, - *::before, - *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } +.back-to-top { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 100; + display: none; /* Hidden by default */ } -.theme-toggle { - width: 42px; - height: 42px; - border-radius: 12px; - border: 1px solid rgba(255,255,255,0.15); - background: rgba(255,255,255,0.08); - color: white; - cursor: pointer; - font-size: 1rem; - transition: all 0.25s ease; +.back-to-top img { + width: 50px; + height: 50px; + opacity: 0.7; + transition: opacity 0.3s ease; } -.theme-toggle:hover { - background: rgba(255,255,255,0.18); - transform: translateY(-2px); +.back-to-top img:hover { + opacity: 1; } -/* ============================================================ - WORKING DARK MODE +.back-to-top button { + background: transparent; + border: none; + cursor: pointer; +} diff --git a/templates/index.html b/templates/index.html index ebd499c3..66d67420 100644 --- a/templates/index.html +++ b/templates/index.html @@ -494,6 +494,8 @@

Find Your Next Project

+ +
@@ -684,6 +686,15 @@

What it leads to

+ +
+ +