GitHub 文件高亮

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

当前为 2025-03-18 提交的版本,查看 最新版本

// ==UserScript==
// @name         GitHub 文件高亮
// @namespace    http://tampermonkey.net/
// @version      0.23
// @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)' } },
        'blue': { name: '科技蓝', BGC: { highlight: 'rgba(0, 121, 255, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' } },
        'purple': { name: '优雅紫', BGC: { highlight: 'rgba(147, 112, 219, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' } },
        'orange': { name: '活力橙', BGC: { highlight: 'rgba(255, 140, 0, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' } },
        'red': { name: '热情红', BGC: { highlight: 'rgba(220, 53, 69, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' } },
        'teal': { name: '青色调', BGC: { highlight: 'rgba(32, 201, 151, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' } },
        'indigo': { name: '深靛蓝', BGC: { highlight: 'rgba(75, 0, 130, 0.3)', grey: 'rgba(245, 245, 245, 0.24)' } }
    };

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

    // 获取/设置当前主题
    let currentTheme = GM_getValue('currentTheme', 'default');
    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 setElementTIME_FORMAT(el, datetime) {
        if (el.css('display') !== 'none') {
            el.css('display', 'none');
            const formattedDate = DateTime.fromISO(datetime).toFormat('yyyy-MM-dd HH:mm:ss');
            const timeSpan = $(`<span>${formattedDate}</span>`).css({
                'display': 'inline',
                'white-space': 'nowrap',
                'font-size': '0.9em',
                'max-width': '100%',
                'overflow': 'hidden',
                'text-overflow': 'ellipsis'
            });
            el.before(timeSpan);
        }
    }

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

        const elements = $('.sc-aXZVg');
        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');

                trRows.push(trElement[0]);
                const BGC_element = $(this).closest('td');
                setElementBGC(BGC_element, timeResult);
                setElementTIME_FORMAT($(this), datetime);
            }
        });

        if (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();
    }

    // 添加油猴菜单
    GM_registerMenuCommand(`当前主题:${THEMES[currentTheme].name}`, () => {}, '0');
    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或关注我们的公众号极客氢云获取最新地址