在 GitHub 仓库页面添加快速跳转到 Releases 页面的按钮
// ==UserScript==
// @name Go to Github Releases Page
// @name:zh-CN 跳转到 Github Releases 页面
// @namespace https://github.com/xlsama/tampermonkey-scripts
// @version 0.1.0
// @author xlsama
// @description Add a quick link button to navigate to GitHub repository releases page
// @description:zh-CN 在 GitHub 仓库页面添加快速跳转到 Releases 页面的按钮
// @homepageURL https://github.com/xlsama/tampermonkey-scripts
// @supportURL https://github.com/xlsama/tampermonkey-scripts/issues
// @match *://github.com/*
// @include *://*github*
// @grant none
// @license MIT
// ==/UserScript==
// 判断当前path是否是一个 github repo,且位于项目的主页面
function isGithubRepo(path) {
path = path.slice(0, -1)
return path.split('/').length === 3
}
// 创建 package 图标 SVG 的辅助函数
function createPackageIcon() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('aria-hidden', 'true')
svg.setAttribute('focusable', 'false')
svg.setAttribute('class', 'octicon octicon-package')
svg.setAttribute('viewBox', '0 0 16 16')
svg.setAttribute('width', '16')
svg.setAttribute('height', '16')
svg.setAttribute('fill', 'currentColor')
svg.setAttribute('display', 'inline-block')
svg.setAttribute('overflow', 'visible')
svg.setAttribute('style', 'vertical-align: text-bottom;')
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
path.setAttribute(
'd',
'm8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.2.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 4.775v5.913c0 .09.047.171.125.216l4.625 2.683V7.653Zm6.25 8.832 4.625-2.683a.25.25 0 0 0 .125-.216V4.775L8.75 7.653Z'
)
svg.appendChild(path)
return svg
}
// 创建 releases 按钮(带文本)
function createReleasesButton() {
const el = document.querySelector('[class^="OverviewContent-module__Box_4"]')
if (!el) {
return
}
// 检查是否已经存在 releases 按钮
if (el.querySelector('a[href*="/releases"]')) {
return
}
// 创建按钮链接
const a = document.createElement('a')
a.type = 'button'
a.href = `${window.location.pathname}/releases`
a.className = 'prc-Button-ButtonBase-c50BI OverviewContent-module__Button--MDoYP'
a.setAttribute('data-loading', 'false')
a.setAttribute('data-size', 'medium')
a.setAttribute('data-variant', 'invisible')
// 创建按钮内容容器
const buttonContent = document.createElement('span')
buttonContent.setAttribute('data-component', 'buttonContent')
buttonContent.setAttribute('data-align', 'center')
buttonContent.className = 'prc-Button-ButtonContent-HKbr-'
// 创建图标容器
const visualWrap = document.createElement('span')
visualWrap.setAttribute('data-component', 'leadingVisual')
visualWrap.className = 'prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB'
const svg = createPackageIcon()
visualWrap.appendChild(svg)
// 创建文本标签
const label = document.createElement('span')
label.setAttribute('data-component', 'text')
label.className = 'prc-Button-Label-pTQ3x'
label.textContent = 'Releases'
// 组装按钮
buttonContent.appendChild(visualWrap)
buttonContent.appendChild(label)
a.appendChild(buttonContent)
// 添加到容器
el.appendChild(a)
}
// 创建 releases 按钮(仅图标)
function createReleasesButtonMobile() {
const el = document.querySelector('[class^="OverviewContent-module__Box_5"]')
if (!el) {
return
}
// 检查是否已经存在 releases 按钮
if (el.querySelector('a[href*="/releases"]')) {
return
}
// 创建按钮链接
const a = document.createElement('a')
a.type = 'button'
a.href = `${window.location.pathname}/releases`
a.setAttribute('aria-label', 'Go to Releases page')
a.className = 'prc-Button-ButtonBase-c50BI OverviewContent-module__Button_1--_1Ng2'
a.setAttribute('data-loading', 'false')
a.setAttribute('data-no-visuals', 'true')
a.setAttribute('data-size', 'medium')
a.setAttribute('data-variant', 'invisible')
const svg = createPackageIcon()
a.appendChild(svg)
// 添加到容器
el.appendChild(a)
}
function initButtons() {
if (!isGithubRepo(window.location.pathname)) {
return
}
createReleasesButton()
createReleasesButtonMobile()
}
;(function () {
'use strict'
// 初始化
initButtons()
// 监听页面变化
new MutationObserver(() => {
// 检查两个容器是否存在
if (
document.querySelector('[class^="OverviewContent-module__Box_4"]') ||
document.querySelector('[class^="OverviewContent-module__Box_5"]')
) {
initButtons()
}
}).observe(document, {
childList: true,
subtree: true,
})
})()