Perplexity Scroll Buttons (AFU IT)

Adds Apple-style scroll buttons with auto-scroll enabled by default

  1. // ==UserScript==
  2. // @name Perplexity Scroll Buttons (AFU IT)
  3. // @namespace PerplexityTools
  4. // @version 1.1
  5. // @description Adds Apple-style scroll buttons with auto-scroll enabled by default
  6. // @author AFU IT
  7. // @match https://*.perplexity.ai/*
  8. // @license MIT
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. // Configuration
  15. const buttonColor = '#20b8cd';
  16. let autoScrollInterval = null;
  17. let isAutoScrollEnabled = true; // Set to true by default
  18. // Create and add the scroll buttons
  19. function addScrollButtons() {
  20. // Remove existing buttons if any
  21. const existingBottomButton = document.getElementById('scroll-bottom-btn');
  22. const existingTopButton = document.getElementById('scroll-top-btn');
  23. const existingAutoButton = document.getElementById('auto-scroll-btn');
  24. if (existingBottomButton) existingBottomButton.remove();
  25. if (existingTopButton) existingTopButton.remove();
  26. if (existingAutoButton) existingAutoButton.remove();
  27. // Create the bottom scroll button
  28. const bottomButton = document.createElement('div');
  29. bottomButton.id = 'scroll-bottom-btn';
  30. bottomButton.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M19 12l-7 7-7-7"></path></svg>';
  31. bottomButton.title = 'Scroll to bottom';
  32. // Style the bottom button
  33. bottomButton.style.cssText = `
  34. position: fixed;
  35. right: 20px;
  36. bottom: 120px;
  37. width: 32px;
  38. height: 32px;
  39. background: ${buttonColor};
  40. color: white;
  41. border-radius: 50%;
  42. font-size: 18px;
  43. display: flex;
  44. align-items: center;
  45. justify-content: center;
  46. cursor: pointer;
  47. z-index: 99999;
  48. box-shadow: 0 2px 5px rgba(0,0,0,0.2);
  49. transition: transform 0.2s;
  50. `;
  51. // Add hover effect
  52. bottomButton.addEventListener('mouseover', function() {
  53. this.style.transform = 'scale(1.1)';
  54. });
  55. bottomButton.addEventListener('mouseout', function() {
  56. this.style.transform = 'scale(1)';
  57. });
  58. // Add click event for bottom button
  59. bottomButton.addEventListener('click', function() {
  60. const scrollContainer = document.querySelector('.scrollable-container.scrollbar');
  61. if (scrollContainer) {
  62. scrollContainer.scrollTop = scrollContainer.scrollHeight;
  63. }
  64. });
  65. // Create the top scroll button
  66. const topButton = document.createElement('div');
  67. topButton.id = 'scroll-top-btn';
  68. topButton.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"></path></svg>';
  69. topButton.title = 'Scroll to top';
  70. // Style the top button
  71. topButton.style.cssText = `
  72. position: fixed;
  73. right: 20px;
  74. bottom: 162px;
  75. width: 32px;
  76. height: 32px;
  77. background: ${buttonColor};
  78. color: white;
  79. border-radius: 50%;
  80. font-size: 18px;
  81. display: flex;
  82. align-items: center;
  83. justify-content: center;
  84. cursor: pointer;
  85. z-index: 99999;
  86. box-shadow: 0 2px 5px rgba(0,0,0,0.2);
  87. transition: transform 0.2s;
  88. `;
  89. // Add hover effect
  90. topButton.addEventListener('mouseover', function() {
  91. this.style.transform = 'scale(1.1)';
  92. });
  93. topButton.addEventListener('mouseout', function() {
  94. this.style.transform = 'scale(1)';
  95. });
  96. // Add click event for top button
  97. topButton.addEventListener('click', function() {
  98. const scrollContainer = document.querySelector('.scrollable-container.scrollbar');
  99. if (scrollContainer) {
  100. scrollContainer.scrollTop = 0;
  101. }
  102. });
  103. // Create the auto-scroll toggle button with mouse scroll wheel icon
  104. const autoButton = document.createElement('div');
  105. autoButton.id = 'auto-scroll-btn';
  106. // Mouse scroll wheel SVG icon
  107. autoButton.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="3" width="12" height="18" rx="6" ry="6"></rect><line x1="12" y1="7" x2="12" y2="11"></line></svg>';
  108. autoButton.title = 'Toggle auto-scroll';
  109. // Style the auto-scroll button - active by default
  110. autoButton.style.cssText = `
  111. position: fixed;
  112. right: 20px;
  113. bottom: 204px;
  114. width: 32px;
  115. height: 32px;
  116. background: ${isAutoScrollEnabled ? buttonColor : '#888888'};
  117. color: white;
  118. border-radius: 50%;
  119. font-size: 16px;
  120. display: flex;
  121. align-items: center;
  122. justify-content: center;
  123. cursor: pointer;
  124. z-index: 99999;
  125. box-shadow: 0 2px 5px rgba(0,0,0,0.2);
  126. transition: transform 0.2s, background-color 0.3s;
  127. `;
  128. // Add hover effect
  129. autoButton.addEventListener('mouseover', function() {
  130. this.style.transform = 'scale(1.1)';
  131. });
  132. autoButton.addEventListener('mouseout', function() {
  133. this.style.transform = 'scale(1)';
  134. });
  135. // Add click event for auto-scroll button
  136. autoButton.addEventListener('click', function() {
  137. toggleAutoScroll();
  138. this.style.backgroundColor = isAutoScrollEnabled ? buttonColor : '#888888';
  139. });
  140. // Add to document
  141. document.body.appendChild(bottomButton);
  142. document.body.appendChild(topButton);
  143. document.body.appendChild(autoButton);
  144. }
  145. // Function to check if Perplexity is generating content
  146. function isGenerating() {
  147. return !!document.querySelector('button[aria-label="Stop generating response"]');
  148. }
  149. // Function to scroll to bottom
  150. function scrollToBottom() {
  151. const scrollContainer = document.querySelector('.scrollable-container.scrollbar');
  152. if (scrollContainer) {
  153. scrollContainer.scrollTop = scrollContainer.scrollHeight;
  154. }
  155. }
  156. // Toggle auto-scroll functionality
  157. function toggleAutoScroll() {
  158. isAutoScrollEnabled = !isAutoScrollEnabled;
  159. if (isAutoScrollEnabled) {
  160. // Start auto-scrolling
  161. startAutoScroll();
  162. } else {
  163. // Stop auto-scrolling
  164. stopAutoScroll();
  165. }
  166. }
  167. // Start auto-scrolling
  168. function startAutoScroll() {
  169. if (!autoScrollInterval) {
  170. autoScrollInterval = setInterval(() => {
  171. if (isGenerating()) {
  172. scrollToBottom();
  173. }
  174. }, 300);
  175. }
  176. }
  177. // Stop auto-scrolling
  178. function stopAutoScroll() {
  179. if (autoScrollInterval) {
  180. clearInterval(autoScrollInterval);
  181. autoScrollInterval = null;
  182. }
  183. }
  184. // Initialize everything
  185. function initialize() {
  186. // Add the buttons
  187. addScrollButtons();
  188. // Start auto-scroll by default
  189. startAutoScroll();
  190. // Watch for URL changes
  191. let lastUrl = location.href;
  192. new MutationObserver(() => {
  193. if (location.href !== lastUrl) {
  194. lastUrl = location.href;
  195. setTimeout(() => {
  196. addScrollButtons();
  197. if (isAutoScrollEnabled) {
  198. startAutoScroll();
  199. }
  200. }, 1000);
  201. }
  202. }).observe(document, {subtree: true, childList: true});
  203. // Make sure buttons are always present
  204. setInterval(() => {
  205. if (!document.getElementById('auto-scroll-btn')) {
  206. addScrollButtons();
  207. if (isAutoScrollEnabled) {
  208. startAutoScroll();
  209. }
  210. }
  211. }, 5000);
  212. }
  213. // Start when the page is ready
  214. if (document.readyState === 'complete') {
  215. initialize();
  216. } else {
  217. window.addEventListener('load', initialize);
  218. }
  219. })();