github-custom-styles

github custom styles

As of 2020-07-28. See the latest version.

  1. // ==UserScript==
  2. // @name github-custom-styles
  3. // @namespace github-custom-styles
  4. // @description github custom styles
  5. // @version 1.1.0
  6. // @author roojay <roojay520@gmail.com>
  7. // @homepage https://github.com/roojay520/github-custom-styles
  8. // @license MIT
  9.  
  10. // @include https://github.com/*
  11. // @run-at document-start
  12.  
  13. // @grant GM_addStyle
  14. // @require https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js
  15.  
  16. // @noframes
  17. // @connect *
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. const styles = `:root {
  22. --border-color: #e1e4e8;
  23. --border-radius: 4px;
  24. --width: 1248px;
  25. --max-width: 1280px;
  26.  
  27. --bg-gray-light: #f5f7fa;
  28. --border-color-btn: #dcdfe6;
  29. }
  30.  
  31. .Box {
  32. border-radius: var(--border-radius);
  33. }
  34.  
  35. .Box-row:last-of-type {
  36. border-bottom-right-radius: var(--border-radius);
  37. border-bottom-left-radius: var(--border-radius);
  38. }
  39.  
  40. .Box-header {
  41. border-top-left-radius: var(--border-radius) !important;
  42. border-top-right-radius: var(--border-radius) !important;
  43. }
  44.  
  45. .btn {
  46. border-color: var(--border-color-btn);
  47. border-radius: var(--border-radius);
  48.  
  49. box-shadow: none;
  50. }
  51.  
  52. .btn-with-count {
  53. border-top-right-radius: 0;
  54. border-bottom-right-radius: 0;
  55. }
  56.  
  57. .social-count {
  58. border-color: var(--border-color-btn);
  59. border-top-right-radius: var(--border-radius);
  60. border-bottom-right-radius: var(--border-radius);
  61.  
  62. box-shadow: none;
  63. }
  64.  
  65. main > div.container-xl.new-discussion-timeline.px3 {
  66. padding-right: 32px !important;
  67. padding-left: 32px !important;
  68. }
  69.  
  70. @media (min-width: 768px) {
  71. main > div.container-xl.new-discussion-timeline.px-md-4 {
  72. padding-right: 32px !important;
  73. padding-left: 32px !important;
  74. }
  75. }
  76.  
  77. @media (min-width: 1012px) {
  78. main > div.container-xl.new-discussion-timeline.px-lg-5 {
  79. padding-right: 40px !important;
  80. padding-left: 40px !important;
  81. }
  82. }
  83.  
  84. main > div.bg-gray-light.hide-full-screen {
  85. box-shadow: inset 0 -1px 0 var(--border-color);
  86. }
  87.  
  88. /* Repository title header */
  89. main > div.bg-gray-light.hide-full-screen > div:first-child {
  90. margin-right: auto;
  91. margin-left: auto;
  92. width: 100%;
  93. max-width: var(--max-width);
  94. }
  95.  
  96. /* Repository navigation tab */
  97. main > div.bg-gray-light.hide-full-screen > nav.js-repo-nav {
  98. margin: 0 auto;
  99. width: 100%;
  100. max-width: var(--max-width);
  101. }
  102.  
  103. main > div.bg-gray-light.hide-full-screen > nav.js-repo-nav .UnderlineNav-item {
  104. border-bottom: 2px solid transparent;
  105. }
  106.  
  107. main > div.bg-gray-light.hide-full-screen > nav.js-repo-nav .UnderlineNav-item.selected {
  108. border-bottom-color: #f9826c;
  109. }
  110.  
  111. .repository-content > div.gutter-condensed > div.flex-shrink-0:first-child:not(.col-3):not(.col-md-3) {
  112. margin-top: 16px;
  113. width: 100%;
  114. max-width: var(--max-width);
  115. }
  116.  
  117. .repository-content > div.gutter-condensed div.js-details-container.Details div.Box-row:not(:last-child) {
  118. box-shadow: inset 0 -1px 0 0 rgba(227, 233, 237, .5);
  119. }
  120.  
  121. #js-repo-pjax-container .repository-content > div.gutter-condensed > div.col-md-3.flex-shrink-0:last-child {
  122. display: none;
  123. }
  124.  
  125. #readme > div.Box-header {
  126. color: #333;
  127. background: var(--bg-gray-light) !important;
  128.  
  129. box-shadow: inset 0 -1px 0 var(--border-color);
  130. }
  131.  
  132. .IssueLabel,
  133. .IssueLabel--big.lh-condensed {
  134. border-radius: 2px !important;
  135. }
  136.  
  137. .topic-tag {
  138. border-radius: var(--border-radius);
  139. }
  140.  
  141. #repo-stats-info {
  142. padding: 8px 0;
  143. min-height: 100px;
  144. }
  145.  
  146. #repo-stats-info .BorderGrid-row {
  147. display: block;
  148.  
  149. margin-bottom: 8px;
  150. }
  151.  
  152. #repo-stats-info .BorderGrid-row:first-child {
  153. margin-bottom: 16px;
  154. }
  155.  
  156. #repo-stats-info .BorderGrid-cell {
  157. display: block;
  158.  
  159. border: none;
  160. padding-top: 0;
  161. padding-bottom: 0;
  162. width: 100%;
  163. }
  164.  
  165. #lang-stats-wrap .lang-stats-list {
  166. display: flex;
  167.  
  168. border: 1px solid var(--border-color);
  169. border-bottom: none;
  170. border-radius: 4px 4px 0 0;
  171. padding: 4px 16px;
  172.  
  173. justify-content: space-between;
  174. }
  175.  
  176. #lang-stats-wrap .Progress {
  177. border-radius: 0 0 4px 4px;
  178. }
  179.  
  180. #repo-stats-wrap .repo-stats-list {
  181. display: flex;
  182.  
  183. border: 1px solid var(--border-color);
  184. border-radius: 4px;
  185. padding: 8px 16px;
  186.  
  187. flex-wrap: wrap;
  188. justify-content: space-between;
  189. }
  190. `;
  191. if (typeof GM_addStyle !== 'undefined') {
  192. GM_addStyle(styles);
  193. } else {
  194. let styleNode = document.createElement('style');
  195. styleNode.appendChild(document.createTextNode(styles));
  196. (document.querySelector('head') || document.documentElement).appendChild(styleNode);
  197. }
  198. const ICON = {
  199. ICON_USER: `<svg class="octicon octicon-person text-gray" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"></path></svg>`,
  200. ICON_PACKAGE: `<svg class="octicon octicon-package text-gray" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8.878.392a1.75 1.75 0 00-1.756 0l-5.25 3.045A1.75 1.75 0 001 4.951v6.098c0 .624.332 1.2.872 1.514l5.25 3.045a1.75 1.75 0 001.756 0l5.25-3.045c.54-.313.872-.89.872-1.514V4.951c0-.624-.332-1.2-.872-1.514L8.878.392zM7.875 1.69a.25.25 0 01.25 0l4.63 2.685L8 7.133 3.245 4.375l4.63-2.685zM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432L2.5 5.677zm6.25 8.271l4.625-2.683a.25.25 0 00.125-.216V5.677L8.75 8.432v5.516z"></path></svg>`,
  201. ICON_TAG: `<svg class="octicon octicon-tag text-gray" viewBox="0 0 16 16" version="1.1" width="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.5 7.775V2.75a.25.25 0 01.25-.25h5.025a.25.25 0 01.177.073l6.25 6.25a.25.25 0 010 .354l-5.025 5.025a.25.25 0 01-.354 0l-6.25-6.25a.25.25 0 01-.073-.177zm-1.5 0V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 010 2.474l-5.026 5.026a1.75 1.75 0 01-2.474 0l-6.25-6.25A1.75 1.75 0 011 7.775zM6 5a1 1 0 100 2 1 1 0 000-2z"></path></svg>`,
  202. ICON_USERS: `<svg class="octicon octicon-people text-gray" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>`,
  203. ICON_FOLD: `<svg class="octicon octicon-fold link-gray" aria-label="Collapse" viewBox="0 0 16 16" version="1.1" width="16" height="16" role="img"><path fill-rule="evenodd" d="M10.896 2H8.75V.75a.75.75 0 00-1.5 0V2H5.104a.25.25 0 00-.177.427l2.896 2.896a.25.25 0 00.354 0l2.896-2.896A.25.25 0 0010.896 2zM8.75 15.25a.75.75 0 01-1.5 0V14H5.104a.25.25 0 01-.177-.427l2.896-2.896a.25.25 0 01.354 0l2.896 2.896a.25.25 0 01-.177.427H8.75v1.25zm-6.5-6.5a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5h.5zM6 8a.75.75 0 01-.75.75h-.5a.75.75 0 010-1.5h.5A.75.75 0 016 8zm2.25.75a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5h.5zM12 8a.75.75 0 01-.75.75h-.5a.75.75 0 010-1.5h.5A.75.75 0 0112 8zm2.25.75a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5h.5z"></path></svg>`,
  204. ICON_UNFOLD: `<svg class="octicon octicon-unfold link-gray" aria-label="Expand" viewBox="0 0 16 16" version="1.1" width="16" height="16" role="img"><path fill-rule="evenodd" d="M8.177.677l2.896 2.896a.25.25 0 01-.177.427H8.75v1.25a.75.75 0 01-1.5 0V4H5.104a.25.25 0 01-.177-.427L7.823.677a.25.25 0 01.354 0zM7.25 10.75a.75.75 0 011.5 0V12h2.146a.25.25 0 01.177.427l-2.896 2.896a.25.25 0 01-.354 0l-2.896-2.896A.25.25 0 015.104 12H7.25v-1.25zm-5-2a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5h.5zM6 8a.75.75 0 01-.75.75h-.5a.75.75 0 010-1.5h.5A.75.75 0 016 8zm2.25.75a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5h.5zM12 8a.75.75 0 01-.75.75h-.5a.75.75 0 010-1.5h.5A.75.75 0 0112 8zm2.25.75a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5h.5z"></path></svg>`
  205. };
  206.  
  207. // lang percentage
  208. function renderLang(el) {
  209. const langDom = $(el).children('.BorderGrid-cell').attr('id', 'lang-stats-wrap');
  210. // title
  211. langDom.children('h2.h4').remove();
  212. // lang progress
  213. langDom.children('div').removeClass('mb-2').appendTo(langDom);
  214. // lang text
  215. const langList = langDom.children('ul').addClass('lang-stats-list');
  216. langList.children('li:last-child').children('span:last-child').removeClass('mr-3');
  217. langList.find('.text-small').removeClass('text-small');
  218. langList.find('.octicon.octicon-dot-fill').removeClass('mr-2');
  219. // lang percent text
  220. const percentText = langList.children('li').children('.d-inline-flex').children('span:last-child');
  221. percentText.addClass('text-gray-light').addClass('text-small');
  222. }
  223.  
  224. // top repo stats
  225. function renderRepoStats(stats) {
  226. const renderRepoStatsList = () => stats.map((item) => `
  227. <li class="d-inline">
  228. <a href="${item.href}" class="d-inline-flex flex-items-center flex-nowrap link-gray no-underline mr-3">
  229. ${ICON[item.icon]}
  230. <span class="text-gray-dark text-bold ml-1 mr-1">${item.count}</span>
  231. <span class="text-gray-light">${item.text}</span>
  232. </a>
  233. </li>
  234. `).join('');
  235. return $(`
  236. <div class="BorderGrid-row" >
  237. <div class="BorderGrid-cell" id="repo-stats-wrap">
  238. <ul class="list-style-none repo-stats-list">
  239. ${renderRepoStatsList()}
  240. </ul>
  241. </div>
  242. </div>
  243. `);
  244. }
  245.  
  246. // files fold & unfold
  247. function renderFold() {
  248. const fileDir = $('#files ~ .js-details-container.Details');
  249. const fold = $(ICON.ICON_FOLD).attr('id', 'files-fold');
  250. const unfold = $(ICON.ICON_UNFOLD).attr('id', 'files-unfold').css('display', 'none');
  251. fold.on('click', () => {
  252. unfold.show();
  253. fold.hide();
  254. fileDir.hide();
  255. });
  256. unfold.on('click', () => {
  257. fold.show();
  258. unfold.hide();
  259. fileDir.show();
  260. });
  261. return $('<li>').addClass('link-gray ml-2').css('cursor', 'pointer').append(fold, unfold);
  262. }
  263.  
  264. function main() {
  265. // fix security page with
  266. $('#js-pjax-container > div.container-xl.clearfix.new-discussion-timeline.p-0').addClass('px-4 px-md-5 px-lg-6');
  267.  
  268. const repositoryMain = 'main#js-repo-pjax-container .repository-content > div:last-child';
  269. const repositoryContent = $(`${repositoryMain} > div:first-child`);
  270. const rightSidebar = $(`${repositoryMain} > div.col-md-3:nth-last-of-type(1)`)
  271. .removeClass('col-md-3').attr('id', 'repo-stats-info')
  272. .hide();
  273. rightSidebar.find('.BorderGrid--spacious').removeClass('BorderGrid--spacious');
  274. rightSidebar.find('.mt-3').removeClass('mt-3').addClass('mt-2');
  275. rightSidebar.find('.mb-3').removeClass('mb-3').addClass('mb-2');
  276.  
  277. // repo stats
  278. const repoStats = [];
  279. const repoStatsType = ['about', 'releases', 'packages', 'sponsor', 'used', 'contributors', 'environments', 'lang'];
  280. const title = rightSidebar.find('.BorderGrid-cell > h2');
  281. $.each(title, (i, e) => {
  282. const text = e.textContent.toLowerCase();
  283. repoStatsType.forEach((type, index) => {
  284. if (text.includes(type)) {
  285. const repoStatsWrap = e.parentElement.parentElement;
  286. repoStatsType.splice(index, 1);
  287. if (type === 'lang') return renderLang(repoStatsWrap);
  288. if (['releases', 'used', 'contributors', 'packages'].includes(type)) {
  289. const item = $(repoStatsWrap).find('h2 > a').addClass('d-inline-flex flex-items-center flex-nowrap link-gray no-underline mr-3');
  290. const href = item.attr('href');
  291. const count = item.find('span.Counter').text() || 0;
  292. const obj = { text: type, href: href, count: count };
  293. if (type === 'used' || type === 'packages') obj.icon = 'ICON_PACKAGE';
  294. if (type === 'contributors') obj.icon = 'ICON_USERS';
  295. if (type === 'releases') obj.icon = 'ICON_TAG';
  296. repoStats.push(obj);
  297. $(repoStatsWrap).remove();
  298. return;
  299. }
  300. if (type !== 'about') $(repoStatsWrap).remove();
  301. }
  302. });
  303. });
  304.  
  305. // about
  306. const aboutWrap = $('#repo-stats-info > div.BorderGrid > div.BorderGrid-row:first-child')
  307. .after(renderRepoStats(repoStats))
  308. .children('div.BorderGrid-cell');
  309. aboutWrap.children('h2').remove();
  310. const aboutInfo = aboutWrap.children('p:first-child');
  311. const aboutLink = aboutInfo.next();
  312. aboutInfo.append(aboutLink.children('span:last-child'));
  313. aboutLink.remove();
  314. const readmeAndLicense = aboutWrap.find('div.mt-2 > a');
  315. readmeAndLicense.find('svg.mr-2').removeClass('mr-2').addClass('text-gray');
  316. $.each(readmeAndLicense, (i, el) => {
  317. const li = $('<li>').addClass('d-inline').append(el);
  318. $('#repo-stats-wrap > .repo-stats-list').append(li);
  319. });
  320.  
  321. // commits
  322. const commits = $('#js-repo-pjax-container div.Box-header > div.js-details-container').children('div:last-child');
  323. const commitsLi = commits.find('ul.d-flex > li:first').removeClass().addClass('d-inline');
  324. commitsLi.find('.d-none').removeClass('d-none');
  325. commitsLi.children('a').removeClass('pl-3 pr-3 py-3 p-md-0 mt-n3 mb-n3 mr-n3 m-md-0').addClass('mr-3');
  326. // files fold & unfold
  327. commitsLi.after(renderFold());
  328. $('#repo-stats-wrap > .repo-stats-list').prepend(commitsLi);
  329.  
  330. // move the sidebar to the top
  331. repositoryContent.parent().before(rightSidebar.show());
  332.  
  333. // localTime
  334. setTimeout(() => {
  335. const time = $('relative-time');
  336. time.text(time.attr('title'));
  337. }, 500);
  338. };
  339.  
  340. $(main);
  341.  
  342. $(document).on('pjax:end', main);
  343.  
  344. })();