GitHub Custom Global Navigation

Customize GitHub's new global navigation

当前为 2023-10-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Custom Global Navigation
  3. // @namespace https://github.com/blakegearin/github-custom-global-navigation
  4. // @version 1.0.1
  5. // @description Customize GitHub's new global navigation
  6. // @author Blake Gearin
  7. // @match *://github.com/*
  8. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  9. // @grant GM.getValue
  10. // @grant GM.setValue
  11. // @license MIT
  12. // @icon https://raw.githubusercontent.com/blakegearin/github-custom-global-navigation/main/img/white_logo.svg
  13. // @supportURL https://github.com/blakegearin/github-custom-global-navigation/issues
  14. // ==/UserScript==
  15.  
  16. /*global GM_config*/
  17.  
  18. (function () {
  19. 'use strict';
  20.  
  21. const SILENT = 0;
  22. const QUIET = 1;
  23. const INFO = 2;
  24. const DEBUG = 3;
  25. const VERBOSE = 4;
  26. const TRACE = 5;
  27.  
  28. let CURRENT_LOG_LEVEL = QUIET;
  29.  
  30. const USERSCRIPT_NAME = 'GitHub Custom Global Navigation';
  31.  
  32. function log(level, message, variable = null) {
  33. if (CURRENT_LOG_LEVEL < level) return;
  34.  
  35. console.log(`${USERSCRIPT_NAME}: ${message}`);
  36. if (variable) console.log(variable);
  37. }
  38.  
  39. function logError(message) {
  40. console.error(`${USERSCRIPT_NAME}: ${message}`);
  41. }
  42.  
  43. log(TRACE, 'Starting');
  44.  
  45. function updateHeader() {
  46. log(DEBUG, 'updateHeader()');
  47.  
  48. if (CONFIG.backgroundColor !== '') {
  49. HEADER_STYLE.textContent += `
  50. ${SELECTORS.header.self}
  51. {
  52. background-color: ${CONFIG.backgroundColor} !important;
  53. }
  54. `;
  55. }
  56.  
  57. updateHamburgerButton();
  58. updateLogo();
  59.  
  60. if (CONFIG.repositoryHeader.import) importRepositoryHeader();
  61.  
  62. updatePageTitle();
  63. updateSearch();
  64.  
  65. if (CONFIG.divider.remove) removeDivider();
  66.  
  67. updateLink('issues');
  68. updateLink('pullRequests');
  69.  
  70. if (CONFIG.flipIssuesPullRequests) flipIssuesPullRequests();
  71.  
  72. updateCreateNewButton();
  73. updateInboxLink();
  74.  
  75. if (CONFIG.flipCreateInbox) flipCreateInbox();
  76.  
  77. updateAvatar();
  78.  
  79. updateGlobalBar();
  80. updateLocalBar();
  81.  
  82. updateSidebars();
  83.  
  84. modifyThenObserve(() => {
  85. document.body.appendChild(HEADER_STYLE);
  86. });
  87. }
  88.  
  89. function updateHamburgerButton() {
  90. log(DEBUG, 'updateHamburgerButton()');
  91.  
  92. const configKey = 'hamburgerButton';
  93. const elementConfig = CONFIG.hamburgerButton;
  94. log(DEBUG, 'elementConfig', elementConfig);
  95.  
  96. const hamburgerButton = HEADER.querySelector(SELECTORS[configKey]);
  97.  
  98. if (!hamburgerButton) {
  99. logError(`Selector '${SELECTORS[configKey]}' not found`);
  100. return;
  101. }
  102.  
  103. if (elementConfig.remove) {
  104. HEADER_STYLE.textContent += cssHideElement(SELECTORS[configKey]);
  105.  
  106. return;
  107. }
  108. }
  109.  
  110. function updateLogo() {
  111. log(DEBUG, 'updateLogo()');
  112.  
  113. const elementConfig = CONFIG.logo;
  114.  
  115. if (elementConfig.remove) {
  116. HEADER_STYLE.textContent += cssHideElement(SELECTORS.logo.topDiv);
  117. }
  118.  
  119. const logo = HEADER.querySelector(SELECTORS.logo.svg);
  120.  
  121. if (elementConfig.color !== '') {
  122. HEADER_STYLE.textContent += `
  123. ${SELECTORS.logo.svg} path
  124. {
  125. fill: ${elementConfig.color} !important;
  126. }
  127. `;
  128. }
  129.  
  130. if (elementConfig.customSvg !== '') {
  131. const oldSvg = logo;
  132.  
  133. let newSvg;
  134.  
  135. if (isValidURL(elementConfig.customSvg)) {
  136. newSvg = document.createElement('img');
  137. newSvg.src = elementConfig.customSvg;
  138. } else {
  139. const parser = new DOMParser();
  140. const svgDoc = parser.parseFromString(elementConfig.customSvg, 'image/svg+xml');
  141. newSvg = svgDoc.documentElement;
  142. }
  143.  
  144. oldSvg.parentNode.replaceChild(newSvg, oldSvg);
  145. }
  146. }
  147.  
  148. function removePageTitle() {
  149. HEADER_STYLE.textContent += cssHideElement(createId(SELECTORS.pageTitle.id));
  150. }
  151.  
  152. function updatePageTitle() {
  153. log(DEBUG, 'updatePageTitle()');
  154.  
  155. const elementConfig = CONFIG.pageTitle;
  156. log(DEBUG, 'elementConfig', elementConfig);
  157.  
  158. const pageTitle = HEADER.querySelector(SELECTORS.pageTitle.topDiv);
  159.  
  160. if (!pageTitle) {
  161. logError(`Selector '${SELECTORS.pageTitle.topDiv}' not found`);
  162. return;
  163. }
  164.  
  165. pageTitle.setAttribute('id', SELECTORS.pageTitle.id);
  166.  
  167. if (elementConfig.remove) {
  168. removePageTitle();
  169. return;
  170. }
  171.  
  172. if (elementConfig.color !== '') {
  173. HEADER_STYLE.textContent += `
  174. ${SELECTORS.pageTitle.links}
  175. {
  176. color: ${elementConfig.color} !important;
  177. }
  178. `;
  179. }
  180.  
  181. if (elementConfig.hover.color !== '') {
  182. HEADER_STYLE.textContent += `
  183. ${SELECTORS.pageTitle.links}:hover
  184. {
  185. color: ${elementConfig.hover.color} !important;
  186. }
  187. `;
  188. }
  189.  
  190. if (elementConfig.hover.backgroundColor !== '') {
  191. HEADER_STYLE.textContent += `
  192. ${SELECTORS.pageTitle.links}:hover
  193. {
  194. background-color: ${elementConfig.hover.backgroundColor} !important;
  195. }
  196. `;
  197. }
  198. }
  199.  
  200. function updateSearch() {
  201. log(DEBUG, 'updateSearch()');
  202.  
  203. const configKey = 'search';
  204.  
  205. const elementConfig = CONFIG[configKey];
  206. const elementSelector = SELECTORS[configKey];
  207.  
  208. let topDivSelector = elementSelector.id;
  209. const topDiv = HEADER.querySelector(createId(elementSelector.id)) ||
  210. HEADER.querySelector(elementSelector.topDiv);
  211.  
  212. if (!topDiv) {
  213. logError(`Selectors '${createId(elementSelector.id)}' and '${elementSelector.topDiv}' not found`);
  214. return;
  215. }
  216.  
  217. topDiv.setAttribute('id', elementSelector.id);
  218.  
  219. if (elementConfig.alignLeft) {
  220. const response = cloneAndLeftAlignElement(createId(topDivSelector), topDivSelector);
  221.  
  222. if (response.length == 0) return;
  223.  
  224. // Also need to hide button due to it showing up on larger screen widths
  225. HEADER_STYLE.textContent += cssHideElement(`${createId(topDivSelector)} ${elementSelector.input}`);
  226.  
  227. HEADER_STYLE.textContent += `
  228. ${createId(topDivSelector)}
  229. {
  230. flex-grow: 1 !important;
  231. }
  232. `;
  233.  
  234. const [cloneId, _cloneElement] = response;
  235.  
  236. topDivSelector = createId(cloneId);
  237.  
  238. HEADER_STYLE.textContent += `
  239. ${topDivSelector}
  240. {
  241. flex: 0 1 auto !important;
  242. justify-content: flex-start !important;
  243. }
  244. `;
  245. }
  246.  
  247. if (elementConfig.width === 'max') {
  248. log(DEBUG, 'elementSelector', elementSelector);
  249.  
  250. HEADER_STYLE.textContent += `
  251. @media (min-width: 1012px) {
  252. ${elementSelector.input}
  253. {
  254. width: auto !important
  255. }
  256.  
  257. ${SELECTORS.header.leftAligned}
  258. {
  259. flex: 0 1 auto !important;
  260. }
  261.  
  262. ${SELECTORS.header.rightAligned}
  263. {
  264. flex: 1 1 auto !important;
  265. justify-content: space-between !important;
  266. }
  267.  
  268. ${createId(topDivSelector)}
  269. {
  270. display: block !important;
  271. }
  272.  
  273. ${elementSelector.topDiv}-whenRegular
  274. {
  275. max-width: none !important;
  276. }
  277. }
  278. `;
  279. } else if (elementConfig.width !== '') {
  280. HEADER_STYLE.textContent += `
  281. @media (min-width: 1012px)
  282. {
  283. ${topDivSelector},
  284. ${elementSelector.input}
  285. {
  286. width: ${elementConfig.width} !important
  287. }
  288. }
  289.  
  290. @media (min-width: 768px)
  291. {
  292. ${topDivSelector},
  293. ${elementSelector.input}
  294. {
  295. --feed-sidebar: 320px;
  296. }
  297. }
  298.  
  299. @media (min-width: 1400px)
  300. {
  301. ${topDivSelector},
  302. ${elementSelector.input}
  303. {
  304. --feed-sidebar: 336px;
  305. }
  306. }
  307. `;
  308. }
  309.  
  310. if (elementConfig.margin.left !== '') {
  311. HEADER_STYLE.textContent += `
  312. @media (min-width: 1012px)
  313. {
  314. ${elementSelector.input}
  315. {
  316. margin-left: ${elementConfig.margin.left} !important
  317. }
  318. }
  319. `;
  320. }
  321.  
  322. if (elementConfig.margin.right!== '') {
  323. HEADER_STYLE.textContent += `
  324. @media (min-width: 1012px)
  325. {
  326. ${elementSelector.input}
  327. {
  328. margin-right: ${elementConfig.margin.right} !important
  329. }
  330. }
  331. `;
  332. }
  333.  
  334. if (elementConfig.rightButton !== 'command palette') {
  335. const commandPaletteButton = HEADER.querySelector(elementSelector.commandPalette);
  336. if (!commandPaletteButton) {
  337. logError(`Selector '${elementSelector.commandPalette}' not found`);
  338. } else {
  339. HEADER_STYLE.textContent += cssHideElement(elementSelector.commandPalette);
  340. }
  341. }
  342.  
  343. const placeholderSpan = HEADER.querySelector(elementSelector.placeholderSpan);
  344.  
  345. if (!placeholderSpan) {
  346. logError(`Selector '${elementSelector.placeholderSpan}' not found`);
  347. return;
  348. }
  349.  
  350. if (elementConfig.placeholder.text !== '') {
  351. // Without this, the placeholder text is overwritten by the shadow DOM
  352. // You may see the following error in the console:
  353. // qbsearch-input-element.ts:421 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'innerHTML')
  354. placeholderSpan.setAttribute('data-target', 'avoidShadowDOM');
  355. placeholderSpan.innerText = elementConfig.placeholder.text;
  356. }
  357.  
  358. if (elementConfig.placeholder.color !== '') {
  359. HEADER_STYLE.textContent += `
  360. ${elementSelector.placeholderSpan}
  361. {
  362. color: ${elementConfig.placeholder.color} !important;
  363. }
  364. `;
  365. }
  366.  
  367. const searchButton = HEADER.querySelector(elementSelector.button);
  368.  
  369. if (!searchButton) {
  370. logError(`Selector '${elementSelector.button}' not found`);
  371. return;
  372. }
  373.  
  374. if (elementConfig.backgroundColor !== '') {
  375. HEADER_STYLE.textContent += `
  376. ${elementSelector.button}
  377. {
  378. background-color: ${elementConfig.backgroundColor} !important;
  379. }
  380. `;
  381. }
  382.  
  383. if (elementConfig.borderColor !== '') {
  384. // There are different buttons at different widths
  385. HEADER_STYLE.textContent += `
  386. ${elementSelector.input} button
  387. {
  388. border-color: ${elementConfig.borderColor} !important;
  389. }
  390. `;
  391. }
  392.  
  393. if (elementConfig.boxShadow !== '') {
  394. HEADER_STYLE.textContent += `
  395. ${elementSelector.button}
  396. {
  397. box-shadow: ${elementConfig.boxShadow} !important;
  398. }
  399. `;
  400. }
  401.  
  402. if (elementConfig.magnifyingGlassIcon.remove) {
  403. HEADER_STYLE.textContent += cssHideElement(elementSelector.magnifyingGlassIcon);
  404. }
  405.  
  406. if (elementConfig.modal.width !== '') {
  407. HEADER_STYLE.textContent += `
  408. ${elementSelector.modal}
  409. {
  410. width: ${elementConfig.modal.width} !important;
  411. }
  412. `;
  413. }
  414.  
  415. if (elementConfig.rightButton === 'slash key') {
  416. HEADER_STYLE.textContent += `
  417. ${elementSelector.placeholderSpan}
  418. {
  419. width: 100% !important;
  420. }
  421. `;
  422.  
  423. const slashImg = document.createElement('img');
  424. slashImg.src = 'https://github.githubassets.com/images/search-key-slash.svg';
  425. slashImg.alt = 'slash key to search';
  426. slashImg.className = 'header-search-key-slash';
  427.  
  428. const placeholderDiv = HEADER.querySelector(elementSelector.placeholderDiv);
  429.  
  430. if (!placeholderDiv) {
  431. logError(`Selector '${elementSelector.placeholderDiv}' not found`);
  432. return;
  433. }
  434.  
  435. HEADER_STYLE.textContent += `
  436. ${elementSelector.placeholderDiv}
  437. {
  438. display: flex !important;
  439. }
  440.  
  441. ${elementSelector.button}
  442. {
  443. padding-inline-start: 8px !important;
  444. }
  445. `;
  446.  
  447. placeholderDiv.appendChild(slashImg);
  448. }
  449. }
  450.  
  451. function removeDivider() {
  452. log(DEBUG, 'removeDivider()');
  453.  
  454. HEADER_STYLE.textContent += `
  455. ${SELECTORS.header.actionsDiv}::before
  456. {
  457. content: none !important;
  458. }
  459. `;
  460. }
  461.  
  462. function updateLink(configKey) {
  463. log(DEBUG, 'updateLink()');
  464.  
  465. const tooltipElement = SELECTORS.toolTips[configKey];
  466.  
  467. if (!tooltipElement) {
  468. logError(`Selector '${configKey}' not found`);
  469. return;
  470. }
  471.  
  472. let link = tooltipElement.previousElementSibling;
  473.  
  474. const elementConfig = CONFIG[configKey];
  475. const elementSelector = SELECTORS[configKey];
  476.  
  477. let topDivSelector = `${configKey}-div`;
  478. link.parentNode.setAttribute('id', topDivSelector);
  479.  
  480. if (elementConfig.remove) {
  481. HEADER_STYLE.textContent += cssHideElement(createId(topDivSelector));
  482.  
  483. return;
  484. } else if (!elementConfig.tooltip) {
  485. HEADER_STYLE.textContent += cssHideElement(createId(SELECTORS.toolTips[configKey].id));
  486. }
  487.  
  488. if (elementConfig.alignLeft) {
  489. const response = cloneAndLeftAlignElement(createId(elementSelector.id), elementSelector.id);
  490.  
  491. if (response.length == 0) return;
  492.  
  493. const [cloneId, cloneElement] = response;
  494.  
  495. if (!elementConfig.tooltip) cloneElement.querySelector('tool-tip').remove();
  496.  
  497. elementSelector.id = createId(cloneId);
  498. link = cloneElement.querySelector('a');
  499. }
  500.  
  501. const padding = '7px';
  502. link.style.setProperty('padding-left', padding, 'important');
  503. link.style.setProperty('padding-right', padding, 'important');
  504.  
  505. link.style.setProperty('display', 'flex', 'important');
  506.  
  507. let textContent = elementConfig.text.content;
  508.  
  509. if (elementConfig.icon.remove) {
  510. const svgId = `${configKey}-svg`;
  511. const svg = link.querySelector('svg');
  512.  
  513. if (!svg) logError(`Selector '${configKey}' not found`);
  514.  
  515. svg.setAttribute('id', svgId);
  516.  
  517. HEADER_STYLE.textContent += cssHideElement(createId(svgId));
  518. } else {
  519. link.querySelector('svg').style.setProperty('fill', elementConfig.icon.color);
  520. textContent = UNICODE_NON_BREAKING_SPACE + textContent;
  521. }
  522.  
  523. modifyThenObserve(() => {
  524. HEADER.querySelector(createId(elementSelector.textContent))?.remove();
  525. });
  526.  
  527. if (elementConfig.text.content !== '') {
  528. const spanElement = document.createElement('span');
  529. const spanId = `${configKey}-text-content-span`;
  530. spanElement.setAttribute('id', spanId);
  531.  
  532. if (elementConfig.text.color) {
  533. HEADER_STYLE.textContent += `
  534. ${createId(spanId)}
  535. {
  536. color: ${elementConfig.text.color} !important;
  537. }
  538. `;
  539. }
  540.  
  541. const textNode = document.createTextNode(textContent);
  542. spanElement.appendChild(textNode);
  543.  
  544. link.appendChild(spanElement);
  545. }
  546.  
  547. if (!elementConfig.border) {
  548. HEADER_STYLE.textContent += `
  549. ${elementSelector.id} a
  550. {
  551. border: none !important;
  552. }
  553. `;
  554. }
  555.  
  556. if (elementConfig.boxShadow !== '') {
  557. HEADER_STYLE.textContent += `
  558. ${elementSelector.id} a
  559. {
  560. box-shadow: ${elementConfig.boxShadow} !important;
  561. }
  562. `;
  563. }
  564.  
  565. if (elementConfig.hover.backgroundColor !== '') {
  566. HEADER_STYLE.textContent += `
  567. ${elementSelector.id} a:hover
  568. {
  569. background-color: ${elementConfig.hover.backgroundColor} !important;
  570. }
  571. `;
  572. }
  573.  
  574. if (elementConfig.hover.color !== '') {
  575. HEADER_STYLE.textContent += `
  576. ${elementSelector.id} a span:hover
  577. {
  578. color: ${elementConfig.hover.color} !important;
  579. }
  580. `;
  581. }
  582.  
  583. log(DEBUG, `Updates applied to link ${configKey}: `, link);
  584. }
  585.  
  586. function cloneAndFlipElements(firstElementSelector, secondElementSelector, firstElementId, secondElementId) {
  587. log(DEBUG, 'cloneAndFlipElements()');
  588.  
  589. const firstElement = HEADER.querySelector(firstElementSelector);
  590.  
  591. if (!firstElement) {
  592. logError(`Selector '${firstElementSelector}' not found`);
  593. return [];
  594. }
  595.  
  596. const secondElement = HEADER.querySelector(secondElementSelector);
  597.  
  598. if (!secondElement) {
  599. logError(`Selector '${secondElementSelector}' not found`);
  600. return [];
  601. }
  602.  
  603. const firstElementClone = firstElement.cloneNode(true);
  604. const secondElementClone = secondElement.cloneNode(true);
  605.  
  606. const firstElementCloneId = `${firstElementId}-clone`;
  607. const secondElementCloneId = `${secondElementId}-clone`;
  608.  
  609. firstElementClone.setAttribute('id', firstElementCloneId);
  610. secondElementClone.setAttribute('id', secondElementCloneId);
  611.  
  612. firstElementClone.style.setProperty('display', 'none');
  613. secondElementClone.style.setProperty('display', 'none');
  614.  
  615. HEADER_STYLE.textContent = HEADER_STYLE.textContent.replace(
  616. new RegExp(escapeRegExp(firstElementSelector), 'g'),
  617. createId(firstElementCloneId),
  618. );
  619.  
  620. HEADER_STYLE.textContent = HEADER_STYLE.textContent.replace(
  621. new RegExp(escapeRegExp(secondElementSelector), 'g'),
  622. createId(secondElementCloneId),
  623. );
  624.  
  625. HEADER_STYLE.textContent += cssHideElement(firstElementSelector);
  626. HEADER_STYLE.textContent += cssHideElement(secondElementSelector);
  627.  
  628. HEADER_STYLE.textContent += `
  629. #${firstElementCloneId},
  630. #${secondElementCloneId}
  631. {
  632. display: initial !important;
  633. }
  634. `;
  635.  
  636. if (secondElement.nextElementSibling === null) {
  637. secondElement.parentNode.appendChild(firstElementClone);
  638. } else {
  639. secondElement.parentNode.insertBefore(firstElementClone, secondElement.nextElementSibling);
  640. }
  641.  
  642. if (firstElement.nextElementSibling === null) {
  643. firstElement.parentNode.appendChild(secondElementClone);
  644. } else{
  645. firstElement.parentNode.insertBefore(secondElementClone, firstElement.nextElementSibling);
  646. }
  647.  
  648. return [firstElementClone, secondElementClone];
  649. }
  650.  
  651. function flipIssuesPullRequests() {
  652. log(DEBUG, 'flipIssuesPullRequest()');
  653.  
  654. cloneAndFlipElements(
  655. createId(SELECTORS.issues.id),
  656. createId(SELECTORS.pullRequests.id),
  657. 'issues-flip-div',
  658. 'pullRequests-flip-div'
  659. );
  660. }
  661.  
  662. function updateCreateNewButton() {
  663. log(DEBUG, 'updateCreateNewButton()');
  664.  
  665. const configKey = 'create';
  666. const tooltipElement = SELECTORS.toolTips[configKey];
  667. const elementSelector = SELECTORS[configKey];
  668.  
  669. if (!tooltipElement) {
  670. logError(`Selector '${configKey}' not found`);
  671. return;
  672. }
  673.  
  674. const button = HEADER.querySelector(elementSelector.button);
  675.  
  676. if (!button) {
  677. logError(`Selector '${elementSelector.button}' not found`);
  678. return;
  679. }
  680.  
  681. const elementConfig = CONFIG[configKey];
  682.  
  683. if (elementConfig.remove) {
  684. HEADER_STYLE.textContent += cssHideElement(elementSelector.topDiv);
  685.  
  686. return;
  687. } else if (!elementConfig.tooltip) {
  688. HEADER_STYLE.textContent += cssHideElement(createId(tooltipElement.id));
  689. }
  690.  
  691. const topDiv = HEADER.querySelector(elementSelector.topDiv);
  692.  
  693. if (!topDiv) {
  694. logError(`Selector '${elementSelector.topDiv}' not found`);
  695. return;
  696. }
  697.  
  698. topDiv.setAttribute('id', elementSelector.id);
  699.  
  700. const buttonLabel = button.querySelector(elementSelector.dropdownIcon);
  701.  
  702. if (elementConfig.plusIcon.remove) {
  703. HEADER_STYLE.textContent += `
  704. ${elementSelector.button} ${elementSelector.plusIcon}
  705. {
  706. display: none !important
  707. }
  708. `;
  709. } else {
  710.  
  711. if (elementConfig.plusIcon.color !== '') {
  712. HEADER_STYLE.textContent += `
  713. ${elementSelector.plusIcon}
  714. {
  715. color: ${elementConfig.plusIcon.color} !important;
  716. }
  717. `;
  718. }
  719.  
  720. if (elementConfig.plusIcon.hover.color !== '') {
  721. HEADER_STYLE.textContent += `
  722. ${elementSelector.plusIcon.split(' ').join(':hover ')} svg path
  723. {
  724. fill: ${elementConfig.plusIcon.hover.color} !important;
  725. }
  726. `;
  727. }
  728.  
  729. if (elementConfig.plusIcon.marginRight !== '') {
  730. HEADER_STYLE.textContent += `
  731. ${elementSelector.plusIcon}
  732. {
  733. margin-right: ${elementConfig.plusIcon.marginRight} !important;
  734. }
  735. `;
  736. }
  737. }
  738.  
  739. modifyThenObserve(() => {
  740. HEADER.querySelector(createId(SELECTORS[configKey].textContent))?.remove();
  741. });
  742.  
  743. if (elementConfig.text.content !== '') {
  744. // Update the text's font properties to match the others
  745. HEADER_STYLE.textContent += `
  746. ${elementSelector.button}
  747. {
  748. font-size: var(--text-body-size-medium, 0.875rem) !important;
  749. font-weight: var(--base-text-weight-medium, 500) !important;
  750. }
  751. `;
  752.  
  753. const spanElement = document.createElement('span');
  754. spanElement.setAttribute('id', elementSelector.textContent);
  755.  
  756. spanElement.style.setProperty('color', elementConfig.text.color);
  757. spanElement.textContent = elementConfig.text.content;
  758.  
  759. // New span is inserted between the plus sign and dropdown icon
  760. buttonLabel.parentNode.insertBefore(spanElement, buttonLabel);
  761. }
  762.  
  763. if (elementConfig.dropdownIcon.remove) {
  764. HEADER_STYLE.textContent += `
  765. ${elementSelector.dropdownIcon}
  766. {
  767. display: none !important
  768. }
  769. `;
  770. } else {
  771. HEADER_STYLE.textContent += `
  772. ${elementSelector.dropdownIcon}
  773. {
  774. grid-area: initial !important;
  775. }
  776. `;
  777.  
  778. if (elementConfig.dropdownIcon.color !== '') {
  779. HEADER_STYLE.textContent += `
  780. ${elementSelector.dropdownIcon}
  781. {
  782. color: ${elementConfig.dropdownIcon.color} !important;
  783. }
  784. `;
  785. }
  786.  
  787. if (elementConfig.dropdownIcon.hover.color !== '') {
  788. HEADER_STYLE.textContent += `
  789. ${elementSelector.dropdownIcon.split(' ').join(':hover ')} svg path
  790. {
  791. fill: ${elementConfig.dropdownIcon.hover.color} !important;
  792. }
  793. `;
  794. }
  795. }
  796.  
  797. if (!elementConfig.border) {
  798. HEADER_STYLE.textContent += `
  799. ${elementSelector.button}
  800. {
  801. border: none !important;
  802. }
  803. `;
  804. }
  805.  
  806. if (elementConfig.boxShadow !== '') {
  807. HEADER_STYLE.textContent += `
  808. ${elementSelector.button}
  809. {
  810. box-shadow: ${elementConfig.boxShadow} !important;
  811. }
  812. `;
  813. }
  814.  
  815. if (elementConfig.hoverBackgroundColor !== '') {
  816. HEADER_STYLE.textContent += `
  817. ${elementSelector.button}:hover
  818. {
  819. background-color: ${elementConfig.hoverBackgroundColor} !important;
  820. }
  821. `;
  822. }
  823. }
  824.  
  825. function updateInboxLink() {
  826. log(DEBUG, 'updateInboxLink()');
  827.  
  828. const configKey = 'notifications';
  829.  
  830. const elementConfig = CONFIG[configKey];
  831. const elementSelector = SELECTORS[configKey];
  832.  
  833. const notificationIndicator = HEADER.querySelector(createId(elementSelector.id)) ||
  834. HEADER.querySelector(elementSelector.indicator);
  835.  
  836. if (!notificationIndicator) {
  837. logError(`Selectors '${createId(elementSelector.id)}' and '${elementSelector.indicator}' not found`);
  838. return;
  839. }
  840.  
  841. notificationIndicator.setAttribute('id', elementSelector.id);
  842.  
  843. const inboxLink = notificationIndicator.querySelector('a');
  844.  
  845. if (!inboxLink) {
  846. logError(`Selector '${elementSelector.indicator} a' not found`);
  847. return;
  848. }
  849.  
  850. if (elementConfig.remove) {
  851. HEADER_STYLE.textContent += cssHideElement(elementSelector.indicator);
  852. }
  853.  
  854. if (!elementConfig.tooltip) {
  855. HEADER_STYLE.textContent += cssHideElement(createId(SELECTORS.toolTips.notifications.id));
  856. }
  857.  
  858. if (elementConfig.dot.remove) {
  859. HEADER_STYLE.textContent += `
  860. ${elementSelector.dot}
  861. {
  862. content: none !important;
  863. }
  864. `;
  865. } else {
  866. if (elementConfig.dot.color !== '') {
  867. HEADER_STYLE.textContent += `
  868. ${elementSelector.dot}
  869. {
  870. background: ${elementConfig.dot.color} !important;
  871. }
  872. `;
  873. }
  874.  
  875. if (elementConfig.dot.boxShadowColor !== '') {
  876. HEADER_STYLE.textContent += `
  877. ${elementSelector.dot}
  878. {
  879. box-shadow: 0 0 0 calc(var(--base-size-4, 4px)/2) ${elementConfig.dot.boxShadowColor} !important;
  880. }
  881. `;
  882. }
  883. }
  884.  
  885. if (elementConfig.icon.symbol === 'inbox') {
  886. if (elementConfig.icon.color !== '') {
  887. HEADER_STYLE.textContent += `
  888. ${createId(elementSelector.id)} a svg
  889. {
  890. fill: elementConfig.icon.color !important;
  891. }
  892. `;
  893. }
  894. } else {
  895. const inboxSvgId = 'inbox-svg';
  896. const inboxSvg = inboxLink.querySelector('svg');
  897. inboxSvg.setAttribute('id', inboxSvgId);
  898.  
  899. HEADER_STYLE.textContent += cssHideElement(createId(inboxSvgId));
  900. }
  901.  
  902. if (elementConfig.icon.symbol === 'bell') {
  903. // Bell icon from https://gist.github.com
  904. const bellSvgId = 'bell-svg';
  905. const bellSvg = `
  906. <svg id=${bellSvgId} style="display: none;" aria-hidden='true' height='16' viewBox='0 0 16 16' version='1.1' width='16' data-view-component='true' class='octicon octicon-bell'>
  907. <path d='M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z'></path>
  908. </svg>
  909. `;
  910.  
  911. inboxLink.insertAdjacentHTML('afterbegin', bellSvg);
  912.  
  913. HEADER_STYLE.textContent += `
  914. ${createId(bellSvgId)}
  915. {
  916. display: initial !important;
  917. }
  918. `;
  919.  
  920. if (elementConfig.icon.color !== '') {
  921. HEADER_STYLE.textContent += `
  922. ${createId(bellSvgId)} path
  923. {
  924. fill: ${elementConfig.icon.color} !important;
  925. }
  926. `;
  927. }
  928. }
  929.  
  930. if (elementConfig.icon.hover.color !== '') {
  931. HEADER_STYLE.textContent += `
  932. ${createId(elementSelector.id)} a:hover svg path
  933. {
  934. fill: ${elementConfig.icon.hover.color} !important;
  935. }
  936. `;
  937. }
  938.  
  939. modifyThenObserve(() => {
  940. HEADER.querySelector(createId(SELECTORS[configKey].textContent))?.remove();
  941. });
  942.  
  943. if (elementConfig.text.content !== '') {
  944. const padding = '9px';
  945.  
  946. HEADER_STYLE.textContent += `
  947. ${createId(elementSelector.id)} a
  948. {
  949. padding-left: ${padding} !important;
  950. padding-right: ${padding} !important;
  951. width: auto !important;
  952. text-decoration: none !important;
  953. display: flex !important;
  954. }
  955. `;
  956.  
  957. let textContent = elementConfig.text.content;
  958.  
  959. if (elementConfig.icon !== '') {
  960. textContent = UNICODE_NON_BREAKING_SPACE + UNICODE_NON_BREAKING_SPACE + textContent;
  961. }
  962.  
  963. const spanElement = document.createElement('span');
  964. spanElement.setAttribute('id', elementSelector.textContent);
  965.  
  966. // Update the text's font properties to match the others
  967. spanElement.style.setProperty('font-size', 'var(--text-body-size-medium, 0.875rem)', 'important');
  968. spanElement.style.setProperty('font-weight', 'var(--base-text-weight-medium, 500)', 'important');
  969.  
  970. if (elementConfig.text.color) spanElement.style.setProperty('color', elementConfig.text.color);
  971.  
  972. const textNode = document.createTextNode(textContent);
  973. spanElement.appendChild(textNode);
  974.  
  975. inboxLink.appendChild(spanElement);
  976. }
  977.  
  978. if (!elementConfig.border) {
  979. HEADER_STYLE.textContent += `
  980. ${createId(elementSelector.id)} a
  981. {
  982. border: none !important;
  983. }
  984. `;
  985. }
  986.  
  987. if (elementConfig.boxShadow !== '') {
  988. HEADER_STYLE.textContent += `
  989. ${createId(elementSelector.id)} a
  990. {
  991. box-shadow: ${elementConfig.boxShadow} !important;
  992. }
  993. `;
  994. }
  995.  
  996. if (elementConfig.dot.displayOverIcon) {
  997. HEADER_STYLE.textContent += `
  998. ${elementSelector.dot}
  999. {
  1000. top: 5px !important;
  1001. left: 18px !important;
  1002. }
  1003. `;
  1004. }
  1005.  
  1006. if (elementConfig.hoverBackgroundColor !== '') {
  1007. HEADER_STYLE.textContent += `
  1008. ${createId(elementSelector.id)} a:hover
  1009. {
  1010. background-color: ${elementConfig.hoverBackgroundColor} !important;
  1011. }
  1012. `;
  1013. }
  1014.  
  1015. log(DEBUG, `Updates applied to link ${configKey}: `, inboxLink);
  1016. }
  1017.  
  1018. function insertAvatarDropdown() {
  1019. log(DEBUG, 'insertAvatarDropdown()');
  1020.  
  1021. const elementSelector = SELECTORS.avatar;
  1022. const svgSelector = elementSelector.svg;
  1023.  
  1024. if (HEADER.querySelector(createId(svgSelector))) {
  1025. log(VERBOSE, `Selector ${createId(svgSelector)} not found`);
  1026. return;
  1027. }
  1028.  
  1029. const dropdownSvg = `
  1030. <svg id='${svgSelector}' style="display: none;" height="100%" width="100%" fill="#FFFFFF" class="octicon octicon-triangle-down" aria-hidden="true" viewBox="0 0 16 16" version="1.1" data-view-component="true">
  1031. <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path>
  1032. </svg>
  1033. `;
  1034.  
  1035. const button = HEADER.querySelector(elementSelector.button);
  1036.  
  1037. if (!button) {
  1038. logError(`Selector '${elementSelector.button}' not found`);
  1039. return;
  1040. }
  1041.  
  1042. const divElement = document.createElement('div');
  1043. divElement.insertAdjacentHTML('afterbegin', dropdownSvg);
  1044.  
  1045. button.appendChild(divElement);
  1046. }
  1047.  
  1048. function updateAvatarButton() {
  1049. log(DEBUG, 'updateAvatarButton()');
  1050.  
  1051. const elementSelector = SELECTORS.sidebars.right;
  1052. const topDivSelector = elementSelector.topDiv;
  1053.  
  1054. const topDiv = HEADER.querySelector(topDivSelector);
  1055.  
  1056. if (!topDiv) {
  1057. log(DEBUG, `Selector ${topDivSelector} not found`);
  1058. return;
  1059. }
  1060.  
  1061. const avatarButton = HEADER.querySelector(SELECTORS.avatar.button);
  1062.  
  1063. if (!avatarButton) {
  1064. log(DEBUG, `Selector ${SELECTORS.avatar.button} not found`);
  1065. return;
  1066. }
  1067.  
  1068. if (topDiv.classList.contains('Overlay--hidden')) {
  1069. if (avatarButton.hasAttribute('data-close-dialog-id')) {
  1070. const dialogId = avatarButton.getAttribute('data-close-dialog-id');
  1071. avatarButton.setAttribute('data-show-dialog-id', dialogId);
  1072.  
  1073. avatarButton.removeAttribute('data-close-dialog-id');
  1074. }
  1075. } else {
  1076. if (avatarButton.hasAttribute('data-show-dialog-id')) {
  1077. const dialogId = avatarButton.getAttribute('data-show-dialog-id');
  1078. avatarButton.setAttribute('data-close-dialog-id', dialogId);
  1079.  
  1080. avatarButton.removeAttribute('data-show-dialog-id');
  1081. }
  1082. }
  1083. }
  1084.  
  1085. function updateAvatar() {
  1086. log(DEBUG, 'updateAvatar()');
  1087.  
  1088. const configKey = 'avatar';
  1089.  
  1090. const elementConfig = CONFIG[configKey];
  1091. const elementSelector = SELECTORS[configKey];
  1092.  
  1093. if (elementConfig.size !== '') {
  1094. HEADER_STYLE.textContent += `
  1095. ${elementSelector.img}
  1096. {
  1097. height: ${elementConfig.size} !important;
  1098. width: ${elementConfig.size} !important;
  1099. }
  1100. `;
  1101. }
  1102.  
  1103. if (elementConfig.dropdownIcon) {
  1104. insertAvatarDropdown();
  1105.  
  1106. HEADER_STYLE.textContent += `
  1107. ${elementSelector.topDiv}
  1108. {
  1109. background-color: transparent !important;
  1110. }
  1111.  
  1112. ${createId(elementSelector.svg)}
  1113. {
  1114. display: initial !important;
  1115. fill: #FFFFFF;
  1116. height: 16px;
  1117. width: 16px;
  1118. margin-bottom: 1.5px;
  1119. }
  1120.  
  1121. ${elementSelector.button}:hover ${createId(elementSelector.svg)} path
  1122. {
  1123. fill: #FFFFFFB3 !important;
  1124. }
  1125.  
  1126. ${elementSelector.button}
  1127. {
  1128. gap: 0px !important;
  1129. }
  1130. `;
  1131. }
  1132. }
  1133.  
  1134. function flipCreateInbox() {
  1135. log(DEBUG, 'flipCreateInbox()');
  1136.  
  1137. cloneAndFlipElements(
  1138. createId(SELECTORS.create.id),
  1139. createId(SELECTORS.notifications.id),
  1140. `${SELECTORS.create.id}-flip`,
  1141. `${SELECTORS.notifications.id}-flip`,
  1142. );
  1143. }
  1144.  
  1145. function updateGlobalBar() {
  1146. log(DEBUG, 'updateGlobalBar()');
  1147.  
  1148. const elementConfig = CONFIG.globalBar;
  1149.  
  1150. if (elementConfig.boxShadowColor !== '') {
  1151. HEADER_STYLE.textContent += `
  1152. ${SELECTORS.header.globalBar}
  1153. {
  1154. box-shadow: inset 0 calc(var(--borderWidth-thin, 1px)*-1) ${elementConfig.boxShadowColor} !important;
  1155. }
  1156. `;
  1157. }
  1158.  
  1159. if (elementConfig.rightAligned.gap !== '') {
  1160. HEADER_STYLE.textContent += `
  1161. ${SELECTORS.header.rightAligned}
  1162. {
  1163. gap: ${elementConfig.rightAligned.gap} !important;
  1164. }
  1165. `;
  1166. }
  1167.  
  1168. if (elementConfig.leftAligned.gap !== '') {
  1169. HEADER_STYLE.textContent += `
  1170. ${SELECTORS.header.leftAligned}
  1171. {
  1172. gap: ${elementConfig.leftAligned.gap} !important;
  1173. }
  1174. `;
  1175. }
  1176. }
  1177.  
  1178. function updateLocalBar() {
  1179. log(DEBUG, 'updateLocalBar()');
  1180.  
  1181. const elementConfig = CONFIG.localBar;
  1182.  
  1183. if (elementConfig.backgroundColor !== '') {
  1184. HEADER_STYLE.textContent += `
  1185. ${SELECTORS.header.localBar.topDiv}
  1186. {
  1187. background-color: ${elementConfig.backgroundColor} !important;
  1188. box-shadow: inset 0 calc(var(--borderWidth-thin, 1px)*-1) var(--color-border-default) !important;
  1189. }
  1190. `;
  1191. }
  1192.  
  1193. if (elementConfig.alignCenter) {
  1194. HEADER_STYLE.textContent += `
  1195. ${SELECTORS.header.localBar.underlineNavActions}
  1196. {
  1197. display: initial !important;
  1198. padding-right: 0px !important;
  1199. }
  1200.  
  1201. ${SELECTORS.header.localBar.topDiv} nav
  1202. {
  1203. max-width: 1280px;
  1204. margin-right: auto;
  1205. margin-left: auto;
  1206. }
  1207.  
  1208. @media (min-width: 768px) {
  1209. ${SELECTORS.header.localBar.topDiv} nav
  1210. {
  1211. padding-right: var(--base-size-24, 24px) !important;
  1212. padding-left: var(--base-size-24, 24px) !important;
  1213. }
  1214. }
  1215.  
  1216. @media (min-width: 1012px) {
  1217. ${SELECTORS.header.localBar.topDiv} nav
  1218. {
  1219. padding-right: var(--base-size-32, 32px) !important;
  1220. padding-left: var(--base-size-32, 32px) !important;
  1221. }
  1222. }
  1223. `;
  1224. }
  1225.  
  1226. if (elementConfig.boxShadow.consistentColor) {
  1227. HEADER_STYLE.textContent += `
  1228. .UnderlineNav
  1229. {
  1230. box-shadow: none !important;
  1231. }
  1232. `;
  1233. }
  1234.  
  1235. if (elementConfig.links.color !== '') {
  1236. HEADER_STYLE.textContent += `
  1237. ${SELECTORS.header.localBar.topDiv} a,
  1238. ${SELECTORS.header.localBar.topDiv} a span
  1239. {
  1240. color: ${elementConfig.links.color} !important;
  1241. }
  1242. `;
  1243. }
  1244. }
  1245.  
  1246. function updateSidebars() {
  1247. log(DEBUG, 'updateSidebars()');
  1248.  
  1249. const configKey = 'sidebars';
  1250.  
  1251. const elementConfig = CONFIG[configKey];
  1252. const elementSelector = SELECTORS[configKey];
  1253.  
  1254. if (elementConfig.backdrop.color !== '') {
  1255. HEADER_STYLE.textContent += `
  1256. ${elementSelector.backdrop}
  1257. {
  1258. background-color: ${CONFIG.sidebars.backdrop.color} !important;
  1259. }
  1260. `;
  1261. }
  1262.  
  1263. if (elementConfig.backdrop.pointerEvents !== '') {
  1264. HEADER_STYLE.textContent += `
  1265. ${elementSelector.backdrop}
  1266. {
  1267. pointer-events: ${CONFIG.sidebars.backdrop.pointerEvents} !important;
  1268. }
  1269.  
  1270. ${elementSelector.backdrop} > *
  1271. {
  1272. pointer-events: initial !important;
  1273. }
  1274. `;
  1275. }
  1276.  
  1277. if (elementConfig.right.floatUnderneath) {
  1278. HEADER_STYLE.textContent += `
  1279. ${elementSelector.right.backdrop}
  1280. {
  1281. padding-top: 10px !important;
  1282. padding-right: 15px !important;
  1283. border-top-right-radius: 6px !important;
  1284. bottom: initial !important;
  1285. top: initial !important;
  1286. }
  1287.  
  1288. ${elementSelector.right.modalDialog}
  1289. {
  1290. border-top-right-radius: var(--borderRadius-large, 0.75rem) !important;
  1291. border-bottom-right-radius: var(--borderRadius-large, 0.75rem) !important;
  1292. }
  1293.  
  1294. ${elementSelector.right.navParentDiv}
  1295. {
  1296. margin-bottom: 0px !important;
  1297. }
  1298.  
  1299. ${elementSelector.right.nav}
  1300. {
  1301. padding-bottom: 0px !important;
  1302. }
  1303. `;
  1304. }
  1305.  
  1306. if (elementConfig.right.preload) {
  1307. HEADER.querySelector(elementSelector.right.backdrop).remove();
  1308. HEADER.querySelector(SELECTORS.avatar.button).click();
  1309. }
  1310.  
  1311. if (elementConfig.right.maxHeight) {
  1312. HEADER_STYLE.textContent += `
  1313. ${elementSelector.right.modalDialog}
  1314. {
  1315. max-height: ${elementConfig.right.maxHeight} !important;
  1316. }
  1317. `;
  1318. }
  1319. }
  1320.  
  1321. function importRepositoryHeader() {
  1322. log(DEBUG, 'importRepositoryHeader()');
  1323.  
  1324. const configKey = 'repositoryHeader';
  1325. const repositoryHeader = document.querySelector(SELECTORS[configKey].id);
  1326.  
  1327. if (!repositoryHeader) {
  1328. // This is expected on pages that aren't repositories
  1329. log(DEBUG, `Selector '${SELECTORS[configKey].id}' not found`);
  1330. return;
  1331. }
  1332.  
  1333. const topRepositoryHeaderElement = document.createElement('div');
  1334. topRepositoryHeaderElement.style.setProperty('display', 'flex');
  1335. topRepositoryHeaderElement.style.setProperty('padding', '0px');
  1336. topRepositoryHeaderElement.style.setProperty('box-shadow', 'none');
  1337.  
  1338. const elementConfig = CONFIG[configKey];
  1339.  
  1340. if (elementConfig.backgroundColor !== '') {
  1341. topRepositoryHeaderElement.style.setProperty('background-color', elementConfig.backgroundColor);
  1342. }
  1343.  
  1344. if (repositoryHeader.hidden) {
  1345. log(DEBUG, `${SELECTORS[configKey].id} is hidden`);
  1346.  
  1347. if (!HEADER.querySelector(SELECTORS.pageTitle.separator)) {
  1348. logError(`Selector '${SELECTORS.pageTitle.separator}' not found`);
  1349. log(INFO, 'Not creating a repository header');
  1350.  
  1351. return;
  1352. }
  1353.  
  1354. // A repo tab other than Code is being loaded for the first time
  1355. if (!CONFIG.pageTitle.remove) return;
  1356.  
  1357. const pageTitle = HEADER.querySelector(SELECTORS.pageTitle.topDiv);
  1358.  
  1359. if (!pageTitle) {
  1360. logError(`Selector '${SELECTORS.pageTitle.topDiv}' not found`);
  1361. return;
  1362. }
  1363.  
  1364. const repositoryHeaderElement = document.createElement('div');
  1365. repositoryHeaderElement.id = TEMP_REPOSITORY_HEADER_FLAG;
  1366. repositoryHeaderElement.classList.add('pt-3', 'mb-2', REPOSITORY_HEADER_CLASS);
  1367.  
  1368. const clonedPageTitle = pageTitle.cloneNode(true);
  1369. repositoryHeaderElement.appendChild(clonedPageTitle);
  1370.  
  1371. topRepositoryHeaderElement.appendChild(repositoryHeaderElement);
  1372. insertNewGlobalBar(topRepositoryHeaderElement);
  1373. } else if (HEADER.querySelector(createId(TEMP_REPOSITORY_HEADER_FLAG))) {
  1374. // The Code tab is being loaded from another tab which has a temporary header
  1375. HEADER_STYLE.textContent += cssHideElement(createId(TEMP_REPOSITORY_HEADER_FLAG));
  1376.  
  1377. insertPermanentRepositoryHeader(topRepositoryHeaderElement, repositoryHeader);
  1378. } else {
  1379. // The Code tab being loaded for the first time
  1380. insertPermanentRepositoryHeader(topRepositoryHeaderElement, repositoryHeader);
  1381. }
  1382.  
  1383. updateRepositoryHeaderName();
  1384.  
  1385. if (elementConfig.backgroundColor !== '') {
  1386. HEADER_STYLE.textContent += `
  1387. .${REPOSITORY_HEADER_CLASS}
  1388. {
  1389. background-color: ${elementConfig.backgroundColor} !important;
  1390. }
  1391. `;
  1392. }
  1393.  
  1394. if (elementConfig.alignCenter) {
  1395. HEADER_STYLE.textContent += `
  1396. .${REPOSITORY_HEADER_CLASS}
  1397. {
  1398. max-width: 1280px;
  1399. margin-right: auto;
  1400. margin-left: auto;
  1401. }
  1402.  
  1403. .${REPOSITORY_HEADER_CLASS} div
  1404. {
  1405. padding-left: 0px !important;
  1406. padding-right: 0px !important;
  1407. }
  1408.  
  1409. @media (min-width: 768px) {
  1410. .${REPOSITORY_HEADER_CLASS}
  1411. {
  1412. padding-right: var(--base-size-24, 24px) !important;
  1413. padding-left: var(--base-size-24, 24px) !important;
  1414. }
  1415. }
  1416.  
  1417. @media (min-width: 1012px) {
  1418. .${REPOSITORY_HEADER_CLASS}
  1419. {
  1420. padding-right: var(--base-size-32, 32px) !important;
  1421. padding-left: var(--base-size-32, 32px) !important;
  1422. }
  1423. }
  1424. `;
  1425. }
  1426.  
  1427. if (elementConfig.link.color !== '') {
  1428. HEADER_STYLE.textContent += `
  1429. ${SELECTORS.repositoryHeader.links}
  1430. {
  1431. color: ${elementConfig.link.color} !important;
  1432. }
  1433. `;
  1434. }
  1435.  
  1436. if (elementConfig.link.hover.color !== '') {
  1437. HEADER_STYLE.textContent += `
  1438. ${SELECTORS.repositoryHeader.links}:hover
  1439. {
  1440. color: ${elementConfig.link.hover.color} !important;
  1441. }
  1442. `;
  1443. }
  1444.  
  1445. if (elementConfig.link.hover.backgroundColor !== '') {
  1446. HEADER_STYLE.textContent += `
  1447. ${SELECTORS.repositoryHeader.links}:hover
  1448. {
  1449. background-color: ${elementConfig.link.hover.backgroundColor} !important;
  1450. }
  1451. `;
  1452. }
  1453.  
  1454. if (elementConfig.link.hover.textDecoration !== '') {
  1455. HEADER_STYLE.textContent += `
  1456. ${SELECTORS.repositoryHeader.links}:hover
  1457. {
  1458. text-decoration: ${elementConfig.link.hover.textDecoration} !important;
  1459. }
  1460. `;
  1461. }
  1462.  
  1463. HEADER_STYLE.textContent += `
  1464. .${REPOSITORY_HEADER_CLASS}
  1465. {
  1466. flex: auto !important;
  1467. }
  1468.  
  1469. ${SELECTORS.repositoryHeader.details}
  1470. {
  1471. display: flex;
  1472. align-items: center;
  1473. }
  1474.  
  1475. ${SELECTORS.pageTitle.topDiv}
  1476. {
  1477. flex: 0 1 auto !important;
  1478. height: auto !important;
  1479. min-width: 0 !important;
  1480. }
  1481.  
  1482. @media (min-width: 768px)
  1483. {
  1484. .AppHeader-context .AppHeader-context-compact
  1485. {
  1486. display: none !important;
  1487. }
  1488. }
  1489.  
  1490. .AppHeader-context .AppHeader-context-full
  1491. {
  1492. display: inline-flex !important;
  1493. width: 100% !important;
  1494. min-width: 0 !important;
  1495. max-width: 100% !important;
  1496. overflow: hidden !important;
  1497. }
  1498.  
  1499. .AppHeader-context .AppHeader-context-full ul {
  1500. display: flex;
  1501. flex-direction: row;
  1502. }
  1503.  
  1504. .AppHeader-context .AppHeader-context-full li:first-child {
  1505. flex: 0 100 max-content;
  1506. }
  1507.  
  1508. .AppHeader-context .AppHeader-context-full li {
  1509. display: inline-grid;
  1510. grid-auto-flow: column;
  1511. align-items: center;
  1512. flex: 0 99999 auto;
  1513. }
  1514.  
  1515. .AppHeader-context .AppHeader-context-full ul, .AppHeader .AppHeader-globalBar .AppHeader-context .AppHeader-context-full li {
  1516. list-style: none;
  1517. }
  1518.  
  1519. .AppHeader-context .AppHeader-context-item {
  1520. display: flex;
  1521. align-items: center;
  1522. min-width: 3ch;
  1523. line-height: var(--text-body-lineHeight-medium, 1.4285714286);
  1524. text-decoration: none !important;
  1525. border-radius: var(--borderRadius-medium, 6px);
  1526. padding-inline: var(--control-medium-paddingInline-condensed, 8px);
  1527. padding-block: var(--control-medium-paddingBlock, 6px);
  1528. }
  1529.  
  1530. .AppHeader-context .AppHeader-context-full li:last-child .AppHeader-context-item {
  1531. font-weight: var(--base-text-weight-semibold, 600);
  1532. }
  1533.  
  1534. .AppHeader-context .AppHeader-context-item-separator {
  1535. color: var(--fgColor-muted, var(--color-fg-muted));
  1536. white-space: nowrap;
  1537. }
  1538.  
  1539. ${SELECTORS.header.globalBar}
  1540. {
  1541. padding: 16px !important;
  1542. }
  1543. `;
  1544.  
  1545. if (elementConfig.removePageTitle) removePageTitle();
  1546.  
  1547. return true;
  1548. }
  1549.  
  1550. function insertPermanentRepositoryHeader(topRepositoryHeaderElement, repositoryHeader) {
  1551. log(DEBUG, 'insertPermanentRepositoryHeader()');
  1552.  
  1553. const clonedRepositoryHeader = repositoryHeader.cloneNode(true);
  1554.  
  1555. // This is needed to prevent pop-in via Turbo when navigating between tabs on a repo
  1556. repositoryHeader.removeAttribute('data-turbo-replace');
  1557. clonedRepositoryHeader.removeAttribute('data-turbo-replace');
  1558.  
  1559. repositoryHeader.style.setProperty('display', 'none', 'important');
  1560.  
  1561. clonedRepositoryHeader.classList.add(REPOSITORY_HEADER_SUCCESS_FLAG, REPOSITORY_HEADER_CLASS);
  1562.  
  1563. topRepositoryHeaderElement.appendChild(clonedRepositoryHeader);
  1564.  
  1565. insertNewGlobalBar(topRepositoryHeaderElement);
  1566.  
  1567. clonedRepositoryHeader.firstElementChild.classList.remove('container-xl', 'px-lg-5');
  1568. }
  1569.  
  1570. function updateRepositoryHeaderName() {
  1571. log(DEBUG, 'updateRepositoryHeaderName()');
  1572.  
  1573. const elementConfig = CONFIG.repositoryHeader;
  1574.  
  1575. const name = document.querySelector(SELECTORS.repositoryHeader.name);
  1576.  
  1577. if (!name) {
  1578. // When not in a repo, this is expected
  1579. log(DEBUG, `Selector '${SELECTORS.repositoryHeader.name}' not found`);
  1580. return;
  1581. }
  1582.  
  1583. name.style.setProperty('display', 'none', 'important');
  1584.  
  1585. const pageTitle = HEADER.querySelector(SELECTORS.pageTitle.topDiv);
  1586.  
  1587. if (!pageTitle) {
  1588. logError(`Selector '${SELECTORS.pageTitle.topDiv}' not found`);
  1589. return;
  1590. }
  1591.  
  1592. const ownerImg = document.querySelector(SELECTORS.repositoryHeader.ownerImg);
  1593.  
  1594. if (!ownerImg) {
  1595. logError(`Selector '${SELECTORS.repositoryHeader.ownerImg}' not found`);
  1596. return;
  1597. }
  1598.  
  1599. const clonedPageTitle = pageTitle.cloneNode(true);
  1600. clonedPageTitle.style.display = '';
  1601.  
  1602. clonedPageTitle.querySelectorAll('svg').forEach(svg => svg.remove());
  1603.  
  1604. ownerImg.parentNode.insertBefore(clonedPageTitle, ownerImg.nextSibling);
  1605.  
  1606. if (elementConfig.avatar.remove) {
  1607. ownerImg.remove();
  1608. } else if (elementConfig.avatar.customSvg !== '') {
  1609. if (isValidURL(elementConfig.avatar.customSvg)) {
  1610. ownerImg.src = elementConfig.avatar.customSvg;
  1611. } else {
  1612. const divElement = document.createElement('div');
  1613. divElement.style.setProperty('display', 'flex');
  1614. divElement.style.setProperty('align-items', 'center');
  1615.  
  1616. divElement.innerHTML = elementConfig.avatar.customSvg;
  1617.  
  1618. ownerImg.parentNode.replaceChild(divElement, ownerImg);
  1619. }
  1620. }
  1621.  
  1622. HEADER_STYLE.textContent += cssHideElement(SELECTORS.repositoryHeader.bottomBorder);
  1623. }
  1624.  
  1625. function cloneAndLeftAlignElement(elementSelector, elementId) {
  1626. log(DEBUG, 'cloneAndLeftAlignElement()');
  1627.  
  1628. const leftAlignedDiv = HEADER.querySelector(SELECTORS.header.leftAligned);
  1629.  
  1630. if (!leftAlignedDiv) {
  1631. logError(`Selector '${SELECTORS.header.leftAligned}' not found`);
  1632. return [];
  1633. }
  1634.  
  1635. const element = HEADER.querySelector(elementSelector);
  1636.  
  1637. if (!element) {
  1638. logError(`Selector '${elementSelector}' not found`);
  1639. return [];
  1640. }
  1641.  
  1642. const elementClone = element.cloneNode(true);
  1643. const elementCloneId = `${elementId}-clone`;
  1644.  
  1645. elementClone.setAttribute('id', elementCloneId);
  1646.  
  1647. elementClone.style.setProperty('display', 'none');
  1648.  
  1649. HEADER_STYLE.textContent += cssHideElement(elementSelector);
  1650.  
  1651. HEADER_STYLE.textContent += `
  1652. ${createId(elementCloneId)}
  1653. {
  1654. display: initial !important;
  1655. }
  1656. `;
  1657.  
  1658. leftAlignedDiv.appendChild(elementClone);
  1659.  
  1660. return [elementCloneId, elementClone];
  1661. }
  1662.  
  1663. function insertNewGlobalBar(element) {
  1664. log(DEBUG, 'insertNewGlobalBar()');
  1665.  
  1666. const elementToInsertAfter = HEADER.querySelector(SELECTORS.header.globalBar);
  1667.  
  1668. elementToInsertAfter.parentNode.insertBefore(element, elementToInsertAfter.nextSibling);
  1669. }
  1670.  
  1671. function createId(string) {
  1672. if (string.startsWith('#')) return string;
  1673.  
  1674. return `#${string}`;
  1675. }
  1676.  
  1677. function cssHideElement(elementSelector) {
  1678. return `
  1679. ${elementSelector}
  1680. {
  1681. display: none !important;
  1682. }
  1683. `;
  1684. }
  1685.  
  1686. function isValidURL(string) {
  1687. log(DEBUG, 'isValidURL()');
  1688.  
  1689. const urlPattern = /^(https?:\/\/)?([\w.]+)\.([a-z]{2,6}\.?)(\/[\w.]*)*\/?$/i;
  1690. return urlPattern.test(string);
  1691. }
  1692.  
  1693. function escapeRegExp(string) {
  1694. log(DEBUG, 'escapeRegExp()');
  1695.  
  1696. return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  1697. }
  1698.  
  1699. function updateSelectors() {
  1700. log(DEBUG, 'updateSelectors()');
  1701.  
  1702. const toolTips = Array.from(HEADER.querySelectorAll('tool-tip'));
  1703. SELECTORS.toolTips = {
  1704. create: toolTips.find(
  1705. tooltip => tooltip.textContent.includes('Create new')
  1706. ),
  1707. pullRequests: toolTips.find(
  1708. tooltip => tooltip.textContent.includes('Pull requests')
  1709. ),
  1710. issues: toolTips.find(
  1711. tooltip => tooltip.textContent.includes('Issues')
  1712. ),
  1713. notifications: toolTips.find(
  1714. tooltip => tooltip.getAttribute('data-target') === 'notification-indicator.tooltip'
  1715. ),
  1716. };
  1717. }
  1718.  
  1719. function waitForFeaturePreviewButton() {
  1720. log(DEBUG, 'waitForFeaturePreviewButton()');
  1721.  
  1722. if (!HEADER) return;
  1723.  
  1724. const liElementId = 'custom-global-navigation-menu-item';
  1725.  
  1726. if (HEADER.querySelector(createId(liElementId))) return;
  1727.  
  1728. const featurePreviewSearch = HEADER.querySelectorAll('[data-analytics-event*="FEATURE_PREVIEW"]');
  1729.  
  1730. if (featurePreviewSearch.length === 1) {
  1731. const featurePreviewButton = featurePreviewSearch[0];
  1732. const featurePreviewLi = featurePreviewButton.parentNode;
  1733.  
  1734. const newLiElement = featurePreviewLi.cloneNode(true);
  1735. newLiElement.setAttribute('id', liElementId);
  1736. newLiElement.removeAttribute('data-targets');
  1737.  
  1738. const newButton = newLiElement.querySelector('button');
  1739. newButton.removeAttribute('id');
  1740. newButton.removeAttribute('data-analytics-event');
  1741. newButton.removeAttribute('data-show-dialog-id');
  1742. newButton.removeAttribute('data-view-component');
  1743. newButton.onclick = () => {
  1744. GMC.open();
  1745.  
  1746. if (GMC.get('on_open') === 'close sidebar') HEADER.querySelector(SELECTORS.sidebars.right.closeButton)?.click();
  1747. };
  1748.  
  1749. const textElement = newLiElement.querySelector('.ActionListItem-label');
  1750. textElement.textContent = 'Custom global navigation';
  1751.  
  1752. const oldSvg = newLiElement.querySelector('svg');
  1753.  
  1754. const newSvg = document.createElement('img');
  1755. newSvg.setAttribute('height', '16px');
  1756. newSvg.setAttribute('width', '16px');
  1757. newSvg.src = `https://raw.githubusercontent.com/blakegearin/github-custom-global-navigation/main/img/${THEME}_logo.svg`;
  1758.  
  1759. oldSvg.parentNode.replaceChild(newSvg, oldSvg);
  1760.  
  1761. const parentUl = featurePreviewLi.parentNode;
  1762. const settingsLi = HEADER.querySelector('a[href="/settings/profile"]').parentNode;
  1763.  
  1764. parentUl.insertBefore(newLiElement, settingsLi.nextSibling);
  1765.  
  1766. const divider = featurePreviewLi.parentNode.querySelector('.ActionList-sectionDivider');
  1767. const newDivider = divider.cloneNode(true);
  1768.  
  1769. parentUl.insertBefore(newDivider, settingsLi.nextSibling);
  1770. } else {
  1771. setTimeout(waitForFeaturePreviewButton, 100);
  1772. }
  1773. }
  1774.  
  1775. function generateCustomConfig() {
  1776. log(DEBUG, 'generateCustomConfig()');
  1777.  
  1778. const customConfig = {
  1779. light: {},
  1780. dark: {},
  1781. };
  1782.  
  1783. function recursivelyGenerateCustomConfig(obj, customObj, themePrefix, parentKey = '') {
  1784. for (const key in obj) {
  1785. const currentKey = parentKey ? `${parentKey}.${key}` : key;
  1786. if (typeof obj[key] === 'object') {
  1787. customObj[key] = {};
  1788. recursivelyGenerateCustomConfig(obj[key], customObj[key], themePrefix, currentKey);
  1789. } else {
  1790. const gmcKey = `${themePrefix}_${currentKey.replace(/\./g, '_')}`;
  1791.  
  1792. log(VERBOSE, 'gmcKey', gmcKey);
  1793.  
  1794. customObj[key] = GMC.get(gmcKey);
  1795. }
  1796. }
  1797. }
  1798.  
  1799. recursivelyGenerateCustomConfig(configs.happyMedium.light, customConfig.light, 'light');
  1800. recursivelyGenerateCustomConfig(configs.happyMedium.dark, customConfig.dark, 'dark');
  1801.  
  1802. return customConfig;
  1803. }
  1804.  
  1805. function setTheme() {
  1806. log(DEBUG, 'setTheme()');
  1807.  
  1808. const dataColorMode = document.querySelector('html').getAttribute('data-color-mode');
  1809.  
  1810. if (dataColorMode === 'auto') {
  1811. if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  1812. THEME = 'dark';
  1813. }
  1814. } else if (dataColorMode === 'dark') {
  1815. THEME = 'dark';
  1816. } else if (dataColorMode !== 'light') {
  1817. logError('Unknown color mode');
  1818. }
  1819.  
  1820. log(VERBOSE, `THEME: ${THEME}`);
  1821. }
  1822.  
  1823. function gmcInitialized() {
  1824. log(DEBUG, 'gmcInitialized()');
  1825.  
  1826. updateLogLevel();
  1827.  
  1828. log(QUIET, 'Running');
  1829.  
  1830. GMC.css.basic = '';
  1831. window.addEventListener('load', () => {
  1832. startObserving();
  1833. });
  1834. }
  1835.  
  1836. function gmcAddSavedSpan(div) {
  1837. log(DEBUG, 'gmcAddSavedSpan()');
  1838.  
  1839. const savedDiv = document.createElement('div');
  1840. savedDiv.setAttribute('id', 'gmc-saved');
  1841.  
  1842. const iconSpan = document.createElement('span');
  1843. iconSpan.style = 'margin-right: 4px;';
  1844.  
  1845. iconSpan.innerHTML = `
  1846. <svg aria-hidden="true" focusable="false" role="img" class="octicon octicon-check-circle-fill" viewBox="0 0 12 12" width="12" height="12" fill="currentColor" style="display: inline-block;user-select: none;vertical-align: text-bottom;">
  1847. <path d="M6 0a6 6 0 1 1 0 12A6 6 0 0 1 6 0Zm-.705 8.737L9.63 4.403 8.392 3.166 5.295 6.263l-1.7-1.702L2.356 5.8l2.938 2.938Z"></path>
  1848. </svg>
  1849. `;
  1850.  
  1851. const textSpan = document.createElement('span');
  1852. textSpan.innerText = 'Saved';
  1853.  
  1854. savedDiv.appendChild(iconSpan);
  1855. savedDiv.appendChild(textSpan);
  1856.  
  1857. div.insertBefore(savedDiv, div.firstChild);
  1858. }
  1859.  
  1860. function gmcAddNewIssueButton(div) {
  1861. log(DEBUG, 'gmcAddNewIssueButton()');
  1862.  
  1863. const small = document.createElement('small');
  1864. small.classList.add('left-aligned');
  1865. small.setAttribute('title', 'Submit bug or feature request');
  1866.  
  1867. const link = document.createElement('a');
  1868. link.href = 'https://github.com/blakegearin/github-custom-global-navigation/issues';
  1869. link.innerText = 'submit bug or feature request';
  1870.  
  1871. small.appendChild(link);
  1872.  
  1873. div.insertBefore(small, div.firstChild);
  1874. }
  1875.  
  1876. function gmcOpened() {
  1877. log(DEBUG, 'gmcOpened()');
  1878.  
  1879. function updateCheckboxes() {
  1880. log(DEBUG, 'updateCheckboxes()');
  1881.  
  1882. const checkboxes = document.querySelectorAll('#gmc-frame input[type="checkbox"]');
  1883.  
  1884. if (checkboxes.length > 0) {
  1885. checkboxes.forEach(checkbox => {
  1886. checkbox.classList.add('gmc-checkbox');
  1887. });
  1888. } else {
  1889. setTimeout(updateCheckboxes, 100);
  1890. }
  1891. }
  1892.  
  1893. updateCheckboxes();
  1894.  
  1895. const configVars = document.querySelectorAll('.config_var');
  1896.  
  1897. configVars.forEach(configVar => {
  1898. const label = configVar.querySelector('.field_label');
  1899. const input = configVar.querySelector('input');
  1900.  
  1901. if (label && input && input.type === 'text') label.style.lineHeight = '33px';
  1902.  
  1903. const select = configVar.querySelector('select');
  1904.  
  1905. if (label && select) label.style.lineHeight = '33px';
  1906. });
  1907.  
  1908. modifyThenObserve(() => {
  1909. document.querySelector('#gmc-frame .reset_holder').remove();
  1910.  
  1911. const buttonHolderSelector = '#gmc-frame_buttons_holder';
  1912. const parentDiv = document.querySelector(buttonHolderSelector);
  1913.  
  1914. if (!parentDiv) {
  1915. logError(`Selector ${buttonHolderSelector} not found`);
  1916. return;
  1917. }
  1918.  
  1919. gmcAddSavedSpan(parentDiv);
  1920. gmcAddNewIssueButton(parentDiv);
  1921. });
  1922.  
  1923. document.querySelector('#gmc').classList.remove('hidden');
  1924. }
  1925.  
  1926. function gmcRefreshTab() {
  1927. location.reload();
  1928. }
  1929.  
  1930. function gmcRunScript() {
  1931. modifyThenObserve(() => {
  1932. document.querySelector(createId(SELECTORS.header.style))?.remove();
  1933. HEADER_STYLE.textContent = '';
  1934. });
  1935.  
  1936. applyCustomizations(true);
  1937. }
  1938.  
  1939. function updateLogLevel() {
  1940. CURRENT_LOG_LEVEL = {
  1941. 'silent': SILENT,
  1942. 'quiet': QUIET,
  1943. 'debug': DEBUG,
  1944. 'verbose': VERBOSE,
  1945. 'trace': TRACE,
  1946. }[GMC.get('log_level')];
  1947. }
  1948.  
  1949. function gmcSaved() {
  1950. log(DEBUG, 'gmcSaved()');
  1951.  
  1952. const gmcSaved = document.getElementById('gmc-saved');
  1953.  
  1954. gmcSaved.style.display = 'block';
  1955.  
  1956. setTimeout(
  1957. () => gmcSaved.style.display = 'none',
  1958. 2750,
  1959. );
  1960.  
  1961. updateLogLevel();
  1962.  
  1963. switch (GMC.get('on_save')) {
  1964. case 'refresh tab':
  1965. gmcRefreshTab();
  1966. break;
  1967. case 'refresh tab and close':
  1968. gmcRefreshTab();
  1969. GMC.close();
  1970. break;
  1971. case 'run script':
  1972. gmcRunScript();
  1973. break;
  1974. case 'run script and close':
  1975. gmcRunScript();
  1976. GMC.close();
  1977. break;
  1978. }
  1979. }
  1980.  
  1981. function gmcClosed() {
  1982. log(DEBUG, 'gmcClosed()');
  1983.  
  1984. switch (GMC.get('on_close')) {
  1985. case 'refresh tab':
  1986. gmcRefreshTab();
  1987. break;
  1988. case 'run script':
  1989. gmcRunScript();
  1990. break;
  1991. }
  1992.  
  1993. document.querySelector('#gmc').classList.add('hidden');
  1994. }
  1995.  
  1996. function gmcClearCustom() {
  1997. log(DEBUG, 'gmcClearCustom()');
  1998.  
  1999. const confirmed = confirm('Are you sure you want to clear your custom configuration? This is irreversible.');
  2000.  
  2001. if (confirmed) {
  2002. const currentType = GMC.get('type');
  2003. GMC.reset();
  2004. GMC.save();
  2005.  
  2006. GMC.set('type', currentType);
  2007. GMC.save();
  2008. }
  2009. }
  2010.  
  2011. function configsToGMC(config, path = []) {
  2012. log(DEBUG, 'configsToGMC()');
  2013.  
  2014. for (const key in config) {
  2015. if (typeof config[key] === 'object' && !Array.isArray(config[key])) {
  2016. configsToGMC(config[key], path.concat(key));
  2017. } else {
  2018. const fieldName = path.concat(key).join('_');
  2019. const fieldValue = config[key];
  2020.  
  2021. log(VERBOSE, 'fieldName', fieldName);
  2022. GMC.set(fieldName, fieldValue);
  2023. }
  2024. }
  2025. }
  2026.  
  2027. function gmcApplyCustomHappyMediumConfig() {
  2028. log(DEBUG, 'gmcApplyCustomHappyMediumConfig()');
  2029.  
  2030. const confirmed = confirm('Are you sure you want to overwrite your custom configuration with Happy Medium? This is irreversible.');
  2031.  
  2032. if (confirmed) {
  2033. configsToGMC(configs.happyMedium);
  2034. GMC.save();
  2035. }
  2036. }
  2037.  
  2038. function gmcApplyCustomOldSchoolConfig() {
  2039. log(DEBUG, 'gmcApplyCustomOldSchoolConfig()');
  2040.  
  2041. const confirmed = confirm('Are you sure you want to overwrite your custom configuration with Old School? This is irreversible.');
  2042.  
  2043. if (confirmed) {
  2044. configsToGMC(configs.oldSchool);
  2045. GMC.save();
  2046. }
  2047. }
  2048.  
  2049. function gmcBuildStyle() {
  2050. log(DEBUG, 'gmcBuildStyle()');
  2051.  
  2052. const gmcFrameStyle = document.createElement('style');
  2053. gmcFrameStyle.textContent += `
  2054. /* Modal */
  2055.  
  2056. #gmc
  2057. {
  2058. display: inline-flex !important;
  2059. justify-content: center !important;
  2060. align-items: center !important;
  2061. position: fixed !important;
  2062. top: 0 !important;
  2063. left: 0 !important;
  2064. width: 100vw !important;
  2065. height: 100vh !important;
  2066. z-index: 9999;
  2067. background: none !important;
  2068.  
  2069. pointer-events: none;
  2070. }
  2071.  
  2072. #gmc.hidden
  2073. {
  2074. display: none !important;
  2075. }
  2076.  
  2077. #gmc-frame
  2078. {
  2079. font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
  2080. text-align: left;
  2081.  
  2082. inset: initial !important;
  2083. border: none !important;
  2084. max-height: initial !important;
  2085. max-width: initial !important;
  2086. opacity: 1 !important;
  2087. position: static !important;
  2088. z-index: initial !important;
  2089.  
  2090. width: 85% !important;
  2091. height: 75% !important;
  2092. overflow-y: auto !important;
  2093.  
  2094. border: none !important;
  2095. border-radius: 0.375rem !important;
  2096.  
  2097. pointer-events: auto;
  2098. }
  2099.  
  2100. #gmc-frame_wrapper
  2101. {
  2102. display: flow-root !important;
  2103. padding: 2rem !important;
  2104. }
  2105.  
  2106. /* Sections */
  2107.  
  2108. #gmc-frame #gmc-frame_section_0
  2109. {
  2110. width: 100%;
  2111. border-radius: 6px;
  2112. display: table;
  2113. }
  2114.  
  2115. #gmc-frame #gmc-frame_section_1,
  2116. #gmc-frame #gmc-frame_section_2,
  2117. #gmc-frame #gmc-frame_section_3,
  2118. #gmc-frame #gmc-frame_section_4
  2119. {
  2120. margin-top: 2rem;
  2121. width: 49%;
  2122. box-sizing: border-box;
  2123. }
  2124.  
  2125. #gmc-frame #gmc-frame_section_1
  2126. {
  2127. border-radius: 6px;
  2128. float: left;
  2129. }
  2130.  
  2131. #gmc-frame #gmc-frame_section_2
  2132. {
  2133. border-radius: 6px;
  2134. float: right;
  2135. }
  2136.  
  2137. #gmc-frame #gmc-frame_section_3
  2138. {
  2139. width: 49%;
  2140. margin-top: 2rem;
  2141. box-sizing: border-box;
  2142. border-radius: 6px;
  2143. float: left;
  2144. }
  2145.  
  2146. #gmc-frame #gmc-frame_section_4
  2147. {
  2148. display: inline-grid;
  2149. width: 49%;
  2150. margin-top: 2rem;
  2151. box-sizing: border-box;
  2152. border-radius: 6px;
  2153. float: right
  2154. }
  2155.  
  2156. #gmc-frame #gmc-frame_section_3 .config_var:not(:last-child),
  2157. #gmc-frame #gmc-frame_section_4 .config_var:not(:last-child)
  2158. {
  2159. padding-bottom: 1rem;
  2160. }
  2161.  
  2162. /* Fields */
  2163.  
  2164. #gmc-frame .config_header
  2165. {
  2166. font-size: 2em;
  2167. font-weight: 400;
  2168. line-height: 1.25;
  2169.  
  2170. padding-bottom: 0.3em;
  2171. margin-bottom: 16px;
  2172. }
  2173.  
  2174. #gmc-frame #gmc-frame_type_var
  2175. {
  2176. display: inline-flex;
  2177. }
  2178.  
  2179. #gmc-frame .section_header
  2180. {
  2181. font-size: 1.5em;
  2182. font-weight: 600;
  2183. line-height: 1.25;
  2184.  
  2185. margin-bottom: 16px;
  2186. padding: 1rem 1.5rem;
  2187. }
  2188.  
  2189. #gmc-frame .section_desc,
  2190. #gmc-frame h3
  2191. {
  2192. background: none;
  2193. border: none;
  2194. font-size: 1.25em;
  2195.  
  2196. margin-bottom: 16px;
  2197. font-weight: 600;
  2198. line-height: 1.25;
  2199. text-align: left;
  2200. }
  2201.  
  2202. #gmc-frame .config_var
  2203. {
  2204. padding: 0rem 1.5rem;
  2205. margin-bottom: 1rem;
  2206. display: flex;
  2207. }
  2208.  
  2209. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2210. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2211. #gmc-frame .config_var[id*='logo_remove_var'],
  2212. #gmc-frame .config_var[id*='pageTitle_remove_var'],
  2213. #gmc-frame .config_var[id*='search_backgroundColor_var'],
  2214. #gmc-frame .config_var[id*='divider_remove_var'],
  2215. #gmc-frame .config_var[id*='create_remove_var'],
  2216. #gmc-frame .config_var[id*='issues_remove_var'],
  2217. #gmc-frame .config_var[id*='pullRequests_remove_var'],
  2218. #gmc-frame .config_var[id*='notifications_remove_var'],
  2219. #gmc-frame .config_var[id*='avatar_size_var'],
  2220. #gmc-frame .config_var[id*='globalBar_boxShadowColor_var'],
  2221. #gmc-frame .config_var[id*='localBar_backgroundColor_var'],
  2222. #gmc-frame .config_var[id*='sidebars_backdrop_color_var'],
  2223. #gmc-frame .config_var[id*='repositoryHeader_import_var'],
  2224. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2225. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2226. {
  2227. display: flow;
  2228. padding-top: 1rem;
  2229. }
  2230.  
  2231. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2232. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2233. {
  2234. display: flex;
  2235. }
  2236.  
  2237. #gmc-frame .field_label
  2238. {
  2239. font-weight: 600;
  2240. margin-right: 0.5rem;
  2241. }
  2242.  
  2243. #gmc-frame .field_label,
  2244. #gmc-frame .gmc-label
  2245. {
  2246. width: 15vw;
  2247. }
  2248.  
  2249. #gmc-frame .radio_label:not(:last-child)
  2250. {
  2251. margin-right: 4rem;
  2252. }
  2253.  
  2254. #gmc-frame .radio_label
  2255. {
  2256. line-height: 17px;
  2257. }
  2258.  
  2259. #gmc-frame .gmc-label
  2260. {
  2261. display: table-caption;
  2262. line-height: 17px;
  2263. }
  2264.  
  2265. #gmc-frame input[type="radio"]
  2266. {
  2267. appearance: none;
  2268. border-style: solid;
  2269. cursor: pointer;
  2270. height: 1rem;
  2271. place-content: center;
  2272. position: relative;
  2273. width: 1rem;
  2274. border-radius: 624rem;
  2275. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s;
  2276. margin-right: 0.5rem;
  2277. flex: none;
  2278. }
  2279.  
  2280. #gmc-frame input[type="checkbox"]
  2281. {
  2282. appearance: none;
  2283. border-style: solid;
  2284. border-width: 1px;
  2285. cursor: pointer;
  2286. place-content: center;
  2287. position: relative;
  2288. height: 17px;
  2289. width: 17px;
  2290. border-radius: 3px;
  2291. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s;
  2292. }
  2293.  
  2294. #gmc-frame #gmc-frame_field_type
  2295. {
  2296. display: flex;
  2297. }
  2298.  
  2299. #gmc-frame input[type="radio"]:checked
  2300. {
  2301. border-width: 0.25rem;
  2302. }
  2303.  
  2304. #gmc-frame input[type="radio"]:checked,
  2305. #gmc-frame .gmc-checkbox:checked
  2306. {
  2307. border-color: #2f81f7;
  2308. }
  2309.  
  2310. #gmc-frame .gmc-checkbox:checked
  2311. {
  2312. background-color: #2f81f7;
  2313. }
  2314.  
  2315. #gmc-frame .gmc-checkbox:checked::before
  2316. {
  2317. visibility: visible;
  2318. transition: visibility 0s linear 0s;
  2319. }
  2320.  
  2321. #gmc-frame .gmc-checkbox::before,
  2322. #gmc-frame .gmc-checkbox:indeterminate::before
  2323. {
  2324. animation: 80ms cubic-bezier(0.65, 0, 0.35, 1) 80ms 1 normal forwards running checkmarkIn;
  2325. }
  2326.  
  2327. #gmc-frame .gmc-checkbox::before
  2328. {
  2329. width: 1rem;
  2330. height: 1rem;
  2331. visibility: hidden;
  2332. content: "";
  2333. background-color: #FFFFFF;
  2334. clip-path: inset(1rem 0 0 0);
  2335. -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTEuNzgwMyAwLjIxOTYyNUMxMS45MjEgMC4zNjA0MjcgMTIgMC41NTEzMDUgMTIgMC43NTAzMTNDMTIgMC45NDkzMjEgMTEuOTIxIDEuMTQwMTkgMTEuNzgwMyAxLjI4MUw0LjUxODYgOC41NDA0MkM0LjM3Nzc1IDguNjgxIDQuMTg2ODIgOC43NiAzLjk4Nzc0IDguNzZDMy43ODg2NyA4Ljc2IDMuNTk3NzMgOC42ODEgMy40NTY4OSA4LjU0MDQyTDAuMjAxNjIyIDUuMjg2MkMwLjA2ODkyNzcgNS4xNDM4MyAtMC4wMDMzMDkwNSA0Ljk1NTU1IDAuMDAwMTE2NDkzIDQuNzYwOThDMC4wMDM1NTIwNSA0LjU2NjQzIDAuMDgyMzg5NCA0LjM4MDgxIDAuMjIwMDMyIDQuMjQzMjFDMC4zNTc2NjUgNC4xMDU2MiAwLjU0MzM1NSA0LjAyNjgxIDAuNzM3OTcgNC4wMjMzOEMwLjkzMjU4NCA0LjAxOTk0IDEuMTIwOTMgNC4wOTIxNyAxLjI2MzM0IDQuMjI0ODJMMy45ODc3NCA2Ljk0ODM1TDEwLjcxODYgMC4yMTk2MjVDMTAuODU5NSAwLjA3ODk5MjMgMTEuMDUwNCAwIDExLjI0OTUgMEMxMS40NDg1IDAgMTEuNjM5NSAwLjA3ODk5MjMgMTEuNzgwMyAwLjIxOTYyNVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=");
  2336. -webkit-mask-size: 75%;
  2337. -webkit-mask-repeat: no-repeat;
  2338. -webkit-mask-position: center center;
  2339. display: block;
  2340. }
  2341.  
  2342. #gmc-frame .gmc-checkbox
  2343. {
  2344. appearance: none;
  2345. border-style: solid;
  2346. border-width: 1px;
  2347. cursor: pointer;
  2348.  
  2349. height: var(--base-size-16,16px);
  2350. margin: 0.125rem 0px 0px;
  2351. place-content: center;
  2352. position: relative;
  2353. width: var(--base-size-16,16px);
  2354. border-radius: 3px;
  2355. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s;
  2356. }
  2357.  
  2358. #gmc-frame input
  2359. {
  2360. color: fieldtext;
  2361. letter-spacing: normal;
  2362. word-spacing: normal;
  2363. text-transform: none;
  2364. text-indent: 0px;
  2365. text-shadow: none;
  2366. display: inline-block;
  2367. text-align: start;
  2368. appearance: auto;
  2369. -webkit-rtl-ordering: logical;
  2370. }
  2371.  
  2372. #gmc-frame .gmc-checkbox:checked
  2373. {
  2374. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms;
  2375. }
  2376.  
  2377. #gmc-frame input[type="text"],
  2378. #gmc-frame textarea,
  2379. #gmc-frame select
  2380. {
  2381. padding: 5px 12px;
  2382. border-radius: 6px;
  2383. }
  2384.  
  2385. #gmc-frame input[type="text"]:focus,
  2386. #gmc-frame textarea:focus,
  2387. #gmc-frame select:focus
  2388. {
  2389. border-color: #2f81f7;
  2390. outline: 1px solid #2f81f7;
  2391. }
  2392.  
  2393. #gmc-frame svg
  2394. {
  2395. height: 17px;
  2396. width: 17px;
  2397. margin-left: 0.5rem;
  2398. }
  2399.  
  2400. #gmc small
  2401. {
  2402. font-size: x-small;
  2403. font-weight: 600;
  2404. margin-left: 3px;
  2405. }
  2406.  
  2407. /* Button bar */
  2408.  
  2409. #gmc-frame #gmc-frame_buttons_holder
  2410. {
  2411. position: fixed;
  2412. width: 85%;
  2413. text-align: right;
  2414.  
  2415. left: 50%;
  2416. bottom: 2%;
  2417. transform: translate(-50%, 0%);
  2418. padding: 1rem;
  2419.  
  2420. border-radius: 0.375rem;
  2421.  
  2422. display: flex;
  2423. align-items: center;
  2424. }
  2425.  
  2426. #gmc-frame #gmc-frame_buttons_holder .left-aligned
  2427. {
  2428. order: 1;
  2429. margin-right: auto;
  2430. }
  2431.  
  2432. #gmc-frame #gmc-frame_buttons_holder > *
  2433. {
  2434. order: 2;
  2435. }
  2436.  
  2437. #gmc-frame .saveclose_buttons
  2438. {
  2439. margin-left: 0.5rem;
  2440. }
  2441.  
  2442. #gmc-frame [type=button],
  2443. #gmc-frame .saveclose_buttons
  2444. {
  2445. position: relative;
  2446. display: inline-block;
  2447. padding: 5px 16px;
  2448. font-size: 14px;
  2449. font-weight: 500;
  2450. line-height: 20px;
  2451. white-space: nowrap;
  2452. vertical-align: middle;
  2453. cursor: pointer;
  2454. -webkit-user-select: none;
  2455. user-select: none;
  2456. border: 1px solid;
  2457. border-radius: 6px;
  2458. -webkit-appearance: none;
  2459. appearance: none;
  2460.  
  2461. font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
  2462. }
  2463.  
  2464. @keyframes fadeOut
  2465. {
  2466. from {
  2467. opacity: 1;
  2468. }
  2469. to {
  2470. opacity: 0;
  2471. }
  2472. }
  2473.  
  2474. #gmc-saved
  2475. {
  2476. display: none;
  2477. margin-right: 10px;
  2478. animation: fadeOut 0.75s ease 2s forwards;
  2479. }
  2480. `;
  2481.  
  2482. if (THEME === 'light') {
  2483. gmcFrameStyle.textContent += `
  2484. #gmc-frame
  2485. {
  2486. background-color: #F6F8FA;
  2487. color: #1F2328;
  2488. box-shadow: 0 0 0 1px #D0D7DE, 0 16px 32px rgba(1,4,9,0.2) !important;
  2489. }
  2490.  
  2491. #gmc-frame .section_header_holder
  2492. {
  2493. background-color: #FFFFFF;
  2494. border: 1px solid #D0D7DE;
  2495. }
  2496.  
  2497. #gmc-frame_buttons_holder
  2498. {
  2499. background-color: #FFFFFF;
  2500. box-shadow: 0 0 0 1px #D0D7DE, 0 16px 32px rgba(1,4,9,0.2) !important;
  2501. }
  2502.  
  2503. #gmc-frame input[type="text"],
  2504. #gmc-frame textarea,
  2505. #gmc-frame select
  2506. {
  2507. border: 1px solid #D0D7DE;
  2508. }
  2509.  
  2510. #gmc-frame select
  2511. {
  2512. background-color: #F6F8FA;
  2513. }
  2514.  
  2515. #gmc-frame select:hover
  2516. {
  2517. background-color: #F3F4F6;
  2518. border-color: #1F232826;
  2519. }
  2520.  
  2521. #gmc-frame input[type="text"],
  2522. #gmc-frame textarea
  2523. {
  2524. background-color: #F6F8FA;
  2525. color: #1F2328;
  2526. }
  2527.  
  2528. #gmc-frame input[type="text"]:focus,
  2529. #gmc-frame textarea:focus
  2530. {
  2531. background-color: #FFFFFF;
  2532. }
  2533.  
  2534. #gmc-frame [type=button],
  2535. #gmc-frame .saveclose_buttons
  2536. {
  2537. background-color: #f6f8fa;
  2538. border-color: #1f232826;
  2539. box-shadow: 0 1px 0 rgba(31,35,40,0.04), inset 0 1px 0 rgba(255,255,255,0.25);
  2540. color: #24292f;
  2541. }
  2542.  
  2543. #gmc-frame [type=button]:hover,
  2544. #gmc-frame .saveclose_buttons:hover
  2545. {
  2546. background-color: #f3f4f6;
  2547. border-color: #1f232826;
  2548. }
  2549.  
  2550. #gmc-frame .gmc-checkbox
  2551. {
  2552. border-color: #6E7781;
  2553. }
  2554.  
  2555. #gmc-frame input[type="radio"]
  2556. {
  2557. color: #6E7781;
  2558. }
  2559.  
  2560. #gmc-frame svg
  2561. {
  2562. fill: #000000;
  2563. }
  2564.  
  2565. #gmc-frame .section_header
  2566. {
  2567. border-bottom: 1px solid #D0D7DE;
  2568. }
  2569.  
  2570. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2571. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2572. #gmc-frame .config_var[id*='logo_remove_var'],
  2573. #gmc-frame .config_var[id*='pageTitle_remove_var'],
  2574. #gmc-frame .config_var[id*='search_backgroundColor_var'],
  2575. #gmc-frame .config_var[id*='divider_remove_var'],
  2576. #gmc-frame .config_var[id*='create_remove_var'],
  2577. #gmc-frame .config_var[id*='issues_remove_var'],
  2578. #gmc-frame .config_var[id*='pullRequests_remove_var'],
  2579. #gmc-frame .config_var[id*='notifications_remove_var'],
  2580. #gmc-frame .config_var[id*='avatar_size_var'],
  2581. #gmc-frame .config_var[id*='globalBar_boxShadowColor_var'],
  2582. #gmc-frame .config_var[id*='localBar_backgroundColor_var'],
  2583. #gmc-frame .config_var[id*='sidebars_backdrop_color_var'],
  2584. #gmc-frame .config_var[id*='repositoryHeader_import_var'],
  2585. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2586. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2587. {
  2588. border-top: 1px solid #D0D7DE;
  2589. }
  2590.  
  2591. #gmc-frame #gmc-frame_section_3 .config_var:not(:last-child),
  2592. #gmc-frame #gmc-frame_section_4 .config_var:not(:last-child)
  2593. {
  2594. border-bottom: 1px solid #D0D7DE;
  2595. }
  2596.  
  2597. #gmc-frame #gmc-frame_saveBtn
  2598. {
  2599. background-color: #1F883D;
  2600. border-color: rgba(31, 35, 40, 0.15);
  2601. box-shadow: rgba(31, 35, 40, 0.1) 0px 1px 0px;
  2602. color: #FFFFFF;
  2603. }
  2604.  
  2605. #gmc-frame #gmc-frame_saveBtn:hover
  2606. {
  2607. background-color: rgb(26, 127, 55);
  2608. }
  2609.  
  2610. #gmc-frame #gmc-frame_section_4
  2611. {
  2612. border: 1px solid #FF818266;
  2613. }
  2614.  
  2615. #gmc-frame #gmc-frame_section_4 input
  2616. {
  2617. background-color: #F6F8FA;
  2618. border-color: #1F232826;
  2619. box-shadow: 0 1px 0 rgba(31,35,40,0.04), inset 0 1px 0 rgba(255,255,255,0.25);
  2620. color: #CF222E;
  2621. }
  2622.  
  2623. #gmc-frame #gmc-frame_section_4 input:hover
  2624. {
  2625. background-color: #A40E26;
  2626. border-color: #1F232826;
  2627. box-shadow: 0 1px 0 rgba(31,35,40,0.04);
  2628. color: #ffffff;
  2629. }
  2630.  
  2631. #gmc-saved
  2632. {
  2633. color: #1a7f37;
  2634. }
  2635.  
  2636. #gmc-saved svg path
  2637. {
  2638. fill: #1a7f37;
  2639. }
  2640. `;
  2641. } else if (THEME === 'dark') {
  2642. gmcFrameStyle.textContent += `
  2643. #gmc-frame
  2644. {
  2645. background-color: #161B22;
  2646. color: #E6EDF3;
  2647. box-shadow: 0 0 0 1px #30363D, 0 16px 32px #010409 !important;
  2648. }
  2649.  
  2650. #gmc-frame .section_header_holder
  2651. {
  2652. background-color: #0D1117;
  2653. border: 1px solid #30363D;
  2654. }
  2655.  
  2656. #gmc-frame_buttons_holder
  2657. {
  2658. background-color: #161B22;
  2659. box-shadow: 0 0 0 1px #30363D, 0 16px 32px #010409 !important;
  2660. }
  2661.  
  2662. #gmc-frame input[type="text"],
  2663. #gmc-frame textarea,
  2664. #gmc-frame select
  2665. {
  2666. border: 1px solid #5B626C;
  2667. }
  2668.  
  2669. #gmc-frame input[type="text"],
  2670. #gmc-frame textarea
  2671. {
  2672. background-color: #010409;
  2673. color: #FFFFFF;
  2674. }
  2675.  
  2676. #gmc-frame [type=button]:hover,
  2677. #gmc-frame .saveclose_buttons:hover
  2678. {
  2679. background-color: #30363d;
  2680. border-color: #8b949e;
  2681. }
  2682.  
  2683. #gmc-frame .gmc-checkbox
  2684. {
  2685. border-color: #6E7681;
  2686. }
  2687.  
  2688. #gmc-frame input[type="radio"]
  2689. {
  2690. color: #6D7681;
  2691. }
  2692.  
  2693. #gmc-frame input[type="text"]:focus,
  2694. textarea:focus
  2695. {
  2696. background-color: #0D1117;
  2697. }
  2698.  
  2699. #gmc-frame [type=button],
  2700. #gmc-frame .saveclose_buttons
  2701. {
  2702. color: #c9d1d9;
  2703. background-color: #21262d;
  2704. border-color: #f0f6fc1a;
  2705. }
  2706.  
  2707. #gmc-frame svg
  2708. {
  2709. fill: #E6EDF3;
  2710. }
  2711.  
  2712. #gmc-frame .section_header
  2713. {
  2714. border-bottom: 1px solid #30363D;
  2715. }
  2716.  
  2717. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2718. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2719. #gmc-frame .config_var[id*='logo_remove_var'],
  2720. #gmc-frame .config_var[id*='pageTitle_remove_var'],
  2721. #gmc-frame .config_var[id*='search_backgroundColor_var'],
  2722. #gmc-frame .config_var[id*='divider_remove_var'],
  2723. #gmc-frame .config_var[id*='create_remove_var'],
  2724. #gmc-frame .config_var[id*='issues_remove_var'],
  2725. #gmc-frame .config_var[id*='pullRequests_remove_var'],
  2726. #gmc-frame .config_var[id*='notifications_remove_var'],
  2727. #gmc-frame .config_var[id*='avatar_size_var'],
  2728. #gmc-frame .config_var[id*='globalBar_boxShadowColor_var'],
  2729. #gmc-frame .config_var[id*='localBar_backgroundColor_var'],
  2730. #gmc-frame .config_var[id*='sidebars_backdrop_color_var'],
  2731. #gmc-frame .config_var[id*='repositoryHeader_import_var'],
  2732. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2733. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2734. {
  2735. border-top: 1px solid #30363D;
  2736. }
  2737.  
  2738. #gmc-frame #gmc-frame_section_3 .config_var:not(:last-child),
  2739. #gmc-frame #gmc-frame_section_4 .config_var:not(:last-child)
  2740. {
  2741. padding-bottom: 1rem;
  2742. border-bottom: 1px solid #30363D;
  2743. }
  2744.  
  2745. #gmc-frame #gmc-frame_saveBtn
  2746. {
  2747. background-color: #238636;
  2748. border-color: #F0F6FC1A;
  2749. box-shadow: 0 0 transparent;
  2750. color: #FFFFFF;
  2751. }
  2752.  
  2753. #gmc-frame #gmc-frame_saveBtn:hover
  2754. {
  2755. background-color: #2EA043;
  2756. border-color: #F0F6FC1A;
  2757. }
  2758.  
  2759. #gmc-frame #gmc-frame_section_4
  2760. {
  2761. border: 1px solid #f8514966;
  2762. }
  2763.  
  2764. #gmc-frame #gmc-frame_section_4 input
  2765. {
  2766. background-color: #21262D;
  2767. border-color: #F0F6FC1A;
  2768. }
  2769.  
  2770. #gmc-frame #gmc-frame_section_4 input
  2771. {
  2772. color: #F85149;
  2773. }
  2774.  
  2775. #gmc-frame #gmc-frame_section_4 input:hover
  2776. {
  2777. background-color: #DA3633;
  2778. border-color: #F85149;
  2779. color: #FFFFFF;
  2780. }
  2781.  
  2782. #gmc-saved
  2783. {
  2784. color: #3FB950;
  2785. }
  2786.  
  2787. #gmc-saved svg path
  2788. {
  2789. fill: #3FB950;
  2790. }
  2791. `;
  2792. }
  2793.  
  2794. document.head.appendChild(gmcFrameStyle);
  2795. }
  2796.  
  2797. function gmcBuildFrame() {
  2798. log(DEBUG, 'gmcBuildFrame()');
  2799.  
  2800. const body = document.querySelector('body');
  2801. const gmcDiv = document.createElement('div');
  2802.  
  2803. gmcDiv.setAttribute('id', 'gmc');
  2804. gmcDiv.classList.add('hidden');
  2805.  
  2806. body.appendChild(gmcDiv);
  2807.  
  2808. const gmcFrameDiv = document.createElement('div');
  2809. gmcFrameDiv.id = 'gmc-frame';
  2810.  
  2811. gmcDiv.appendChild(gmcFrameDiv);
  2812.  
  2813. gmcBuildStyle();
  2814.  
  2815. return gmcFrameDiv;
  2816. }
  2817.  
  2818. function applyCustomizations(refresh = false) {
  2819. log(DEBUG, 'applyCustomizations()');
  2820.  
  2821. HEADER = document.querySelector(SELECTORS.header.self);
  2822.  
  2823. if (!HEADER) return 'continue';
  2824.  
  2825. const featurePreviewButton = document.querySelector(SELECTORS.avatar.button);
  2826.  
  2827. if (!featurePreviewButton) {
  2828. logError(`Selector ${SELECTORS.avatar.button} not found`);
  2829. return 'break';
  2830. }
  2831.  
  2832. featurePreviewButton.addEventListener('click', waitForFeaturePreviewButton);
  2833.  
  2834. const configName = {
  2835. 'Off': 'off',
  2836. 'Happy Medium': 'happyMedium',
  2837. 'Old School': 'oldSchool',
  2838. 'Custom': 'custom',
  2839. }[GMC.get('type')];
  2840.  
  2841. if (configName === 'off') return 'break';
  2842.  
  2843. if (configName === 'custom') configs.custom = generateCustomConfig();
  2844.  
  2845. CONFIG = configs[configName][THEME];
  2846.  
  2847. log(VERBOSE, 'CONFIG', CONFIG);
  2848.  
  2849. const headerSuccessFlag = 'customizedHeader';
  2850.  
  2851. if (!document.getElementById(headerSuccessFlag) || refresh) {
  2852. updateSelectors();
  2853.  
  2854. if (configName === 'oldSchool') {
  2855. HEADER_STYLE.textContent += `
  2856. @media (max-width: 767.98px)
  2857. {
  2858. action-menu
  2859. {
  2860. display: none !important;
  2861. }
  2862. }
  2863. `;
  2864. }
  2865.  
  2866. HEADER_UPDATES_COUNT++;
  2867. updateHeader();
  2868.  
  2869. HEADER.setAttribute('id', headerSuccessFlag);
  2870.  
  2871. log(QUIET, 'Complete');
  2872.  
  2873. return 'break';
  2874. } else {
  2875. if (CONFIG.avatar.dropdownIcon) insertAvatarDropdown();
  2876. if (CONFIG.avatar.canCloseSidebar) updateAvatarButton();
  2877.  
  2878. if (CONFIG.repositoryHeader.import) {
  2879. // When starting in a repository tab like Issues, the proper repository header
  2880. // (including Unwatch, Star, and Fork) is not present per GitHub's design.
  2881. // If page title is removed, the page will be missing any location context in the header.
  2882. // To improve this experience, a temporary repository header is created with the
  2883. // page title or breadcrumbs.
  2884. // The proper repository header replaces the temporary one when navigating to the Code tab.
  2885. if (
  2886. !document.querySelector(SELECTORS.repositoryHeader.id)?.hidden &&
  2887. (
  2888. document.querySelector(createId(TEMP_REPOSITORY_HEADER_FLAG)) ||
  2889. !document.querySelector(`.${REPOSITORY_HEADER_SUCCESS_FLAG}`)
  2890. )
  2891. ) {
  2892. const updated = importRepositoryHeader();
  2893.  
  2894. if (updated) {
  2895. log(QUIET, 'Repository header updated');
  2896. } else {
  2897. IDLE_MUTATION_COUNT++;
  2898. }
  2899.  
  2900. return 'break';
  2901. }
  2902. }
  2903. }
  2904.  
  2905. if (CONFIG.avatar.dropdownIcon) insertAvatarDropdown();
  2906. }
  2907.  
  2908. function startObserving() {
  2909. log(DEBUG, 'startObserving()');
  2910.  
  2911. OBSERVER.observe(
  2912. document.body,
  2913. {
  2914. childList: true,
  2915. subtree: true,
  2916. },
  2917. );
  2918. }
  2919.  
  2920. function modifyThenObserve(callback) {
  2921. log(DEBUG, 'modifyThenObserve()');
  2922. OBSERVER.disconnect();
  2923.  
  2924. callback();
  2925.  
  2926. startObserving();
  2927. }
  2928.  
  2929. function observeAndModify(mutationsList) {
  2930. log(VERBOSE, 'observeAndModify()');
  2931.  
  2932. if (IDLE_MUTATION_COUNT > MAX_IDLE_MUTATIONS) {
  2933. // This is a failsafe to prevent infinite loops
  2934. logError('MAX_IDLE_MUTATIONS exceeded');
  2935. OBSERVER.disconnect();
  2936.  
  2937. return;
  2938. } else if (HEADER_UPDATES_COUNT >= MAX_HEADER_UPDATES) {
  2939. // This is a failsafe to prevent infinite loops
  2940. logError('MAX_HEADER_UPDATES exceeded');
  2941. OBSERVER.disconnect();
  2942.  
  2943. return;
  2944. }
  2945.  
  2946. for (const mutation of mutationsList) {
  2947. // Use header id to determine if updates have already been applied
  2948. if (mutation.type !== 'childList') return;
  2949.  
  2950. log(TRACE, 'mutation', mutation);
  2951.  
  2952. const outcome = applyCustomizations();
  2953.  
  2954. if (outcome === 'continue') continue;
  2955. if (outcome === 'break') break;
  2956. }
  2957. }
  2958.  
  2959. const UNICODE_NON_BREAKING_SPACE = '\u00A0';
  2960. const REPOSITORY_HEADER_SUCCESS_FLAG = 'permCustomizedRepositoryHeader';
  2961. const TEMP_REPOSITORY_HEADER_FLAG = 'tempCustomizedRepositoryHeader';
  2962. const REPOSITORY_HEADER_CLASS = 'customizedRepositoryHeader';
  2963. const MAX_IDLE_MUTATIONS = 1000;
  2964. const MAX_HEADER_UPDATES = 100;
  2965.  
  2966. let CONFIG;
  2967. let HEADER;
  2968. let HEADER_STYLE = document.createElement('style');
  2969.  
  2970. let THEME = 'light';
  2971. let IDLE_MUTATION_COUNT = 0;
  2972. let HEADER_UPDATES_COUNT = 0;
  2973. let SELECTORS = {
  2974. header: {
  2975. self: 'header.AppHeader',
  2976. actionsDiv: '.AppHeader-actions',
  2977. globalBar: '.AppHeader-globalBar',
  2978. localBar: {
  2979. topDiv: '.AppHeader-localBar',
  2980. underlineNavActions: '.UnderlineNav-actions'
  2981. },
  2982. leftAligned: '.AppHeader-globalBar-start',
  2983. rightAligned: '.AppHeader-globalBar-end',
  2984. style: 'customHeaderStyle',
  2985. },
  2986. logo: {
  2987. topDiv: '.AppHeader-globalBar-start .AppHeader-logo',
  2988. svg: '.AppHeader-logo svg',
  2989. },
  2990. hamburgerButton: '.AppHeader-globalBar-start deferred-side-panel',
  2991. pageTitle: {
  2992. id: 'custom-page-title',
  2993. topDiv: '.AppHeader-context',
  2994. links: '.AppHeader-context a',
  2995. separator: '.AppHeader-context-item-separator',
  2996. },
  2997. search: {
  2998. id: 'search-div',
  2999. topDiv: '.AppHeader-search',
  3000. input: '.search-input',
  3001. button: '[data-target="qbsearch-input.inputButton"]',
  3002. magnifyingGlassIcon: '.AppHeader-search-control label',
  3003. commandPalette: '#AppHeader-commandPalette-button',
  3004. placeholderSpan: '#qb-input-query',
  3005. placeholderDiv: '.AppHeader-search-control .overflow-hidden',
  3006. modal: '[data-target="qbsearch-input.queryBuilderContainer"]',
  3007. },
  3008. create: {
  3009. id: 'create-div',
  3010. topDiv: 'action-menu',
  3011. button: '#global-create-menu-button',
  3012. plusIcon: '#global-create-menu-button .Button-visual.Button-leadingVisual',
  3013. dropdownIcon: '#global-create-menu-button .Button-label',
  3014. textContent: 'create-text-content-span',
  3015. },
  3016. issues: {
  3017. id: 'issues-div',
  3018. topDiv: '#issues-div',
  3019. textContent: 'issues-text-content-span',
  3020. },
  3021. pullRequests: {
  3022. id: 'pullRequests-div',
  3023. topDiv: '#pullRequests-div',
  3024. textContent: 'pullRequests-text-content-span',
  3025. },
  3026. notifications: {
  3027. id: 'custom-notifications',
  3028. indicator: 'notification-indicator',
  3029. dot: '.AppHeader-button.AppHeader-button--hasIndicator::before',
  3030. textContent: 'textContent-text-content-spa'
  3031. },
  3032. avatar: {
  3033. topDiv: '.AppHeader-user',
  3034. button: '.AppHeader-user button',
  3035. img: '.AppHeader-user button img.avatar',
  3036. svg: 'avatar-dropdown',
  3037. },
  3038. repositoryHeader: {
  3039. id: '#repository-container-header',
  3040. ownerImg: `.${REPOSITORY_HEADER_CLASS} img`,
  3041. name: `.${REPOSITORY_HEADER_CLASS} strong`,
  3042. links: `.${REPOSITORY_HEADER_CLASS} nav[role="navigation"] a`,
  3043. details: '#repository-details-container',
  3044. bottomBorder: `.${REPOSITORY_HEADER_CLASS} .border-bottom.mx-xl-5`,
  3045. },
  3046. sidebars: {
  3047. backdrop: '.Overlay-backdrop--side',
  3048. right: {
  3049. backdrop: '.AppHeader-user .Overlay-backdrop--side',
  3050. topDiv: '.AppHeader-user .Overlay-backdrop--placement-right',
  3051. modalDialog: '.AppHeader-user modal-dialog',
  3052. closeButton: '.AppHeader-user modal-dialog .Overlay-closeButton.close-button',
  3053. navParentDiv: '.AppHeader-user modal-dialog div.Overlay-body > div',
  3054. nav: '.AppHeader-user modal-dialog nav',
  3055. },
  3056. }
  3057. };
  3058.  
  3059. HEADER_STYLE.id = SELECTORS.header.style;
  3060.  
  3061. setTheme();
  3062.  
  3063. const oldSchoolColor = '#F0F6FC';
  3064. const oldSchoolHoverColor = '#FFFFFFB3';
  3065. const oldSchoolHoverBackgroundColor = 'transparent';
  3066. let configs = {
  3067. happyMedium: {
  3068. light: {
  3069. backgroundColor: '',
  3070. hamburgerButton: {
  3071. remove: false,
  3072. },
  3073. logo: {
  3074. remove: false,
  3075. color: '',
  3076. customSvg: '',
  3077. },
  3078. pageTitle: {
  3079. remove: false,
  3080. color: '',
  3081. hover: {
  3082. backgroundColor: '',
  3083. color: '',
  3084. },
  3085. },
  3086. search: {
  3087. backgroundColor: '',
  3088. borderColor: '',
  3089. boxShadow: '',
  3090. alignLeft: false,
  3091. width: 'max',
  3092. margin: {
  3093. left: '',
  3094. right: '',
  3095. },
  3096. magnifyingGlassIcon: {
  3097. remove: false,
  3098. },
  3099. placeholder: {
  3100. text: '',
  3101. color: '',
  3102. },
  3103. rightButton: 'command palette',
  3104. modal: {
  3105. width: '',
  3106. },
  3107. },
  3108. divider: {
  3109. remove: true,
  3110. },
  3111. flipCreateInbox: false,
  3112. create: {
  3113. remove: false,
  3114. border: true,
  3115. tooltip: false,
  3116. boxShadow: '',
  3117. hoverBackgroundColor: '',
  3118. plusIcon: {
  3119. remove: false,
  3120. color: '',
  3121. marginRight: '0.25rem',
  3122. hover: {
  3123. color: '',
  3124. }
  3125. },
  3126. text: {
  3127. content: 'Create',
  3128. color: '',
  3129. },
  3130. dropdownIcon: {
  3131. remove: false,
  3132. color: '',
  3133. hover: {
  3134. color: '',
  3135. },
  3136. },
  3137. },
  3138. flipIssuesPullRequests: true,
  3139. issues: {
  3140. remove: false,
  3141. border: true,
  3142. tooltip: false,
  3143. alignLeft: false,
  3144. boxShadow: '',
  3145. icon: {
  3146. remove: false,
  3147. color: '',
  3148. },
  3149. text: {
  3150. content: 'Issues',
  3151. color: '',
  3152. },
  3153. hover: {
  3154. backgroundColor: '',
  3155. color: '',
  3156. },
  3157. },
  3158. pullRequests: {
  3159. remove: false,
  3160. border: true,
  3161. tooltip: false,
  3162. alignLeft: false,
  3163. boxShadow: '',
  3164. icon: {
  3165. remove: false,
  3166. color: '',
  3167. },
  3168. text: {
  3169. content: 'Pull requests',
  3170. color: '',
  3171. },
  3172. hover: {
  3173. backgroundColor: '',
  3174. color: '',
  3175. },
  3176. },
  3177. notifications: {
  3178. remove: false,
  3179. border: true,
  3180. tooltip: false,
  3181. boxShadow: '',
  3182. hoverBackgroundColor: '',
  3183. icon: {
  3184. symbol: 'bell', // Accepts 'inbox', 'bell', or ''
  3185. color: '',
  3186. hover: {
  3187. color: '',
  3188. }
  3189. },
  3190. text: {
  3191. content: 'Inbox',
  3192. color: '',
  3193. },
  3194. dot: {
  3195. remove: false,
  3196. boxShadowColor: '',
  3197. color: '',
  3198. displayOverIcon: true,
  3199. },
  3200. },
  3201. avatar: {
  3202. size: '',
  3203. dropdownIcon: false,
  3204. canCloseSidebar: true,
  3205. },
  3206. globalBar: {
  3207. boxShadowColor: '',
  3208. leftAligned: {
  3209. gap: '',
  3210. },
  3211. rightAligned: {
  3212. gap: '',
  3213. },
  3214. },
  3215. localBar: {
  3216. backgroundColor: '#F6F8FA',
  3217. alignCenter: false,
  3218. boxShadow: {
  3219. consistentColor: true,
  3220. },
  3221. links: {
  3222. color: '',
  3223. },
  3224. },
  3225. sidebars: {
  3226. backdrop: {
  3227. color: 'transparent',
  3228. pointerEvents: 'none',
  3229. },
  3230. right: {
  3231. preload: true,
  3232. floatUnderneath: true,
  3233. maxHeight: '',
  3234. margin: '',
  3235. },
  3236. },
  3237. repositoryHeader: {
  3238. import: true,
  3239. alignCenter: false,
  3240. removePageTitle: true,
  3241. backgroundColor: '#F6F8FA',
  3242. avatar: {
  3243. remove: false,
  3244. customSvg: '',
  3245. },
  3246. link: {
  3247. color: '',
  3248. hover: {
  3249. backgroundColor: 'transparent',
  3250. color: 'var(--color-accent-fg)',
  3251. textDecoration: 'underline',
  3252. },
  3253. },
  3254. },
  3255. },
  3256. dark: {
  3257. backgroundColor: '',
  3258. hamburgerButton: {
  3259. remove: false,
  3260. },
  3261. logo: {
  3262. remove: false,
  3263. color: '',
  3264. customSvg: '',
  3265. },
  3266. pageTitle: {
  3267. remove: false,
  3268. color: '',
  3269. hover: {
  3270. backgroundColor: '',
  3271. color: '',
  3272. },
  3273. },
  3274. search: {
  3275. backgroundColor: '',
  3276. borderColor: '',
  3277. boxShadow: '',
  3278. alignLeft: false,
  3279. width: 'max',
  3280. margin: {
  3281. left: '',
  3282. right: '',
  3283. },
  3284. magnifyingGlassIcon: {
  3285. remove: false,
  3286. },
  3287. placeholder: {
  3288. text: '',
  3289. color: '',
  3290. },
  3291. rightButton: 'command palette',
  3292. modal: {
  3293. width: '',
  3294. },
  3295. },
  3296. divider: {
  3297. remove: true,
  3298. },
  3299. flipCreateInbox: false,
  3300. create: {
  3301. remove: false,
  3302. border: true,
  3303. tooltip: false,
  3304. boxShadow: '',
  3305. hoverBackgroundColor: '',
  3306. plusIcon: {
  3307. remove: false,
  3308. color: '',
  3309. marginRight: '0.25rem',
  3310. hover: {
  3311. color: '',
  3312. }
  3313. },
  3314. text: {
  3315. content: 'Create',
  3316. color: '',
  3317. },
  3318. dropdownIcon: {
  3319. remove: false,
  3320. color: '',
  3321. hover: {
  3322. color: '',
  3323. },
  3324. },
  3325. },
  3326. flipIssuesPullRequests: true,
  3327. issues: {
  3328. remove: false,
  3329. border: true,
  3330. tooltip: false,
  3331. alignLeft: false,
  3332. boxShadow: '',
  3333. icon: {
  3334. remove: false,
  3335. color: '',
  3336. },
  3337. text: {
  3338. content: 'Issues',
  3339. color: '',
  3340. },
  3341. hover: {
  3342. backgroundColor: '',
  3343. color: '',
  3344. },
  3345. },
  3346. pullRequests: {
  3347. remove: false,
  3348. border: true,
  3349. tooltip: false,
  3350. alignLeft: false,
  3351. boxShadow: '',
  3352. icon: {
  3353. remove: false,
  3354. color: '',
  3355. },
  3356. text: {
  3357. content: 'Pull requests',
  3358. color: '',
  3359. },
  3360. hover: {
  3361. backgroundColor: '',
  3362. color: '',
  3363. },
  3364. },
  3365. notifications: {
  3366. remove: false,
  3367. border: true,
  3368. tooltip: false,
  3369. boxShadow: '',
  3370. hoverBackgroundColor: '',
  3371. icon: {
  3372. symbol: 'bell', // Accepts 'inbox', 'bell', or ''
  3373. color: '',
  3374. hover: {
  3375. color: '',
  3376. }
  3377. },
  3378. text: {
  3379. content: 'Inbox',
  3380. color: '',
  3381. },
  3382. dot: {
  3383. remove: false,
  3384. boxShadowColor: '',
  3385. color: '',
  3386. displayOverIcon: true,
  3387. },
  3388. },
  3389. avatar: {
  3390. size: '',
  3391. dropdownIcon: false,
  3392. canCloseSidebar: true,
  3393. },
  3394. globalBar: {
  3395. boxShadowColor: '',
  3396. leftAligned: {
  3397. gap: '',
  3398. },
  3399. rightAligned: {
  3400. gap: '',
  3401. },
  3402. },
  3403. localBar: {
  3404. backgroundColor: '#02040A',
  3405. alignCenter: false,
  3406. boxShadow: {
  3407. consistentColor: true,
  3408. },
  3409. links: {
  3410. color: '',
  3411. },
  3412. },
  3413. sidebars: {
  3414. backdrop: {
  3415. color: 'transparent',
  3416. pointerEvents: 'none',
  3417. },
  3418. right: {
  3419. preload: true,
  3420. floatUnderneath: false,
  3421. maxHeight: '',
  3422. },
  3423. },
  3424. repositoryHeader: {
  3425. import: true,
  3426. alignCenter: false,
  3427. removePageTitle: true,
  3428. backgroundColor: '#02040A',
  3429. avatar: {
  3430. remove: false,
  3431. customSvg: '',
  3432. },
  3433. link: {
  3434. color: '#6AAFF9',
  3435. hover: {
  3436. backgroundColor: 'transparent',
  3437. color: 'var(--color-accent-fg)',
  3438. textDecoration: 'underline',
  3439. },
  3440. },
  3441. },
  3442. },
  3443. },
  3444. oldSchool: {
  3445. light: {
  3446. backgroundColor: '#161C20',
  3447. hamburgerButton: {
  3448. remove: true,
  3449. },
  3450. logo: {
  3451. remove: false,
  3452. color: '#e6edf3',
  3453. customSvg: '',
  3454. },
  3455. pageTitle: {
  3456. remove: true,
  3457. color: oldSchoolColor,
  3458. hover: {
  3459. backgroundColor: oldSchoolHoverBackgroundColor,
  3460. color: oldSchoolHoverColor,
  3461. },
  3462. },
  3463. search: {
  3464. backgroundColor: '#494D54',
  3465. borderColor: '#30363d',
  3466. boxShadow: 'none',
  3467. alignLeft: true,
  3468. width: 'calc(var(--feed-sidebar) - 67px)',
  3469. margin: {
  3470. left: '',
  3471. right: '',
  3472. },
  3473. magnifyingGlassIcon: {
  3474. remove: true,
  3475. },
  3476. placeholder: {
  3477. text: 'Search or jump to...',
  3478. color: '#B3B3B5',
  3479. },
  3480. rightButton: 'slash key',
  3481. modal: {
  3482. width: '450px',
  3483. },
  3484. },
  3485. divider: {
  3486. remove: true,
  3487. },
  3488. flipCreateInbox: true,
  3489. create: {
  3490. remove: false,
  3491. border: false,
  3492. tooltip: false,
  3493. boxShadow: 'none',
  3494. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3495. plusIcon: {
  3496. remove: false,
  3497. color: oldSchoolColor,
  3498. marginRight: '0px',
  3499. hover: {
  3500. color: oldSchoolHoverColor,
  3501. },
  3502. },
  3503. text: {
  3504. content: '',
  3505. color: '',
  3506. },
  3507. dropdownIcon: {
  3508. remove: false,
  3509. color: oldSchoolColor,
  3510. hover: {
  3511. color: oldSchoolHoverColor,
  3512. },
  3513. },
  3514. },
  3515. flipIssuesPullRequests: true,
  3516. issues: {
  3517. remove: false,
  3518. border: false,
  3519. tooltip: false,
  3520. alignLeft: true,
  3521. boxShadow: 'none',
  3522. icon: {
  3523. remove: true,
  3524. color: '',
  3525. },
  3526. text: {
  3527. content: 'Issues',
  3528. color: oldSchoolColor,
  3529. },
  3530. hover: {
  3531. backgroundColor: oldSchoolHoverBackgroundColor,
  3532. color: oldSchoolHoverColor,
  3533. },
  3534. },
  3535. pullRequests: {
  3536. remove: false,
  3537. border: false,
  3538. tooltip: false,
  3539. alignLeft: true,
  3540. boxShadow: 'none',
  3541. icon: {
  3542. remove: true,
  3543. color: '',
  3544. },
  3545. text: {
  3546. content: 'Pull requests',
  3547. color: oldSchoolColor,
  3548. },
  3549. hover: {
  3550. backgroundColor: oldSchoolHoverBackgroundColor,
  3551. color: oldSchoolHoverColor,
  3552. },
  3553. },
  3554. notifications: {
  3555. remove: false,
  3556. border: false,
  3557. tooltip: false,
  3558. boxShadow: 'none',
  3559. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3560. icon: {
  3561. symbol: 'bell',
  3562. color: oldSchoolColor,
  3563. hover: {
  3564. color: oldSchoolHoverColor,
  3565. }
  3566. },
  3567. text: {
  3568. content: '',
  3569. color: '',
  3570. },
  3571. dot: {
  3572. remove: false,
  3573. boxShadowColor: '#161C20',
  3574. color: '#2f81f7',
  3575. displayOverIcon: true,
  3576. },
  3577. },
  3578. avatar: {
  3579. size: '24px',
  3580. dropdownIcon: true,
  3581. canCloseSidebar: true,
  3582. },
  3583. globalBar: {
  3584. boxShadowColor: '#21262D',
  3585. leftAligned: {
  3586. gap: '0.75rem',
  3587. },
  3588. rightAligned: {
  3589. gap: '2px',
  3590. },
  3591. },
  3592. localBar: {
  3593. backgroundColor: '#FAFBFD',
  3594. alignCenter: true,
  3595. boxShadow: {
  3596. consistentColor: true,
  3597. },
  3598. links: {
  3599. color: '',
  3600. },
  3601. },
  3602. sidebars: {
  3603. backdrop: {
  3604. color: oldSchoolHoverBackgroundColor,
  3605. pointerEvents: 'none',
  3606. },
  3607. right: {
  3608. preload: true,
  3609. floatUnderneath: true,
  3610. maxHeight: '50vh',
  3611. }
  3612. },
  3613. repositoryHeader: {
  3614. import: true,
  3615. alignCenter: true,
  3616. removePageTitle: true,
  3617. backgroundColor: '#FAFBFD',
  3618. avatar: {
  3619. remove: false,
  3620. customSvg: '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo mr-1 color-fg-muted"><path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path></svg>',
  3621. },
  3622. link: {
  3623. color: '#2F81F7',
  3624. hover: {
  3625. backgroundColor: 'transparent',
  3626. color: '#0969da',
  3627. textDecoration: 'underline',
  3628. },
  3629. },
  3630. },
  3631. },
  3632. dark: {
  3633. backgroundColor: '#161C20',
  3634. hamburgerButton: {
  3635. remove: true,
  3636. },
  3637. logo: {
  3638. remove: false,
  3639. color: '#e6edf3',
  3640. customSvg: '',
  3641. },
  3642. pageTitle: {
  3643. remove: true,
  3644. color: oldSchoolColor,
  3645. hover: {
  3646. backgroundColor: oldSchoolHoverBackgroundColor,
  3647. color: oldSchoolHoverColor,
  3648. },
  3649. },
  3650. search: {
  3651. backgroundColor: '#0E1217',
  3652. borderColor: '#30363d',
  3653. boxShadow: 'none',
  3654. alignLeft: true,
  3655. width: 'calc(var(--feed-sidebar) - 67px)',
  3656. margin: {
  3657. left: '',
  3658. right: '',
  3659. },
  3660. magnifyingGlassIcon: {
  3661. remove: true,
  3662. },
  3663. placeholder: {
  3664. text: 'Search or jump to...',
  3665. color: '#B3B3B5',
  3666. },
  3667. rightButton: 'slash key',
  3668. modal: {
  3669. width: '450px',
  3670. },
  3671. },
  3672. divider: {
  3673. remove: true,
  3674. },
  3675. flipCreateInbox: true,
  3676. create: {
  3677. remove: false,
  3678. border: false,
  3679. tooltip: false,
  3680. boxShadow: 'none',
  3681. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3682. plusIcon: {
  3683. remove: false,
  3684. color: oldSchoolColor,
  3685. marginRight: '0px',
  3686. hover: {
  3687. color: oldSchoolHoverColor,
  3688. },
  3689. },
  3690. text: {
  3691. content: '',
  3692. color: '',
  3693. },
  3694. dropdownIcon: {
  3695. remove: false,
  3696. color: oldSchoolColor,
  3697. hover: {
  3698. color: oldSchoolHoverColor,
  3699. },
  3700. },
  3701. },
  3702. flipIssuesPullRequests: true,
  3703. issues: {
  3704. remove: false,
  3705. border: false,
  3706. tooltip: false,
  3707. alignLeft: true,
  3708. boxShadow: 'none',
  3709. icon: {
  3710. remove: true,
  3711. color: '',
  3712. },
  3713. text: {
  3714. content: 'Issues',
  3715. color: oldSchoolColor,
  3716. },
  3717. hover: {
  3718. backgroundColor: oldSchoolHoverBackgroundColor,
  3719. color: oldSchoolHoverColor,
  3720. },
  3721. },
  3722. pullRequests: {
  3723. remove: false,
  3724. border: false,
  3725. tooltip: false,
  3726. alignLeft: true,
  3727. boxShadow: 'none',
  3728. icon: {
  3729. remove: true,
  3730. color: '',
  3731. },
  3732. text: {
  3733. content: 'Pull requests',
  3734. color: oldSchoolColor,
  3735. },
  3736. hover: {
  3737. backgroundColor: oldSchoolHoverBackgroundColor,
  3738. color: oldSchoolHoverColor,
  3739. },
  3740. },
  3741. notifications: {
  3742. remove: false,
  3743. border: false,
  3744. tooltip: false,
  3745. boxShadow: 'none',
  3746. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3747. icon: {
  3748. symbol: 'bell',
  3749. color: oldSchoolColor,
  3750. hover: {
  3751. color: oldSchoolHoverColor,
  3752. }
  3753. },
  3754. text: {
  3755. content: '',
  3756. color: '',
  3757. },
  3758. dot: {
  3759. remove: false,
  3760. boxShadowColor: '#161C20',
  3761. color: '#2f81f7',
  3762. displayOverIcon: true,
  3763. },
  3764. },
  3765. avatar: {
  3766. size: '24px',
  3767. dropdownIcon: true,
  3768. canCloseSidebar: true,
  3769. },
  3770. globalBar: {
  3771. boxShadowColor: '#21262D',
  3772. leftAligned: {
  3773. gap: '0.75rem',
  3774. },
  3775. rightAligned: {
  3776. gap: '2px',
  3777. },
  3778. },
  3779. localBar: {
  3780. backgroundColor: '#0D1117',
  3781. alignCenter: true,
  3782. boxShadow: {
  3783. consistentColor: true,
  3784. },
  3785. links: {
  3786. color: '#e6edf3',
  3787. },
  3788. },
  3789. sidebars: {
  3790. backdrop: {
  3791. color: oldSchoolHoverBackgroundColor,
  3792. pointerEvents: 'none',
  3793. },
  3794. right: {
  3795. preload: true,
  3796. floatUnderneath: true,
  3797. maxHeight: '50vh',
  3798. }
  3799. },
  3800. repositoryHeader: {
  3801. import: true,
  3802. alignCenter: true,
  3803. removePageTitle: true,
  3804. backgroundColor: '#0D1116',
  3805. avatar: {
  3806. remove: false,
  3807. customSvg: '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo mr-1 color-fg-muted"><path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path></svg>',
  3808. },
  3809. link: {
  3810. color: '#58A6FF',
  3811. hover: {
  3812. backgroundColor: 'transparent',
  3813. color: '#2F81F7',
  3814. textDecoration: 'underline',
  3815. },
  3816. },
  3817. },
  3818. },
  3819. },
  3820. };
  3821.  
  3822. let OBSERVER = new MutationObserver(observeAndModify);
  3823.  
  3824. let GMC = new GM_config({
  3825. id: 'gmc-frame',
  3826. title: `
  3827. Custom Global Navigation
  3828. <small>
  3829. <a
  3830. href="https://github.com/blakegearin/github-custom-global-navigation"
  3831. target="_blank"
  3832. >
  3833. source
  3834. </a>
  3835. </small>
  3836. `,
  3837. events: {
  3838. init: gmcInitialized,
  3839. open: gmcOpened,
  3840. save: gmcSaved,
  3841. close: gmcClosed,
  3842. },
  3843. frame: gmcBuildFrame(),
  3844. fields: {
  3845. type: {
  3846. section: [
  3847. `
  3848. Configuration Type
  3849. <small>
  3850. <a
  3851. href="https://github.com/blakegearin/github-custom-global-navigation#configurations"
  3852. target="_blank"
  3853. >
  3854. learn more
  3855. </a>
  3856. </small>
  3857. `,
  3858. ],
  3859. type: 'radio',
  3860. options: [
  3861. 'Off',
  3862. 'Happy Medium',
  3863. 'Old School',
  3864. 'Custom',
  3865. ],
  3866. default: 'Old School',
  3867. },
  3868. light_backgroundColor: {
  3869. label: 'Background color',
  3870. section: [
  3871. 'Custom Light',
  3872. ],
  3873. type: 'text',
  3874. default: '',
  3875. },
  3876. light_hamburgerButton_remove: {
  3877. label: '<h3>Hamburger button</h3><div class="gmc-label">Remove</div>',
  3878. type: 'checkbox',
  3879. default: false,
  3880. },
  3881. light_logo_remove: {
  3882. label: '<h3>Logo</h3><div class="gmc-label">Remove</div>',
  3883. type: 'checkbox',
  3884. default: false,
  3885. },
  3886. light_logo_color: {
  3887. label: 'Color',
  3888. type: 'text',
  3889. default: '',
  3890. },
  3891. light_logo_customSvg: {
  3892. label: 'Custom SVG (URL or text)',
  3893. type: 'textarea',
  3894. default: '',
  3895. },
  3896. light_pageTitle_remove: {
  3897. label: '<h3>Page title</h3><div class="gmc-label">Remove</div>',
  3898. type: 'checkbox',
  3899. default: false,
  3900. },
  3901. light_pageTitle_color: {
  3902. label: 'Color',
  3903. type: 'text',
  3904. default: '',
  3905. },
  3906. light_pageTitle_hover_backgroundColor: {
  3907. label: 'Hover background color',
  3908. type: 'text',
  3909. default: '',
  3910. },
  3911. light_pageTitle_hover_color: {
  3912. label: 'Hover color',
  3913. type: 'text',
  3914. default: '',
  3915. },
  3916. light_search_backgroundColor: {
  3917. label: '<h3>Search</h3><div class="gmc-label">Background color</div>',
  3918. type: 'text',
  3919. default: '',
  3920. },
  3921. light_search_borderColor: {
  3922. label: 'Border color',
  3923. type: 'text',
  3924. default: '',
  3925. },
  3926. light_search_boxShadow: {
  3927. label: 'Box shadow',
  3928. type: 'text',
  3929. default: '',
  3930. },
  3931. light_search_alignLeft: {
  3932. label: 'Left aligned',
  3933. type: 'checkbox',
  3934. default: false,
  3935. },
  3936. light_search_width: {
  3937. label: 'Width',
  3938. type: 'text',
  3939. default: '',
  3940. },
  3941. light_search_margin_left: {
  3942. label: 'Margin left',
  3943. type: 'text',
  3944. default: '',
  3945. },
  3946. light_search_margin_right: {
  3947. label: 'Margin right',
  3948. type: 'text',
  3949. default: '',
  3950. },
  3951. light_search_magnifyingGlassIcon_remove: {
  3952. label: 'Magnifying glass icon remove',
  3953. type: 'checkbox',
  3954. default: false,
  3955. },
  3956. light_search_placeholder_text: {
  3957. label: 'Placeholder text',
  3958. type: 'text',
  3959. default: '',
  3960. },
  3961. light_search_placeholder_color: {
  3962. label: 'Placeholder color',
  3963. type: 'text',
  3964. default: '',
  3965. },
  3966. light_search_rightButton: {
  3967. label: 'Right button',
  3968. type: 'select',
  3969. options: [
  3970. 'none',
  3971. 'command palette',
  3972. 'slash key',
  3973. ],
  3974. default: 'command palette',
  3975. },
  3976. light_search_modal_width: {
  3977. label: 'Modal width',
  3978. type: 'text',
  3979. default: '',
  3980. },
  3981. light_divider_remove: {
  3982. label: '<h3>Divider</h3><div class="gmc-label">Remove</div>',
  3983. type: 'checkbox',
  3984. default: false,
  3985. },
  3986. light_flipCreateInbox: {
  3987. label: 'Flip the order of Create and Notifications',
  3988. type: 'checkbox',
  3989. default: false,
  3990. },
  3991. light_create_remove: {
  3992. label: '<h3>Create button</h3><div class="gmc-label">Remove</div>',
  3993. type: 'checkbox',
  3994. default: false,
  3995. },
  3996. light_create_border: {
  3997. label: 'Border',
  3998. type: 'checkbox',
  3999. default: true,
  4000. },
  4001. light_create_tooltip: {
  4002. label: 'Tooltip',
  4003. type: 'checkbox',
  4004. default: true,
  4005. },
  4006. light_create_boxShadow: {
  4007. label: 'Box shadow',
  4008. type: 'text',
  4009. default: '',
  4010. },
  4011. light_create_hoverBackgroundColor: {
  4012. label: 'Hover background color',
  4013. type: 'text',
  4014. default: '',
  4015. },
  4016. light_create_plusIcon_remove: {
  4017. label: 'Plus icon remove',
  4018. type: 'checkbox',
  4019. default: false,
  4020. },
  4021. light_create_plusIcon_color: {
  4022. label: 'Plus icon color',
  4023. type: 'text',
  4024. default: '',
  4025. },
  4026. light_create_plusIcon_marginRight: {
  4027. label: 'Plus icon margin right',
  4028. type: 'text',
  4029. default: '',
  4030. },
  4031. light_create_plusIcon_hover_color: {
  4032. label: 'Plus icon hover color',
  4033. type: 'text',
  4034. default: '',
  4035. },
  4036. light_create_text_content: {
  4037. label: 'Text content',
  4038. type: 'text',
  4039. default: '',
  4040. },
  4041. light_create_text_color: {
  4042. label: 'Text color',
  4043. type: 'text',
  4044. default: '',
  4045. },
  4046. light_create_dropdownIcon_remove: {
  4047. label: 'Dropdown icon remove',
  4048. type: 'checkbox',
  4049. default: false,
  4050. },
  4051. light_create_dropdownIcon_color: {
  4052. label: 'Dropdown icon color',
  4053. type: 'text',
  4054. default: '',
  4055. },
  4056. light_create_dropdownIcon_hover_color: {
  4057. label: 'Dropdown icon hover color',
  4058. type: 'text',
  4059. default: '',
  4060. },
  4061. light_flipIssuesPullRequests: {
  4062. label: 'Flip the order of Issues and Pull requests',
  4063. type: 'checkbox',
  4064. default: false,
  4065. },
  4066. light_issues_remove: {
  4067. label: '<h3>Issues button</h3><div class="gmc-label">Remove</div>',
  4068. type: 'checkbox',
  4069. default: false,
  4070. },
  4071. light_issues_border: {
  4072. label: 'Border',
  4073. type: 'checkbox',
  4074. default: true,
  4075. },
  4076. light_issues_tooltip: {
  4077. label: 'Tooltip',
  4078. type: 'checkbox',
  4079. default: true,
  4080. },
  4081. light_issues_alignLeft: {
  4082. label: 'Align left',
  4083. type: 'checkbox',
  4084. default: false,
  4085. },
  4086. light_issues_boxShadow: {
  4087. label: 'Box shadow',
  4088. type: 'text',
  4089. default: '',
  4090. },
  4091. light_issues_icon_remove: {
  4092. label: 'Icon remove',
  4093. type: 'checkbox',
  4094. default: false,
  4095. },
  4096. light_issues_icon_color: {
  4097. label: 'Icon color',
  4098. type: 'text',
  4099. default: '',
  4100. },
  4101. light_issues_text_content: {
  4102. label: 'Text content',
  4103. type: 'text',
  4104. default: '',
  4105. },
  4106. light_issues_text_color: {
  4107. label: 'Text color',
  4108. type: 'text',
  4109. default: '',
  4110. },
  4111. light_issues_hover_backgroundColor: {
  4112. label: 'Hover background color',
  4113. type: 'text',
  4114. default: '',
  4115. },
  4116. light_issues_hover_color: {
  4117. label: 'Hover color',
  4118. type: 'text',
  4119. default: '',
  4120. },
  4121. light_pullRequests_remove: {
  4122. label: '<h3>Pull requests button</h3><div class="gmc-label">Remove</div>',
  4123. type: 'checkbox',
  4124. default: false,
  4125. },
  4126. light_pullRequests_border: {
  4127. label: 'Border',
  4128. type: 'checkbox',
  4129. default: true,
  4130. },
  4131. light_pullRequests_tooltip: {
  4132. label: 'Tooltip',
  4133. type: 'checkbox',
  4134. default: true,
  4135. },
  4136. light_pullRequests_alignLeft: {
  4137. label: 'Align left',
  4138. type: 'checkbox',
  4139. default: false,
  4140. },
  4141. light_pullRequests_boxShadow: {
  4142. label: 'Box shadow',
  4143. type: 'text',
  4144. default: '',
  4145. },
  4146. light_pullRequests_icon_remove: {
  4147. label: 'Icon remove',
  4148. type: 'checkbox',
  4149. default: false,
  4150. },
  4151. light_pullRequests_icon_color: {
  4152. label: 'Icon color',
  4153. type: 'text',
  4154. default: '',
  4155. },
  4156. light_pullRequests_text_content: {
  4157. label: 'Text content',
  4158. type: 'text',
  4159. default: '',
  4160. },
  4161. light_pullRequests_text_color: {
  4162. label: 'Text color',
  4163. type: 'text',
  4164. default: '',
  4165. },
  4166. light_pullRequests_hover_backgroundColor: {
  4167. label: 'Hover background color',
  4168. type: 'text',
  4169. default: '',
  4170. },
  4171. light_pullRequests_hover_color: {
  4172. label: 'Hover color',
  4173. type: 'text',
  4174. default: '',
  4175. },
  4176. light_notifications_remove: {
  4177. label: '<h3>Notifications button</h3><div class="gmc-label">Remove</div>',
  4178. type: 'checkbox',
  4179. default: false,
  4180. },
  4181. light_notifications_border: {
  4182. label: 'Border',
  4183. type: 'checkbox',
  4184. default: true,
  4185. },
  4186. light_notifications_tooltip: {
  4187. label: 'Tooltip',
  4188. type: 'checkbox',
  4189. default: true,
  4190. },
  4191. light_notifications_boxShadow: {
  4192. label: 'Box shadow',
  4193. type: 'text',
  4194. default: '',
  4195. },
  4196. light_notifications_hoverBackgroundColor: {
  4197. label: 'Hover background color',
  4198. type: 'text',
  4199. default: '',
  4200. },
  4201. light_notifications_icon_symbol: {
  4202. label: 'Icon symbol',
  4203. type: 'select',
  4204. options: [
  4205. 'none',
  4206. 'inbox',
  4207. 'bell',
  4208. ],
  4209. default: 'inbox',
  4210. },
  4211. light_notifications_icon_color: {
  4212. label: 'Icon color',
  4213. type: 'text',
  4214. default: '',
  4215. },
  4216. light_notifications_icon_hover_color: {
  4217. label: 'Icon hover color',
  4218. type: 'text',
  4219. default: '',
  4220. },
  4221. light_notifications_text_content: {
  4222. label: 'Text content',
  4223. type: 'text',
  4224. default: '',
  4225. },
  4226. light_notifications_text_color: {
  4227. label: 'Text color',
  4228. type: 'text',
  4229. default: '',
  4230. },
  4231. light_notifications_dot_remove: {
  4232. label: 'Dot remove',
  4233. type: 'checkbox',
  4234. default: false,
  4235. },
  4236. light_notifications_dot_boxShadowColor: {
  4237. label: 'Dot hover color',
  4238. type: 'text',
  4239. default: '',
  4240. },
  4241. light_notifications_dot_color: {
  4242. label: 'Dot color',
  4243. type: 'text',
  4244. default: '',
  4245. },
  4246. light_notifications_dot_displayOverIcon: {
  4247. label: 'Dot display over icon',
  4248. type: 'checkbox',
  4249. default: false,
  4250. },
  4251. light_avatar_size: {
  4252. label: '<h3>Avatar</h3><div class="gmc-label">Size</div>',
  4253. type: 'text',
  4254. default: '',
  4255. },
  4256. light_avatar_dropdownIcon: {
  4257. label: 'Dropdown icon',
  4258. type: 'checkbox',
  4259. default: false,
  4260. },
  4261. light_sidebars_right_canCloseSidebar: {
  4262. label: 'Can close sidebar',
  4263. type: 'checkbox',
  4264. default: false,
  4265. },
  4266. light_globalBar_boxShadowColor: {
  4267. label: '<h3>Global bar</h3><div class="gmc-label">Box shadow color</div>',
  4268. type: 'text',
  4269. default: '',
  4270. },
  4271. light_globalBar_leftAligned_gap: {
  4272. label: 'Left aligned gap',
  4273. type: 'text',
  4274. default: '',
  4275. },
  4276. light_globalBar_rightAligned_gap: {
  4277. label: 'Right aligned gap',
  4278. type: 'text',
  4279. default: '',
  4280. },
  4281. light_localBar_backgroundColor: {
  4282. label: '<h3>Local bar</h3><div class="gmc-label">Background color</div>',
  4283. type: 'text',
  4284. default: '',
  4285. },
  4286. light_localBar_alignCenter: {
  4287. label: 'Align center',
  4288. type: 'checkbox',
  4289. default: false,
  4290. },
  4291. light_localBar_boxShadow_consistentColor: {
  4292. label: 'Box shadow consistent color',
  4293. type: 'checkbox',
  4294. default: false,
  4295. },
  4296. light_localBar_links_color: {
  4297. label: 'Links color',
  4298. type: 'text',
  4299. default: '',
  4300. },
  4301. light_sidebars_backdrop_color: {
  4302. label: '<h3>Sidebars</h3><div class="gmc-label">Backdrop color</div>',
  4303. type: 'text',
  4304. default: '',
  4305. },
  4306. light_sidebars_backdrop_pointerEvents: {
  4307. label: 'Backdrop pointer events',
  4308. type: 'text',
  4309. default: '',
  4310. },
  4311. light_sidebars_right_preload: {
  4312. label: 'Right preload',
  4313. type: 'checkbox',
  4314. default: false,
  4315. },
  4316. light_sidebars_right_floatUnderneath: {
  4317. label: 'Right float underneath',
  4318. type: 'checkbox',
  4319. default: false,
  4320. },
  4321. light_sidebars_right_maxHeight: {
  4322. label: 'Right max height',
  4323. type: 'text',
  4324. default: '',
  4325. },
  4326. light_repositoryHeader_import: {
  4327. label: '<h3>Repository header</h3><div class="gmc-label">Import</div>',
  4328. type: 'checkbox',
  4329. default: false,
  4330. },
  4331. light_repositoryHeader_alignCenter: {
  4332. label: 'Align center',
  4333. type: 'checkbox',
  4334. default: false,
  4335. },
  4336. light_repositoryHeader_removePageTitle: {
  4337. label: 'Remove page title',
  4338. type: 'checkbox',
  4339. default: false,
  4340. },
  4341. light_repositoryHeader_backgroundColor: {
  4342. label: 'Background color',
  4343. type: 'text',
  4344. default: '',
  4345. },
  4346. light_repositoryHeader_avatar_remove: {
  4347. label: 'Avatar remove',
  4348. type: 'checkbox',
  4349. default: false,
  4350. },
  4351. light_repositoryHeader_avatar_customSvg: {
  4352. label: 'Custom SVG (URL or text)',
  4353. type: 'textarea',
  4354. default: '',
  4355. },
  4356. light_repositoryHeader_link_color: {
  4357. label: 'Link color',
  4358. type: 'text',
  4359. default: '',
  4360. },
  4361. light_repositoryHeader_link_hover_backgroundColor: {
  4362. label: 'Link hover background color',
  4363. type: 'text',
  4364. default: '',
  4365. },
  4366. light_repositoryHeader_link_hover_color: {
  4367. label: 'Link hover color',
  4368. type: 'text',
  4369. default: '',
  4370. },
  4371. light_repositoryHeader_link_hover_textDecoration: {
  4372. label: 'Link hover text decoration',
  4373. type: 'text',
  4374. default: '',
  4375. },
  4376. dark_backgroundColor: {
  4377. label: 'Background color',
  4378. section: [
  4379. 'Custom Dark',
  4380. ],
  4381. type: 'text',
  4382. default: '',
  4383. },
  4384. dark_hamburgerButton_remove: {
  4385. label: '<h3>Hamburger button</h3><div class="gmc-label">Remove</div>',
  4386. type: 'checkbox',
  4387. default: false,
  4388. },
  4389. dark_logo_remove: {
  4390. label: '<h3>Logo</h3><div class="gmc-label">Remove</div>',
  4391. type: 'checkbox',
  4392. default: false,
  4393. },
  4394. dark_logo_color: {
  4395. label: 'Color',
  4396. type: 'text',
  4397. default: '',
  4398. },
  4399. dark_logo_customSvg: {
  4400. label: 'Custom SVG (URL or text)',
  4401. type: 'textarea',
  4402. default: '',
  4403. },
  4404. dark_pageTitle_remove: {
  4405. label: '<h3>Page title</h3><div class="gmc-label">Remove</div>',
  4406. type: 'checkbox',
  4407. default: false,
  4408. },
  4409. dark_pageTitle_color: {
  4410. label: 'Color',
  4411. type: 'text',
  4412. default: '',
  4413. },
  4414. dark_pageTitle_hover_backgroundColor: {
  4415. label: 'Hover background color',
  4416. type: 'text',
  4417. default: '',
  4418. },
  4419. dark_pageTitle_hover_color: {
  4420. label: 'Hover color',
  4421. type: 'text',
  4422. default: '',
  4423. },
  4424. dark_search_backgroundColor: {
  4425. label: '<h3>Search</h3><div class="gmc-label">Background color</div>',
  4426. type: 'text',
  4427. default: '',
  4428. },
  4429. dark_search_borderColor: {
  4430. label: 'Border color',
  4431. type: 'text',
  4432. default: '',
  4433. },
  4434. dark_search_boxShadow: {
  4435. label: 'Box shadow',
  4436. type: 'text',
  4437. default: '',
  4438. },
  4439. dark_search_alignLeft: {
  4440. label: 'Left aligned',
  4441. type: 'checkbox',
  4442. default: false,
  4443. },
  4444. dark_search_width: {
  4445. label: 'Width',
  4446. type: 'text',
  4447. default: '',
  4448. },
  4449. dark_search_margin_left: {
  4450. label: 'Margin left',
  4451. type: 'text',
  4452. default: '',
  4453. },
  4454. dark_search_margin_right: {
  4455. label: 'Margin right',
  4456. type: 'text',
  4457. default: '',
  4458. },
  4459. dark_search_magnifyingGlassIcon_remove: {
  4460. label: 'Magnifying glass icon remove',
  4461. type: 'checkbox',
  4462. default: false,
  4463. },
  4464. dark_search_placeholder_text: {
  4465. label: 'Placeholder text',
  4466. type: 'text',
  4467. default: '',
  4468. },
  4469. dark_search_placeholder_color: {
  4470. label: 'Placeholder color',
  4471. type: 'text',
  4472. default: '',
  4473. },
  4474. dark_search_rightButton: {
  4475. label: 'Right button',
  4476. type: 'select',
  4477. options: [
  4478. 'none',
  4479. 'command palette',
  4480. 'slash key',
  4481. ],
  4482. default: 'command palette',
  4483. },
  4484. dark_search_modal_width: {
  4485. label: 'Modal width',
  4486. type: 'text',
  4487. default: '',
  4488. },
  4489. dark_divider_remove: {
  4490. label: '<h3>Divider</h3><div class="gmc-label">Remove</div>',
  4491. type: 'checkbox',
  4492. default: false,
  4493. },
  4494. dark_flipCreateInbox: {
  4495. label: 'Flip the order of Create and Notifications',
  4496. type: 'checkbox',
  4497. default: false,
  4498. },
  4499. dark_create_remove: {
  4500. label: '<h3>Create button</h3><div class="gmc-label">Remove</div>',
  4501. type: 'checkbox',
  4502. default: false,
  4503. },
  4504. dark_create_border: {
  4505. label: 'Border',
  4506. type: 'checkbox',
  4507. default: true,
  4508. },
  4509. dark_create_tooltip: {
  4510. label: 'Tooltip',
  4511. type: 'checkbox',
  4512. default: true,
  4513. },
  4514. dark_create_boxShadow: {
  4515. label: 'Box shadow',
  4516. type: 'text',
  4517. default: '',
  4518. },
  4519. dark_create_hoverBackgroundColor: {
  4520. label: 'Hover background color',
  4521. type: 'text',
  4522. default: '',
  4523. },
  4524. dark_create_plusIcon_remove: {
  4525. label: 'Plus icon remove',
  4526. type: 'checkbox',
  4527. default: false,
  4528. },
  4529. dark_create_plusIcon_color: {
  4530. label: 'Plus icon color',
  4531. type: 'text',
  4532. default: '',
  4533. },
  4534. dark_create_plusIcon_marginRight: {
  4535. label: 'Plus icon margin right',
  4536. type: 'text',
  4537. default: '',
  4538. },
  4539. dark_create_plusIcon_hover_color: {
  4540. label: 'Plus icon hover color',
  4541. type: 'text',
  4542. default: '',
  4543. },
  4544. dark_create_text_content: {
  4545. label: 'Text content',
  4546. type: 'text',
  4547. default: '',
  4548. },
  4549. dark_create_text_color: {
  4550. label: 'Text color',
  4551. type: 'text',
  4552. default: '',
  4553. },
  4554. dark_create_dropdownIcon_remove: {
  4555. label: 'Dropdown icon remove',
  4556. type: 'checkbox',
  4557. default: false,
  4558. },
  4559. dark_create_dropdownIcon_color: {
  4560. label: 'Dropdown icon color',
  4561. type: 'text',
  4562. default: '',
  4563. },
  4564. dark_create_dropdownIcon_hover_color: {
  4565. label: 'Dropdown icon hover color',
  4566. type: 'text',
  4567. default: '',
  4568. },
  4569. dark_flipIssuesPullRequests: {
  4570. label: 'Flip the order of Issues and Pull requests',
  4571. type: 'checkbox',
  4572. default: false,
  4573. },
  4574. dark_issues_remove: {
  4575. label: '<h3>Issues button</h3><div class="gmc-label">Remove</div>',
  4576. type: 'checkbox',
  4577. default: false,
  4578. },
  4579. dark_issues_border: {
  4580. label: 'Border',
  4581. type: 'checkbox',
  4582. default: true,
  4583. },
  4584. dark_issues_tooltip: {
  4585. label: 'Tooltip',
  4586. type: 'checkbox',
  4587. default: true,
  4588. },
  4589. dark_issues_boxShadow: {
  4590. label: 'Box shadow',
  4591. type: 'text',
  4592. default: '',
  4593. },
  4594. dark_issues_alignLeft: {
  4595. label: 'Align left',
  4596. type: 'checkbox',
  4597. default: false,
  4598. },
  4599. dark_issues_icon_remove: {
  4600. label: 'Icon remove',
  4601. type: 'checkbox',
  4602. default: false,
  4603. },
  4604. dark_issues_icon_color: {
  4605. label: 'Icon color',
  4606. type: 'text',
  4607. default: '',
  4608. },
  4609. dark_issues_text_content: {
  4610. label: 'Text content',
  4611. type: 'text',
  4612. default: '',
  4613. },
  4614. dark_issues_text_color: {
  4615. label: 'Text color',
  4616. type: 'text',
  4617. default: '',
  4618. },
  4619. dark_issues_hover_backgroundColor: {
  4620. label: 'Hover background color',
  4621. type: 'text',
  4622. default: '',
  4623. },
  4624. dark_issues_hover_color: {
  4625. label: 'Hover color',
  4626. type: 'text',
  4627. default: '',
  4628. },
  4629. dark_pullRequests_remove: {
  4630. label: '<h3>Pull requests button</h3><div class="gmc-label">Remove</div>',
  4631. type: 'checkbox',
  4632. default: false,
  4633. },
  4634. dark_pullRequests_border: {
  4635. label: 'Border',
  4636. type: 'checkbox',
  4637. default: true,
  4638. },
  4639. dark_pullRequests_tooltip: {
  4640. label: 'Tooltip',
  4641. type: 'checkbox',
  4642. default: true,
  4643. },
  4644. dark_pullRequests_alignLeft: {
  4645. label: 'Align left',
  4646. type: 'checkbox',
  4647. default: false,
  4648. },
  4649. dark_pullRequests_boxShadow: {
  4650. label: 'Box shadow',
  4651. type: 'text',
  4652. default: '',
  4653. },
  4654. dark_pullRequests_icon_remove: {
  4655. label: 'Icon remove',
  4656. type: 'checkbox',
  4657. default: false,
  4658. },
  4659. dark_pullRequests_icon_color: {
  4660. label: 'Icon color',
  4661. type: 'text',
  4662. default: '',
  4663. },
  4664. dark_pullRequests_text_content: {
  4665. label: 'Text content',
  4666. type: 'text',
  4667. default: '',
  4668. },
  4669. dark_pullRequests_text_color: {
  4670. label: 'Text color',
  4671. type: 'text',
  4672. default: '',
  4673. },
  4674. dark_pullRequests_hover_backgroundColor: {
  4675. label: 'Hover background color',
  4676. type: 'text',
  4677. default: '',
  4678. },
  4679. dark_pullRequests_hover_color: {
  4680. label: 'Hover color',
  4681. type: 'text',
  4682. default: '',
  4683. },
  4684. dark_notifications_remove: {
  4685. label: '<h3>Notifications button</h3><div class="gmc-label">Remove</div>',
  4686. type: 'checkbox',
  4687. default: false,
  4688. },
  4689. dark_notifications_border: {
  4690. label: 'Border',
  4691. type: 'checkbox',
  4692. default: true,
  4693. },
  4694. dark_notifications_tooltip: {
  4695. label: 'Tooltip',
  4696. type: 'checkbox',
  4697. default: true,
  4698. },
  4699. dark_notifications_boxShadow: {
  4700. label: 'Box shadow',
  4701. type: 'text',
  4702. default: '',
  4703. },
  4704. dark_notifications_hoverBackgroundColor: {
  4705. label: 'Hover background color',
  4706. type: 'text',
  4707. default: '',
  4708. },
  4709. dark_notifications_icon_symbol: {
  4710. label: 'Icon symbol',
  4711. type: 'select',
  4712. options: [
  4713. 'none',
  4714. 'inbox',
  4715. 'bell',
  4716. ],
  4717. default: 'inbox',
  4718. },
  4719. dark_notifications_icon_color: {
  4720. label: 'Icon color',
  4721. type: 'text',
  4722. default: '',
  4723. },
  4724. dark_notifications_icon_hover_color: {
  4725. label: 'Icon hover color',
  4726. type: 'text',
  4727. default: '',
  4728. },
  4729. dark_notifications_text_content: {
  4730. label: 'Text content',
  4731. type: 'text',
  4732. default: '',
  4733. },
  4734. dark_notifications_text_color: {
  4735. label: 'Text color',
  4736. type: 'text',
  4737. default: '',
  4738. },
  4739. dark_notifications_dot_remove: {
  4740. label: 'Dot remove',
  4741. type: 'checkbox',
  4742. default: false,
  4743. },
  4744. dark_notifications_dot_boxShadowColor: {
  4745. label: 'Dot hover color',
  4746. type: 'text',
  4747. default: '',
  4748. },
  4749. dark_notifications_dot_color: {
  4750. label: 'Dot color',
  4751. type: 'text',
  4752. default: '',
  4753. },
  4754. dark_notifications_dot_displayOverIcon: {
  4755. label: 'Dot display over icon',
  4756. type: 'checkbox',
  4757. default: false,
  4758. },
  4759. dark_avatar_size: {
  4760. label: '<h3>Avatar</h3><div class="gmc-label">Size</div>',
  4761. type: 'text',
  4762. default: '',
  4763. },
  4764. dark_avatar_dropdownIcon: {
  4765. label: 'Dropdown icon',
  4766. type: 'checkbox',
  4767. default: false,
  4768. },
  4769. dark_sidebars_right_canCloseSidebar: {
  4770. label: 'Can close sidebar',
  4771. type: 'checkbox',
  4772. default: false,
  4773. },
  4774. dark_globalBar_boxShadowColor: {
  4775. label: '<h3>Global bar</h3><div class="gmc-label">Box shadow color</div>',
  4776. type: 'text',
  4777. default: '',
  4778. },
  4779. dark_globalBar_leftAligned_gap: {
  4780. label: 'Left aligned gap',
  4781. type: 'text',
  4782. default: '',
  4783. },
  4784. dark_globalBar_rightAligned_gap: {
  4785. label: 'Right aligned gap',
  4786. type: 'text',
  4787. default: '',
  4788. },
  4789. dark_localBar_backgroundColor: {
  4790. label: '<h3>Local bar</h3><div class="gmc-label">Background color</div>',
  4791. type: 'text',
  4792. default: '',
  4793. },
  4794. dark_localBar_alignCenter: {
  4795. label: 'Align center',
  4796. type: 'checkbox',
  4797. default: false,
  4798. },
  4799. dark_localBar_boxShadow_consistentColor: {
  4800. label: 'Box shadow consistent color',
  4801. type: 'checkbox',
  4802. default: false,
  4803. },
  4804. dark_localBar_links_color: {
  4805. label: 'Links color',
  4806. type: 'text',
  4807. default: '',
  4808. },
  4809. dark_sidebars_backdrop_color: {
  4810. label: '<h3>Sidebars</h3><div class="gmc-label">Backdrop color</div>',
  4811. type: 'text',
  4812. default: '',
  4813. },
  4814. dark_sidebars_backdrop_pointerEvents: {
  4815. label: 'Backdrop pointer events',
  4816. type: 'text',
  4817. default: '',
  4818. },
  4819. dark_sidebars_right_preload: {
  4820. label: 'Right preload',
  4821. type: 'checkbox',
  4822. default: false,
  4823. },
  4824. dark_sidebars_right_floatUnderneath: {
  4825. label: 'Right float underneath',
  4826. type: 'checkbox',
  4827. default: false,
  4828. },
  4829. dark_sidebars_right_maxHeight: {
  4830. label: 'Right max height',
  4831. type: 'text',
  4832. default: '',
  4833. },
  4834. dark_repositoryHeader_import: {
  4835. label: '<h3>Repository header</h3><div class="gmc-label">Import</div>',
  4836. type: 'checkbox',
  4837. default: false,
  4838. },
  4839. dark_repositoryHeader_alignCenter: {
  4840. label: 'Align enter',
  4841. type: 'checkbox',
  4842. default: false,
  4843. },
  4844. dark_repositoryHeader_removePageTitle: {
  4845. label: 'Remove page title',
  4846. type: 'checkbox',
  4847. default: false,
  4848. },
  4849. dark_repositoryHeader_backgroundColor: {
  4850. label: 'Background color',
  4851. type: 'text',
  4852. default: '',
  4853. },
  4854. dark_repositoryHeader_avatar_remove: {
  4855. label: 'Avatar remove',
  4856. type: 'checkbox',
  4857. default: false,
  4858. },
  4859. dark_repositoryHeader_avatar_customSvg: {
  4860. label: 'Custom SVG (URL or text)',
  4861. type: 'textarea',
  4862. default: '',
  4863. },
  4864. dark_repositoryHeader_link_color: {
  4865. label: 'Link color',
  4866. type: 'text',
  4867. default: '',
  4868. },
  4869. dark_repositoryHeader_link_hover_backgroundColor: {
  4870. label: 'Link hover background color',
  4871. type: 'text',
  4872. default: '',
  4873. },
  4874. dark_repositoryHeader_link_hover_color: {
  4875. label: 'Link hover color',
  4876. type: 'text',
  4877. default: '',
  4878. },
  4879. dark_repositoryHeader_link_hover_textDecoration: {
  4880. label: 'Link hover text decoration',
  4881. type: 'text',
  4882. default: '',
  4883. },
  4884. on_save: {
  4885. label: 'On save',
  4886. section: ['Settings'],
  4887. type: 'select',
  4888. options: [
  4889. 'do nothing',
  4890. 'refresh tab',
  4891. 'refresh tab and close',
  4892. 'run script',
  4893. 'run script and close',
  4894. ],
  4895. default: 'do nothing',
  4896. },
  4897. on_close: {
  4898. label: 'On close',
  4899. type: 'select',
  4900. options: [
  4901. 'do nothing',
  4902. 'refresh tab',
  4903. 'run script',
  4904. ],
  4905. default: 'do nothing',
  4906. },
  4907. on_open: {
  4908. label: 'On open',
  4909. type: 'select',
  4910. options: [
  4911. 'do nothing',
  4912. 'close sidebar',
  4913. ],
  4914. default: 'do nothing',
  4915. },
  4916. log_level: {
  4917. label: 'Log level',
  4918. type: 'select',
  4919. options: [
  4920. 'silent',
  4921. 'quiet',
  4922. 'debug',
  4923. 'verbose',
  4924. 'trace',
  4925. ],
  4926. default: 'quiet',
  4927. },
  4928. clear_custom_config: {
  4929. label: 'Clear Custom',
  4930. section: ['Danger Zone'],
  4931. type: 'button',
  4932. click: gmcClearCustom,
  4933. },
  4934. apply_happyMedium_config: {
  4935. label: 'Overwrite Custom with Happy Medium',
  4936. type: 'button',
  4937. click: gmcApplyCustomHappyMediumConfig,
  4938. },
  4939. apply_oldSchool_config: {
  4940. label: 'Overwrite Custom with Old School',
  4941. type: 'button',
  4942. click: gmcApplyCustomOldSchoolConfig,
  4943. },
  4944. },
  4945. });
  4946. })();