Perplexity Scroll Buttons (AFU IT)

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

目前為 2025-05-07 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Perplexity Scroll Buttons (AFU IT)
// @namespace    PerplexityTools
// @version      1.1
// @description  Adds Apple-style scroll buttons with auto-scroll enabled by default
// @author       AFU IT
// @match        https://*.perplexity.ai/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    
    // Configuration
    const buttonColor = '#20b8cd';
    let autoScrollInterval = null;
    let isAutoScrollEnabled = true; // Set to true by default
    
    // Create and add the scroll buttons
    function addScrollButtons() {
        // Remove existing buttons if any
        const existingBottomButton = document.getElementById('scroll-bottom-btn');
        const existingTopButton = document.getElementById('scroll-top-btn');
        const existingAutoButton = document.getElementById('auto-scroll-btn');
        
        if (existingBottomButton) existingBottomButton.remove();
        if (existingTopButton) existingTopButton.remove();
        if (existingAutoButton) existingAutoButton.remove();
        
        // Create the bottom scroll button
        const bottomButton = document.createElement('div');
        bottomButton.id = 'scroll-bottom-btn';
        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>';
        bottomButton.title = 'Scroll to bottom';
        
        // Style the bottom button
        bottomButton.style.cssText = `
            position: fixed;
            right: 20px;
            bottom: 120px;
            width: 32px;
            height: 32px;
            background: ${buttonColor};
            color: white;
            border-radius: 50%;
            font-size: 18px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            z-index: 99999;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            transition: transform 0.2s;
        `;
        
        // Add hover effect
        bottomButton.addEventListener('mouseover', function() {
            this.style.transform = 'scale(1.1)';
        });
        
        bottomButton.addEventListener('mouseout', function() {
            this.style.transform = 'scale(1)';
        });
        
        // Add click event for bottom button
        bottomButton.addEventListener('click', function() {
            const scrollContainer = document.querySelector('.scrollable-container.scrollbar');
            if (scrollContainer) {
                scrollContainer.scrollTop = scrollContainer.scrollHeight;
            }
        });
        
        // Create the top scroll button
        const topButton = document.createElement('div');
        topButton.id = 'scroll-top-btn';
        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>';
        topButton.title = 'Scroll to top';
        
        // Style the top button
        topButton.style.cssText = `
            position: fixed;
            right: 20px;
            bottom: 162px;
            width: 32px;
            height: 32px;
            background: ${buttonColor};
            color: white;
            border-radius: 50%;
            font-size: 18px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            z-index: 99999;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            transition: transform 0.2s;
        `;
        
        // Add hover effect
        topButton.addEventListener('mouseover', function() {
            this.style.transform = 'scale(1.1)';
        });
        
        topButton.addEventListener('mouseout', function() {
            this.style.transform = 'scale(1)';
        });
        
        // Add click event for top button
        topButton.addEventListener('click', function() {
            const scrollContainer = document.querySelector('.scrollable-container.scrollbar');
            if (scrollContainer) {
                scrollContainer.scrollTop = 0;
            }
        });
        
        // Create the auto-scroll toggle button with mouse scroll wheel icon
        const autoButton = document.createElement('div');
        autoButton.id = 'auto-scroll-btn';
        // Mouse scroll wheel SVG icon
        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>';
        autoButton.title = 'Toggle auto-scroll';
        
        // Style the auto-scroll button - active by default
        autoButton.style.cssText = `
            position: fixed;
            right: 20px;
            bottom: 204px;
            width: 32px;
            height: 32px;
            background: ${isAutoScrollEnabled ? buttonColor : '#888888'};
            color: white;
            border-radius: 50%;
            font-size: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            z-index: 99999;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            transition: transform 0.2s, background-color 0.3s;
        `;
        
        // Add hover effect
        autoButton.addEventListener('mouseover', function() {
            this.style.transform = 'scale(1.1)';
        });
        
        autoButton.addEventListener('mouseout', function() {
            this.style.transform = 'scale(1)';
        });
        
        // Add click event for auto-scroll button
        autoButton.addEventListener('click', function() {
            toggleAutoScroll();
            this.style.backgroundColor = isAutoScrollEnabled ? buttonColor : '#888888';
        });
        
        // Add to document
        document.body.appendChild(bottomButton);
        document.body.appendChild(topButton);
        document.body.appendChild(autoButton);
    }
    
    // Function to check if Perplexity is generating content
    function isGenerating() {
        return !!document.querySelector('button[aria-label="Stop generating response"]');
    }
    
    // Function to scroll to bottom
    function scrollToBottom() {
        const scrollContainer = document.querySelector('.scrollable-container.scrollbar');
        if (scrollContainer) {
            scrollContainer.scrollTop = scrollContainer.scrollHeight;
        }
    }
    
    // Toggle auto-scroll functionality
    function toggleAutoScroll() {
        isAutoScrollEnabled = !isAutoScrollEnabled;
        
        if (isAutoScrollEnabled) {
            // Start auto-scrolling
            startAutoScroll();
        } else {
            // Stop auto-scrolling
            stopAutoScroll();
        }
    }
    
    // Start auto-scrolling
    function startAutoScroll() {
        if (!autoScrollInterval) {
            autoScrollInterval = setInterval(() => {
                if (isGenerating()) {
                    scrollToBottom();
                }
            }, 300);
        }
    }
    
    // Stop auto-scrolling
    function stopAutoScroll() {
        if (autoScrollInterval) {
            clearInterval(autoScrollInterval);
            autoScrollInterval = null;
        }
    }
    
    // Initialize everything
    function initialize() {
        // Add the buttons
        addScrollButtons();
        
        // Start auto-scroll by default
        startAutoScroll();
        
        // Watch for URL changes
        let lastUrl = location.href;
        new MutationObserver(() => {
            if (location.href !== lastUrl) {
                lastUrl = location.href;
                setTimeout(() => {
                    addScrollButtons();
                    if (isAutoScrollEnabled) {
                        startAutoScroll();
                    }
                }, 1000);
            }
        }).observe(document, {subtree: true, childList: true});
        
        // Make sure buttons are always present
        setInterval(() => {
            if (!document.getElementById('auto-scroll-btn')) {
                addScrollButtons();
                if (isAutoScrollEnabled) {
                    startAutoScroll();
                }
            }
        }, 5000);
    }
    
    // Start when the page is ready
    if (document.readyState === 'complete') {
        initialize();
    } else {
        window.addEventListener('load', initialize);
    }
})();