GitHub Scroll To Top

Adds a scroll to top button to github

  1. // ==UserScript==
  2. // @name GitHub Scroll To Top
  3. // @namespace http://tampermonkey.net/
  4. // @version 2025-04-11
  5. // @description Adds a scroll to top button to github
  6. // @author Charles Pritchard
  7. // @match https://github.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. const targetElementSelector = ".application-main";
  16. const buttonClassName = "simple-scroll-top-button";
  17. const scrollThreshold = 200; // Pixels to scroll before showing button
  18.  
  19. let scrollButton = null; // Keep a reference to the button
  20.  
  21. // Function to handle showing/hiding the button based on scroll
  22. function handleScroll() {
  23. if (!scrollButton) return; // Exit if button doesn't exist
  24.  
  25. if (window.scrollY > scrollThreshold) {
  26. // Show button
  27. scrollButton.style.opacity = "1";
  28. scrollButton.style.transform = "translateY(0)";
  29. } else {
  30. // Hide button
  31. scrollButton.style.opacity = "0";
  32. scrollButton.style.transform = "translateY(50px)"; // Move down
  33. }
  34. }
  35.  
  36. function addButton() {
  37. if (document.querySelector(`.${buttonClassName}`)) {
  38. scrollButton = document.querySelector(`.${buttonClassName}`); // Ensure reference is set if already exists
  39. return; // Button already exists
  40. }
  41.  
  42. const button = document.createElement("button");
  43. button.textContent = "↑ Top";
  44. button.className = buttonClassName;
  45. button.onclick = () => {
  46. window.scrollTo({ top: 0, behavior: "smooth" });
  47. };
  48.  
  49. // Base styles
  50. button.style.position = "fixed";
  51. button.style.bottom = "20px";
  52. button.style.right = "20px";
  53. button.style.zIndex = "9999";
  54. button.style.padding = "8px 12px";
  55. button.style.cursor = "pointer";
  56. button.style.backgroundColor = "#222"; // Darker background
  57. button.style.color = "#eee"; // Lighter text
  58. button.style.border = "1px solid #555"; // Adjusted border
  59. button.style.borderRadius = "4px";
  60.  
  61. // Animation styles
  62. button.style.opacity = "0"; // Start hidden
  63. button.style.transform = "translateY(50px)"; // Start shifted down
  64. button.style.transition =
  65. "opacity 0.3s ease-out, transform 0.3s ease-out"; // Smooth transition
  66.  
  67. document.body.appendChild(button);
  68. scrollButton = button; // Store reference
  69. console.log("Scroll Top button added (initially hidden).");
  70.  
  71. // Add scroll listener only once
  72. window.removeEventListener("scroll", handleScroll); // Remove previous just in case
  73. window.addEventListener("scroll", handleScroll, { passive: true });
  74.  
  75. // Check initial scroll position immediately
  76. handleScroll();
  77. }
  78.  
  79. const observer = new MutationObserver((mutationsList, observer) => {
  80. if (document.querySelector(targetElementSelector)) {
  81. addButton();
  82. // Keep observer running? If GitHub SPA navigation removes/re-adds
  83. // .application-main, you might need the button added again.
  84. // If you only want it added once per full page load, disconnect.
  85. // observer.disconnect();
  86. }
  87. });
  88.  
  89. const checkBodyInterval = setInterval(() => {
  90. if (document.body) {
  91. clearInterval(checkBodyInterval);
  92. // Initial check
  93. if (document.querySelector(targetElementSelector)) {
  94. addButton();
  95. } else {
  96. // Start observing if target not found initially
  97. observer.observe(document.body, {
  98. childList: true,
  99. subtree: true,
  100. });
  101. }
  102. }
  103. }, 100);
  104. })();