Go to Github Releases Page

Add a quick link button to navigate to GitHub repository releases page

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==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,
  })
})()