Make-GitHub-Great-Again!

为 Release Assets 每条条目添加交替的背景色

  1. // ==UserScript==
  2. // @name Make-GitHub-Great-Again!
  3. // @name:en Make-GitHub-Great-Again!
  4. // @namespace https://github.com
  5. // @version 3.1
  6. // @description 为 Release Assets 每条条目添加交替的背景色
  7. // @description:en Add alternating background colors to each item in the Release Assets list
  8. // @author https://github.com/HumanMus1c
  9. // @match https://github.com/*/releases*
  10. // @grant GM_addStyle
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant unsafeWindow
  15. // @license MIT
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. // 更可靠的主题检测函数
  20. function getCurrentTheme() {
  21. // 检测GitHub的显式主题设置
  22. const explicitTheme = document.documentElement.getAttribute('data-color-mode');
  23. if (explicitTheme === 'light' || explicitTheme === 'dark') {
  24. return explicitTheme;
  25. }
  26.  
  27. // 检测GitHub的类名主题设置
  28. if (document.documentElement.classList.contains('dark')) {
  29. return 'dark';
  30. }
  31.  
  32. // 检测系统级主题设置
  33. return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
  34. }
  35.  
  36. // 默认颜色配置(亮色主题)
  37. const defaultColorsLight = {
  38. oddRowColor: "#f8f9fa",
  39. evenRowColor: "#ffffff",
  40. hoverColor: "#e9ecef"
  41. };
  42.  
  43. // 默认颜色配置(暗色主题)
  44. const defaultColorsDark = {
  45. oddRowColor: "#161b22",
  46. evenRowColor: "#0d1117",
  47. hoverColor: "#30363d"
  48. };
  49.  
  50. // 获取当前主题的默认颜色
  51. function getDefaultColors() {
  52. return getCurrentTheme() === 'dark' ? defaultColorsDark : defaultColorsLight;
  53. }
  54.  
  55. // 创建样式元素并添加到文档头部
  56. const styleElement = document.createElement('style');
  57. styleElement.id = 'Make-GitHub-Great-Again-style';
  58. document.head.appendChild(styleElement);
  59.  
  60. // 应用颜色的函数 - 根据当前主题动态更新样式
  61. function applyColors() {
  62. const theme = getCurrentTheme();
  63. const themeKey = `customColors${theme.charAt(0).toUpperCase() + theme.slice(1)}`;
  64. const customColors = GM_getValue(themeKey, null);
  65. const colors = customColors || getDefaultColors();
  66.  
  67. // 动态更新样式
  68. styleElement.textContent = `
  69. .Box.Box--condensed.mt-3 li.Box-row:nth-child(odd) {
  70. background-color: ${colors.oddRowColor} !important;
  71. }
  72. .Box.Box--condensed.mt-3 li.Box-row:nth-child(even) {
  73. background-color: ${colors.evenRowColor} !important;
  74. }
  75. .Box.Box--condensed.mt-3 li.Box-row:hover {
  76. background-color: ${colors.hoverColor} !important;
  77. }
  78. `;
  79.  
  80. // 如果对话框是打开的,更新对话框中的颜色
  81. const dialog = document.querySelector('.color-picker-dialog.visible');
  82. if (dialog) {
  83. updateDialogColors();
  84. }
  85. }
  86.  
  87. // 更新对话框中的颜色显示
  88. function updateDialogColors() {
  89. const dialog = document.querySelector('.color-picker-dialog');
  90. if (!dialog) return;
  91.  
  92. const currentTheme = getCurrentTheme();
  93. const themeKey = `customColors${currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1)}`;
  94. const customColors = GM_getValue(themeKey, null);
  95. const colors = customColors || (currentTheme === 'dark' ? defaultColorsDark : defaultColorsLight);
  96.  
  97. // 更新标题
  98. const title = dialog.querySelector('.color-picker-title');
  99. if (title) {
  100. title.textContent = `颜色选择器 (${currentTheme === 'dark' ? '暗色主题' : '亮色主题'})`;
  101. }
  102.  
  103. // 更新颜色按钮
  104. const oddRowColorBtn = dialog.querySelector('#oddRowColorBtn');
  105. const evenRowColorBtn = dialog.querySelector('#evenRowColorBtn');
  106. const hoverColorBtn = dialog.querySelector('#hoverColorBtn');
  107.  
  108. if (oddRowColorBtn) oddRowColorBtn.style.backgroundColor = colors.oddRowColor;
  109. if (evenRowColorBtn) evenRowColorBtn.style.backgroundColor = colors.evenRowColor;
  110. if (hoverColorBtn) hoverColorBtn.style.backgroundColor = colors.hoverColor;
  111.  
  112. // 更新颜色选择器值
  113. const oddRowColorPicker = dialog.querySelector('#oddRowColorPicker');
  114. const evenRowColorPicker = dialog.querySelector('#evenRowColorPicker');
  115. const hoverColorPicker = dialog.querySelector('#hoverColorPicker');
  116.  
  117. if (oddRowColorPicker) oddRowColorPicker.value = colors.oddRowColor;
  118. if (evenRowColorPicker) evenRowColorPicker.value = colors.evenRowColor;
  119. if (hoverColorPicker) hoverColorPicker.value = colors.hoverColor;
  120. }
  121.  
  122. // 初始应用颜色
  123. applyColors();
  124.  
  125. // 监听主题变化并动态更新样式
  126. function setupThemeObserver() {
  127. // 监听HTML元素的属性变化
  128. const observer = new MutationObserver((mutations) => {
  129. for (const mutation of mutations) {
  130. if (mutation.attributeName === 'data-color-mode' ||
  131. mutation.attributeName === 'class') {
  132. applyColors();
  133. break;
  134. }
  135. }
  136. });
  137.  
  138. // 监听系统主题变化
  139. const systemThemeMedia = window.matchMedia('(prefers-color-scheme: dark)');
  140. systemThemeMedia.addEventListener('change', applyColors);
  141.  
  142. // 开始观察文档元素
  143. observer.observe(document.documentElement, {
  144. attributes: true,
  145. attributeFilter: ['data-color-mode', 'class']
  146. });
  147. }
  148.  
  149. // 设置主题观察器
  150. setupThemeObserver();
  151.  
  152. // 添加CSS样式 - 对话框样式(固定不变)
  153. GM_addStyle(`
  154. /* 对话框样式 - 修复主题跟随问题 */
  155. .color-picker-dialog {
  156. position: fixed;
  157. top: 50%; /* 垂直居中 */
  158. left: 15px; /* 距离左侧15px */
  159. transform: translateY(-50%) translateX(-100%);
  160. border-radius: 8px;
  161. padding: 20px;
  162. box-shadow: 0 2px 20px rgba(0,0,0,0.2);
  163. z-index: 10000;
  164. min-width: 300px !important;
  165. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  166. max-height: 300px; /* 最大高度为视口的90% */
  167. overflow-y: auto;
  168.  
  169. /* 初始状态 - 不可见 */
  170. opacity: 0;
  171. visibility: hidden;
  172. pointer-events: none;
  173.  
  174. /* 过渡动画设置 */
  175. transition: opacity 0.5s ease, visibility 0.5s ease, transform 0.5s ease;
  176. }
  177.  
  178. /* 明亮主题样式 */
  179. @media (prefers-color-scheme: light) {
  180. .color-picker-dialog {
  181. background: #ffffff;
  182. border: 1px solid #d0d7de;
  183. color: #24292f;
  184. }
  185.  
  186. .color-picker-header {
  187. border-bottom: 1px solid #d8dee4;
  188. }
  189.  
  190. .color-picker-title {
  191. color: #24292f;
  192. }
  193.  
  194. .color-picker-close {
  195. color: #57606a;
  196. }
  197.  
  198. .color-picker-close:hover {
  199. color: #24292f;
  200. }
  201.  
  202. .menu-command {
  203. color: #24292f;
  204. }
  205.  
  206. .color-button {
  207. border: 1px solid #d0d7de;
  208. background: #f6f8fa;
  209. }
  210. }
  211.  
  212. /* 暗色主题样式 */
  213. @media (prefers-color-scheme: dark) {
  214. .color-picker-dialog {
  215. background: #0d1117;
  216. border: 1px solid #30363d;
  217. color: #c9d1d9;
  218. }
  219.  
  220. .color-picker-header {
  221. border-bottom: 1px solid #21262d;
  222. }
  223.  
  224. .color-picker-title {
  225. color: #c9d1d9;
  226. }
  227.  
  228. .color-picker-close {
  229. color: #8b949e;
  230. }
  231.  
  232. .color-picker-close:hover {
  233. color: #c9d1d9;
  234. }
  235.  
  236. .menu-command {
  237. color: #c9d1d9;
  238. }
  239.  
  240. .color-button {
  241. border: 1px solid #30363d;
  242. background: #161b22;
  243. }
  244. }
  245.  
  246. /* 对话框可见状态 */
  247. .color-picker-dialog.visible {
  248. opacity: 1;
  249. visibility: visible;
  250. pointer-events: auto;
  251. transform: translateY(-50%) translateX(0);
  252. }
  253.  
  254. .color-picker-header {
  255. display: flex;
  256. justify-content: space-between;
  257. align-items: center;
  258. margin-bottom: 20px;
  259. padding-bottom: 10px;
  260. }
  261.  
  262. .color-picker-title {
  263. font-weight: bold;
  264. margin: 0;
  265. font-size: 18px;
  266. }
  267.  
  268. .color-picker-close {
  269. cursor: pointer;
  270. padding: 5px 10px;
  271. font-size: 24px;
  272. transition: all 0.3s ease;
  273. }
  274.  
  275. .color-picker-close:hover {
  276. transform: scale(1.1);
  277. }
  278.  
  279. .color-picker-content {
  280. display: flex;
  281. flex-direction: column;
  282. gap: 10px;
  283. }
  284.  
  285. .color-picker-row {
  286. display: flex;
  287. align-items: center;
  288. gap: 10px;
  289. justify-content: space-between;
  290. }
  291.  
  292. .menu-command {
  293. font-size: 16px;
  294. font-weight: 500;
  295. min-width: 120px;
  296. }
  297.  
  298. .button-row {
  299. display: flex;
  300. justify-content: flex-end;
  301. gap: 10px;
  302. margin-top: 10px;
  303. }
  304.  
  305. .dialog-button {
  306. padding: 8px 16px;
  307. border: none;
  308. border-radius: 6px;
  309. cursor: pointer;
  310. font-weight: bold;
  311. transition: all 0.3s ease;
  312. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  313. }
  314.  
  315. /* 按钮颜色保持不变 */
  316. .cancel-button {
  317. background-color: #007bff; /* 蓝色背景 */
  318. color: white;
  319. }
  320.  
  321. .cancel-button:hover {
  322. background-color: #0069d9;
  323. transform: translateY(-2px);
  324. }
  325.  
  326. .confirm-button {
  327. background-color: #ffa500; /* 橙黄色背景 */
  328. color: black;
  329. }
  330.  
  331. .confirm-button:hover {
  332. background-color: #e69500;
  333. transform: translateY(-2px);
  334. }
  335.  
  336. /* 新添加的重置按钮样式 */
  337. .reset-button {
  338. background-color: #ff6b6b; /* 浅红色背景 */
  339. color: white;
  340. }
  341.  
  342. .reset-button:hover {
  343. background-color: #ff5252; /* 悬停时加深红色 */
  344. transform: translateY(-2px);
  345. }
  346.  
  347. .color-button {
  348. width: 30px;
  349. height: 30px;
  350. border-radius: 6px;
  351. cursor: pointer;
  352. transition: all 0.3s ease;
  353. }
  354.  
  355. .color-button:hover {
  356. transform: scale(1.1);
  357. box-shadow: 0 0 5px rgba(0,0,0,0.1);
  358. }
  359.  
  360. .color-picker-container {
  361. position: relative;
  362. display: inline-block;
  363. }
  364.  
  365. .color-picker-container input[type="color"] {
  366. position: absolute;
  367. left: 0;
  368. top: 0;
  369. width: 100%;
  370. height: 100%;
  371. opacity: 0;
  372. cursor: pointer;
  373. }
  374. `);
  375.  
  376. // 创建颜色选择器对话框
  377. function createColorPickerDialog() {
  378. // 如果对话框已存在,则显示它并更新颜色
  379. let dialog = document.querySelector('.color-picker-dialog');
  380. if (dialog) {
  381. updateDialogColors();
  382. openDialog(dialog);
  383. return;
  384. }
  385.  
  386. // 获取当前主题
  387. const currentTheme = getCurrentTheme();
  388.  
  389. // 获取当前主题的自定义颜色(如果存在)
  390. let customColors = GM_getValue(`customColors${currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1)}`, null);
  391.  
  392. // 如果没有自定义颜色,使用当前主题的默认颜色
  393. if (!customColors) {
  394. customColors = currentTheme === 'dark' ? defaultColorsDark : defaultColorsLight;
  395. }
  396.  
  397. // 创建新的对话框
  398. dialog = document.createElement('div');
  399. dialog.className = 'color-picker-dialog';
  400. dialog.innerHTML = `
  401. <div class="color-picker-header">
  402. <h3 class="color-picker-title">颜色选择器 (${currentTheme === 'dark' ? '暗色主题' : '亮色主题'})</h3>
  403. <span class="color-picker-close" title="关闭">&times;</span>
  404. </div>
  405. <div class="color-picker-content">
  406. <div class="color-picker-row">
  407. <span class="menu-command">⚙️ 设置奇数行颜色</span>
  408. <div class="color-picker-container">
  409. <button class="color-button" id="oddRowColorBtn" style="background-color: ${customColors.oddRowColor}"></button>
  410. <input type="color" id="oddRowColorPicker" value="${customColors.oddRowColor}">
  411. </div>
  412. </div>
  413. <div class="color-picker-row">
  414. <span class="menu-command">⚙️ 设置偶数行颜色</span>
  415. <div class="color-picker-container">
  416. <button class="color-button" id="evenRowColorBtn" style="background-color: ${customColors.evenRowColor}"></button>
  417. <input type="color" id="evenRowColorPicker" value="${customColors.evenRowColor}">
  418. </div>
  419. </div>
  420. <div class="color-picker-row">
  421. <span class="menu-command">⚙️ 设置悬停颜色</span>
  422. <div class="color-picker-container">
  423. <button class="color-button" id="hoverColorBtn" style="background-color: ${customColors.hoverColor}"></button>
  424. <input type="color" id="hoverColorPicker" value="${customColors.hoverColor}">
  425. </div>
  426. </div>
  427. <div class="button-row">
  428. <button class="dialog-button reset-button" title="重置为当前主题默认颜色">重置</button>
  429. <div style="margin-left: auto; display: flex; gap: 10px;">
  430. <button class="dialog-button cancel-button">取消</button>
  431. <button class="dialog-button confirm-button">确认</button>
  432. </div>
  433. </div>
  434. `;
  435.  
  436. document.body.appendChild(dialog);
  437.  
  438. // 打开对话框并应用滑入动画
  439. openDialog(dialog);
  440.  
  441. // 获取元素引用
  442. const closeBtn = dialog.querySelector('.color-picker-close');
  443. const cancelBtn = dialog.querySelector('.cancel-button');
  444. const confirmBtn = dialog.querySelector('.confirm-button');
  445. const resetBtn = dialog.querySelector('.reset-button');
  446.  
  447. const oddRowColorBtn = dialog.querySelector('#oddRowColorBtn');
  448. const evenRowColorBtn = dialog.querySelector('#evenRowColorBtn');
  449. const hoverColorBtn = dialog.querySelector('#hoverColorBtn');
  450.  
  451. const oddRowColorPicker = dialog.querySelector('#oddRowColorPicker');
  452. const evenRowColorPicker = dialog.querySelector('#evenRowColorPicker');
  453. const hoverColorPicker = dialog.querySelector('#hoverColorPicker');
  454.  
  455. // 设置颜色按钮点击事件 - 打开颜色选择器
  456. [oddRowColorBtn, evenRowColorBtn, hoverColorBtn].forEach(btn => {
  457. btn.addEventListener('click', (e) => {
  458. e.stopPropagation(); // 阻止事件冒泡
  459.  
  460. // 找到对应的颜色选择器
  461. const picker = btn.nextElementSibling;
  462. if (picker && picker.tagName === 'INPUT' && picker.type === 'color') {
  463. picker.click();
  464. }
  465. });
  466. });
  467.  
  468. // 颜色选择器变化事件 - 只更新按钮颜色
  469. oddRowColorPicker.addEventListener('input', (e) => {
  470. oddRowColorBtn.style.backgroundColor = e.target.value;
  471. });
  472.  
  473. evenRowColorPicker.addEventListener('input', (e) => {
  474. evenRowColorBtn.style.backgroundColor = e.target.value;
  475. });
  476.  
  477. hoverColorPicker.addEventListener('input', (e) => {
  478. hoverColorBtn.style.backgroundColor = e.target.value;
  479. });
  480.  
  481. // 关闭按钮功能 - 应用滑出动画
  482. closeBtn.addEventListener('click', () => {
  483. closeDialog(dialog);
  484. });
  485.  
  486. // 取消按钮功能 - 应用滑出动画
  487. cancelBtn.addEventListener('click', () => {
  488. closeDialog(dialog);
  489. });
  490.  
  491. // 新增的重置按钮功能
  492. resetBtn.addEventListener('click', () => {
  493. const resetTheme = getCurrentTheme(); // 动态获取当前主题
  494.  
  495. if (confirm(`确定要重置${resetTheme === 'dark' ? '暗色' : '亮色'}主题的自定义颜色吗?`)) {
  496. // 删除当前主题的自定义颜色设置
  497. GM_setValue(`customColors${resetTheme.charAt(0).toUpperCase() + resetTheme.slice(1)}`, null);
  498.  
  499. // 关闭对话框并更新颜色
  500. closeDialog(dialog);
  501. applyColors();
  502. }
  503. });
  504.  
  505. // 确认按钮功能 - 修复:只保存到当前主题
  506. confirmBtn.addEventListener('click', () => {
  507. // 动态获取当前主题
  508. const saveTheme = getCurrentTheme();
  509.  
  510. // 从颜色选择器获取值
  511. const newOddColor = oddRowColorPicker.value;
  512. const newEvenColor = evenRowColorPicker.value;
  513. const newHoverColor = hoverColorPicker.value;
  514.  
  515. // 保存为当前主题的自定义颜色
  516. const newCustomColors = {
  517. oddRowColor: newOddColor,
  518. evenRowColor: newEvenColor,
  519. hoverColor: newHoverColor
  520. };
  521.  
  522. // 保存到对应主题的存储键
  523. GM_setValue(`customColors${saveTheme.charAt(0).toUpperCase() + saveTheme.slice(1)}`, newCustomColors);
  524.  
  525. closeDialog(dialog);
  526. applyColors(); // 动态更新颜色
  527. });
  528.  
  529. // 添加ESC键关闭支持
  530. document.addEventListener('keydown', function handleEsc(e) {
  531. if (e.key === 'Escape') {
  532. closeDialog(dialog);
  533. }
  534. });
  535.  
  536. // 点击外部关闭
  537. document.addEventListener('click', function handleOutsideClick(e) {
  538. if (dialog && !dialog.contains(e.target)) {
  539. closeDialog(dialog);
  540. }
  541. });
  542. }
  543.  
  544. // 打开对话框并应用滑入动画
  545. function openDialog(dialog) {
  546. // 确保对话框在DOM中
  547. if (!document.body.contains(dialog)) {
  548. document.body.appendChild(dialog);
  549. }
  550.  
  551. // 触发重绘
  552. void dialog.offsetHeight;
  553.  
  554. // 添加可见类触发动画
  555. dialog.classList.add('visible');
  556. }
  557.  
  558. // 关闭对话框并应用滑出动画
  559. function closeDialog(dialog) {
  560. // 移除可见类触发滑出动画
  561. dialog.classList.remove('visible');
  562.  
  563. // 动画完成后移除对话框
  564. setTimeout(() => {
  565. if (dialog && dialog.parentNode) {
  566. dialog.parentNode.removeChild(dialog);
  567. }
  568. }, 500); // 500ms是动画持续时间
  569. }
  570.  
  571. // 注册(不可用)油猴菜单选项
  572. GM_registerMenuCommand("🎨 取色器", createColorPickerDialog);
  573.  
  574. // 独立的菜单命令
  575. GM_registerMenuCommand("⚙️ 设置奇数行颜色", () => {
  576. const currentTheme = getCurrentTheme();
  577. const themeKey = `customColors${currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1)}`;
  578. const customColors = GM_getValue(themeKey, null);
  579. const defaultColors = currentTheme === 'dark' ? defaultColorsDark : defaultColorsLight;
  580.  
  581. const currentColor = customColors ? customColors.oddRowColor : defaultColors.oddRowColor;
  582.  
  583. const newColor = prompt("请输入奇数行背景色(HEX格式,如#f8f9fa):", currentColor);
  584. if (newColor) {
  585. // 获取或创建当前主题的自定义颜色
  586. const updatedColors = customColors ? {...customColors} : {...defaultColors};
  587. updatedColors.oddRowColor = newColor;
  588.  
  589. // 保存更新
  590. GM_setValue(themeKey, updatedColors);
  591. applyColors(); // 动态更新颜色
  592. }
  593. });
  594.  
  595. GM_registerMenuCommand("⚙️ 设置偶数行颜色", () => {
  596. const currentTheme = getCurrentTheme();
  597. const themeKey = `customColors${currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1)}`;
  598. const customColors = GM_getValue(themeKey, null);
  599. const defaultColors = currentTheme === 'dark' ? defaultColorsDark : defaultColorsLight;
  600.  
  601. const currentColor = customColors ? customColors.evenRowColor : defaultColors.evenRowColor;
  602.  
  603. const newColor = prompt("请输入偶数行背景色(HEX格式,如#ffffff):", currentColor);
  604. if (newColor) {
  605. // 获取或创建当前主题的自定义颜色
  606. const updatedColors = customColors ? {...customColors} : {...defaultColors};
  607. updatedColors.evenRowColor = newColor;
  608.  
  609. // 保存更新
  610. GM_setValue(themeKey, updatedColors);
  611. applyColors(); // 动态更新颜色
  612. }
  613. });
  614.  
  615. GM_registerMenuCommand("⚙️ 设置悬停颜色", () => {
  616. const currentTheme = getCurrentTheme();
  617. const themeKey = `customColors${currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1)}`;
  618. const customColors = GM_getValue(themeKey, null);
  619. const defaultColors = currentTheme === 'dark' ? defaultColorsDark : defaultColorsLight;
  620.  
  621. const currentColor = customColors ? customColors.hoverColor : defaultColors.hoverColor;
  622.  
  623. const newColor = prompt("请输入鼠标悬停颜色(HEX格式,如#e9ecef):", currentColor);
  624. if (newColor) {
  625. // 获取或创建当前主题的自定义颜色
  626. const updatedColors = customColors ? {...customColors} : {...defaultColors};
  627. updatedColors.hoverColor = newColor;
  628.  
  629. // 保存更新
  630. GM_setValue(themeKey, updatedColors);
  631. applyColors(); // 动态更新颜色
  632. }
  633. });
  634.  
  635. // 重置为当前主题的默认颜色
  636. GM_registerMenuCommand("🔄 重置为默认颜色", () => {
  637. const currentTheme = getCurrentTheme();
  638.  
  639. if (confirm(`确定要重置${currentTheme === 'dark' ? '暗色' : '亮色'}主题的自定义颜色吗?`)) {
  640. // 删除当前主题的自定义颜色设置
  641. GM_setValue(`customColors${currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1)}`, null);
  642. applyColors(); // 动态更新颜色
  643. }
  644. });
  645. })();

QingJ © 2025

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