您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
实现GitHub文件列表按时间倒序排列,高亮30天内更新的文件(背景色),支持鼠标悬停加深背景,支持多主题切换
// ==UserScript== // @name GitHub 文件高亮 - 优化版 // @namespace http://tampermonkey.net/ // @version 0.24 // @description 实现GitHub文件列表按时间倒序排列,高亮30天内更新的文件(背景色),支持鼠标悬停加深背景,支持多主题切换 // @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 THEMES = { 'default': { name: '默认淡蓝色', BGC: { highlight: 'rgba(40, 135, 255, 0.15)', grey: 'rgba(200, 200, 200, 0.1)', highlightHover: 'rgba(40, 135, 255, 0.3)', greyHover: 'rgba(200, 200, 200, 0.25)' } }, 'green': { name: '代码绿色', BGC: { highlight: 'rgba(60, 135, 80, 0.15)', grey: 'rgba(200, 200, 200, 0.1)', highlightHover: 'rgba(60, 135, 80, 0.3)', greyHover: 'rgba(200, 200, 200, 0.25)' } }, 'purple': { name: '优雅紫色', BGC: { highlight: 'rgba(147, 112, 219, 0.15)', grey: 'rgba(200, 200, 200, 0.1)', highlightHover: 'rgba(147, 112, 219, 0.3)', greyHover: 'rgba(200, 200, 200, 0.25)' } }, 'orange': { name: '活力橙色', BGC: { highlight: 'rgba(255, 147, 0, 0.15)', grey: 'rgba(200, 200, 200, 0.1)', highlightHover: 'rgba(255, 147, 0, 0.3)', greyHover: 'rgba(200, 200, 200, 0.25)' } }, 'teal': { name: '青色调', BGC: { highlight: 'rgba(32, 201, 151, 0.15)', grey: 'rgba(200, 200, 200, 0.1)', highlightHover: 'rgba(32, 201, 151, 0.3)', greyHover: 'rgba(200, 200, 200, 0.25)' } } }; // 时间阈值(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 setElementStyles(el, timeResult) { if (el.length) { // 设置默认背景色(为 td 元素设置) const defaultBgColor = timeResult ? COLORS.BGC.highlight : COLORS.BGC.grey; const tdElements = el.find('td'); if (tdElements.length) { tdElements.each(function() { this.style.setProperty('background-color', defaultBgColor, 'important'); }); } // 添加类名以标记高亮状态(用于悬停时判断) el.removeClass('highlight-row non-highlight-row'); el.addClass(timeResult ? 'highlight-row' : 'non-highlight-row'); // 绑定鼠标悬停事件 el.off('mouseenter mouseleave'); // 移除旧的事件监听,防止重复绑定 el.on('mouseenter', function() { const hoverBgColor = $(this).hasClass('highlight-row') ? COLORS.BGC.highlightHover : COLORS.BGC.greyHover; const tdEls = $(this).find('td'); if (tdEls.length) { tdEls.each(function() { this.style.setProperty('background-color', hoverBgColor, 'important'); }); } }); el.on('mouseleave', function() { const tdEls = $(this).find('td'); if (tdEls.length) { tdEls.each(function() { this.style.setProperty('background-color', defaultBgColor, 'important'); }); } }); } } // 主函数:实现文件倒序排列、高亮和鼠标悬停效果 function GitHub_Freshness() { if (!isMatchedUrl()) return; const elements = $('relative-time'); // 直接使用 <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'); trRows.push(trElement[0]); setElementStyles(trElement, timeResult); } }); 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('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 ($('relative-time').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); })();