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.1.0
  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.left.preload) {
  1278. HEADER.querySelector(elementSelector.left.backdrop).remove();
  1279. HEADER.querySelector(`${SELECTORS.hamburgerButton} button`).click();
  1280. }
  1281.  
  1282. if (elementConfig.right.floatUnderneath) {
  1283. HEADER_STYLE.textContent += `
  1284. ${elementSelector.right.backdrop}
  1285. {
  1286. padding-top: 10px !important;
  1287. padding-right: 15px !important;
  1288. border-top-right-radius: 6px !important;
  1289. bottom: initial !important;
  1290. top: initial !important;
  1291. }
  1292.  
  1293. ${elementSelector.right.modalDialog}
  1294. {
  1295. border-top-right-radius: var(--borderRadius-large, 0.75rem) !important;
  1296. border-bottom-right-radius: var(--borderRadius-large, 0.75rem) !important;
  1297. }
  1298.  
  1299. ${elementSelector.right.navParentDiv}
  1300. {
  1301. margin-bottom: 0px !important;
  1302. }
  1303.  
  1304. ${elementSelector.right.nav}
  1305. {
  1306. padding-bottom: 0px !important;
  1307. }
  1308. `;
  1309. }
  1310.  
  1311. if (elementConfig.right.preload) {
  1312. HEADER.querySelector(elementSelector.right.backdrop).remove();
  1313. HEADER.querySelector(SELECTORS.avatar.button).click();
  1314. }
  1315.  
  1316. if (elementConfig.right.maxHeight) {
  1317. HEADER_STYLE.textContent += `
  1318. ${elementSelector.right.modalDialog}
  1319. {
  1320. max-height: ${elementConfig.right.maxHeight} !important;
  1321. }
  1322. `;
  1323. }
  1324.  
  1325. if (elementConfig.right.width !== '') {
  1326. HEADER_STYLE.textContent += `
  1327. ${elementSelector.right.modalDialog}.Overlay.Overlay--size-small-portrait
  1328. {
  1329. --overlay-width: ${elementConfig.right.width};
  1330. }
  1331. `;
  1332. }
  1333. }
  1334.  
  1335. function importRepositoryHeader() {
  1336. log(DEBUG, 'importRepositoryHeader()');
  1337.  
  1338. const configKey = 'repositoryHeader';
  1339. const repositoryHeader = document.querySelector(SELECTORS[configKey].id);
  1340.  
  1341. if (!repositoryHeader) {
  1342. // This is expected on pages that aren't repositories
  1343. log(DEBUG, `Selector '${SELECTORS[configKey].id}' not found`);
  1344. return;
  1345. }
  1346.  
  1347. const topRepositoryHeaderElement = document.createElement('div');
  1348. topRepositoryHeaderElement.style.setProperty('display', 'flex');
  1349. topRepositoryHeaderElement.style.setProperty('padding', '0px');
  1350. topRepositoryHeaderElement.style.setProperty('box-shadow', 'none');
  1351.  
  1352. const elementConfig = CONFIG[configKey];
  1353.  
  1354. if (elementConfig.backgroundColor !== '') {
  1355. topRepositoryHeaderElement.style.setProperty('background-color', elementConfig.backgroundColor);
  1356. }
  1357.  
  1358. if (repositoryHeader.hidden) {
  1359. log(DEBUG, `${SELECTORS[configKey].id} is hidden`);
  1360.  
  1361. if (!HEADER.querySelector(SELECTORS.pageTitle.separator)) {
  1362. logError(`Selector '${SELECTORS.pageTitle.separator}' not found`);
  1363. log(INFO, 'Not creating a repository header');
  1364.  
  1365. return;
  1366. }
  1367.  
  1368. // A repo tab other than Code is being loaded for the first time
  1369. if (!CONFIG.pageTitle.remove) return;
  1370.  
  1371. const pageTitle = HEADER.querySelector(SELECTORS.pageTitle.topDiv);
  1372.  
  1373. if (!pageTitle) {
  1374. logError(`Selector '${SELECTORS.pageTitle.topDiv}' not found`);
  1375. return;
  1376. }
  1377.  
  1378. const repositoryHeaderElement = document.createElement('div');
  1379. repositoryHeaderElement.id = TEMP_REPOSITORY_HEADER_FLAG;
  1380. repositoryHeaderElement.classList.add('pt-3', 'mb-2', REPOSITORY_HEADER_CLASS);
  1381.  
  1382. const clonedPageTitle = pageTitle.cloneNode(true);
  1383. repositoryHeaderElement.appendChild(clonedPageTitle);
  1384.  
  1385. topRepositoryHeaderElement.appendChild(repositoryHeaderElement);
  1386. insertNewGlobalBar(topRepositoryHeaderElement);
  1387. } else if (HEADER.querySelector(createId(TEMP_REPOSITORY_HEADER_FLAG))) {
  1388. // The Code tab is being loaded from another tab which has a temporary header
  1389. HEADER_STYLE.textContent += cssHideElement(createId(TEMP_REPOSITORY_HEADER_FLAG));
  1390.  
  1391. insertPermanentRepositoryHeader(topRepositoryHeaderElement, repositoryHeader);
  1392. } else {
  1393. // The Code tab being loaded for the first time
  1394. insertPermanentRepositoryHeader(topRepositoryHeaderElement, repositoryHeader);
  1395. }
  1396.  
  1397. updateRepositoryHeaderName();
  1398.  
  1399. if (elementConfig.backgroundColor !== '') {
  1400. HEADER_STYLE.textContent += `
  1401. .${REPOSITORY_HEADER_CLASS}
  1402. {
  1403. background-color: ${elementConfig.backgroundColor} !important;
  1404. }
  1405. `;
  1406. }
  1407.  
  1408. if (elementConfig.alignCenter) {
  1409. HEADER_STYLE.textContent += `
  1410. .${REPOSITORY_HEADER_CLASS}
  1411. {
  1412. max-width: 1280px;
  1413. margin-right: auto;
  1414. margin-left: auto;
  1415. }
  1416.  
  1417. .${REPOSITORY_HEADER_CLASS} div
  1418. {
  1419. padding-left: 0px !important;
  1420. padding-right: 0px !important;
  1421. }
  1422.  
  1423. @media (min-width: 768px) {
  1424. .${REPOSITORY_HEADER_CLASS}
  1425. {
  1426. padding-right: var(--base-size-24, 24px) !important;
  1427. padding-left: var(--base-size-24, 24px) !important;
  1428. }
  1429. }
  1430.  
  1431. @media (min-width: 1012px) {
  1432. .${REPOSITORY_HEADER_CLASS}
  1433. {
  1434. padding-right: var(--base-size-32, 32px) !important;
  1435. padding-left: var(--base-size-32, 32px) !important;
  1436. }
  1437. }
  1438. `;
  1439. }
  1440.  
  1441. if (elementConfig.link.color !== '') {
  1442. HEADER_STYLE.textContent += `
  1443. ${SELECTORS.repositoryHeader.links}
  1444. {
  1445. color: ${elementConfig.link.color} !important;
  1446. }
  1447. `;
  1448. }
  1449.  
  1450. if (elementConfig.link.hover.color !== '') {
  1451. HEADER_STYLE.textContent += `
  1452. ${SELECTORS.repositoryHeader.links}:hover
  1453. {
  1454. color: ${elementConfig.link.hover.color} !important;
  1455. }
  1456. `;
  1457. }
  1458.  
  1459. if (elementConfig.link.hover.backgroundColor !== '') {
  1460. HEADER_STYLE.textContent += `
  1461. ${SELECTORS.repositoryHeader.links}:hover
  1462. {
  1463. background-color: ${elementConfig.link.hover.backgroundColor} !important;
  1464. }
  1465. `;
  1466. }
  1467.  
  1468. if (elementConfig.link.hover.textDecoration !== '') {
  1469. HEADER_STYLE.textContent += `
  1470. ${SELECTORS.repositoryHeader.links}:hover
  1471. {
  1472. text-decoration: ${elementConfig.link.hover.textDecoration} !important;
  1473. }
  1474. `;
  1475. }
  1476.  
  1477. HEADER_STYLE.textContent += `
  1478. .${REPOSITORY_HEADER_CLASS}
  1479. {
  1480. flex: auto !important;
  1481. }
  1482.  
  1483. ${SELECTORS.repositoryHeader.details}
  1484. {
  1485. display: flex;
  1486. align-items: center;
  1487. }
  1488.  
  1489. ${SELECTORS.pageTitle.topDiv}
  1490. {
  1491. flex: 0 1 auto !important;
  1492. height: auto !important;
  1493. min-width: 0 !important;
  1494. }
  1495.  
  1496. @media (min-width: 768px)
  1497. {
  1498. .AppHeader-context .AppHeader-context-compact
  1499. {
  1500. display: none !important;
  1501. }
  1502. }
  1503.  
  1504. .AppHeader-context .AppHeader-context-full
  1505. {
  1506. display: inline-flex !important;
  1507. width: 100% !important;
  1508. min-width: 0 !important;
  1509. max-width: 100% !important;
  1510. overflow: hidden !important;
  1511. }
  1512.  
  1513. .AppHeader-context .AppHeader-context-full ul {
  1514. display: flex;
  1515. flex-direction: row;
  1516. }
  1517.  
  1518. .AppHeader-context .AppHeader-context-full li:first-child {
  1519. flex: 0 100 max-content;
  1520. }
  1521.  
  1522. .AppHeader-context .AppHeader-context-full li {
  1523. display: inline-grid;
  1524. grid-auto-flow: column;
  1525. align-items: center;
  1526. flex: 0 99999 auto;
  1527. }
  1528.  
  1529. .AppHeader-context .AppHeader-context-full ul, .AppHeader .AppHeader-globalBar .AppHeader-context .AppHeader-context-full li {
  1530. list-style: none;
  1531. }
  1532.  
  1533. .AppHeader-context .AppHeader-context-item {
  1534. display: flex;
  1535. align-items: center;
  1536. min-width: 3ch;
  1537. line-height: var(--text-body-lineHeight-medium, 1.4285714286);
  1538. text-decoration: none !important;
  1539. border-radius: var(--borderRadius-medium, 6px);
  1540. padding-inline: var(--control-medium-paddingInline-condensed, 8px);
  1541. padding-block: var(--control-medium-paddingBlock, 6px);
  1542. }
  1543.  
  1544. .AppHeader-context .AppHeader-context-full li:last-child .AppHeader-context-item {
  1545. font-weight: var(--base-text-weight-semibold, 600);
  1546. }
  1547.  
  1548. .AppHeader-context .AppHeader-context-item-separator {
  1549. color: var(--fgColor-muted, var(--color-fg-muted));
  1550. white-space: nowrap;
  1551. }
  1552.  
  1553. ${SELECTORS.header.globalBar}
  1554. {
  1555. padding: 16px !important;
  1556. }
  1557. `;
  1558.  
  1559. if (elementConfig.removePageTitle) removePageTitle();
  1560.  
  1561. return true;
  1562. }
  1563.  
  1564. function insertPermanentRepositoryHeader(topRepositoryHeaderElement, repositoryHeader) {
  1565. log(DEBUG, 'insertPermanentRepositoryHeader()');
  1566.  
  1567. const clonedRepositoryHeader = repositoryHeader.cloneNode(true);
  1568.  
  1569. // This is needed to prevent pop-in via Turbo when navigating between tabs on a repo
  1570. repositoryHeader.removeAttribute('data-turbo-replace');
  1571. clonedRepositoryHeader.removeAttribute('data-turbo-replace');
  1572.  
  1573. repositoryHeader.style.setProperty('display', 'none', 'important');
  1574.  
  1575. clonedRepositoryHeader.classList.add(REPOSITORY_HEADER_SUCCESS_FLAG, REPOSITORY_HEADER_CLASS);
  1576.  
  1577. topRepositoryHeaderElement.appendChild(clonedRepositoryHeader);
  1578.  
  1579. insertNewGlobalBar(topRepositoryHeaderElement);
  1580.  
  1581. clonedRepositoryHeader.firstElementChild.classList.remove('container-xl', 'px-lg-5');
  1582. }
  1583.  
  1584. function updateRepositoryHeaderName() {
  1585. log(DEBUG, 'updateRepositoryHeaderName()');
  1586.  
  1587. const elementConfig = CONFIG.repositoryHeader;
  1588.  
  1589. const name = document.querySelector(SELECTORS.repositoryHeader.name);
  1590.  
  1591. if (!name) {
  1592. // When not in a repo, this is expected
  1593. log(DEBUG, `Selector '${SELECTORS.repositoryHeader.name}' not found`);
  1594. return;
  1595. }
  1596.  
  1597. name.style.setProperty('display', 'none', 'important');
  1598.  
  1599. const pageTitle = HEADER.querySelector(SELECTORS.pageTitle.topDiv);
  1600.  
  1601. if (!pageTitle) {
  1602. logError(`Selector '${SELECTORS.pageTitle.topDiv}' not found`);
  1603. return;
  1604. }
  1605.  
  1606. const ownerImg = document.querySelector(SELECTORS.repositoryHeader.ownerImg);
  1607.  
  1608. if (!ownerImg) {
  1609. logError(`Selector '${SELECTORS.repositoryHeader.ownerImg}' not found`);
  1610. return;
  1611. }
  1612.  
  1613. const clonedPageTitle = pageTitle.cloneNode(true);
  1614. clonedPageTitle.style.display = '';
  1615.  
  1616. clonedPageTitle.querySelectorAll('svg').forEach(svg => svg.remove());
  1617.  
  1618. ownerImg.parentNode.insertBefore(clonedPageTitle, ownerImg.nextSibling);
  1619.  
  1620. if (elementConfig.avatar.remove) {
  1621. ownerImg.remove();
  1622. } else if (elementConfig.avatar.customSvg !== '') {
  1623. if (isValidURL(elementConfig.avatar.customSvg)) {
  1624. ownerImg.src = elementConfig.avatar.customSvg;
  1625. } else {
  1626. const divElement = document.createElement('div');
  1627. divElement.style.setProperty('display', 'flex');
  1628. divElement.style.setProperty('align-items', 'center');
  1629.  
  1630. divElement.innerHTML = elementConfig.avatar.customSvg;
  1631.  
  1632. ownerImg.parentNode.replaceChild(divElement, ownerImg);
  1633. }
  1634. }
  1635.  
  1636. HEADER_STYLE.textContent += cssHideElement(SELECTORS.repositoryHeader.bottomBorder);
  1637. }
  1638.  
  1639. function cloneAndLeftAlignElement(elementSelector, elementId) {
  1640. log(DEBUG, 'cloneAndLeftAlignElement()');
  1641.  
  1642. const leftAlignedDiv = HEADER.querySelector(SELECTORS.header.leftAligned);
  1643.  
  1644. if (!leftAlignedDiv) {
  1645. logError(`Selector '${SELECTORS.header.leftAligned}' not found`);
  1646. return [];
  1647. }
  1648.  
  1649. const element = HEADER.querySelector(elementSelector);
  1650.  
  1651. if (!element) {
  1652. logError(`Selector '${elementSelector}' not found`);
  1653. return [];
  1654. }
  1655.  
  1656. const elementClone = element.cloneNode(true);
  1657. const elementCloneId = `${elementId}-clone`;
  1658.  
  1659. elementClone.setAttribute('id', elementCloneId);
  1660.  
  1661. elementClone.style.setProperty('display', 'none');
  1662.  
  1663. HEADER_STYLE.textContent += cssHideElement(elementSelector);
  1664.  
  1665. HEADER_STYLE.textContent += `
  1666. ${createId(elementCloneId)}
  1667. {
  1668. display: initial !important;
  1669. }
  1670. `;
  1671.  
  1672. leftAlignedDiv.appendChild(elementClone);
  1673.  
  1674. return [elementCloneId, elementClone];
  1675. }
  1676.  
  1677. function insertNewGlobalBar(element) {
  1678. log(DEBUG, 'insertNewGlobalBar()');
  1679.  
  1680. const elementToInsertAfter = HEADER.querySelector(SELECTORS.header.globalBar);
  1681.  
  1682. elementToInsertAfter.parentNode.insertBefore(element, elementToInsertAfter.nextSibling);
  1683. }
  1684.  
  1685. function createId(string) {
  1686. if (string.startsWith('#')) return string;
  1687.  
  1688. return `#${string}`;
  1689. }
  1690.  
  1691. function cssHideElement(elementSelector) {
  1692. return `
  1693. ${elementSelector}
  1694. {
  1695. display: none !important;
  1696. }
  1697. `;
  1698. }
  1699.  
  1700. function isValidURL(string) {
  1701. log(DEBUG, 'isValidURL()');
  1702.  
  1703. const urlPattern = /^(https?:\/\/)?([\w.]+)\.([a-z]{2,6}\.?)(\/[\w.]*)*\/?$/i;
  1704. return urlPattern.test(string);
  1705. }
  1706.  
  1707. function escapeRegExp(string) {
  1708. log(DEBUG, 'escapeRegExp()');
  1709.  
  1710. return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  1711. }
  1712.  
  1713. function updateSelectors() {
  1714. log(DEBUG, 'updateSelectors()');
  1715.  
  1716. const toolTips = Array.from(HEADER.querySelectorAll('tool-tip'));
  1717. SELECTORS.toolTips = {
  1718. create: toolTips.find(
  1719. tooltip => tooltip.textContent.includes('Create new')
  1720. ),
  1721. pullRequests: toolTips.find(
  1722. tooltip => tooltip.textContent.includes('Pull requests')
  1723. ),
  1724. issues: toolTips.find(
  1725. tooltip => tooltip.textContent.includes('Issues')
  1726. ),
  1727. notifications: toolTips.find(
  1728. tooltip => tooltip.getAttribute('data-target') === 'notification-indicator.tooltip'
  1729. ),
  1730. };
  1731. }
  1732.  
  1733. function waitForFeaturePreviewButton() {
  1734. log(DEBUG, 'waitForFeaturePreviewButton()');
  1735.  
  1736. if (!HEADER) return;
  1737.  
  1738. const liElementId = 'custom-global-navigation-menu-item';
  1739.  
  1740. if (HEADER.querySelector(createId(liElementId))) return;
  1741.  
  1742. const featurePreviewSearch = HEADER.querySelectorAll('[data-analytics-event*="FEATURE_PREVIEW"]');
  1743.  
  1744. if (featurePreviewSearch.length === 1) {
  1745. const featurePreviewButton = featurePreviewSearch[0];
  1746. const featurePreviewLi = featurePreviewButton.parentNode;
  1747.  
  1748. const newLiElement = featurePreviewLi.cloneNode(true);
  1749. newLiElement.setAttribute('id', liElementId);
  1750. newLiElement.removeAttribute('data-targets');
  1751.  
  1752. const newButton = newLiElement.querySelector('button');
  1753. newButton.removeAttribute('id');
  1754. newButton.removeAttribute('data-analytics-event');
  1755. newButton.removeAttribute('data-show-dialog-id');
  1756. newButton.removeAttribute('data-view-component');
  1757. newButton.onclick = () => {
  1758. GMC.open();
  1759.  
  1760. if (GMC.get('on_open') === 'close sidebar') HEADER.querySelector(SELECTORS.sidebars.right.closeButton)?.click();
  1761. };
  1762.  
  1763. const textElement = newLiElement.querySelector('.ActionListItem-label');
  1764. textElement.textContent = GMC.get('menu_item_title');
  1765.  
  1766. const oldSvg = newLiElement.querySelector('svg');
  1767.  
  1768. const menuItemIcon = GMC.get('menu_item_icon');
  1769. if (menuItemIcon === 'logo') {
  1770. const newSvg = document.createElement('img');
  1771. newSvg.setAttribute('height', '16px');
  1772. newSvg.setAttribute('width', '16px');
  1773. newSvg.src = `https://raw.githubusercontent.com/blakegearin/github-custom-global-navigation/main/img/${THEME}_logo.svg`;
  1774.  
  1775. oldSvg.parentNode.replaceChild(newSvg, oldSvg);
  1776. } else {
  1777. let svgString;
  1778.  
  1779. if (menuItemIcon === 'cog') {
  1780. svgString = `
  1781. <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-gear">
  1782. <path d="M8 0a8.2 8.2 0 0 1 .701.031C9.444.095 9.99.645 10.16 1.29l.288 1.107c.018.066.079.158.212.224.231.114.454.243.668.386.123.082.233.09.299.071l1.103-.303c.644-.176 1.392.021 1.82.63.27.385.506.792.704 1.218.315.675.111 1.422-.364 1.891l-.814.806c-.049.048-.098.147-.088.294.016.257.016.515 0 .772-.01.147.038.246.088.294l.814.806c.475.469.679 1.216.364 1.891a7.977 7.977 0 0 1-.704 1.217c-.428.61-1.176.807-1.82.63l-1.102-.302c-.067-.019-.177-.011-.3.071a5.909 5.909 0 0 1-.668.386c-.133.066-.194.158-.211.224l-.29 1.106c-.168.646-.715 1.196-1.458 1.26a8.006 8.006 0 0 1-1.402 0c-.743-.064-1.289-.614-1.458-1.26l-.289-1.106c-.018-.066-.079-.158-.212-.224a5.738 5.738 0 0 1-.668-.386c-.123-.082-.233-.09-.299-.071l-1.103.303c-.644.176-1.392-.021-1.82-.63a8.12 8.12 0 0 1-.704-1.218c-.315-.675-.111-1.422.363-1.891l.815-.806c.05-.048.098-.147.088-.294a6.214 6.214 0 0 1 0-.772c.01-.147-.038-.246-.088-.294l-.815-.806C.635 6.045.431 5.298.746 4.623a7.92 7.92 0 0 1 .704-1.217c.428-.61 1.176-.807 1.82-.63l1.102.302c.067.019.177.011.3-.071.214-.143.437-.272.668-.386.133-.066.194-.158.211-.224l.29-1.106C6.009.645 6.556.095 7.299.03 7.53.01 7.764 0 8 0Zm-.571 1.525c-.036.003-.108.036-.137.146l-.289 1.105c-.147.561-.549.967-.998 1.189-.173.086-.34.183-.5.29-.417.278-.97.423-1.529.27l-1.103-.303c-.109-.03-.175.016-.195.045-.22.312-.412.644-.573.99-.014.031-.021.11.059.19l.815.806c.411.406.562.957.53 1.456a4.709 4.709 0 0 0 0 .582c.032.499-.119 1.05-.53 1.456l-.815.806c-.081.08-.073.159-.059.19.162.346.353.677.573.989.02.03.085.076.195.046l1.102-.303c.56-.153 1.113-.008 1.53.27.161.107.328.204.501.29.447.222.85.629.997 1.189l.289 1.105c.029.109.101.143.137.146a6.6 6.6 0 0 0 1.142 0c.036-.003.108-.036.137-.146l.289-1.105c.147-.561.549-.967.998-1.189.173-.086.34-.183.5-.29.417-.278.97-.423 1.529-.27l1.103.303c.109.029.175-.016.195-.045.22-.313.411-.644.573-.99.014-.031.021-.11-.059-.19l-.815-.806c-.411-.406-.562-.957-.53-1.456a4.709 4.709 0 0 0 0-.582c-.032-.499.119-1.05.53-1.456l.815-.806c.081-.08.073-.159.059-.19a6.464 6.464 0 0 0-.573-.989c-.02-.03-.085-.076-.195-.046l-1.102.303c-.56.153-1.113.008-1.53-.27a4.44 4.44 0 0 0-.501-.29c-.447-.222-.85-.629-.997-1.189l-.289-1.105c-.029-.11-.101-.143-.137-.146a6.6 6.6 0 0 0-1.142 0ZM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM9.5 8a1.5 1.5 0 1 0-3.001.001A1.5 1.5 0 0 0 9.5 8Z"></path>
  1783. </svg>
  1784. `;
  1785. } else if (menuItemIcon === 'compass') {
  1786. svgString = `
  1787. <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512">
  1788. <!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
  1789. <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm306.7 69.1L162.4 380.6c-19.4 7.5-38.5-11.6-31-31l55.5-144.3c3.3-8.5 9.9-15.1 18.4-18.4l144.3-55.5c19.4-7.5 38.5 11.6 31 31L325.1 306.7c-3.2 8.5-9.9 15.1-18.4 18.4zM288 256a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/>
  1790. </svg>
  1791. `;
  1792. }
  1793.  
  1794. const parser = new DOMParser();
  1795. const svgDoc = parser.parseFromString(svgString, 'image/svg+xml');
  1796. const newSvg = svgDoc.documentElement;
  1797.  
  1798. oldSvg.parentNode.replaceChild(newSvg, oldSvg);
  1799. }
  1800.  
  1801. const parentUl = featurePreviewLi.parentNode;
  1802. const settingsLi = HEADER.querySelector('a[href="/settings/profile"]').parentNode;
  1803.  
  1804. parentUl.insertBefore(newLiElement, settingsLi.nextSibling);
  1805.  
  1806. const divider = featurePreviewLi.parentNode.querySelector('.ActionList-sectionDivider');
  1807. const newDivider = divider.cloneNode(true);
  1808.  
  1809. parentUl.insertBefore(newDivider, settingsLi.nextSibling);
  1810. } else {
  1811. setTimeout(waitForFeaturePreviewButton, 100);
  1812. }
  1813. }
  1814.  
  1815. function generateCustomConfig() {
  1816. log(DEBUG, 'generateCustomConfig()');
  1817.  
  1818. const customConfig = {
  1819. light: {},
  1820. dark: {},
  1821. };
  1822.  
  1823. function recursivelyGenerateCustomConfig(obj, customObj, themePrefix, parentKey = '') {
  1824. for (const key in obj) {
  1825. const currentKey = parentKey ? `${parentKey}.${key}` : key;
  1826. if (typeof obj[key] === 'object') {
  1827. customObj[key] = {};
  1828. recursivelyGenerateCustomConfig(obj[key], customObj[key], themePrefix, currentKey);
  1829. } else {
  1830. const gmcKey = `${themePrefix}_${currentKey.replace(/\./g, '_')}`;
  1831.  
  1832. log(VERBOSE, 'gmcKey', gmcKey);
  1833.  
  1834. customObj[key] = GMC.get(gmcKey);
  1835. }
  1836. }
  1837. }
  1838.  
  1839. recursivelyGenerateCustomConfig(configs.happyMedium.light, customConfig.light, 'light');
  1840. recursivelyGenerateCustomConfig(configs.happyMedium.dark, customConfig.dark, 'dark');
  1841.  
  1842. return customConfig;
  1843. }
  1844.  
  1845. function setTheme() {
  1846. log(DEBUG, 'setTheme()');
  1847.  
  1848. const dataColorMode = document.querySelector('html').getAttribute('data-color-mode');
  1849.  
  1850. if (dataColorMode === 'auto') {
  1851. if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  1852. THEME = 'dark';
  1853. }
  1854. } else if (dataColorMode === 'dark') {
  1855. THEME = 'dark';
  1856. } else if (dataColorMode !== 'light') {
  1857. logError('Unknown color mode');
  1858. }
  1859.  
  1860. log(VERBOSE, `THEME: ${THEME}`);
  1861. }
  1862.  
  1863. function gmcInitialized() {
  1864. log(DEBUG, 'gmcInitialized()');
  1865.  
  1866. updateLogLevel();
  1867.  
  1868. log(QUIET, 'Running');
  1869.  
  1870. GMC.css.basic = '';
  1871. window.addEventListener('load', () => {
  1872. startObserving();
  1873. });
  1874. }
  1875.  
  1876. function gmcAddSavedSpan(div) {
  1877. log(DEBUG, 'gmcAddSavedSpan()');
  1878.  
  1879. const savedDiv = document.createElement('div');
  1880. savedDiv.setAttribute('id', 'gmc-saved');
  1881.  
  1882. const iconSpan = document.createElement('span');
  1883. iconSpan.style = 'margin-right: 4px;';
  1884.  
  1885. iconSpan.innerHTML = `
  1886. <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;">
  1887. <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>
  1888. </svg>
  1889. `;
  1890.  
  1891. const textSpan = document.createElement('span');
  1892. textSpan.innerText = 'Saved';
  1893.  
  1894. savedDiv.appendChild(iconSpan);
  1895. savedDiv.appendChild(textSpan);
  1896.  
  1897. div.insertBefore(savedDiv, div.firstChild);
  1898. }
  1899.  
  1900. function gmcAddNewIssueButton(div) {
  1901. log(DEBUG, 'gmcAddNewIssueButton()');
  1902.  
  1903. const small = document.createElement('small');
  1904. small.classList.add('left-aligned');
  1905. small.setAttribute('title', 'Submit bug or feature request');
  1906.  
  1907. const link = document.createElement('a');
  1908. link.href = 'https://github.com/blakegearin/github-custom-global-navigation/issues';
  1909. link.innerText = 'submit bug or feature request';
  1910.  
  1911. small.appendChild(link);
  1912.  
  1913. div.insertBefore(small, div.firstChild);
  1914. }
  1915.  
  1916. function gmcOpened() {
  1917. log(DEBUG, 'gmcOpened()');
  1918.  
  1919. function updateCheckboxes() {
  1920. log(DEBUG, 'updateCheckboxes()');
  1921.  
  1922. const checkboxes = document.querySelectorAll('#gmc-frame input[type="checkbox"]');
  1923.  
  1924. if (checkboxes.length > 0) {
  1925. checkboxes.forEach(checkbox => {
  1926. checkbox.classList.add('gmc-checkbox');
  1927. });
  1928. } else {
  1929. setTimeout(updateCheckboxes, 100);
  1930. }
  1931. }
  1932.  
  1933. updateCheckboxes();
  1934.  
  1935. const configVars = document.querySelectorAll('.config_var');
  1936.  
  1937. configVars.forEach(configVar => {
  1938. const label = configVar.querySelector('.field_label');
  1939. const input = configVar.querySelector('input');
  1940.  
  1941. if (label && input && input.type === 'text') label.style.lineHeight = '33px';
  1942.  
  1943. const select = configVar.querySelector('select');
  1944.  
  1945. if (label && select) label.style.lineHeight = '33px';
  1946. });
  1947.  
  1948. modifyThenObserve(() => {
  1949. document.querySelector('#gmc-frame .reset_holder').remove();
  1950.  
  1951. const buttonHolderSelector = '#gmc-frame_buttons_holder';
  1952. const parentDiv = document.querySelector(buttonHolderSelector);
  1953.  
  1954. if (!parentDiv) {
  1955. logError(`Selector ${buttonHolderSelector} not found`);
  1956. return;
  1957. }
  1958.  
  1959. gmcAddSavedSpan(parentDiv);
  1960. gmcAddNewIssueButton(parentDiv);
  1961. });
  1962.  
  1963. document.querySelector('#gmc').classList.remove('hidden');
  1964. }
  1965.  
  1966. function gmcRefreshTab() {
  1967. location.reload();
  1968. }
  1969.  
  1970. function gmcRunScript() {
  1971. modifyThenObserve(() => {
  1972. document.querySelector(createId(SELECTORS.header.style))?.remove();
  1973. HEADER_STYLE.textContent = '';
  1974. });
  1975.  
  1976. applyCustomizations(true);
  1977. }
  1978.  
  1979. function updateLogLevel() {
  1980. CURRENT_LOG_LEVEL = {
  1981. 'silent': SILENT,
  1982. 'quiet': QUIET,
  1983. 'debug': DEBUG,
  1984. 'verbose': VERBOSE,
  1985. 'trace': TRACE,
  1986. }[GMC.get('log_level')];
  1987. }
  1988.  
  1989. function gmcSaved() {
  1990. log(DEBUG, 'gmcSaved()');
  1991.  
  1992. const gmcSaved = document.getElementById('gmc-saved');
  1993.  
  1994. gmcSaved.style.display = 'block';
  1995.  
  1996. setTimeout(
  1997. () => gmcSaved.style.display = 'none',
  1998. 2750,
  1999. );
  2000.  
  2001. updateLogLevel();
  2002.  
  2003. switch (GMC.get('on_save')) {
  2004. case 'refresh tab':
  2005. gmcRefreshTab();
  2006. break;
  2007. case 'refresh tab and close':
  2008. gmcRefreshTab();
  2009. GMC.close();
  2010. break;
  2011. case 'run script':
  2012. gmcRunScript();
  2013. break;
  2014. case 'run script and close':
  2015. gmcRunScript();
  2016. GMC.close();
  2017. break;
  2018. }
  2019. }
  2020.  
  2021. function gmcClosed() {
  2022. log(DEBUG, 'gmcClosed()');
  2023.  
  2024. switch (GMC.get('on_close')) {
  2025. case 'refresh tab':
  2026. gmcRefreshTab();
  2027. break;
  2028. case 'run script':
  2029. gmcRunScript();
  2030. break;
  2031. }
  2032.  
  2033. document.querySelector('#gmc').classList.add('hidden');
  2034. }
  2035.  
  2036. function gmcClearCustom() {
  2037. log(DEBUG, 'gmcClearCustom()');
  2038.  
  2039. const confirmed = confirm('Are you sure you want to clear your custom configuration? This is irreversible.');
  2040.  
  2041. if (confirmed) {
  2042. const currentType = GMC.get('type');
  2043. GMC.reset();
  2044. GMC.save();
  2045.  
  2046. GMC.set('type', currentType);
  2047. GMC.save();
  2048. }
  2049. }
  2050.  
  2051. function configsToGMC(config, path = []) {
  2052. log(DEBUG, 'configsToGMC()');
  2053.  
  2054. for (const key in config) {
  2055. if (typeof config[key] === 'object' && !Array.isArray(config[key])) {
  2056. configsToGMC(config[key], path.concat(key));
  2057. } else {
  2058. const fieldName = path.concat(key).join('_');
  2059. const fieldValue = config[key];
  2060.  
  2061. log(VERBOSE, 'fieldName', fieldName);
  2062. GMC.set(fieldName, fieldValue);
  2063. }
  2064. }
  2065. }
  2066.  
  2067. function gmcApplyCustomHappyMediumConfig() {
  2068. log(DEBUG, 'gmcApplyCustomHappyMediumConfig()');
  2069.  
  2070. const confirmed = confirm('Are you sure you want to overwrite your custom configuration with Happy Medium? This is irreversible.');
  2071.  
  2072. if (confirmed) {
  2073. configsToGMC(configs.happyMedium);
  2074. GMC.save();
  2075. }
  2076. }
  2077.  
  2078. function gmcApplyCustomOldSchoolConfig() {
  2079. log(DEBUG, 'gmcApplyCustomOldSchoolConfig()');
  2080.  
  2081. const confirmed = confirm('Are you sure you want to overwrite your custom configuration with Old School? This is irreversible.');
  2082.  
  2083. if (confirmed) {
  2084. configsToGMC(configs.oldSchool);
  2085. GMC.save();
  2086. }
  2087. }
  2088.  
  2089. function gmcBuildStyle() {
  2090. log(DEBUG, 'gmcBuildStyle()');
  2091.  
  2092. const gmcFrameStyle = document.createElement('style');
  2093. gmcFrameStyle.textContent += `
  2094. /* Modal */
  2095.  
  2096. #gmc
  2097. {
  2098. display: inline-flex !important;
  2099. justify-content: center !important;
  2100. align-items: center !important;
  2101. position: fixed !important;
  2102. top: 0 !important;
  2103. left: 0 !important;
  2104. width: 100vw !important;
  2105. height: 100vh !important;
  2106. z-index: 9999;
  2107. background: none !important;
  2108.  
  2109. pointer-events: none;
  2110. }
  2111.  
  2112. #gmc.hidden
  2113. {
  2114. display: none !important;
  2115. }
  2116.  
  2117. #gmc-frame
  2118. {
  2119. font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
  2120. text-align: left;
  2121.  
  2122. inset: initial !important;
  2123. border: none !important;
  2124. max-height: initial !important;
  2125. max-width: initial !important;
  2126. opacity: 1 !important;
  2127. position: static !important;
  2128. z-index: initial !important;
  2129.  
  2130. width: 85% !important;
  2131. height: 75% !important;
  2132. overflow-y: auto !important;
  2133.  
  2134. border: none !important;
  2135. border-radius: 0.375rem !important;
  2136.  
  2137. pointer-events: auto;
  2138. }
  2139.  
  2140. #gmc-frame_wrapper
  2141. {
  2142. display: flow-root !important;
  2143. padding: 2rem !important;
  2144. }
  2145.  
  2146. /* Sections */
  2147.  
  2148. #gmc-frame #gmc-frame_section_0
  2149. {
  2150. width: 100%;
  2151. border-radius: 6px;
  2152. display: table;
  2153. }
  2154.  
  2155. #gmc-frame #gmc-frame_section_1,
  2156. #gmc-frame #gmc-frame_section_2,
  2157. #gmc-frame #gmc-frame_section_3,
  2158. #gmc-frame #gmc-frame_section_4
  2159. {
  2160. margin-top: 2rem;
  2161. width: 49%;
  2162. box-sizing: border-box;
  2163. }
  2164.  
  2165. #gmc-frame #gmc-frame_section_1
  2166. {
  2167. border-radius: 6px;
  2168. float: left;
  2169. }
  2170.  
  2171. #gmc-frame #gmc-frame_section_2
  2172. {
  2173. border-radius: 6px;
  2174. float: right;
  2175. }
  2176.  
  2177. #gmc-frame #gmc-frame_section_3
  2178. {
  2179. width: 49%;
  2180. margin-top: 2rem;
  2181. box-sizing: border-box;
  2182. border-radius: 6px;
  2183. float: left;
  2184. }
  2185.  
  2186. #gmc-frame #gmc-frame_section_4
  2187. {
  2188. display: inline-grid;
  2189. width: 49%;
  2190. margin-top: 2rem;
  2191. box-sizing: border-box;
  2192. border-radius: 6px;
  2193. float: right
  2194. }
  2195.  
  2196. #gmc-frame #gmc-frame_section_3 .config_var:not(:last-child),
  2197. #gmc-frame #gmc-frame_section_4 .config_var:not(:last-child)
  2198. {
  2199. padding-bottom: 1rem;
  2200. }
  2201.  
  2202. /* Fields */
  2203.  
  2204. #gmc-frame .config_header
  2205. {
  2206. font-size: 2em;
  2207. font-weight: 400;
  2208. line-height: 1.25;
  2209.  
  2210. padding-bottom: 0.3em;
  2211. margin-bottom: 16px;
  2212. }
  2213.  
  2214. #gmc-frame #gmc-frame_type_var
  2215. {
  2216. display: inline-flex;
  2217. }
  2218.  
  2219. #gmc-frame .section_header
  2220. {
  2221. font-size: 1.5em;
  2222. font-weight: 600;
  2223. line-height: 1.25;
  2224.  
  2225. margin-bottom: 16px;
  2226. padding: 1rem 1.5rem;
  2227. }
  2228.  
  2229. #gmc-frame .section_desc,
  2230. #gmc-frame h3
  2231. {
  2232. background: none;
  2233. border: none;
  2234. font-size: 1.25em;
  2235.  
  2236. margin-bottom: 16px;
  2237. font-weight: 600;
  2238. line-height: 1.25;
  2239. text-align: left;
  2240. }
  2241.  
  2242. #gmc-frame .config_var
  2243. {
  2244. padding: 0rem 1.5rem;
  2245. margin-bottom: 1rem;
  2246. display: flex;
  2247. }
  2248.  
  2249. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2250. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2251. #gmc-frame .config_var[id*='logo_remove_var'],
  2252. #gmc-frame .config_var[id*='pageTitle_remove_var'],
  2253. #gmc-frame .config_var[id*='search_backgroundColor_var'],
  2254. #gmc-frame .config_var[id*='divider_remove_var'],
  2255. #gmc-frame .config_var[id*='create_remove_var'],
  2256. #gmc-frame .config_var[id*='issues_remove_var'],
  2257. #gmc-frame .config_var[id*='pullRequests_remove_var'],
  2258. #gmc-frame .config_var[id*='notifications_remove_var'],
  2259. #gmc-frame .config_var[id*='avatar_size_var'],
  2260. #gmc-frame .config_var[id*='globalBar_boxShadowColor_var'],
  2261. #gmc-frame .config_var[id*='localBar_backgroundColor_var'],
  2262. #gmc-frame .config_var[id*='sidebars_backdrop_color_var'],
  2263. #gmc-frame .config_var[id*='repositoryHeader_import_var'],
  2264. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2265. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2266. {
  2267. display: flow;
  2268. padding-top: 1rem;
  2269. }
  2270.  
  2271. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2272. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2273. {
  2274. display: flex;
  2275. }
  2276.  
  2277. #gmc-frame .field_label
  2278. {
  2279. font-weight: 600;
  2280. margin-right: 0.5rem;
  2281. }
  2282.  
  2283. #gmc-frame .field_label,
  2284. #gmc-frame .gmc-label
  2285. {
  2286. width: 15vw;
  2287. }
  2288.  
  2289. #gmc-frame .radio_label:not(:last-child)
  2290. {
  2291. margin-right: 4rem;
  2292. }
  2293.  
  2294. #gmc-frame .radio_label
  2295. {
  2296. line-height: 17px;
  2297. }
  2298.  
  2299. #gmc-frame .gmc-label
  2300. {
  2301. display: table-caption;
  2302. line-height: 17px;
  2303. }
  2304.  
  2305. #gmc-frame input[type="radio"]
  2306. {
  2307. appearance: none;
  2308. border-style: solid;
  2309. cursor: pointer;
  2310. height: 1rem;
  2311. place-content: center;
  2312. position: relative;
  2313. width: 1rem;
  2314. border-radius: 624rem;
  2315. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s;
  2316. margin-right: 0.5rem;
  2317. flex: none;
  2318. }
  2319.  
  2320. #gmc-frame input[type="checkbox"]
  2321. {
  2322. appearance: none;
  2323. border-style: solid;
  2324. border-width: 1px;
  2325. cursor: pointer;
  2326. place-content: center;
  2327. position: relative;
  2328. height: 17px;
  2329. width: 17px;
  2330. border-radius: 3px;
  2331. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s;
  2332. }
  2333.  
  2334. #gmc-frame #gmc-frame_field_type
  2335. {
  2336. display: flex;
  2337. }
  2338.  
  2339. #gmc-frame input[type="radio"]:checked
  2340. {
  2341. border-width: 0.25rem;
  2342. }
  2343.  
  2344. #gmc-frame input[type="radio"]:checked,
  2345. #gmc-frame .gmc-checkbox:checked
  2346. {
  2347. border-color: #2f81f7;
  2348. }
  2349.  
  2350. #gmc-frame .gmc-checkbox:checked
  2351. {
  2352. background-color: #2f81f7;
  2353. }
  2354.  
  2355. #gmc-frame .gmc-checkbox:checked::before
  2356. {
  2357. visibility: visible;
  2358. transition: visibility 0s linear 0s;
  2359. }
  2360.  
  2361. #gmc-frame .gmc-checkbox::before,
  2362. #gmc-frame .gmc-checkbox:indeterminate::before
  2363. {
  2364. animation: 80ms cubic-bezier(0.65, 0, 0.35, 1) 80ms 1 normal forwards running checkmarkIn;
  2365. }
  2366.  
  2367. #gmc-frame .gmc-checkbox::before
  2368. {
  2369. width: 1rem;
  2370. height: 1rem;
  2371. visibility: hidden;
  2372. content: "";
  2373. background-color: #FFFFFF;
  2374. clip-path: inset(1rem 0 0 0);
  2375. -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTEuNzgwMyAwLjIxOTYyNUMxMS45MjEgMC4zNjA0MjcgMTIgMC41NTEzMDUgMTIgMC43NTAzMTNDMTIgMC45NDkzMjEgMTEuOTIxIDEuMTQwMTkgMTEuNzgwMyAxLjI4MUw0LjUxODYgOC41NDA0MkM0LjM3Nzc1IDguNjgxIDQuMTg2ODIgOC43NiAzLjk4Nzc0IDguNzZDMy43ODg2NyA4Ljc2IDMuNTk3NzMgOC42ODEgMy40NTY4OSA4LjU0MDQyTDAuMjAxNjIyIDUuMjg2MkMwLjA2ODkyNzcgNS4xNDM4MyAtMC4wMDMzMDkwNSA0Ljk1NTU1IDAuMDAwMTE2NDkzIDQuNzYwOThDMC4wMDM1NTIwNSA0LjU2NjQzIDAuMDgyMzg5NCA0LjM4MDgxIDAuMjIwMDMyIDQuMjQzMjFDMC4zNTc2NjUgNC4xMDU2MiAwLjU0MzM1NSA0LjAyNjgxIDAuNzM3OTcgNC4wMjMzOEMwLjkzMjU4NCA0LjAxOTk0IDEuMTIwOTMgNC4wOTIxNyAxLjI2MzM0IDQuMjI0ODJMMy45ODc3NCA2Ljk0ODM1TDEwLjcxODYgMC4yMTk2MjVDMTAuODU5NSAwLjA3ODk5MjMgMTEuMDUwNCAwIDExLjI0OTUgMEMxMS40NDg1IDAgMTEuNjM5NSAwLjA3ODk5MjMgMTEuNzgwMyAwLjIxOTYyNVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=");
  2376. -webkit-mask-size: 75%;
  2377. -webkit-mask-repeat: no-repeat;
  2378. -webkit-mask-position: center center;
  2379. display: block;
  2380. }
  2381.  
  2382. #gmc-frame .gmc-checkbox
  2383. {
  2384. appearance: none;
  2385. border-style: solid;
  2386. border-width: 1px;
  2387. cursor: pointer;
  2388.  
  2389. height: var(--base-size-16,16px);
  2390. margin: 0.125rem 0px 0px;
  2391. place-content: center;
  2392. position: relative;
  2393. width: var(--base-size-16,16px);
  2394. border-radius: 3px;
  2395. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s;
  2396. }
  2397.  
  2398. #gmc-frame input
  2399. {
  2400. color: fieldtext;
  2401. letter-spacing: normal;
  2402. word-spacing: normal;
  2403. text-transform: none;
  2404. text-indent: 0px;
  2405. text-shadow: none;
  2406. display: inline-block;
  2407. text-align: start;
  2408. appearance: auto;
  2409. -webkit-rtl-ordering: logical;
  2410. }
  2411.  
  2412. #gmc-frame .gmc-checkbox:checked
  2413. {
  2414. transition: background-color 0s ease 0s, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms;
  2415. }
  2416.  
  2417. #gmc-frame input[type="text"],
  2418. #gmc-frame textarea,
  2419. #gmc-frame select
  2420. {
  2421. padding: 5px 12px;
  2422. border-radius: 6px;
  2423. }
  2424.  
  2425. #gmc-frame input[type="text"]:focus,
  2426. #gmc-frame textarea:focus,
  2427. #gmc-frame select:focus
  2428. {
  2429. border-color: #2f81f7;
  2430. outline: 1px solid #2f81f7;
  2431. }
  2432.  
  2433. #gmc-frame svg
  2434. {
  2435. height: 17px;
  2436. width: 17px;
  2437. margin-left: 0.5rem;
  2438. }
  2439.  
  2440. #gmc small
  2441. {
  2442. font-size: x-small;
  2443. font-weight: 600;
  2444. margin-left: 3px;
  2445. }
  2446.  
  2447. /* Button bar */
  2448.  
  2449. #gmc-frame #gmc-frame_buttons_holder
  2450. {
  2451. position: fixed;
  2452. width: 85%;
  2453. text-align: right;
  2454.  
  2455. left: 50%;
  2456. bottom: 2%;
  2457. transform: translate(-50%, 0%);
  2458. padding: 1rem;
  2459.  
  2460. border-radius: 0.375rem;
  2461.  
  2462. display: flex;
  2463. align-items: center;
  2464. }
  2465.  
  2466. #gmc-frame #gmc-frame_buttons_holder .left-aligned
  2467. {
  2468. order: 1;
  2469. margin-right: auto;
  2470. }
  2471.  
  2472. #gmc-frame #gmc-frame_buttons_holder > *
  2473. {
  2474. order: 2;
  2475. }
  2476.  
  2477. #gmc-frame .saveclose_buttons
  2478. {
  2479. margin-left: 0.5rem;
  2480. }
  2481.  
  2482. #gmc-frame [type=button],
  2483. #gmc-frame .saveclose_buttons
  2484. {
  2485. position: relative;
  2486. display: inline-block;
  2487. padding: 5px 16px;
  2488. font-size: 14px;
  2489. font-weight: 500;
  2490. line-height: 20px;
  2491. white-space: nowrap;
  2492. vertical-align: middle;
  2493. cursor: pointer;
  2494. -webkit-user-select: none;
  2495. user-select: none;
  2496. border: 1px solid;
  2497. border-radius: 6px;
  2498. -webkit-appearance: none;
  2499. appearance: none;
  2500.  
  2501. font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
  2502. }
  2503.  
  2504. @keyframes fadeOut
  2505. {
  2506. from {
  2507. opacity: 1;
  2508. }
  2509. to {
  2510. opacity: 0;
  2511. }
  2512. }
  2513.  
  2514. #gmc-saved
  2515. {
  2516. display: none;
  2517. margin-right: 10px;
  2518. animation: fadeOut 0.75s ease 2s forwards;
  2519. }
  2520. `;
  2521.  
  2522. if (THEME === 'light') {
  2523. gmcFrameStyle.textContent += `
  2524. #gmc-frame
  2525. {
  2526. background-color: #F6F8FA;
  2527. color: #1F2328;
  2528. box-shadow: 0 0 0 1px #D0D7DE, 0 16px 32px rgba(1,4,9,0.2) !important;
  2529. }
  2530.  
  2531. #gmc-frame .section_header_holder
  2532. {
  2533. background-color: #FFFFFF;
  2534. border: 1px solid #D0D7DE;
  2535. }
  2536.  
  2537. #gmc-frame_buttons_holder
  2538. {
  2539. background-color: #FFFFFF;
  2540. box-shadow: 0 0 0 1px #D0D7DE, 0 16px 32px rgba(1,4,9,0.2) !important;
  2541. }
  2542.  
  2543. #gmc-frame input[type="text"],
  2544. #gmc-frame textarea,
  2545. #gmc-frame select
  2546. {
  2547. border: 1px solid #D0D7DE;
  2548. }
  2549.  
  2550. #gmc-frame select
  2551. {
  2552. background-color: #F6F8FA;
  2553. }
  2554.  
  2555. #gmc-frame select:hover
  2556. {
  2557. background-color: #F3F4F6;
  2558. border-color: #1F232826;
  2559. }
  2560.  
  2561. #gmc-frame input[type="text"],
  2562. #gmc-frame textarea
  2563. {
  2564. background-color: #F6F8FA;
  2565. color: #1F2328;
  2566. }
  2567.  
  2568. #gmc-frame input[type="text"]:focus,
  2569. #gmc-frame textarea:focus
  2570. {
  2571. background-color: #FFFFFF;
  2572. }
  2573.  
  2574. #gmc-frame [type=button],
  2575. #gmc-frame .saveclose_buttons
  2576. {
  2577. background-color: #f6f8fa;
  2578. border-color: #1f232826;
  2579. box-shadow: 0 1px 0 rgba(31,35,40,0.04), inset 0 1px 0 rgba(255,255,255,0.25);
  2580. color: #24292f;
  2581. }
  2582.  
  2583. #gmc-frame [type=button]:hover,
  2584. #gmc-frame .saveclose_buttons:hover
  2585. {
  2586. background-color: #f3f4f6;
  2587. border-color: #1f232826;
  2588. }
  2589.  
  2590. #gmc-frame .gmc-checkbox
  2591. {
  2592. border-color: #6E7781;
  2593. }
  2594.  
  2595. #gmc-frame input[type="radio"]
  2596. {
  2597. color: #6E7781;
  2598. }
  2599.  
  2600. #gmc-frame svg
  2601. {
  2602. fill: #000000;
  2603. }
  2604.  
  2605. #gmc-frame .section_header
  2606. {
  2607. border-bottom: 1px solid #D0D7DE;
  2608. }
  2609.  
  2610. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2611. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2612. #gmc-frame .config_var[id*='logo_remove_var'],
  2613. #gmc-frame .config_var[id*='pageTitle_remove_var'],
  2614. #gmc-frame .config_var[id*='search_backgroundColor_var'],
  2615. #gmc-frame .config_var[id*='divider_remove_var'],
  2616. #gmc-frame .config_var[id*='create_remove_var'],
  2617. #gmc-frame .config_var[id*='issues_remove_var'],
  2618. #gmc-frame .config_var[id*='pullRequests_remove_var'],
  2619. #gmc-frame .config_var[id*='notifications_remove_var'],
  2620. #gmc-frame .config_var[id*='avatar_size_var'],
  2621. #gmc-frame .config_var[id*='globalBar_boxShadowColor_var'],
  2622. #gmc-frame .config_var[id*='localBar_backgroundColor_var'],
  2623. #gmc-frame .config_var[id*='sidebars_backdrop_color_var'],
  2624. #gmc-frame .config_var[id*='repositoryHeader_import_var'],
  2625. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2626. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2627. {
  2628. border-top: 1px solid #D0D7DE;
  2629. }
  2630.  
  2631. #gmc-frame #gmc-frame_section_3 .config_var:not(:last-child),
  2632. #gmc-frame #gmc-frame_section_4 .config_var:not(:last-child)
  2633. {
  2634. border-bottom: 1px solid #D0D7DE;
  2635. }
  2636.  
  2637. #gmc-frame #gmc-frame_saveBtn
  2638. {
  2639. background-color: #1F883D;
  2640. border-color: rgba(31, 35, 40, 0.15);
  2641. box-shadow: rgba(31, 35, 40, 0.1) 0px 1px 0px;
  2642. color: #FFFFFF;
  2643. }
  2644.  
  2645. #gmc-frame #gmc-frame_saveBtn:hover
  2646. {
  2647. background-color: rgb(26, 127, 55);
  2648. }
  2649.  
  2650. #gmc-frame #gmc-frame_section_4
  2651. {
  2652. border: 1px solid #FF818266;
  2653. }
  2654.  
  2655. #gmc-frame #gmc-frame_section_4 input
  2656. {
  2657. background-color: #F6F8FA;
  2658. border-color: #1F232826;
  2659. box-shadow: 0 1px 0 rgba(31,35,40,0.04), inset 0 1px 0 rgba(255,255,255,0.25);
  2660. color: #CF222E;
  2661. }
  2662.  
  2663. #gmc-frame #gmc-frame_section_4 input:hover
  2664. {
  2665. background-color: #A40E26;
  2666. border-color: #1F232826;
  2667. box-shadow: 0 1px 0 rgba(31,35,40,0.04);
  2668. color: #ffffff;
  2669. }
  2670.  
  2671. #gmc-saved
  2672. {
  2673. color: #1a7f37;
  2674. }
  2675.  
  2676. #gmc-saved svg path
  2677. {
  2678. fill: #1a7f37;
  2679. }
  2680. `;
  2681. } else if (THEME === 'dark') {
  2682. gmcFrameStyle.textContent += `
  2683. #gmc-frame
  2684. {
  2685. background-color: #161B22;
  2686. color: #E6EDF3;
  2687. box-shadow: 0 0 0 1px #30363D, 0 16px 32px #010409 !important;
  2688. }
  2689.  
  2690. #gmc-frame .section_header_holder
  2691. {
  2692. background-color: #0D1117;
  2693. border: 1px solid #30363D;
  2694. }
  2695.  
  2696. #gmc-frame_buttons_holder
  2697. {
  2698. background-color: #161B22;
  2699. box-shadow: 0 0 0 1px #30363D, 0 16px 32px #010409 !important;
  2700. }
  2701.  
  2702. #gmc-frame input[type="text"],
  2703. #gmc-frame textarea,
  2704. #gmc-frame select
  2705. {
  2706. border: 1px solid #5B626C;
  2707. }
  2708.  
  2709. #gmc-frame input[type="text"],
  2710. #gmc-frame textarea
  2711. {
  2712. background-color: #010409;
  2713. color: #FFFFFF;
  2714. }
  2715.  
  2716. #gmc-frame [type=button]:hover,
  2717. #gmc-frame .saveclose_buttons:hover
  2718. {
  2719. background-color: #30363d;
  2720. border-color: #8b949e;
  2721. }
  2722.  
  2723. #gmc-frame .gmc-checkbox
  2724. {
  2725. border-color: #6E7681;
  2726. }
  2727.  
  2728. #gmc-frame input[type="radio"]
  2729. {
  2730. color: #6D7681;
  2731. }
  2732.  
  2733. #gmc-frame input[type="text"]:focus,
  2734. textarea:focus
  2735. {
  2736. background-color: #0D1117;
  2737. }
  2738.  
  2739. #gmc-frame [type=button],
  2740. #gmc-frame .saveclose_buttons
  2741. {
  2742. color: #c9d1d9;
  2743. background-color: #21262d;
  2744. border-color: #f0f6fc1a;
  2745. }
  2746.  
  2747. #gmc-frame svg
  2748. {
  2749. fill: #E6EDF3;
  2750. }
  2751.  
  2752. #gmc-frame .section_header
  2753. {
  2754. border-bottom: 1px solid #30363D;
  2755. }
  2756.  
  2757. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2758. #gmc-frame .config_var[id*='hamburgerButton_remove_var'],
  2759. #gmc-frame .config_var[id*='logo_remove_var'],
  2760. #gmc-frame .config_var[id*='pageTitle_remove_var'],
  2761. #gmc-frame .config_var[id*='search_backgroundColor_var'],
  2762. #gmc-frame .config_var[id*='divider_remove_var'],
  2763. #gmc-frame .config_var[id*='create_remove_var'],
  2764. #gmc-frame .config_var[id*='issues_remove_var'],
  2765. #gmc-frame .config_var[id*='pullRequests_remove_var'],
  2766. #gmc-frame .config_var[id*='notifications_remove_var'],
  2767. #gmc-frame .config_var[id*='avatar_size_var'],
  2768. #gmc-frame .config_var[id*='globalBar_boxShadowColor_var'],
  2769. #gmc-frame .config_var[id*='localBar_backgroundColor_var'],
  2770. #gmc-frame .config_var[id*='sidebars_backdrop_color_var'],
  2771. #gmc-frame .config_var[id*='repositoryHeader_import_var'],
  2772. #gmc-frame .config_var[id*='flipCreateInbox_var'],
  2773. #gmc-frame .config_var[id*='flipIssuesPullRequests_var']
  2774. {
  2775. border-top: 1px solid #30363D;
  2776. }
  2777.  
  2778. #gmc-frame #gmc-frame_section_3 .config_var:not(:last-child),
  2779. #gmc-frame #gmc-frame_section_4 .config_var:not(:last-child)
  2780. {
  2781. padding-bottom: 1rem;
  2782. border-bottom: 1px solid #30363D;
  2783. }
  2784.  
  2785. #gmc-frame #gmc-frame_saveBtn
  2786. {
  2787. background-color: #238636;
  2788. border-color: #F0F6FC1A;
  2789. box-shadow: 0 0 transparent;
  2790. color: #FFFFFF;
  2791. }
  2792.  
  2793. #gmc-frame #gmc-frame_saveBtn:hover
  2794. {
  2795. background-color: #2EA043;
  2796. border-color: #F0F6FC1A;
  2797. }
  2798.  
  2799. #gmc-frame #gmc-frame_section_4
  2800. {
  2801. border: 1px solid #f8514966;
  2802. }
  2803.  
  2804. #gmc-frame #gmc-frame_section_4 input
  2805. {
  2806. background-color: #21262D;
  2807. border-color: #F0F6FC1A;
  2808. }
  2809.  
  2810. #gmc-frame #gmc-frame_section_4 input
  2811. {
  2812. color: #F85149;
  2813. }
  2814.  
  2815. #gmc-frame #gmc-frame_section_4 input:hover
  2816. {
  2817. background-color: #DA3633;
  2818. border-color: #F85149;
  2819. color: #FFFFFF;
  2820. }
  2821.  
  2822. #gmc-saved
  2823. {
  2824. color: #3FB950;
  2825. }
  2826.  
  2827. #gmc-saved svg path
  2828. {
  2829. fill: #3FB950;
  2830. }
  2831. `;
  2832. }
  2833.  
  2834. document.head.appendChild(gmcFrameStyle);
  2835. }
  2836.  
  2837. function gmcBuildFrame() {
  2838. log(DEBUG, 'gmcBuildFrame()');
  2839.  
  2840. const body = document.querySelector('body');
  2841. const gmcDiv = document.createElement('div');
  2842.  
  2843. gmcDiv.setAttribute('id', 'gmc');
  2844. gmcDiv.classList.add('hidden');
  2845.  
  2846. body.appendChild(gmcDiv);
  2847.  
  2848. const gmcFrameDiv = document.createElement('div');
  2849. gmcFrameDiv.id = 'gmc-frame';
  2850.  
  2851. gmcDiv.appendChild(gmcFrameDiv);
  2852.  
  2853. gmcBuildStyle();
  2854.  
  2855. return gmcFrameDiv;
  2856. }
  2857.  
  2858. function applyCustomizations(refresh = false) {
  2859. log(DEBUG, 'applyCustomizations()');
  2860.  
  2861. HEADER = document.querySelector(SELECTORS.header.self);
  2862.  
  2863. if (!HEADER) return 'continue';
  2864.  
  2865. const featurePreviewButton = document.querySelector(SELECTORS.avatar.button);
  2866.  
  2867. if (!featurePreviewButton) {
  2868. logError(`Selector ${SELECTORS.avatar.button} not found`);
  2869. return 'break';
  2870. }
  2871.  
  2872. featurePreviewButton.addEventListener('click', waitForFeaturePreviewButton);
  2873.  
  2874. const configName = {
  2875. 'Off': 'off',
  2876. 'Happy Medium': 'happyMedium',
  2877. 'Old School': 'oldSchool',
  2878. 'Custom': 'custom',
  2879. }[GMC.get('type')];
  2880.  
  2881. if (configName === 'off') return 'break';
  2882.  
  2883. if (configName === 'custom') configs.custom = generateCustomConfig();
  2884.  
  2885. CONFIG = configs[configName][THEME];
  2886.  
  2887. log(VERBOSE, 'CONFIG', CONFIG);
  2888.  
  2889. const headerSuccessFlag = 'customizedHeader';
  2890.  
  2891. if (!document.getElementById(headerSuccessFlag) || refresh) {
  2892. updateSelectors();
  2893.  
  2894. if (configName === 'oldSchool') {
  2895. HEADER_STYLE.textContent += `
  2896. @media (max-width: 767.98px)
  2897. {
  2898. action-menu
  2899. {
  2900. display: none !important;
  2901. }
  2902. }
  2903. `;
  2904. }
  2905.  
  2906. HEADER_UPDATES_COUNT++;
  2907. updateHeader();
  2908.  
  2909. HEADER.setAttribute('id', headerSuccessFlag);
  2910.  
  2911. log(QUIET, 'Complete');
  2912.  
  2913. return 'break';
  2914. } else {
  2915. if (CONFIG.avatar.dropdownIcon) insertAvatarDropdown();
  2916. if (CONFIG.avatar.canCloseSidebar) updateAvatarButton();
  2917.  
  2918. if (CONFIG.repositoryHeader.import) {
  2919. // When starting in a repository tab like Issues, the proper repository header
  2920. // (including Unwatch, Star, and Fork) is not present per GitHub's design.
  2921. // If page title is removed, the page will be missing any location context in the header.
  2922. // To improve this experience, a temporary repository header is created with the
  2923. // page title or breadcrumbs.
  2924. // The proper repository header replaces the temporary one when navigating to the Code tab.
  2925. if (
  2926. !document.querySelector(SELECTORS.repositoryHeader.id)?.hidden &&
  2927. (
  2928. document.querySelector(createId(TEMP_REPOSITORY_HEADER_FLAG)) ||
  2929. !document.querySelector(`.${REPOSITORY_HEADER_SUCCESS_FLAG}`)
  2930. )
  2931. ) {
  2932. const updated = importRepositoryHeader();
  2933.  
  2934. if (updated) {
  2935. log(QUIET, 'Repository header updated');
  2936. } else {
  2937. IDLE_MUTATION_COUNT++;
  2938. }
  2939.  
  2940. return 'break';
  2941. }
  2942. }
  2943. }
  2944.  
  2945. if (CONFIG.avatar.dropdownIcon) insertAvatarDropdown();
  2946. }
  2947.  
  2948. function startObserving() {
  2949. log(DEBUG, 'startObserving()');
  2950.  
  2951. OBSERVER.observe(
  2952. document.body,
  2953. {
  2954. childList: true,
  2955. subtree: true,
  2956. },
  2957. );
  2958. }
  2959.  
  2960. function modifyThenObserve(callback) {
  2961. log(DEBUG, 'modifyThenObserve()');
  2962. OBSERVER.disconnect();
  2963.  
  2964. callback();
  2965.  
  2966. startObserving();
  2967. }
  2968.  
  2969. function observeAndModify(mutationsList) {
  2970. log(VERBOSE, 'observeAndModify()');
  2971.  
  2972. if (IDLE_MUTATION_COUNT > MAX_IDLE_MUTATIONS) {
  2973. // This is a failsafe to prevent infinite loops
  2974. logError('MAX_IDLE_MUTATIONS exceeded');
  2975. OBSERVER.disconnect();
  2976.  
  2977. return;
  2978. } else if (HEADER_UPDATES_COUNT >= MAX_HEADER_UPDATES) {
  2979. // This is a failsafe to prevent infinite loops
  2980. logError('MAX_HEADER_UPDATES exceeded');
  2981. OBSERVER.disconnect();
  2982.  
  2983. return;
  2984. }
  2985.  
  2986. for (const mutation of mutationsList) {
  2987. // Use header id to determine if updates have already been applied
  2988. if (mutation.type !== 'childList') return;
  2989.  
  2990. log(TRACE, 'mutation', mutation);
  2991.  
  2992. const outcome = applyCustomizations();
  2993.  
  2994. if (outcome === 'continue') continue;
  2995. if (outcome === 'break') break;
  2996. }
  2997. }
  2998.  
  2999. const UNICODE_NON_BREAKING_SPACE = '\u00A0';
  3000. const REPOSITORY_HEADER_SUCCESS_FLAG = 'permCustomizedRepositoryHeader';
  3001. const TEMP_REPOSITORY_HEADER_FLAG = 'tempCustomizedRepositoryHeader';
  3002. const REPOSITORY_HEADER_CLASS = 'customizedRepositoryHeader';
  3003. const MAX_IDLE_MUTATIONS = 1000;
  3004. const MAX_HEADER_UPDATES = 100;
  3005.  
  3006. let CONFIG;
  3007. let HEADER;
  3008. let HEADER_STYLE = document.createElement('style');
  3009.  
  3010. let THEME = 'light';
  3011. let IDLE_MUTATION_COUNT = 0;
  3012. let HEADER_UPDATES_COUNT = 0;
  3013. let SELECTORS = {
  3014. header: {
  3015. self: 'header.AppHeader',
  3016. actionsDiv: '.AppHeader-actions',
  3017. globalBar: '.AppHeader-globalBar',
  3018. localBar: {
  3019. topDiv: '.AppHeader-localBar',
  3020. underlineNavActions: '.UnderlineNav-actions'
  3021. },
  3022. leftAligned: '.AppHeader-globalBar-start',
  3023. rightAligned: '.AppHeader-globalBar-end',
  3024. style: 'customHeaderStyle',
  3025. },
  3026. logo: {
  3027. topDiv: '.AppHeader-globalBar-start .AppHeader-logo',
  3028. svg: '.AppHeader-logo svg',
  3029. },
  3030. hamburgerButton: '.AppHeader-globalBar-start deferred-side-panel',
  3031. pageTitle: {
  3032. id: 'custom-page-title',
  3033. topDiv: '.AppHeader-context',
  3034. links: '.AppHeader-context a',
  3035. separator: '.AppHeader-context-item-separator',
  3036. },
  3037. search: {
  3038. id: 'search-div',
  3039. topDiv: '.AppHeader-search',
  3040. input: '.search-input',
  3041. button: '[data-target="qbsearch-input.inputButton"]',
  3042. magnifyingGlassIcon: '.AppHeader-search-control label',
  3043. commandPalette: '#AppHeader-commandPalette-button',
  3044. placeholderSpan: '#qb-input-query',
  3045. placeholderDiv: '.AppHeader-search-control .overflow-hidden',
  3046. modal: '[data-target="qbsearch-input.queryBuilderContainer"]',
  3047. },
  3048. create: {
  3049. id: 'create-div',
  3050. topDiv: 'action-menu',
  3051. button: '#global-create-menu-button',
  3052. plusIcon: '#global-create-menu-button .Button-visual.Button-leadingVisual',
  3053. dropdownIcon: '#global-create-menu-button .Button-label',
  3054. textContent: 'create-text-content-span',
  3055. },
  3056. issues: {
  3057. id: 'issues-div',
  3058. topDiv: '#issues-div',
  3059. textContent: 'issues-text-content-span',
  3060. },
  3061. pullRequests: {
  3062. id: 'pullRequests-div',
  3063. topDiv: '#pullRequests-div',
  3064. textContent: 'pullRequests-text-content-span',
  3065. },
  3066. notifications: {
  3067. id: 'custom-notifications',
  3068. indicator: 'notification-indicator',
  3069. dot: '.AppHeader-button.AppHeader-button--hasIndicator::before',
  3070. textContent: 'textContent-text-content-spa'
  3071. },
  3072. avatar: {
  3073. topDiv: '.AppHeader-user',
  3074. button: '.AppHeader-user button',
  3075. img: '.AppHeader-user button img.avatar',
  3076. svg: 'avatar-dropdown',
  3077. },
  3078. repositoryHeader: {
  3079. id: '#repository-container-header',
  3080. ownerImg: `.${REPOSITORY_HEADER_CLASS} img`,
  3081. name: `.${REPOSITORY_HEADER_CLASS} strong`,
  3082. links: `.${REPOSITORY_HEADER_CLASS} nav[role="navigation"] a`,
  3083. details: '#repository-details-container',
  3084. bottomBorder: `.${REPOSITORY_HEADER_CLASS} .border-bottom.mx-xl-5`,
  3085. },
  3086. sidebars: {
  3087. backdrop: '.Overlay-backdrop--side',
  3088. left: {
  3089. backdrop: '.Overlay-backdrop--placement-left.Overlay-backdrop--side',
  3090. },
  3091. right: {
  3092. backdrop: '.AppHeader-user .Overlay-backdrop--side',
  3093. topDiv: '.AppHeader-user .Overlay-backdrop--placement-right',
  3094. modalDialog: '.AppHeader-user modal-dialog',
  3095. closeButton: '.AppHeader-user modal-dialog .Overlay-closeButton.close-button',
  3096. navParentDiv: '.AppHeader-user modal-dialog div.Overlay-body > div',
  3097. nav: '.AppHeader-user modal-dialog nav',
  3098. },
  3099. }
  3100. };
  3101.  
  3102. HEADER_STYLE.id = SELECTORS.header.style;
  3103.  
  3104. setTheme();
  3105.  
  3106. const oldSchoolColor = '#F0F6FC';
  3107. const oldSchoolHoverColor = '#FFFFFFB3';
  3108. const oldSchoolHoverBackgroundColor = 'transparent';
  3109. let configs = {
  3110. happyMedium: {
  3111. light: {
  3112. backgroundColor: '',
  3113. hamburgerButton: {
  3114. remove: false,
  3115. },
  3116. logo: {
  3117. remove: false,
  3118. color: '',
  3119. customSvg: '',
  3120. },
  3121. pageTitle: {
  3122. remove: false,
  3123. color: '',
  3124. hover: {
  3125. backgroundColor: '',
  3126. color: '',
  3127. },
  3128. },
  3129. search: {
  3130. backgroundColor: '',
  3131. borderColor: '',
  3132. boxShadow: '',
  3133. alignLeft: false,
  3134. width: 'max',
  3135. margin: {
  3136. left: '',
  3137. right: '',
  3138. },
  3139. magnifyingGlassIcon: {
  3140. remove: false,
  3141. },
  3142. placeholder: {
  3143. text: '',
  3144. color: '',
  3145. },
  3146. rightButton: 'command palette',
  3147. modal: {
  3148. width: '',
  3149. },
  3150. },
  3151. divider: {
  3152. remove: true,
  3153. },
  3154. flipCreateInbox: false,
  3155. create: {
  3156. remove: false,
  3157. border: true,
  3158. tooltip: false,
  3159. boxShadow: '',
  3160. hoverBackgroundColor: '',
  3161. plusIcon: {
  3162. remove: false,
  3163. color: '',
  3164. marginRight: '0.25rem',
  3165. hover: {
  3166. color: '',
  3167. }
  3168. },
  3169. text: {
  3170. content: 'Create',
  3171. color: '',
  3172. },
  3173. dropdownIcon: {
  3174. remove: false,
  3175. color: '',
  3176. hover: {
  3177. color: '',
  3178. },
  3179. },
  3180. },
  3181. flipIssuesPullRequests: true,
  3182. issues: {
  3183. remove: false,
  3184. border: true,
  3185. tooltip: false,
  3186. alignLeft: false,
  3187. boxShadow: '',
  3188. icon: {
  3189. remove: false,
  3190. color: '',
  3191. },
  3192. text: {
  3193. content: 'Issues',
  3194. color: '',
  3195. },
  3196. hover: {
  3197. backgroundColor: '',
  3198. color: '',
  3199. },
  3200. },
  3201. pullRequests: {
  3202. remove: false,
  3203. border: true,
  3204. tooltip: false,
  3205. alignLeft: false,
  3206. boxShadow: '',
  3207. icon: {
  3208. remove: false,
  3209. color: '',
  3210. },
  3211. text: {
  3212. content: 'Pull requests',
  3213. color: '',
  3214. },
  3215. hover: {
  3216. backgroundColor: '',
  3217. color: '',
  3218. },
  3219. },
  3220. notifications: {
  3221. remove: false,
  3222. border: true,
  3223. tooltip: false,
  3224. boxShadow: '',
  3225. hoverBackgroundColor: '',
  3226. icon: {
  3227. symbol: 'bell', // Accepts 'inbox', 'bell', or ''
  3228. color: '',
  3229. hover: {
  3230. color: '',
  3231. }
  3232. },
  3233. text: {
  3234. content: 'Inbox',
  3235. color: '',
  3236. },
  3237. dot: {
  3238. remove: false,
  3239. boxShadowColor: '',
  3240. color: '',
  3241. displayOverIcon: true,
  3242. },
  3243. },
  3244. avatar: {
  3245. size: '',
  3246. dropdownIcon: false,
  3247. canCloseSidebar: true,
  3248. },
  3249. globalBar: {
  3250. boxShadowColor: '',
  3251. leftAligned: {
  3252. gap: '',
  3253. },
  3254. rightAligned: {
  3255. gap: '',
  3256. },
  3257. },
  3258. localBar: {
  3259. backgroundColor: '#F6F8FA',
  3260. alignCenter: false,
  3261. boxShadow: {
  3262. consistentColor: true,
  3263. },
  3264. links: {
  3265. color: '',
  3266. },
  3267. },
  3268. sidebars: {
  3269. backdrop: {
  3270. color: 'transparent',
  3271. pointerEvents: 'none',
  3272. },
  3273. left: {
  3274. preload: true,
  3275. },
  3276. right: {
  3277. preload: true,
  3278. floatUnderneath: false,
  3279. width: '',
  3280. maxHeight: '',
  3281. },
  3282. },
  3283. repositoryHeader: {
  3284. import: true,
  3285. alignCenter: false,
  3286. removePageTitle: true,
  3287. backgroundColor: '#F6F8FA',
  3288. avatar: {
  3289. remove: false,
  3290. customSvg: '',
  3291. },
  3292. link: {
  3293. color: '',
  3294. hover: {
  3295. backgroundColor: 'transparent',
  3296. color: 'var(--color-accent-fg)',
  3297. textDecoration: 'underline',
  3298. },
  3299. },
  3300. },
  3301. },
  3302. dark: {
  3303. backgroundColor: '',
  3304. hamburgerButton: {
  3305. remove: false,
  3306. },
  3307. logo: {
  3308. remove: false,
  3309. color: '',
  3310. customSvg: '',
  3311. },
  3312. pageTitle: {
  3313. remove: false,
  3314. color: '',
  3315. hover: {
  3316. backgroundColor: '',
  3317. color: '',
  3318. },
  3319. },
  3320. search: {
  3321. backgroundColor: '',
  3322. borderColor: '',
  3323. boxShadow: '',
  3324. alignLeft: false,
  3325. width: 'max',
  3326. margin: {
  3327. left: '',
  3328. right: '',
  3329. },
  3330. magnifyingGlassIcon: {
  3331. remove: false,
  3332. },
  3333. placeholder: {
  3334. text: '',
  3335. color: '',
  3336. },
  3337. rightButton: 'command palette',
  3338. modal: {
  3339. width: '',
  3340. },
  3341. },
  3342. divider: {
  3343. remove: true,
  3344. },
  3345. flipCreateInbox: false,
  3346. create: {
  3347. remove: false,
  3348. border: true,
  3349. tooltip: false,
  3350. boxShadow: '',
  3351. hoverBackgroundColor: '',
  3352. plusIcon: {
  3353. remove: false,
  3354. color: '',
  3355. marginRight: '0.25rem',
  3356. hover: {
  3357. color: '',
  3358. }
  3359. },
  3360. text: {
  3361. content: 'Create',
  3362. color: '',
  3363. },
  3364. dropdownIcon: {
  3365. remove: false,
  3366. color: '',
  3367. hover: {
  3368. color: '',
  3369. },
  3370. },
  3371. },
  3372. flipIssuesPullRequests: true,
  3373. issues: {
  3374. remove: false,
  3375. border: true,
  3376. tooltip: false,
  3377. alignLeft: false,
  3378. boxShadow: '',
  3379. icon: {
  3380. remove: false,
  3381. color: '',
  3382. },
  3383. text: {
  3384. content: 'Issues',
  3385. color: '',
  3386. },
  3387. hover: {
  3388. backgroundColor: '',
  3389. color: '',
  3390. },
  3391. },
  3392. pullRequests: {
  3393. remove: false,
  3394. border: true,
  3395. tooltip: false,
  3396. alignLeft: false,
  3397. boxShadow: '',
  3398. icon: {
  3399. remove: false,
  3400. color: '',
  3401. },
  3402. text: {
  3403. content: 'Pull requests',
  3404. color: '',
  3405. },
  3406. hover: {
  3407. backgroundColor: '',
  3408. color: '',
  3409. },
  3410. },
  3411. notifications: {
  3412. remove: false,
  3413. border: true,
  3414. tooltip: false,
  3415. boxShadow: '',
  3416. hoverBackgroundColor: '',
  3417. icon: {
  3418. symbol: 'bell', // Accepts 'inbox', 'bell', or ''
  3419. color: '',
  3420. hover: {
  3421. color: '',
  3422. }
  3423. },
  3424. text: {
  3425. content: 'Inbox',
  3426. color: '',
  3427. },
  3428. dot: {
  3429. remove: false,
  3430. boxShadowColor: '',
  3431. color: '',
  3432. displayOverIcon: true,
  3433. },
  3434. },
  3435. avatar: {
  3436. size: '',
  3437. dropdownIcon: false,
  3438. canCloseSidebar: true,
  3439. },
  3440. globalBar: {
  3441. boxShadowColor: '',
  3442. leftAligned: {
  3443. gap: '',
  3444. },
  3445. rightAligned: {
  3446. gap: '',
  3447. },
  3448. },
  3449. localBar: {
  3450. backgroundColor: '#02040A',
  3451. alignCenter: false,
  3452. boxShadow: {
  3453. consistentColor: true,
  3454. },
  3455. links: {
  3456. color: '',
  3457. },
  3458. },
  3459. sidebars: {
  3460. backdrop: {
  3461. color: 'transparent',
  3462. pointerEvents: 'none',
  3463. },
  3464. left: {
  3465. preload: true,
  3466. },
  3467. right: {
  3468. preload: true,
  3469. floatUnderneath: false,
  3470. width: '',
  3471. maxHeight: '',
  3472. },
  3473. },
  3474. repositoryHeader: {
  3475. import: true,
  3476. alignCenter: false,
  3477. removePageTitle: true,
  3478. backgroundColor: '#02040A',
  3479. avatar: {
  3480. remove: false,
  3481. customSvg: '',
  3482. },
  3483. link: {
  3484. color: '#6AAFF9',
  3485. hover: {
  3486. backgroundColor: 'transparent',
  3487. color: 'var(--color-accent-fg)',
  3488. textDecoration: 'underline',
  3489. },
  3490. },
  3491. },
  3492. },
  3493. },
  3494. oldSchool: {
  3495. light: {
  3496. backgroundColor: '#161C20',
  3497. hamburgerButton: {
  3498. remove: true,
  3499. },
  3500. logo: {
  3501. remove: false,
  3502. color: '#e6edf3',
  3503. customSvg: '',
  3504. },
  3505. pageTitle: {
  3506. remove: true,
  3507. color: oldSchoolColor,
  3508. hover: {
  3509. backgroundColor: oldSchoolHoverBackgroundColor,
  3510. color: oldSchoolHoverColor,
  3511. },
  3512. },
  3513. search: {
  3514. backgroundColor: '#494D54',
  3515. borderColor: '#30363d',
  3516. boxShadow: 'none',
  3517. alignLeft: true,
  3518. width: 'calc(var(--feed-sidebar) - 67px)',
  3519. margin: {
  3520. left: '',
  3521. right: '',
  3522. },
  3523. magnifyingGlassIcon: {
  3524. remove: true,
  3525. },
  3526. placeholder: {
  3527. text: 'Search or jump to...',
  3528. color: '#B3B3B5',
  3529. },
  3530. rightButton: 'slash key',
  3531. modal: {
  3532. width: '450px',
  3533. },
  3534. },
  3535. divider: {
  3536. remove: true,
  3537. },
  3538. flipCreateInbox: true,
  3539. create: {
  3540. remove: false,
  3541. border: false,
  3542. tooltip: false,
  3543. boxShadow: 'none',
  3544. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3545. plusIcon: {
  3546. remove: false,
  3547. color: oldSchoolColor,
  3548. marginRight: '0px',
  3549. hover: {
  3550. color: oldSchoolHoverColor,
  3551. },
  3552. },
  3553. text: {
  3554. content: '',
  3555. color: '',
  3556. },
  3557. dropdownIcon: {
  3558. remove: false,
  3559. color: oldSchoolColor,
  3560. hover: {
  3561. color: oldSchoolHoverColor,
  3562. },
  3563. },
  3564. },
  3565. flipIssuesPullRequests: true,
  3566. issues: {
  3567. remove: false,
  3568. border: false,
  3569. tooltip: false,
  3570. alignLeft: true,
  3571. boxShadow: 'none',
  3572. icon: {
  3573. remove: true,
  3574. color: '',
  3575. },
  3576. text: {
  3577. content: 'Issues',
  3578. color: oldSchoolColor,
  3579. },
  3580. hover: {
  3581. backgroundColor: oldSchoolHoverBackgroundColor,
  3582. color: oldSchoolHoverColor,
  3583. },
  3584. },
  3585. pullRequests: {
  3586. remove: false,
  3587. border: false,
  3588. tooltip: false,
  3589. alignLeft: true,
  3590. boxShadow: 'none',
  3591. icon: {
  3592. remove: true,
  3593. color: '',
  3594. },
  3595. text: {
  3596. content: 'Pull requests',
  3597. color: oldSchoolColor,
  3598. },
  3599. hover: {
  3600. backgroundColor: oldSchoolHoverBackgroundColor,
  3601. color: oldSchoolHoverColor,
  3602. },
  3603. },
  3604. notifications: {
  3605. remove: false,
  3606. border: false,
  3607. tooltip: false,
  3608. boxShadow: 'none',
  3609. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3610. icon: {
  3611. symbol: 'bell',
  3612. color: oldSchoolColor,
  3613. hover: {
  3614. color: oldSchoolHoverColor,
  3615. }
  3616. },
  3617. text: {
  3618. content: '',
  3619. color: '',
  3620. },
  3621. dot: {
  3622. remove: false,
  3623. boxShadowColor: '#161C20',
  3624. color: '#2f81f7',
  3625. displayOverIcon: true,
  3626. },
  3627. },
  3628. avatar: {
  3629. size: '24px',
  3630. dropdownIcon: true,
  3631. canCloseSidebar: true,
  3632. },
  3633. globalBar: {
  3634. boxShadowColor: '#21262D',
  3635. leftAligned: {
  3636. gap: '0.75rem',
  3637. },
  3638. rightAligned: {
  3639. gap: '2px',
  3640. },
  3641. },
  3642. localBar: {
  3643. backgroundColor: '#FAFBFD',
  3644. alignCenter: true,
  3645. boxShadow: {
  3646. consistentColor: true,
  3647. },
  3648. links: {
  3649. color: '',
  3650. },
  3651. },
  3652. sidebars: {
  3653. backdrop: {
  3654. color: oldSchoolHoverBackgroundColor,
  3655. pointerEvents: 'none',
  3656. },
  3657. left: {
  3658. preload: true,
  3659. },
  3660. right: {
  3661. preload: true,
  3662. floatUnderneath: true,
  3663. width: '',
  3664. maxHeight: '50vh',
  3665. }
  3666. },
  3667. repositoryHeader: {
  3668. import: true,
  3669. alignCenter: true,
  3670. removePageTitle: true,
  3671. backgroundColor: '#FAFBFD',
  3672. avatar: {
  3673. remove: false,
  3674. 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>',
  3675. },
  3676. link: {
  3677. color: '#2F81F7',
  3678. hover: {
  3679. backgroundColor: 'transparent',
  3680. color: '#0969da',
  3681. textDecoration: 'underline',
  3682. },
  3683. },
  3684. },
  3685. },
  3686. dark: {
  3687. backgroundColor: '#161C20',
  3688. hamburgerButton: {
  3689. remove: true,
  3690. },
  3691. logo: {
  3692. remove: false,
  3693. color: '#e6edf3',
  3694. customSvg: '',
  3695. },
  3696. pageTitle: {
  3697. remove: true,
  3698. color: oldSchoolColor,
  3699. hover: {
  3700. backgroundColor: oldSchoolHoverBackgroundColor,
  3701. color: oldSchoolHoverColor,
  3702. },
  3703. },
  3704. search: {
  3705. backgroundColor: '#0E1217',
  3706. borderColor: '#30363d',
  3707. boxShadow: 'none',
  3708. alignLeft: true,
  3709. width: 'calc(var(--feed-sidebar) - 67px)',
  3710. margin: {
  3711. left: '',
  3712. right: '',
  3713. },
  3714. magnifyingGlassIcon: {
  3715. remove: true,
  3716. },
  3717. placeholder: {
  3718. text: 'Search or jump to...',
  3719. color: '#B3B3B5',
  3720. },
  3721. rightButton: 'slash key',
  3722. modal: {
  3723. width: '450px',
  3724. },
  3725. },
  3726. divider: {
  3727. remove: true,
  3728. },
  3729. flipCreateInbox: true,
  3730. create: {
  3731. remove: false,
  3732. border: false,
  3733. tooltip: false,
  3734. boxShadow: 'none',
  3735. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3736. plusIcon: {
  3737. remove: false,
  3738. color: oldSchoolColor,
  3739. marginRight: '0px',
  3740. hover: {
  3741. color: oldSchoolHoverColor,
  3742. },
  3743. },
  3744. text: {
  3745. content: '',
  3746. color: '',
  3747. },
  3748. dropdownIcon: {
  3749. remove: false,
  3750. color: oldSchoolColor,
  3751. hover: {
  3752. color: oldSchoolHoverColor,
  3753. },
  3754. },
  3755. },
  3756. flipIssuesPullRequests: true,
  3757. issues: {
  3758. remove: false,
  3759. border: false,
  3760. tooltip: false,
  3761. alignLeft: true,
  3762. boxShadow: 'none',
  3763. icon: {
  3764. remove: true,
  3765. color: '',
  3766. },
  3767. text: {
  3768. content: 'Issues',
  3769. color: oldSchoolColor,
  3770. },
  3771. hover: {
  3772. backgroundColor: oldSchoolHoverBackgroundColor,
  3773. color: oldSchoolHoverColor,
  3774. },
  3775. },
  3776. pullRequests: {
  3777. remove: false,
  3778. border: false,
  3779. tooltip: false,
  3780. alignLeft: true,
  3781. boxShadow: 'none',
  3782. icon: {
  3783. remove: true,
  3784. color: '',
  3785. },
  3786. text: {
  3787. content: 'Pull requests',
  3788. color: oldSchoolColor,
  3789. },
  3790. hover: {
  3791. backgroundColor: oldSchoolHoverBackgroundColor,
  3792. color: oldSchoolHoverColor,
  3793. },
  3794. },
  3795. notifications: {
  3796. remove: false,
  3797. border: false,
  3798. tooltip: false,
  3799. boxShadow: 'none',
  3800. hoverBackgroundColor: oldSchoolHoverBackgroundColor,
  3801. icon: {
  3802. symbol: 'bell',
  3803. color: oldSchoolColor,
  3804. hover: {
  3805. color: oldSchoolHoverColor,
  3806. }
  3807. },
  3808. text: {
  3809. content: '',
  3810. color: '',
  3811. },
  3812. dot: {
  3813. remove: false,
  3814. boxShadowColor: '#161C20',
  3815. color: '#2f81f7',
  3816. displayOverIcon: true,
  3817. },
  3818. },
  3819. avatar: {
  3820. size: '24px',
  3821. dropdownIcon: true,
  3822. canCloseSidebar: true,
  3823. },
  3824. globalBar: {
  3825. boxShadowColor: '#21262D',
  3826. leftAligned: {
  3827. gap: '0.75rem',
  3828. },
  3829. rightAligned: {
  3830. gap: '2px',
  3831. },
  3832. },
  3833. localBar: {
  3834. backgroundColor: '#0D1117',
  3835. alignCenter: true,
  3836. boxShadow: {
  3837. consistentColor: true,
  3838. },
  3839. links: {
  3840. color: '#e6edf3',
  3841. },
  3842. },
  3843. sidebars: {
  3844. backdrop: {
  3845. color: oldSchoolHoverBackgroundColor,
  3846. pointerEvents: 'none',
  3847. },
  3848. left: {
  3849. preload: true,
  3850. },
  3851. right: {
  3852. preload: true,
  3853. floatUnderneath: true,
  3854. width: '',
  3855. maxHeight: '50vh',
  3856. }
  3857. },
  3858. repositoryHeader: {
  3859. import: true,
  3860. alignCenter: true,
  3861. removePageTitle: true,
  3862. backgroundColor: '#0D1116',
  3863. avatar: {
  3864. remove: false,
  3865. 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>',
  3866. },
  3867. link: {
  3868. color: '#58A6FF',
  3869. hover: {
  3870. backgroundColor: 'transparent',
  3871. color: '#2F81F7',
  3872. textDecoration: 'underline',
  3873. },
  3874. },
  3875. },
  3876. },
  3877. },
  3878. };
  3879.  
  3880. let OBSERVER = new MutationObserver(observeAndModify);
  3881.  
  3882. let GMC = new GM_config({
  3883. id: 'gmc-frame',
  3884. title: `
  3885. Custom Global Navigation
  3886. <small>
  3887. <a
  3888. href="https://github.com/blakegearin/github-custom-global-navigation"
  3889. target="_blank"
  3890. >
  3891. source
  3892. </a>
  3893. </small>
  3894. `,
  3895. events: {
  3896. init: gmcInitialized,
  3897. open: gmcOpened,
  3898. save: gmcSaved,
  3899. close: gmcClosed,
  3900. },
  3901. frame: gmcBuildFrame(),
  3902. fields: {
  3903. type: {
  3904. section: [
  3905. `
  3906. Configuration Type
  3907. <small>
  3908. <a
  3909. href="https://github.com/blakegearin/github-custom-global-navigation#configurations"
  3910. target="_blank"
  3911. >
  3912. learn more
  3913. </a>
  3914. </small>
  3915. `,
  3916. ],
  3917. type: 'radio',
  3918. options: [
  3919. 'Off',
  3920. 'Happy Medium',
  3921. 'Old School',
  3922. 'Custom',
  3923. ],
  3924. default: 'Old School',
  3925. },
  3926. light_backgroundColor: {
  3927. label: 'Background color',
  3928. section: [
  3929. 'Custom Light',
  3930. ],
  3931. type: 'text',
  3932. default: '',
  3933. },
  3934. light_hamburgerButton_remove: {
  3935. label: '<h3>Hamburger button</h3><div class="gmc-label">Remove</div>',
  3936. type: 'checkbox',
  3937. default: false,
  3938. },
  3939. light_logo_remove: {
  3940. label: '<h3>Logo</h3><div class="gmc-label">Remove</div>',
  3941. type: 'checkbox',
  3942. default: false,
  3943. },
  3944. light_logo_color: {
  3945. label: 'Color',
  3946. type: 'text',
  3947. default: '',
  3948. },
  3949. light_logo_customSvg: {
  3950. label: 'Custom SVG (URL or text)',
  3951. type: 'textarea',
  3952. default: '',
  3953. },
  3954. light_pageTitle_remove: {
  3955. label: '<h3>Page title</h3><div class="gmc-label">Remove</div>',
  3956. type: 'checkbox',
  3957. default: false,
  3958. },
  3959. light_pageTitle_color: {
  3960. label: 'Color',
  3961. type: 'text',
  3962. default: '',
  3963. },
  3964. light_pageTitle_hover_backgroundColor: {
  3965. label: 'Hover background color',
  3966. type: 'text',
  3967. default: '',
  3968. },
  3969. light_pageTitle_hover_color: {
  3970. label: 'Hover color',
  3971. type: 'text',
  3972. default: '',
  3973. },
  3974. light_search_backgroundColor: {
  3975. label: '<h3>Search</h3><div class="gmc-label">Background color</div>',
  3976. type: 'text',
  3977. default: '',
  3978. },
  3979. light_search_borderColor: {
  3980. label: 'Border color',
  3981. type: 'text',
  3982. default: '',
  3983. },
  3984. light_search_boxShadow: {
  3985. label: 'Box shadow',
  3986. type: 'text',
  3987. default: '',
  3988. },
  3989. light_search_alignLeft: {
  3990. label: 'Left aligned',
  3991. type: 'checkbox',
  3992. default: false,
  3993. },
  3994. light_search_width: {
  3995. label: 'Width',
  3996. type: 'text',
  3997. default: '',
  3998. },
  3999. light_search_margin_left: {
  4000. label: 'Margin left',
  4001. type: 'text',
  4002. default: '',
  4003. },
  4004. light_search_margin_right: {
  4005. label: 'Margin right',
  4006. type: 'text',
  4007. default: '',
  4008. },
  4009. light_search_magnifyingGlassIcon_remove: {
  4010. label: 'Magnifying glass icon remove',
  4011. type: 'checkbox',
  4012. default: false,
  4013. },
  4014. light_search_placeholder_text: {
  4015. label: 'Placeholder text',
  4016. type: 'text',
  4017. default: '',
  4018. },
  4019. light_search_placeholder_color: {
  4020. label: 'Placeholder color',
  4021. type: 'text',
  4022. default: '',
  4023. },
  4024. light_search_rightButton: {
  4025. label: 'Right button',
  4026. type: 'select',
  4027. options: [
  4028. 'none',
  4029. 'command palette',
  4030. 'slash key',
  4031. ],
  4032. default: 'command palette',
  4033. },
  4034. light_search_modal_width: {
  4035. label: 'Modal width',
  4036. type: 'text',
  4037. default: '',
  4038. },
  4039. light_divider_remove: {
  4040. label: '<h3>Divider</h3><div class="gmc-label">Remove</div>',
  4041. type: 'checkbox',
  4042. default: false,
  4043. },
  4044. light_flipCreateInbox: {
  4045. label: 'Flip the order of Create and Notifications',
  4046. type: 'checkbox',
  4047. default: false,
  4048. },
  4049. light_create_remove: {
  4050. label: '<h3>Create button</h3><div class="gmc-label">Remove</div>',
  4051. type: 'checkbox',
  4052. default: false,
  4053. },
  4054. light_create_border: {
  4055. label: 'Border',
  4056. type: 'checkbox',
  4057. default: true,
  4058. },
  4059. light_create_tooltip: {
  4060. label: 'Tooltip',
  4061. type: 'checkbox',
  4062. default: true,
  4063. },
  4064. light_create_boxShadow: {
  4065. label: 'Box shadow',
  4066. type: 'text',
  4067. default: '',
  4068. },
  4069. light_create_hoverBackgroundColor: {
  4070. label: 'Hover background color',
  4071. type: 'text',
  4072. default: '',
  4073. },
  4074. light_create_plusIcon_remove: {
  4075. label: 'Plus icon remove',
  4076. type: 'checkbox',
  4077. default: false,
  4078. },
  4079. light_create_plusIcon_color: {
  4080. label: 'Plus icon color',
  4081. type: 'text',
  4082. default: '',
  4083. },
  4084. light_create_plusIcon_marginRight: {
  4085. label: 'Plus icon margin right',
  4086. type: 'text',
  4087. default: '',
  4088. },
  4089. light_create_plusIcon_hover_color: {
  4090. label: 'Plus icon hover color',
  4091. type: 'text',
  4092. default: '',
  4093. },
  4094. light_create_text_content: {
  4095. label: 'Text content',
  4096. type: 'text',
  4097. default: '',
  4098. },
  4099. light_create_text_color: {
  4100. label: 'Text color',
  4101. type: 'text',
  4102. default: '',
  4103. },
  4104. light_create_dropdownIcon_remove: {
  4105. label: 'Dropdown icon remove',
  4106. type: 'checkbox',
  4107. default: false,
  4108. },
  4109. light_create_dropdownIcon_color: {
  4110. label: 'Dropdown icon color',
  4111. type: 'text',
  4112. default: '',
  4113. },
  4114. light_create_dropdownIcon_hover_color: {
  4115. label: 'Dropdown icon hover color',
  4116. type: 'text',
  4117. default: '',
  4118. },
  4119. light_flipIssuesPullRequests: {
  4120. label: 'Flip the order of Issues and Pull requests',
  4121. type: 'checkbox',
  4122. default: false,
  4123. },
  4124. light_issues_remove: {
  4125. label: '<h3>Issues button</h3><div class="gmc-label">Remove</div>',
  4126. type: 'checkbox',
  4127. default: false,
  4128. },
  4129. light_issues_border: {
  4130. label: 'Border',
  4131. type: 'checkbox',
  4132. default: true,
  4133. },
  4134. light_issues_tooltip: {
  4135. label: 'Tooltip',
  4136. type: 'checkbox',
  4137. default: true,
  4138. },
  4139. light_issues_alignLeft: {
  4140. label: 'Align left',
  4141. type: 'checkbox',
  4142. default: false,
  4143. },
  4144. light_issues_boxShadow: {
  4145. label: 'Box shadow',
  4146. type: 'text',
  4147. default: '',
  4148. },
  4149. light_issues_icon_remove: {
  4150. label: 'Icon remove',
  4151. type: 'checkbox',
  4152. default: false,
  4153. },
  4154. light_issues_icon_color: {
  4155. label: 'Icon color',
  4156. type: 'text',
  4157. default: '',
  4158. },
  4159. light_issues_text_content: {
  4160. label: 'Text content',
  4161. type: 'text',
  4162. default: '',
  4163. },
  4164. light_issues_text_color: {
  4165. label: 'Text color',
  4166. type: 'text',
  4167. default: '',
  4168. },
  4169. light_issues_hover_backgroundColor: {
  4170. label: 'Hover background color',
  4171. type: 'text',
  4172. default: '',
  4173. },
  4174. light_issues_hover_color: {
  4175. label: 'Hover color',
  4176. type: 'text',
  4177. default: '',
  4178. },
  4179. light_pullRequests_remove: {
  4180. label: '<h3>Pull requests button</h3><div class="gmc-label">Remove</div>',
  4181. type: 'checkbox',
  4182. default: false,
  4183. },
  4184. light_pullRequests_border: {
  4185. label: 'Border',
  4186. type: 'checkbox',
  4187. default: true,
  4188. },
  4189. light_pullRequests_tooltip: {
  4190. label: 'Tooltip',
  4191. type: 'checkbox',
  4192. default: true,
  4193. },
  4194. light_pullRequests_alignLeft: {
  4195. label: 'Align left',
  4196. type: 'checkbox',
  4197. default: false,
  4198. },
  4199. light_pullRequests_boxShadow: {
  4200. label: 'Box shadow',
  4201. type: 'text',
  4202. default: '',
  4203. },
  4204. light_pullRequests_icon_remove: {
  4205. label: 'Icon remove',
  4206. type: 'checkbox',
  4207. default: false,
  4208. },
  4209. light_pullRequests_icon_color: {
  4210. label: 'Icon color',
  4211. type: 'text',
  4212. default: '',
  4213. },
  4214. light_pullRequests_text_content: {
  4215. label: 'Text content',
  4216. type: 'text',
  4217. default: '',
  4218. },
  4219. light_pullRequests_text_color: {
  4220. label: 'Text color',
  4221. type: 'text',
  4222. default: '',
  4223. },
  4224. light_pullRequests_hover_backgroundColor: {
  4225. label: 'Hover background color',
  4226. type: 'text',
  4227. default: '',
  4228. },
  4229. light_pullRequests_hover_color: {
  4230. label: 'Hover color',
  4231. type: 'text',
  4232. default: '',
  4233. },
  4234. light_notifications_remove: {
  4235. label: '<h3>Notifications button</h3><div class="gmc-label">Remove</div>',
  4236. type: 'checkbox',
  4237. default: false,
  4238. },
  4239. light_notifications_border: {
  4240. label: 'Border',
  4241. type: 'checkbox',
  4242. default: true,
  4243. },
  4244. light_notifications_tooltip: {
  4245. label: 'Tooltip',
  4246. type: 'checkbox',
  4247. default: true,
  4248. },
  4249. light_notifications_boxShadow: {
  4250. label: 'Box shadow',
  4251. type: 'text',
  4252. default: '',
  4253. },
  4254. light_notifications_hoverBackgroundColor: {
  4255. label: 'Hover background color',
  4256. type: 'text',
  4257. default: '',
  4258. },
  4259. light_notifications_icon_symbol: {
  4260. label: 'Icon symbol',
  4261. type: 'select',
  4262. options: [
  4263. 'none',
  4264. 'inbox',
  4265. 'bell',
  4266. ],
  4267. default: 'inbox',
  4268. },
  4269. light_notifications_icon_color: {
  4270. label: 'Icon color',
  4271. type: 'text',
  4272. default: '',
  4273. },
  4274. light_notifications_icon_hover_color: {
  4275. label: 'Icon hover color',
  4276. type: 'text',
  4277. default: '',
  4278. },
  4279. light_notifications_text_content: {
  4280. label: 'Text content',
  4281. type: 'text',
  4282. default: '',
  4283. },
  4284. light_notifications_text_color: {
  4285. label: 'Text color',
  4286. type: 'text',
  4287. default: '',
  4288. },
  4289. light_notifications_dot_remove: {
  4290. label: 'Dot remove',
  4291. type: 'checkbox',
  4292. default: false,
  4293. },
  4294. light_notifications_dot_boxShadowColor: {
  4295. label: 'Dot hover color',
  4296. type: 'text',
  4297. default: '',
  4298. },
  4299. light_notifications_dot_color: {
  4300. label: 'Dot color',
  4301. type: 'text',
  4302. default: '',
  4303. },
  4304. light_notifications_dot_displayOverIcon: {
  4305. label: 'Dot display over icon',
  4306. type: 'checkbox',
  4307. default: false,
  4308. },
  4309. light_avatar_size: {
  4310. label: '<h3>Avatar</h3><div class="gmc-label">Size</div>',
  4311. type: 'text',
  4312. default: '',
  4313. },
  4314. light_avatar_dropdownIcon: {
  4315. label: 'Dropdown icon',
  4316. type: 'checkbox',
  4317. default: false,
  4318. },
  4319. light_avatar_canCloseSidebar: {
  4320. label: 'Can close sidebar',
  4321. type: 'checkbox',
  4322. default: false,
  4323. },
  4324. light_globalBar_boxShadowColor: {
  4325. label: '<h3>Global bar</h3><div class="gmc-label">Box shadow color</div>',
  4326. type: 'text',
  4327. default: '',
  4328. },
  4329. light_globalBar_leftAligned_gap: {
  4330. label: 'Left aligned gap',
  4331. type: 'text',
  4332. default: '',
  4333. },
  4334. light_globalBar_rightAligned_gap: {
  4335. label: 'Right aligned gap',
  4336. type: 'text',
  4337. default: '',
  4338. },
  4339. light_localBar_backgroundColor: {
  4340. label: '<h3>Local bar</h3><div class="gmc-label">Background color</div>',
  4341. type: 'text',
  4342. default: '',
  4343. },
  4344. light_localBar_alignCenter: {
  4345. label: 'Align center',
  4346. type: 'checkbox',
  4347. default: false,
  4348. },
  4349. light_localBar_boxShadow_consistentColor: {
  4350. label: 'Box shadow consistent color',
  4351. type: 'checkbox',
  4352. default: false,
  4353. },
  4354. light_localBar_links_color: {
  4355. label: 'Links color',
  4356. type: 'text',
  4357. default: '',
  4358. },
  4359. light_sidebars_backdrop_color: {
  4360. label: '<h3>Sidebars</h3><div class="gmc-label">Backdrop color</div>',
  4361. type: 'text',
  4362. default: '',
  4363. },
  4364. light_sidebars_backdrop_pointerEvents: {
  4365. label: 'Backdrop pointer events',
  4366. type: 'text',
  4367. default: '',
  4368. },
  4369. light_sidebars_left_preload: {
  4370. label: 'Left preload',
  4371. type: 'checkbox',
  4372. default: false,
  4373. },
  4374. light_sidebars_right_preload: {
  4375. label: 'Right preload',
  4376. type: 'checkbox',
  4377. default: false,
  4378. },
  4379. light_sidebars_right_floatUnderneath: {
  4380. label: 'Right float underneath',
  4381. type: 'checkbox',
  4382. default: false,
  4383. },
  4384. light_sidebars_right_width: {
  4385. label: 'Right width',
  4386. type: 'text',
  4387. default: '',
  4388. },
  4389. light_sidebars_right_maxHeight: {
  4390. label: 'Right max height',
  4391. type: 'text',
  4392. default: '',
  4393. },
  4394. light_repositoryHeader_import: {
  4395. label: '<h3>Repository header</h3><div class="gmc-label">Import</div>',
  4396. type: 'checkbox',
  4397. default: false,
  4398. },
  4399. light_repositoryHeader_alignCenter: {
  4400. label: 'Align center',
  4401. type: 'checkbox',
  4402. default: false,
  4403. },
  4404. light_repositoryHeader_removePageTitle: {
  4405. label: 'Remove page title',
  4406. type: 'checkbox',
  4407. default: false,
  4408. },
  4409. light_repositoryHeader_backgroundColor: {
  4410. label: 'Background color',
  4411. type: 'text',
  4412. default: '',
  4413. },
  4414. light_repositoryHeader_avatar_remove: {
  4415. label: 'Avatar remove',
  4416. type: 'checkbox',
  4417. default: false,
  4418. },
  4419. light_repositoryHeader_avatar_customSvg: {
  4420. label: 'Custom SVG (URL or text)',
  4421. type: 'textarea',
  4422. default: '',
  4423. },
  4424. light_repositoryHeader_link_color: {
  4425. label: 'Link color',
  4426. type: 'text',
  4427. default: '',
  4428. },
  4429. light_repositoryHeader_link_hover_backgroundColor: {
  4430. label: 'Link hover background color',
  4431. type: 'text',
  4432. default: '',
  4433. },
  4434. light_repositoryHeader_link_hover_color: {
  4435. label: 'Link hover color',
  4436. type: 'text',
  4437. default: '',
  4438. },
  4439. light_repositoryHeader_link_hover_textDecoration: {
  4440. label: 'Link hover text decoration',
  4441. type: 'text',
  4442. default: '',
  4443. },
  4444. dark_backgroundColor: {
  4445. label: 'Background color',
  4446. section: [
  4447. 'Custom Dark',
  4448. ],
  4449. type: 'text',
  4450. default: '',
  4451. },
  4452. dark_hamburgerButton_remove: {
  4453. label: '<h3>Hamburger button</h3><div class="gmc-label">Remove</div>',
  4454. type: 'checkbox',
  4455. default: false,
  4456. },
  4457. dark_logo_remove: {
  4458. label: '<h3>Logo</h3><div class="gmc-label">Remove</div>',
  4459. type: 'checkbox',
  4460. default: false,
  4461. },
  4462. dark_logo_color: {
  4463. label: 'Color',
  4464. type: 'text',
  4465. default: '',
  4466. },
  4467. dark_logo_customSvg: {
  4468. label: 'Custom SVG (URL or text)',
  4469. type: 'textarea',
  4470. default: '',
  4471. },
  4472. dark_pageTitle_remove: {
  4473. label: '<h3>Page title</h3><div class="gmc-label">Remove</div>',
  4474. type: 'checkbox',
  4475. default: false,
  4476. },
  4477. dark_pageTitle_color: {
  4478. label: 'Color',
  4479. type: 'text',
  4480. default: '',
  4481. },
  4482. dark_pageTitle_hover_backgroundColor: {
  4483. label: 'Hover background color',
  4484. type: 'text',
  4485. default: '',
  4486. },
  4487. dark_pageTitle_hover_color: {
  4488. label: 'Hover color',
  4489. type: 'text',
  4490. default: '',
  4491. },
  4492. dark_search_backgroundColor: {
  4493. label: '<h3>Search</h3><div class="gmc-label">Background color</div>',
  4494. type: 'text',
  4495. default: '',
  4496. },
  4497. dark_search_borderColor: {
  4498. label: 'Border color',
  4499. type: 'text',
  4500. default: '',
  4501. },
  4502. dark_search_boxShadow: {
  4503. label: 'Box shadow',
  4504. type: 'text',
  4505. default: '',
  4506. },
  4507. dark_search_alignLeft: {
  4508. label: 'Left aligned',
  4509. type: 'checkbox',
  4510. default: false,
  4511. },
  4512. dark_search_width: {
  4513. label: 'Width',
  4514. type: 'text',
  4515. default: '',
  4516. },
  4517. dark_search_margin_left: {
  4518. label: 'Margin left',
  4519. type: 'text',
  4520. default: '',
  4521. },
  4522. dark_search_margin_right: {
  4523. label: 'Margin right',
  4524. type: 'text',
  4525. default: '',
  4526. },
  4527. dark_search_magnifyingGlassIcon_remove: {
  4528. label: 'Magnifying glass icon remove',
  4529. type: 'checkbox',
  4530. default: false,
  4531. },
  4532. dark_search_placeholder_text: {
  4533. label: 'Placeholder text',
  4534. type: 'text',
  4535. default: '',
  4536. },
  4537. dark_search_placeholder_color: {
  4538. label: 'Placeholder color',
  4539. type: 'text',
  4540. default: '',
  4541. },
  4542. dark_search_rightButton: {
  4543. label: 'Right button',
  4544. type: 'select',
  4545. options: [
  4546. 'none',
  4547. 'command palette',
  4548. 'slash key',
  4549. ],
  4550. default: 'command palette',
  4551. },
  4552. dark_search_modal_width: {
  4553. label: 'Modal width',
  4554. type: 'text',
  4555. default: '',
  4556. },
  4557. dark_divider_remove: {
  4558. label: '<h3>Divider</h3><div class="gmc-label">Remove</div>',
  4559. type: 'checkbox',
  4560. default: false,
  4561. },
  4562. dark_flipCreateInbox: {
  4563. label: 'Flip the order of Create and Notifications',
  4564. type: 'checkbox',
  4565. default: false,
  4566. },
  4567. dark_create_remove: {
  4568. label: '<h3>Create button</h3><div class="gmc-label">Remove</div>',
  4569. type: 'checkbox',
  4570. default: false,
  4571. },
  4572. dark_create_border: {
  4573. label: 'Border',
  4574. type: 'checkbox',
  4575. default: true,
  4576. },
  4577. dark_create_tooltip: {
  4578. label: 'Tooltip',
  4579. type: 'checkbox',
  4580. default: true,
  4581. },
  4582. dark_create_boxShadow: {
  4583. label: 'Box shadow',
  4584. type: 'text',
  4585. default: '',
  4586. },
  4587. dark_create_hoverBackgroundColor: {
  4588. label: 'Hover background color',
  4589. type: 'text',
  4590. default: '',
  4591. },
  4592. dark_create_plusIcon_remove: {
  4593. label: 'Plus icon remove',
  4594. type: 'checkbox',
  4595. default: false,
  4596. },
  4597. dark_create_plusIcon_color: {
  4598. label: 'Plus icon color',
  4599. type: 'text',
  4600. default: '',
  4601. },
  4602. dark_create_plusIcon_marginRight: {
  4603. label: 'Plus icon margin right',
  4604. type: 'text',
  4605. default: '',
  4606. },
  4607. dark_create_plusIcon_hover_color: {
  4608. label: 'Plus icon hover color',
  4609. type: 'text',
  4610. default: '',
  4611. },
  4612. dark_create_text_content: {
  4613. label: 'Text content',
  4614. type: 'text',
  4615. default: '',
  4616. },
  4617. dark_create_text_color: {
  4618. label: 'Text color',
  4619. type: 'text',
  4620. default: '',
  4621. },
  4622. dark_create_dropdownIcon_remove: {
  4623. label: 'Dropdown icon remove',
  4624. type: 'checkbox',
  4625. default: false,
  4626. },
  4627. dark_create_dropdownIcon_color: {
  4628. label: 'Dropdown icon color',
  4629. type: 'text',
  4630. default: '',
  4631. },
  4632. dark_create_dropdownIcon_hover_color: {
  4633. label: 'Dropdown icon hover color',
  4634. type: 'text',
  4635. default: '',
  4636. },
  4637. dark_flipIssuesPullRequests: {
  4638. label: 'Flip the order of Issues and Pull requests',
  4639. type: 'checkbox',
  4640. default: false,
  4641. },
  4642. dark_issues_remove: {
  4643. label: '<h3>Issues button</h3><div class="gmc-label">Remove</div>',
  4644. type: 'checkbox',
  4645. default: false,
  4646. },
  4647. dark_issues_border: {
  4648. label: 'Border',
  4649. type: 'checkbox',
  4650. default: true,
  4651. },
  4652. dark_issues_tooltip: {
  4653. label: 'Tooltip',
  4654. type: 'checkbox',
  4655. default: true,
  4656. },
  4657. dark_issues_boxShadow: {
  4658. label: 'Box shadow',
  4659. type: 'text',
  4660. default: '',
  4661. },
  4662. dark_issues_alignLeft: {
  4663. label: 'Align left',
  4664. type: 'checkbox',
  4665. default: false,
  4666. },
  4667. dark_issues_icon_remove: {
  4668. label: 'Icon remove',
  4669. type: 'checkbox',
  4670. default: false,
  4671. },
  4672. dark_issues_icon_color: {
  4673. label: 'Icon color',
  4674. type: 'text',
  4675. default: '',
  4676. },
  4677. dark_issues_text_content: {
  4678. label: 'Text content',
  4679. type: 'text',
  4680. default: '',
  4681. },
  4682. dark_issues_text_color: {
  4683. label: 'Text color',
  4684. type: 'text',
  4685. default: '',
  4686. },
  4687. dark_issues_hover_backgroundColor: {
  4688. label: 'Hover background color',
  4689. type: 'text',
  4690. default: '',
  4691. },
  4692. dark_issues_hover_color: {
  4693. label: 'Hover color',
  4694. type: 'text',
  4695. default: '',
  4696. },
  4697. dark_pullRequests_remove: {
  4698. label: '<h3>Pull requests button</h3><div class="gmc-label">Remove</div>',
  4699. type: 'checkbox',
  4700. default: false,
  4701. },
  4702. dark_pullRequests_border: {
  4703. label: 'Border',
  4704. type: 'checkbox',
  4705. default: true,
  4706. },
  4707. dark_pullRequests_tooltip: {
  4708. label: 'Tooltip',
  4709. type: 'checkbox',
  4710. default: true,
  4711. },
  4712. dark_pullRequests_alignLeft: {
  4713. label: 'Align left',
  4714. type: 'checkbox',
  4715. default: false,
  4716. },
  4717. dark_pullRequests_boxShadow: {
  4718. label: 'Box shadow',
  4719. type: 'text',
  4720. default: '',
  4721. },
  4722. dark_pullRequests_icon_remove: {
  4723. label: 'Icon remove',
  4724. type: 'checkbox',
  4725. default: false,
  4726. },
  4727. dark_pullRequests_icon_color: {
  4728. label: 'Icon color',
  4729. type: 'text',
  4730. default: '',
  4731. },
  4732. dark_pullRequests_text_content: {
  4733. label: 'Text content',
  4734. type: 'text',
  4735. default: '',
  4736. },
  4737. dark_pullRequests_text_color: {
  4738. label: 'Text color',
  4739. type: 'text',
  4740. default: '',
  4741. },
  4742. dark_pullRequests_hover_backgroundColor: {
  4743. label: 'Hover background color',
  4744. type: 'text',
  4745. default: '',
  4746. },
  4747. dark_pullRequests_hover_color: {
  4748. label: 'Hover color',
  4749. type: 'text',
  4750. default: '',
  4751. },
  4752. dark_notifications_remove: {
  4753. label: '<h3>Notifications button</h3><div class="gmc-label">Remove</div>',
  4754. type: 'checkbox',
  4755. default: false,
  4756. },
  4757. dark_notifications_border: {
  4758. label: 'Border',
  4759. type: 'checkbox',
  4760. default: true,
  4761. },
  4762. dark_notifications_tooltip: {
  4763. label: 'Tooltip',
  4764. type: 'checkbox',
  4765. default: true,
  4766. },
  4767. dark_notifications_boxShadow: {
  4768. label: 'Box shadow',
  4769. type: 'text',
  4770. default: '',
  4771. },
  4772. dark_notifications_hoverBackgroundColor: {
  4773. label: 'Hover background color',
  4774. type: 'text',
  4775. default: '',
  4776. },
  4777. dark_notifications_icon_symbol: {
  4778. label: 'Icon symbol',
  4779. type: 'select',
  4780. options: [
  4781. 'none',
  4782. 'inbox',
  4783. 'bell',
  4784. ],
  4785. default: 'inbox',
  4786. },
  4787. dark_notifications_icon_color: {
  4788. label: 'Icon color',
  4789. type: 'text',
  4790. default: '',
  4791. },
  4792. dark_notifications_icon_hover_color: {
  4793. label: 'Icon hover color',
  4794. type: 'text',
  4795. default: '',
  4796. },
  4797. dark_notifications_text_content: {
  4798. label: 'Text content',
  4799. type: 'text',
  4800. default: '',
  4801. },
  4802. dark_notifications_text_color: {
  4803. label: 'Text color',
  4804. type: 'text',
  4805. default: '',
  4806. },
  4807. dark_notifications_dot_remove: {
  4808. label: 'Dot remove',
  4809. type: 'checkbox',
  4810. default: false,
  4811. },
  4812. dark_notifications_dot_boxShadowColor: {
  4813. label: 'Dot hover color',
  4814. type: 'text',
  4815. default: '',
  4816. },
  4817. dark_notifications_dot_color: {
  4818. label: 'Dot color',
  4819. type: 'text',
  4820. default: '',
  4821. },
  4822. dark_notifications_dot_displayOverIcon: {
  4823. label: 'Dot display over icon',
  4824. type: 'checkbox',
  4825. default: false,
  4826. },
  4827. dark_avatar_size: {
  4828. label: '<h3>Avatar</h3><div class="gmc-label">Size</div>',
  4829. type: 'text',
  4830. default: '',
  4831. },
  4832. dark_avatar_dropdownIcon: {
  4833. label: 'Dropdown icon',
  4834. type: 'checkbox',
  4835. default: false,
  4836. },
  4837. dark_avatar_canCloseSidebar: {
  4838. label: 'Can close sidebar',
  4839. type: 'checkbox',
  4840. default: false,
  4841. },
  4842. dark_globalBar_boxShadowColor: {
  4843. label: '<h3>Global bar</h3><div class="gmc-label">Box shadow color</div>',
  4844. type: 'text',
  4845. default: '',
  4846. },
  4847. dark_globalBar_leftAligned_gap: {
  4848. label: 'Left aligned gap',
  4849. type: 'text',
  4850. default: '',
  4851. },
  4852. dark_globalBar_rightAligned_gap: {
  4853. label: 'Right aligned gap',
  4854. type: 'text',
  4855. default: '',
  4856. },
  4857. dark_localBar_backgroundColor: {
  4858. label: '<h3>Local bar</h3><div class="gmc-label">Background color</div>',
  4859. type: 'text',
  4860. default: '',
  4861. },
  4862. dark_localBar_alignCenter: {
  4863. label: 'Align center',
  4864. type: 'checkbox',
  4865. default: false,
  4866. },
  4867. dark_localBar_boxShadow_consistentColor: {
  4868. label: 'Box shadow consistent color',
  4869. type: 'checkbox',
  4870. default: false,
  4871. },
  4872. dark_localBar_links_color: {
  4873. label: 'Links color',
  4874. type: 'text',
  4875. default: '',
  4876. },
  4877. dark_sidebars_backdrop_color: {
  4878. label: '<h3>Sidebars</h3><div class="gmc-label">Backdrop color</div>',
  4879. type: 'text',
  4880. default: '',
  4881. },
  4882. dark_sidebars_backdrop_pointerEvents: {
  4883. label: 'Backdrop pointer events',
  4884. type: 'text',
  4885. default: '',
  4886. },
  4887. dark_sidebars_left_preload: {
  4888. label: 'Left preload',
  4889. type: 'checkbox',
  4890. default: false,
  4891. },
  4892. dark_sidebars_right_preload: {
  4893. label: 'Right preload',
  4894. type: 'checkbox',
  4895. default: false,
  4896. },
  4897. dark_sidebars_right_floatUnderneath: {
  4898. label: 'Right float underneath',
  4899. type: 'checkbox',
  4900. default: false,
  4901. },
  4902. dark_sidebars_right_width: {
  4903. label: 'Right width',
  4904. type: 'text',
  4905. default: '',
  4906. },
  4907. dark_sidebars_right_maxHeight: {
  4908. label: 'Right max height',
  4909. type: 'text',
  4910. default: '',
  4911. },
  4912. dark_repositoryHeader_import: {
  4913. label: '<h3>Repository header</h3><div class="gmc-label">Import</div>',
  4914. type: 'checkbox',
  4915. default: false,
  4916. },
  4917. dark_repositoryHeader_alignCenter: {
  4918. label: 'Align enter',
  4919. type: 'checkbox',
  4920. default: false,
  4921. },
  4922. dark_repositoryHeader_removePageTitle: {
  4923. label: 'Remove page title',
  4924. type: 'checkbox',
  4925. default: false,
  4926. },
  4927. dark_repositoryHeader_backgroundColor: {
  4928. label: 'Background color',
  4929. type: 'text',
  4930. default: '',
  4931. },
  4932. dark_repositoryHeader_avatar_remove: {
  4933. label: 'Avatar remove',
  4934. type: 'checkbox',
  4935. default: false,
  4936. },
  4937. dark_repositoryHeader_avatar_customSvg: {
  4938. label: 'Custom SVG (URL or text)',
  4939. type: 'textarea',
  4940. default: '',
  4941. },
  4942. dark_repositoryHeader_link_color: {
  4943. label: 'Link color',
  4944. type: 'text',
  4945. default: '',
  4946. },
  4947. dark_repositoryHeader_link_hover_backgroundColor: {
  4948. label: 'Link hover background color',
  4949. type: 'text',
  4950. default: '',
  4951. },
  4952. dark_repositoryHeader_link_hover_color: {
  4953. label: 'Link hover color',
  4954. type: 'text',
  4955. default: '',
  4956. },
  4957. dark_repositoryHeader_link_hover_textDecoration: {
  4958. label: 'Link hover text decoration',
  4959. type: 'text',
  4960. default: '',
  4961. },
  4962. on_save: {
  4963. label: 'On save',
  4964. section: ['Settings'],
  4965. type: 'select',
  4966. options: [
  4967. 'do nothing',
  4968. 'refresh tab',
  4969. 'refresh tab and close',
  4970. 'run script',
  4971. 'run script and close',
  4972. ],
  4973. default: 'do nothing',
  4974. },
  4975. on_close: {
  4976. label: 'On close',
  4977. type: 'select',
  4978. options: [
  4979. 'do nothing',
  4980. 'refresh tab',
  4981. 'run script',
  4982. ],
  4983. default: 'do nothing',
  4984. },
  4985. on_open: {
  4986. label: 'On open',
  4987. type: 'select',
  4988. options: [
  4989. 'do nothing',
  4990. 'close sidebar',
  4991. ],
  4992. default: 'close sidebar',
  4993. },
  4994. menu_item_title: {
  4995. label: 'Menu item title',
  4996. type: 'text',
  4997. default: 'Custom global navigation',
  4998. },
  4999. menu_item_icon: {
  5000. label: 'Menu item icon',
  5001. type: 'select',
  5002. options: [
  5003. 'logo',
  5004. 'compass',
  5005. 'cog',
  5006. ],
  5007. default: 'logo',
  5008. },
  5009. log_level: {
  5010. label: 'Log level',
  5011. type: 'select',
  5012. options: [
  5013. 'silent',
  5014. 'quiet',
  5015. 'debug',
  5016. 'verbose',
  5017. 'trace',
  5018. ],
  5019. default: 'quiet',
  5020. },
  5021. clear_custom_config: {
  5022. label: 'Clear Custom',
  5023. section: ['Danger Zone'],
  5024. type: 'button',
  5025. click: gmcClearCustom,
  5026. },
  5027. apply_happyMedium_config: {
  5028. label: 'Overwrite Custom with Happy Medium',
  5029. type: 'button',
  5030. click: gmcApplyCustomHappyMediumConfig,
  5031. },
  5032. apply_oldSchool_config: {
  5033. label: 'Overwrite Custom with Old School',
  5034. type: 'button',
  5035. click: gmcApplyCustomOldSchoolConfig,
  5036. },
  5037. },
  5038. });
  5039. })();