GitHub 文件高亮

通过颜色高亮显示GitHub仓库更新状态的简化版

目前为 2025-03-18 提交的版本。查看 最新版本

// ==UserScript==
// @name         GitHub 文件高亮
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  通过颜色高亮显示GitHub仓库更新状态的简化版
// @author       Grok
// @icon         https://i.miji.bid/2025/03/15/560664f99070e139e28703cf92975c73.jpeg
// @match        https://github.com/*/*
// @match        https://github.com/*/*/tree/*
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/build/global/luxon.min.js
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const DateTime = luxon.DateTime;

    // === 主题配置 ===
    const THEMES = {
        'default': {
            name: '默认绿色',
            BGC: { highlight: 'rgba(15, 172, 83, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' },
            FONT: { highlight: 'rgba(15, 172, 83, 1)', grey: 'rgba(0, 0, 0, 1)' },
            DIR: { highlight: 'rgba(15, 172, 83, 1)', grey: 'rgba(154, 154, 154, 1)' }
        },
        'blue': {
            name: '科技蓝',
            BGC: { highlight: 'rgba(0, 121, 255, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' },
            FONT: { highlight: 'rgba(0, 121, 255, 1)', grey: 'rgba(0, 0, 0, 1)' },
            DIR: { highlight: 'rgba(0, 121, 255, 1)', grey: 'rgba(154, 154, 154, 1)' }
        },
        'purple': {
            name: '优雅紫',
            BGC: { highlight: 'rgba(147, 112, 219, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' },
            FONT: { highlight: 'rgba(147, 112, 219, 1)', grey: 'rgba(0, 0, 0, 1)' },
            DIR: { highlight: 'rgba(147, 112, 219, 1)', grey: 'rgba(154, 154, 154, 1)' }
        },
        'orange': {
            name: '活力橙',
            BGC: { highlight: 'rgba(255, 140, 0, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' },
            FONT: { highlight: 'rgba(255, 140, 0, 1)', grey: 'rgba(0, 0, 0, 1)' },
            DIR: { highlight: 'rgba(255, 140, 0, 1)', grey: 'rgba(154, 154, 154, 1)' }
        }
    };

    // 时间阈值(30天)
    const TIME_BOUNDARY = { number: 30, unit: 'day' };

    // 获取/设置当前主题和排序开关
    let currentTheme = GM_getValue('currentTheme', 'default');
    let isSortEnabled = GM_getValue('isSortEnabled', false);
    let COLORS = THEMES[currentTheme];

    // 处理时间判断
    function handelTime(time) {
        const now = new Date();
        const targetDate = new Date(now);
        targetDate.setDate(now.getDate() - TIME_BOUNDARY.number);
        return new Date(time) >= targetDate;
    }

    // 设置样式函数
    function setElementBGC(el, timeResult) {
        if (el.length) {
            el[0].style.setProperty('background-color',
                timeResult ? COLORS.BGC.highlight : COLORS.BGC.grey,
                'important');
        }
    }

    function setElementFONT(el, timeResult) {
        el.css('color', timeResult ? COLORS.FONT.highlight : COLORS.FONT.grey);
    }

    function setElementDIR(el, timeResult) {
        if (el.length) {
            el.attr('fill', timeResult ? COLORS.DIR.highlight : COLORS.DIR.grey);
        }
    }

    function setElementTIME_FORMAT(el, datetime) {
        if (el.css('display') !== 'none') {
            el.css('display', 'none');
            const formattedDate = DateTime.fromISO(datetime).toFormat('yyyy-MM-dd');
            el.before(`<span>${formattedDate}</span>`);
        }
    }

    // 主函数
    function GitHub_Freshness() {
        if (!isMatchedUrl()) return;

        const elements = $('.sc-aXZVg'); // <relative-time> 元素
        if (elements.length === 0) return;

        let trRows = [];
        elements.each(function() {
            const datetime = $(this).attr('datetime');
            if (datetime) {
                const timeResult = handelTime(datetime);
                const trElement = $(this).closest('tr.react-directory-row');

                if (isSortEnabled) {
                    trRows.push(trElement[0]);
                }

                const BGC_element = $(this).closest('td');
                const DIR_element = trElement.find('.icon-directory');
                const FILE_element = trElement.find('.color-fg-muted');

                setElementBGC(BGC_element, timeResult);
                setElementFONT($(this).parent(), timeResult);
                setElementDIR(DIR_element, timeResult);
                setElementDIR(FILE_element, timeResult);
                setElementTIME_FORMAT($(this), datetime);
            }
        });

        if (isSortEnabled && trRows.length > 0) {
            trRows.sort((a, b) => {
                const dateA = new Date(a.querySelector('relative-time').getAttribute('datetime'));
                const dateB = new Date(b.querySelector('relative-time').getAttribute('datetime'));
                return dateB - dateA; // 时间倒序
            });
            const tbody = document.querySelector('.react-directory-filename-column')?.closest('tbody') || document.querySelector('tbody');
            if (tbody) {
                $(tbody).empty().append(trRows); // 清空并重新追加排序后的行
            } else {
                console.warn('未找到目标 tbody,排序可能失效');
            }
        }
    }

    // URL匹配检查
    function isMatchedUrl() {
        const currentUrl = window.location.href;
        return /^https:\/\/github\.com\/[^/]+\/[^/]+(?:\?.*)?$|^https:\/\/github\.com\/[^/]+\/[^/]+\/tree\/.+$/.test(currentUrl);
    }

    // 防抖函数
    function debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }

    const runScript = debounce(GitHub_Freshness, 200);

    // 主题切换函数
    function switchTheme(themeKey) {
        currentTheme = themeKey;
        COLORS = THEMES[themeKey];
        GM_setValue('currentTheme', themeKey);
        GitHub_Freshness();
    }

    // 排序开关函数
    function toggleSort() {
        isSortEnabled = !isSortEnabled;
        GM_setValue('isSortEnabled', isSortEnabled);
        if (isSortEnabled) {
            alert('已启用时间倒序排列功能\n注意:此功能可能导致页面加载变慢,尤其在文件较多时');
        } else {
            alert('已关闭时间倒序排列功能\n文件将按GitHub默认顺序显示,加载速度更快');
        }
        GitHub_Freshness();
    }

    // 添加油猴菜单
    GM_registerMenuCommand(
        `当前状态:${isSortEnabled ? '时间倒序排列开启' : '时间倒序排列关闭'} | 主题:${THEMES[currentTheme].name}`,
        () => {}, // 无操作,仅显示状态
        '0'
    );
    GM_registerMenuCommand(
        `${isSortEnabled ? '✓ ' : '  '}时间倒序排列`,
        toggleSort,
        's'
    );

    for (const [key, theme] of Object.entries(THEMES)) {
        GM_registerMenuCommand(
            `${currentTheme === key ? '✓ ' : '  '}${theme.name}`,
            () => switchTheme(key),
            key.substring(0, 1)
        );
    }

    // 立即运行一次
    runScript();

    // 使用 MutationObserver 监听 DOM 变化
    const observer = new MutationObserver(debounce(() => {
        if ($('.sc-aXZVg').length > 0) {
            runScript();
        }
    }, 200));
    observer.observe(document.body, { childList: true, subtree: true });

    // 事件监听
    window.addEventListener('load', runScript);
    document.addEventListener('pjax:end', runScript);

    // 处理 URL 变化
    (function(history) {
        const pushState = history.pushState;
        const replaceState = history.replaceState;

        history.pushState = function(state, title, url) {
            pushState.apply(history, arguments);
            setTimeout(runScript, 200);
        };

        history.replaceState = function(state, title, url) {
            replaceState.apply(history, arguments);
            setTimeout(runScript, 200);
        };

        window.addEventListener('popstate', () => setTimeout(runScript, 200));
    })(window.history);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址