GitHub Custom Global Navigation

Customize GitHub's new global navigation

Nainstalovat skript?
Skript doporučený autorem

Mohlo by se vám také líbit Old School Slack.

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