scroll-button

scroll-button (Mobile Optimized: Smaller & Auto-Fade)

Από την 17/12/2025. Δείτε την τελευταία έκδοση.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         scroll-button
// @namespace    https://github.com/livinginpurple
// @version      20251217.03
// @description  scroll-button (Mobile Optimized: Smaller & Auto-Fade)
// @license      WTFPL
// @author       livinginpurple
// @include      *
// @run-at       document-end
// @grant        none
// ==/UserScript==

(() => {
    'use strict';

    const init = () => {
        const btnId = 'gamma-scroll-btn';
        if (document.getElementById(btnId)) return;

        // SVG 圖示 (保持不變)
        const icons = {
            up: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="white" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 12a.5.5 0 0 0 .5-.5V5.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 5.707V11.5a.5.5 0 0 0 .5.5z"/></svg>`,
            down: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="white" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 4a.5.5 0 0 1 .5.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5A.5.5 0 0 1 8 4z"/></svg>`
        };

        const btn = document.createElement('button');
        btn.id = btnId;
        btn.type = 'button';
        btn.setAttribute('aria-label', 'Scroll navigation');

        // 定義樣式 (調整大小與加入透明度過渡)
        const styles = {
            position: 'fixed',
            bottom: '20px',
            right: '20px',
            width: '40px',     // 縮小尺寸
            height: '40px',    // 縮小尺寸
            borderRadius: '50%',
            backgroundColor: '#0d6efd',
            border: 'none',
            boxShadow: '0 0.2rem 0.5rem rgba(0,0,0,0.3)',
            zIndex: '10000',
            cursor: 'pointer',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            // 增加 opacity 的過渡效果
            transition: 'transform 0.2s, background-color 0.2s, opacity 0.5s ease-in-out',
            touchAction: 'manipulation',
            padding: '0',
            opacity: '0.3' // 預設為半透明 (腳本啟動時)
        };

        Object.assign(btn.style, styles);

        // Hover & Active 互動
        btn.onmouseenter = () => { btn.style.transform = 'scale(1.1)'; activeHandler(); };
        btn.onmouseleave = () => { btn.style.transform = 'scale(1)'; };
        btn.onmousedown = () => { btn.style.backgroundColor = '#0b5ed7'; activeHandler(); };
        btn.onmouseup = () => { btn.style.backgroundColor = '#0d6efd'; };
        // 針對手機觸摸也視為「活躍」
        btn.ontouchstart = () => { activeHandler(); };

        document.body.appendChild(btn);

        const State = { TOP: 'top', SCROLLED: 'scrolled' };

        // --- 透明度控制邏輯 ---
        let idleTimer = null;
        const activeHandler = () => {
            // 1. 動作時:顯示按鈕 (不透明)
            btn.style.opacity = '1';
            
            // 2. 重置計時器
            if (idleTimer) clearTimeout(idleTimer);

            // 3. 設定閒置 2 秒後變淡
            idleTimer = setTimeout(() => {
                btn.style.opacity = '0.3'; // 淡出目標透明度
            }, 2000);
        };

        const updateButtonState = () => {
            activeHandler(); // 捲動視為活躍動作

            const scrollTop = window.scrollY || document.documentElement.scrollTop;
            const isAtTop = scrollTop < 50;

            const nextState = isAtTop ? State.TOP : State.SCROLLED;
            if (btn.dataset.state === nextState) return;

            if (isAtTop) {
                btn.innerHTML = icons.down;
                btn.dataset.state = State.TOP;
            } else {
                btn.innerHTML = icons.up;
                btn.dataset.state = State.SCROLLED;
            }
        };

        const handleScrollAction = (e) => {
            e.preventDefault();
            activeHandler(); // 點擊視為活躍動作
            
            if (btn.dataset.state === State.TOP) {
                window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
            } else {
                window.scrollTo({ top: 0, behavior: 'smooth' });
            }
        };

        btn.addEventListener('click', handleScrollAction);
        window.addEventListener('scroll', updateButtonState, { passive: true });
        
        // 初始執行
        updateButtonState();
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();