Skip to content

Instantly share code, notes, and snippets.

@ZhangYiJiang
Last active October 2, 2026 18:34
Show Gist options
  • Select an option

  • Save ZhangYiJiang/8b70e23f4facdfc48aff2c3c19382731 to your computer and use it in GitHub Desktop.

Select an option

Save ZhangYiJiang/8b70e23f4facdfc48aff2c3c19382731 to your computer and use it in GitHub Desktop.
Copy PR stack as Markdown
// ==UserScript==
// @name Copy PR stack as Markdown
// @namespace https://github.com/
// @version 1.0
// @description Adds a button to the GitHub stack overlay that copies the stacked PRs as a Markdown list of links
// @match https://github.com/*
// @grant GM_setClipboard
// ==/UserScript==
(function () {
'use strict';
const BUTTON_ID = 'copy-pr-stack-md';
function escapeLinkText(text) {
return text.replace(/\[/g, '(').replace(/\]/g, ')');
}
function stackToMarkdown(nav) {
return [...nav.querySelectorAll('a[href*="/pull/"]')]
.map((a) => {
const title = a.querySelector('[data-component="ActionList.Item.Label"]')?.textContent.trim();
const number = new URL(a.href).pathname.split('/').pop();
return `- [#${number} ${escapeLinkText(title)}](${a.href})`;
})
.join('\n');
}
function copy(text) {
if (typeof GM_setClipboard === 'function') {
GM_setClipboard(text, 'text');
return Promise.resolve();
}
return navigator.clipboard.writeText(text);
}
function addButton(actions) {
if (actions.querySelector(`#${BUTTON_ID}`)) return;
const button = document.createElement('button');
button.id = BUTTON_ID;
button.type = 'button';
button.textContent = 'Copy as Markdown';
button.className = 'btn btn-sm';
button.addEventListener('click', async () => {
const nav = actions.parentElement.parentElement.querySelector('nav[data-component="NavList"]');
const markdown = nav && stackToMarkdown(nav);
if (!markdown) return;
await copy(markdown);
button.textContent = 'Copied!';
setTimeout(() => (button.textContent = 'Copy as Markdown'), 1500);
});
actions.prepend(button);
}
function scan() {
document
.querySelectorAll('[class*="StackState-module__overlayHeaderActions"]')
.forEach(addButton);
}
new MutationObserver(scan).observe(document.body, { childList: true, subtree: true });
scan();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment