GitHub Gist Link

Adds a Gist link to GitHub profile pages.

As of 2025-02-26. See the latest version.

  1. // ==UserScript==
  2. // @name GitHub Gist Link
  3. // @description Adds a Gist link to GitHub profile pages.
  4. // @icon https://github.githubassets.com/favicons/favicon-dark.svg
  5. // @version 1.0
  6. // @author afkarxyz
  7. // @namespace https://github.com/afkarxyz/misc-scripts/
  8. // @supportURL https://github.com/afkarxyz/misc-scripts/issues
  9. // @license MIT
  10. // @match https://github.com/*
  11. // @exclude https://gist.github.com/*
  12. // @grant none
  13. // @run-at document-idle
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18. function isProfilePage() {
  19. return /^\/[^\/]+\/?$/.test(window.location.pathname);
  20. }
  21. function addGistLink() {
  22. if (!isProfilePage()) return;
  23. const usernameElement = document.querySelector('.p-nickname.vcard-username');
  24. if (usernameElement && !usernameElement.querySelector('.gist-link-userscript')) {
  25. const currentURL = window.location.pathname;
  26. const username = currentURL.split('/')[1];
  27. const linkContainer = document.createElement('span');
  28. linkContainer.className = 'gist-link-container';
  29. const gistLink = document.createElement('a');
  30. gistLink.href = `https://gist.github.com/${username}`;
  31. gistLink.textContent = 'Gist';
  32. gistLink.className = 'Link--secondary gist-link-userscript';
  33. gistLink.style.textDecoration = 'none';
  34. linkContainer.appendChild(gistLink);
  35. linkContainer.appendChild(document.createTextNode(' · '));
  36. usernameElement.insertBefore(linkContainer, usernameElement.firstChild);
  37. }
  38. }
  39. function observeForUsernameElement() {
  40. if (!isProfilePage()) return;
  41. const usernameObserver = new MutationObserver((mutations, observer) => {
  42. const usernameElement = document.querySelector('.p-nickname.vcard-username');
  43. if (usernameElement) {
  44. addGistLink();
  45. observer.disconnect();
  46. }
  47. });
  48. usernameObserver.observe(document.body, {
  49. childList: true,
  50. subtree: true
  51. });
  52. }
  53. if (document.readyState === 'complete' || document.readyState === 'interactive') {
  54. addGistLink();
  55. } else {
  56. document.addEventListener('DOMContentLoaded', addGistLink);
  57. }
  58. let lastUrl = location.href;
  59. const urlChangeObserver = new MutationObserver(() => {
  60. const url = location.href;
  61. if (url !== lastUrl) {
  62. lastUrl = url;
  63. if (document.querySelector('.p-nickname.vcard-username')) {
  64. addGistLink();
  65. } else {
  66. observeForUsernameElement();
  67. }
  68. }
  69. });
  70. urlChangeObserver.observe(document, {
  71. subtree: true,
  72. childList: true
  73. });
  74. window.addEventListener('popstate', function() {
  75. if (document.querySelector('.p-nickname.vcard-username')) {
  76. addGistLink();
  77. } else {
  78. observeForUsernameElement();
  79. }
  80. });
  81. observeForUsernameElement();
  82. })();