├── .gitattributes ├── JS ├── animateContextMenus.uc.js ├── clearDownloadsButton.uc.js ├── hideScrollbar.uc.js ├── macosTheme.uc.js └── navbarToolbarButtonSlider.uc.js ├── LICENSE ├── README.md ├── assets ├── adaptive-tab-bar-extension-support.gif ├── adaptive.gif ├── context.png ├── hide_scroll_bar.gif ├── library.png ├── mac_os_theme.gif ├── navbar.gif └── preview.png ├── img └── new_tab_wallpaper.jpg ├── includes ├── realfire-addons-page.css ├── realfire-button.css ├── realfire-checkbox.css ├── realfire-colours.css ├── realfire-config.css ├── realfire-findbar.css ├── realfire-icons.css ├── realfire-inputs.css ├── realfire-layout.css ├── realfire-library.css ├── realfire-nav-bar.css ├── realfire-popups.css ├── realfire-responsive.css ├── realfire-settings-page.css ├── realfire-side-bar.css └── realfire-tabs.css ├── programs ├── install-curl.bat ├── install-curl.sh ├── install.bat ├── install.sh ├── local-settings.js ├── mozilla.cfg ├── uninstall.bat ├── uninstall.sh └── user.js ├── resources └── material │ ├── actual-zoom.svg │ ├── all-history.svg │ ├── bookmark-manage.svg │ ├── checked copy.svg │ ├── checked.svg │ ├── close-hover.svg │ ├── close-tab-option.svg │ ├── close.svg │ ├── command-pick.svg │ ├── desktop-bg.svg │ ├── duplicate-tab.svg │ ├── experiments.svg │ ├── ideas.svg │ ├── inactive.svg │ ├── maximize-hover.svg │ ├── maximize-restore.svg │ ├── maximize-svg.svg │ ├── maximize.svg │ ├── minimize-hover.svg │ ├── minimize.svg │ ├── move-container.svg │ ├── move-end.svg │ ├── move-start.svg │ ├── move-tab.svg │ ├── new-container.svg │ ├── open_new_tabs.svg │ ├── page-source.svg │ ├── pause.svg │ ├── playButton.svg │ ├── quit.svg │ ├── radio-checked.svg │ ├── radio-unchecked.svg │ ├── redo.svg │ ├── reload.svg │ ├── remote-debug.svg │ ├── restore-session.svg │ ├── select-all.svg │ ├── send-tab.svg │ ├── share-tab.svg │ ├── signout.svg │ ├── terminal.svg │ ├── toolbox.svg │ ├── translate.svg │ ├── unchecked.svg │ ├── userScriptsMenu.svg │ ├── web-page-source-code.svg │ ├── zoom-in.svg │ └── zoom-out.svg ├── userChrome.css ├── userContent.css └── utils ├── boot.sys.mjs ├── chrome.manifest ├── fs.sys.mjs ├── uc_api.sys.mjs └── utils.sys.mjs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /JS/animateContextMenus.uc.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Animate Context Menus 3 | // @version 1.0.4 4 | // @author aminomancer 5 | // @homepage https://github.com/aminomancer/uc.css.js 6 | // @description Give all context menus the same opening animation that panel popups like the app menu have — the menu slides down 70px and fades in opacity at the same time. It's a cool effect that doesn't trigger a reflow since it uses transform, but it does repaint the menu, so I wouldn't recommend using this on weak hardware. 7 | // @downloadURL https://cdn.jsdelivr.net/gh/aminomancer/uc.css.js@master/JS/animateContextMenus.uc.js 8 | // @updateURL https://cdn.jsdelivr.net/gh/aminomancer/uc.css.js@master/JS/animateContextMenus.uc.js 9 | // @license This Source Code Form is subject to the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International License, v. 4.0. If a copy of the CC BY-NC-SA 4.0 was not distributed with this file, You can obtain one at http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 10 | // @include * 11 | // ==/UserScript== 12 | 13 | class AnimateContextMenus { 14 | constructor() { 15 | document.documentElement.setAttribute("animate-menupopups", true); 16 | addEventListener("popupshowing", this); 17 | addEventListener("popupshown", this); 18 | addEventListener("popuphidden", this); 19 | let css = `:root[animate-menupopups] 20 | :not(menulist) 21 | > menupopup:not([position], [type="arrow"], [animate="false"]) { 22 | opacity: 0; 23 | transform: translateY(-70px) scaleX(0.95) scaleY(0.5); 24 | transform-origin: top; 25 | transition-property: transform, opacity; 26 | transition-duration: 0.18s, 0.18s; 27 | transition-timing-function: var(--animation-easing-function, cubic-bezier(0.07, 0.95, 0, 1)), 28 | ease-out; 29 | transform-style: flat; 30 | backface-visibility: hidden; 31 | } 32 | :root[animate-menupopups] 33 | :not(menulist) 34 | > menupopup:not([position], [type="arrow"])[animate][animate="open"] { 35 | opacity: 1; 36 | transition-duration: 0.18s, 0.18s; 37 | transform: none !important; 38 | transition-timing-function: var(--animation-easing-function, cubic-bezier(0.07, 0.95, 0, 1)), 39 | ease-in-out; 40 | } 41 | :root[animate-menupopups] 42 | :not(menulist) 43 | > menupopup:not([position], [type="arrow"])[animate][animate="cancel"] { 44 | transform: none; 45 | } 46 | :root[animate-menupopups] :not(menulist) > menupopup:not([position], [type="arrow"])[animating] { 47 | pointer-events: none; 48 | }`; 49 | let sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService( 50 | Ci.nsIStyleSheetService 51 | ); 52 | let uri = Services.io.newURI( 53 | `data:text/css;charset=UTF=8,${encodeURIComponent(css)}` 54 | ); 55 | if (!sss.sheetRegistered(uri, sss.AUTHOR_SHEET)) { 56 | sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET); 57 | } 58 | } 59 | handleEvent(e) { 60 | if (e.target.tagName !== "menupopup") return; 61 | if (e.target.hasAttribute("position")) return; 62 | if (e.target.getAttribute("type") == "arrow") return; 63 | if (e.target.parentElement) { 64 | if (e.target.parentElement.tagName == "menulist") return; 65 | } 66 | if ( 67 | e.target.shadowRoot && 68 | e.target.shadowRoot.firstElementChild.classList.contains( 69 | "panel-arrowcontainer" 70 | ) 71 | ) { 72 | return; 73 | } 74 | this[`on_${e.type}`](e); 75 | } 76 | on_popupshowing(e) { 77 | if (e.target.getAttribute("animate") != "false") { 78 | e.target.setAttribute("animate", "open"); 79 | e.target.setAttribute("animating", "true"); 80 | } 81 | } 82 | on_popupshown(e) { 83 | e.target.removeAttribute("animating"); 84 | } 85 | on_popuphidden(e) { 86 | if (e.target.getAttribute("animate") != "false") { 87 | e.target.removeAttribute("animate"); 88 | } 89 | } 90 | } 91 | 92 | new AnimateContextMenus(); 93 | -------------------------------------------------------------------------------- /JS/clearDownloadsButton.uc.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Clear Downloads Panel Button 3 | // @version 1.4.2 4 | // @author aminomancer 5 | // @homepageURL https://github.com/aminomancer/uc.css.js 6 | // @description Place a "Clear Downloads" button in the downloads panel, right next to the "Show all downloads" button. 7 | // @downloadURL https://cdn.jsdelivr.net/gh/aminomancer/uc.css.js@master/JS/clearDownloadsButton.uc.js 8 | // @updateURL https://cdn.jsdelivr.net/gh/aminomancer/uc.css.js@master/JS/clearDownloadsButton.uc.js 9 | // @license This Source Code Form is subject to the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International License, v. 4.0. If a copy of the CC BY-NC-SA 4.0 was not distributed with this file, You can obtain one at http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 10 | // ==/UserScript== 11 | 12 | class ClearDLPanel { 13 | constructor() { 14 | this.makeButton(); 15 | this.setCountHandler(); 16 | Services.obs.addObserver(this, "downloads-panel-count-changed"); 17 | } 18 | async genStrings() { 19 | this.strings = await new Localization(["browser/downloads.ftl"], true); 20 | const messages = await this.strings.formatMessages([ 21 | "downloads-cmd-clear-downloads", 22 | ]); 23 | this.label = messages[0].attributes[0].value; 24 | this.accessKey = messages[0].attributes[1].value; 25 | return [this.label, this.accessKey]; 26 | } 27 | async makeButton() { 28 | this.clearPanelButton = document.createXULElement("button"); 29 | let strings = await this.genStrings(); 30 | let labelString = this.sentenceCase(strings[0]); 31 | for (const [key, val] of Object.entries({ 32 | id: "clearDownloadsPanel", 33 | class: 34 | DownloadsView.downloadsHistory.className || 35 | "downloadsPanelFooterButton subviewbutton panel-subview-footer-button toolbarbutton-1", 36 | oncommand: `goDoCommand('downloadsCmd_clearList'); DownloadsPanel.hidePanel();`, 37 | label: labelString, 38 | accesskey: strings[1], 39 | flex: "1", 40 | pack: "start", 41 | })) { 42 | this.clearPanelButton.setAttribute(key, val); 43 | } 44 | DownloadsView.downloadsHistory.after(this.clearPanelButton); 45 | this.clearPanelButton.hidden = !DownloadsView._visibleViewItems?.size > 0; 46 | this.clearPanelButton 47 | ?.closest("#downloadsFooter") 48 | .prepend(document.createXULElement("toolbarseparator")); 49 | this.clearPanelButton?.parentElement.setAttribute("uc-hbox", "true"); 50 | } 51 | sentenceCase(str) { 52 | return str 53 | .toLocaleLowerCase() 54 | .replace(RTL_UI ? /.$/i : /^./i, function (letter) { 55 | return letter.toLocaleUpperCase(); 56 | }) 57 | .trim(); 58 | } 59 | setCountHandler() { 60 | eval( 61 | `DownloadsView._itemCountChanged = function ${DownloadsView._itemCountChanged 62 | .toSource() 63 | .replace( 64 | /hiddenCount \> 0\;\n/, 65 | `hiddenCount > 0;\n Services.obs.notifyObservers(null, "downloads-panel-count-changed", String(count));\n` 66 | )}` 67 | ); 68 | } 69 | observe(_sub, _top, data) { 70 | this.clearPanelButton.hidden = parseInt(data) < 1; 71 | } 72 | } 73 | 74 | if (gBrowserInit.delayedStartupFinished) { 75 | new ClearDLPanel(); 76 | } else { 77 | let delayedListener = (subject, topic) => { 78 | if (topic == "browser-delayed-startup-finished" && subject == window) { 79 | Services.obs.removeObserver(delayedListener, topic); 80 | new ClearDLPanel(); 81 | } 82 | }; 83 | Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished"); 84 | } 85 | -------------------------------------------------------------------------------- /JS/hideScrollbar.uc.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Floating Scrollbar 3 | // @version 1.0.0 4 | // @author Hakanbaban53 5 | // @homepage https://github.com/Hakanbaban53/RealFire 6 | // @description Auto hide scrollbar. 7 | // @downloadURL https://cdn.jsdelivr.net/gh/Hakanbaban53/RealFire@main/JS/hideScrollbar.uc.js 8 | // @updateURL https://cdn.jsdelivr.net/gh/Hakanbaban53/RealFire@main/JS/hideScrollbar.uc.js 9 | // @license This Source Code Form is subject to the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International License, v. 4.0. If a copy of the CC BY-NC-SA 4.0 was not distributed with this file, You can obtain one at http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 10 | // ==/UserScript== 11 | 12 | (function () { 13 | // var prefs = Services.prefs, 14 | // enabled; 15 | // if (prefs.prefHasUserValue('userChromeJS.floatingScrollbar.enabled')) { 16 | // enabled = prefs.getBoolPref('userChromeJS.floatingScrollbar.enabled') 17 | // } else { 18 | // prefs.setBoolPref('userChromeJS.floatingScrollbar.enabled', true); 19 | // enabled = true; 20 | // } 21 | 22 | var css = ` 23 | link[href$="global.css"] ~ scrollbox { 24 | overflow-y: auto !important; 25 | } 26 | link[href$="global.css"] ~ .menupopup-scrollbutton { 27 | display: none !important; 28 | } 29 | link[href$="global.css"] ~ hbox > arrowscrollbox.in-bookmarks-menu { 30 | padding-bottom: 0px !important; 31 | } 32 | link[href$="global.css"] ~ scrollbox { 33 | padding-top: 0px !important; 34 | } 35 | link[href$="global.css"] ~ .scrollbutton-up, 36 | link[href$="global.css"] ~ .scrollbutton-down, 37 | link[href$="global.css"] ~ spacer[part=arrowscrollbox-overflow-start-indicator], 38 | link[href$="global.css"] ~ spacer[part=arrowscrollbox-overflow-end-indicator] { 39 | display: none !important; 40 | } 41 | .hidevscroll-scrollbar { 42 | -moz-appearance: none!important; 43 | margin-left: 7px!important; 44 | border: none!important; 45 | position: relative!important; 46 | background-color: transparent!important; 47 | padding: 0px!important; 48 | z-index: 2147483647!important; 49 | } 50 | .hidevscroll-scrollbar[orient = "vertical"] { 51 | -moz-margin-start: -7px!important; 52 | min-width: 7px!important; 53 | } 54 | .hidevscroll-scrollbar[orient = "vertical"] thumb { 55 | min-height: 20px!important; 56 | } 57 | .hidevscroll-scrollbar thumb { 58 | -moz-appearance: none!important; 59 | border-width: 0px!important; 60 | border-radius: 7px!important; 61 | background-color: rgb(136, 137, 141, 1)!important; 62 | opacity: 0!important; 63 | transition: opacity 0.4s ease-in-out!important; 64 | -webkit-transform-style: preserve-3d!important; 65 | -webkit-backface-visibility: hidden!important; 66 | } 67 | .hidevscroll-scrollbar:hover thumb { 68 | background-color: rgb(136, 137, 141, 1)!important; 69 | opacity: 0.7!important; 70 | transition: opacity 0.1s ease-in-out!important; 71 | -webkit-transform-style: preserve-3d!important; 72 | -webkit-backface-visibility: hidden!important; 73 | } 74 | .hidevscroll-scrollbar[orient = "vertical"] thumb:active { 75 | background: linear-gradient(to top, #c50ed2, #8500f7) !important; 76 | } 77 | .hidevscroll-scrollbar[orient = "horizontal"] thumb:active { 78 | background: linear-gradient(to left, #c50ed2, #8500f7) !important; 79 | } 80 | .hidevscroll-scrollbar thumb:active { 81 | opacity: 0.9!important; 82 | transition: opacity 0.06s ease-in-out!important; 83 | -webkit-transform-style: preserve-3d!important; 84 | -webkit-backface-visibility: hidden!important; 85 | } 86 | .hidevscroll-scrollbar scrollbarbutton, .hidevscroll-scrollbar gripper { 87 | display: none!important; 88 | } 89 | :not(select):not(hbox) > scrollbar { 90 | position: relative; 91 | background-color: transparent; 92 | background-image: none; 93 | z-index: 2147483647; 94 | padding: 0px; 95 | } 96 | :not(select):not(hbox) > scrollbar[orient = "vertical"] { 97 | -moz-margin-start: -7px; 98 | min-width: 7px; 99 | max-width: 7px; 100 | } 101 | :not(select):not(hbox) > scrollbar[orient = "vertical"] thumb { 102 | min-height: 20px; 103 | } 104 | :not(select):not(hbox) > scrollbar[orient = "horizontal"] { 105 | margin-top: -7px; 106 | min-height: 7px; 107 | max-height: 7px; 108 | } 109 | :not(select):not(hbox) > scrollbar[orient = "horizontal"] thumb { 110 | max-width: 20px; 111 | } 112 | :not(select):not(hbox) > scrollbar thumb { 113 | -moz-appearance: none!important; 114 | border-width: 0px!important; 115 | border-radius: 7px!important; 116 | background-color: rgb(136, 137, 141, 1)!important; 117 | opacity: 0!important; 118 | transition: opacity 0.4s ease-in-out; 119 | -webkit-transform-style: preserve-3d; 120 | -webkit-backface-visibility: hidden; 121 | } 122 | :not(select):not(hbox) > scrollbar:hover thumb { 123 | background-color: rgb(136, 137, 141, 1)!important; 124 | opacity: 0.7!important; 125 | transition: opacity 0.1s ease-in-out; 126 | -webkit-transform-style: preserve-3d; 127 | -webkit-backface-visibility: hidden; 128 | } 129 | :not(select):not(hbox) > scrollbar[orient = "vertical"] thumb:active { 130 | background: linear-gradient(to top, #c50ed2, #8500f7) !important; 131 | } 132 | :not(select):not(hbox) > scrollbar[orient = "horizontal"] thumb:active { 133 | background: linear-gradient(to left, #c50ed2, #8500f7) !important; 134 | } 135 | :not(select):not(hbox) > scrollbar thumb:active { 136 | opacity: 0.9!important; 137 | transition: opacity 0.06s ease-in-out; 138 | -webkit-transform-style: preserve-3d; 139 | -webkit-backface-visibility: hidden; 140 | } 141 | :not(select):not(hbox) > scrollbar scrollbarbutton, :not(select):not(hbox) > scrollbar gripper { 142 | display: none; 143 | } 144 | `; 145 | 146 | var sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService); 147 | var uri = makeURI('data:text/css;charset=UTF=8,' + encodeURIComponent(css)); 148 | 149 | // if (enabled) { 150 | sss.loadAndRegisterSheet(uri, sss.AGENT_SHEET); 151 | // } 152 | })(); 153 | -------------------------------------------------------------------------------- /JS/macosTheme.uc.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name MacOS Window Control & Font Theme 3 | // @version 1.1.2 4 | // @author Hakanbaban53 5 | // @homepage https://github.com/Hakanbaban53/RealFire 6 | // @description Move the window control to the left and recolor it and change the font. 7 | // @downloadURL https://cdn.jsdelivr.net/gh/Hakanbaban53/RealFire@main/JS/macosTheme.uc.js 8 | // @updateURL https://cdn.jsdelivr.net/gh/Hakanbaban53/RealFire@main/JS/macosTheme.uc.js 9 | // @license This Source Code Form is subject to the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International License, v. 4.0. If a copy of the CC BY-NC-SA 4.0 was not distributed with this file, You can obtain one at http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 10 | // ==/UserScript== 11 | 12 | (function () { 13 | // CSS rules to apply 14 | var css = ` 15 | /* Default font family for most elements, with fallbacks */ 16 | *:not([class*="FokDXb"]):not([class*="upload"]):not([class*="icon"]):not([class*="mui-amount"]):not([class*="chaoshi"]):not([class*="top-nav"]):not([href*="ju.taobao.com"]):not([class*="Icon"]):not(b):not(ins):not(i):not(s) { 17 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Ubuntu", "Cantarell", sans-serif !important; 18 | } 19 | 20 | #toolbar-menubar .titlebar-buttonbox-container { 21 | display: flex !important; 22 | } 23 | #toolbar-menubar { 24 | display: flex; 25 | flex-direction: row-reverse; 26 | } 27 | 28 | /* Toolbar adjustments for when width is 1000px or more */ 29 | @media (min-width: 1000px) { 30 | #navigator-toolbox:not([inFullscreen]) #TabsToolbar .titlebar-buttonbox-container { 31 | visibility: visible !important; 32 | display: block !important; 33 | position: absolute !important; 34 | top: 12px; 35 | left: -8px; 36 | } 37 | /* Hide titlebar buttonbox container in toolbar menubar by default */ 38 | #toolbar-menubar .titlebar-buttonbox-container { 39 | display: none !important; 40 | } 41 | } 42 | 43 | 44 | /* Reorder toolbar items */ 45 | #TabsToolbar .toolbar-items { 46 | order: 1 !important; 47 | } 48 | 49 | #TabsToolbar .titlebar-buttonbox-container { 50 | order: 0 !important; 51 | } 52 | 53 | /* Styling for titlebar buttons */ 54 | :root[sizemode="maximized"] .titlebar-buttonbox-container { 55 | padding-top: 0 !important; 56 | } 57 | 58 | :root:-moz-window-inactive:not([customizing]) .titlebar-buttonbox > toolbarbutton:not(:hover) { 59 | opacity: 0.65 !important; 60 | list-style-image: url(chrome://userchrome/content/material/inactive.svg) !important; 61 | } 62 | 63 | .titlebar-buttonbox { 64 | gap: 10px; 65 | margin-right: 12px !important; 66 | margin-left: 12px !important; 67 | } 68 | 69 | .titlebar-button > .toolbarbutton-icon, 70 | .toolbarbutton-icon { 71 | opacity: 1 !important; 72 | appearance: none !important; 73 | background-image: none !important; 74 | } 75 | 76 | .titlebar-button > .toolbarbutton-icon { 77 | height: 15px !important; 78 | min-height: 25px !important; 79 | width: 15px !important; 80 | min-width: 25px !important; 81 | padding-left: 6px !important; 82 | padding-right: 6px !important; 83 | } 84 | 85 | /* Order and appearance of titlebar buttons */ 86 | .titlebar-close { 87 | order: 0 !important; 88 | padding: 0 !important; 89 | list-style-image: url(chrome://userchrome/content/material/close.svg) !important; 90 | } 91 | 92 | .titlebar-min { 93 | order: 1 !important; 94 | padding: 0 !important; 95 | list-style-image: url(chrome://userchrome/content/material/minimize.svg) !important; 96 | } 97 | 98 | .titlebar-max, .titlebar-restore { 99 | order: 2 !important; 100 | padding: 0 !important; 101 | list-style-image: url(chrome://userchrome/content/material/maximize.svg) !important; 102 | } 103 | 104 | /* Hover states for titlebar buttons */ 105 | .titlebar-min:hover { 106 | list-style-image: url(chrome://userchrome/content/material/minimize-hover.svg) !important; 107 | } 108 | 109 | .titlebar-max:hover { 110 | list-style-image: url(chrome://userchrome/content/material/maximize-hover.svg) !important; 111 | } 112 | 113 | .titlebar-restore:hover { 114 | list-style-image: url(chrome://userchrome/content/material/maximize-restore.svg) !important; 115 | } 116 | 117 | .titlebar-close:hover { 118 | list-style-image: url(chrome://userchrome/content/material/close-hover.svg) !important; 119 | } 120 | `; 121 | 122 | // Function to initialize the script 123 | function init() { 124 | var root = document.documentElement; 125 | var urlbarPosition = getComputedStyle(root).getPropertyValue('--uc-urlbar-position').trim(); 126 | // console.log('URL Bar Position:', urlbarPosition); 127 | 128 | // Function to apply styles based on the media query status 129 | function applyStyles(matches) { 130 | var navBar = document.getElementById('nav-bar'); 131 | var titleBar = document.getElementById('titlebar'); 132 | 133 | if (urlbarPosition === '1') { 134 | navBar.style.paddingLeft = matches ? '106px' : '0'; 135 | } else if (urlbarPosition === '3') { 136 | titleBar.style.paddingLeft = matches ? '106px' : '0'; 137 | } 138 | } 139 | 140 | // Initial application of styles 141 | applyStyles(window.matchMedia('(min-width: 1000px)').matches); 142 | 143 | // Listen for changes in the media query status 144 | window.matchMedia('(min-width: 1000px)').addEventListener('change', function (event) { 145 | applyStyles(event.matches); 146 | }); 147 | } 148 | 149 | // Check if the browser initialization is complete 150 | if (gBrowserInit.delayedStartupFinished) { 151 | init(); 152 | } else { 153 | let delayedListener = (subject, topic) => { 154 | if (topic == "browser-delayed-startup-finished" && subject == window) { 155 | Services.obs.removeObserver(delayedListener, topic); 156 | init(); 157 | } 158 | }; 159 | Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished"); 160 | } 161 | 162 | // Create a style element and append the CSS rules 163 | var style = document.getElementById("macos-theme-style"); 164 | if (!style) { 165 | style = document.createElement("style"); 166 | style.id = "macos-theme-style"; 167 | style.type = "text/css"; 168 | style.textContent = css; 169 | document.head.appendChild(style); 170 | } 171 | })(); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Hakan İSMAİL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # [RealFire 🔥](https://github.com/Hakanbaban53/RealFire) 4 | 5 | **A minimalist animated oneliner theme for Firefox perfectly matching real Dark** 6 | 7 |
8 |

9 | 10 | ## 🏞 Screenshots 11 | 12 |
Click me 🐈 13 | 14 |

Adaptive Tab Bar Extension Support

15 |

16 | 17 |

MacOs Window Control & Fonts

18 |

19 | 20 |

Animated Background

21 |

22 | 23 |

Context Menu

24 |

25 | 26 |

Auto-hide Scrollbars

27 |

28 | 29 |

Library

30 |

31 | 32 |

Adaptive Window Color With Windows & GNU/Linux

33 |

34 | 35 |
36 | 37 | ## 📃 Browser JS Files 38 | 39 | ### [`userChrome.css`](./userChrome.css) 40 | 41 | This helps to customize Firefox User Interface. 42 | 43 | ### [`userContent.css`](./userContent.css) 44 | 45 | This helps to customize web content like a specific site. 46 | 47 | ### [`hideScrollbar.uc.js`](./JS/hideScrollbar.uc.js) 48 | 49 | It's now possible to autohide scrollbars. 50 | 51 | ### [`macosTheme.uc.js`](./JS/macosTheme.uc.js) 52 | 53 | This script to convert font and window controls to macos style. 54 | 55 | ## ❓ **But how does it work?** 56 | 57 | Custom startup-script (aka [`mozilla.cfg`](./programs/mozilla.cfg) here) is loaded using [`local-settings.js`](./programs/local-settings.js). This startup-script adds "loader" scripts from `utils` folder that loads arbitrary javascript files from the `script` folder into Firefox
58 | `mozilla.cfg` also helps in setting local webpage as your homepage. Details in [Installation](#Installation) (Currently Not Working!). 59 | 60 | ## 💡 Installation 61 | 62 |
GUI Installation 63 | Firefox Theme Installer 64 | 65 | ### [Check This Repo](https://github.com/Hakanbaban53/Firefox-Theme-Installer?tab=readme-ov-file#--------firefox-theme-installer--) 66 | 67 | Explore the Firefox Theme Installer repository for an easy and efficient way to install and manage your Firefox themes. 68 | 69 |
70 | 71 |
Curl based Installation (You can install this theme with one line command) 72 | 73 |
GNU/Linux & MacOS
74 | 75 | ```console 76 | $ curl -s -o- https://raw.githubusercontent.com/Hakanbaban53/RealFire/main/programs/install-curl.sh | bash # Standard 77 | $ curl -s -o- https://raw.githubusercontent.com/Hakanbaban53/RealFire/main/programs/install-curl.sh | bash -s -- -f ~/.var/app/org.mozilla.firefox/.mozilla/firefox # Flatpak 78 | $ curl -s -o- https://raw.githubusercontent.com/Hakanbaban53/RealFire/main/programs/install-curl.sh | bash -s -- -f ~/snap/firefox/common/.mozilla/firefox/ # Snap 79 | ``` 80 | 81 |
82 | 83 |
Windows
84 | 85 | ```powershell 86 | > curl -sL "https://raw.githubusercontent.com/Hakanbaban53/RealFire/main/programs/install-curl.bat" > %TEMP%\install-curl.bat && %TEMP%\install-curl.bat REM Standard 87 | > curl -sL "https://raw.githubusercontent.com/Hakanbaban53/RealFire/main/programs/install-curl.bat" > %TEMP%\install-curl.bat && %TEMP%\install-curl.bat -b "C:\Program Files (x86)\Mozilla Firefox" REM Custom binary folder 88 | ``` 89 |
90 | 91 | This will download the master branch and run the installation script. 92 | `mozilla.cfg` can be configured after complete installation 93 | 94 |
95 | 96 |
Script Installation 97 | 98 | 1. Clone the repository and enter folder: 99 | 100 | ```console 101 | $ git clone https://github.com/Hakanbaban53/RealFire.git && cd RealFire 102 | ``` 103 | 104 | 2. Run installation script 105 | 106 | This script will lookup default Firefox profile location and install the theme with default configurations. 107 | 108 |
GNU/Linux & MacOS
109 | 110 | ```console 111 | $ ./programs/install.sh # Standard 112 | $ ./programs/install.sh -f ~/.var/app/org.mozilla.firefox/.mozilla/firefox # Flatpak 113 | $ ./programs/install.sh -f ~/snap/firefox/common/.mozilla/firefox/ # Snap 114 | ``` 115 | 116 |
117 | 118 |
Windows
119 | 120 | ```powershell 121 | > programs\install.bat REM Standard 122 | > programs\install.bat -e -b "C:\Program Files (x86)\Mozilla Firefox" REM Disable fx-autoconfig and Custom binary folder 123 | ``` 124 | 125 |
126 | 127 | #### Script options 128 | 129 | - `-b ` _optional_ 130 | 131 | - Set custom Firefox binary folder path, for example `/usr/lib32/firefox` 132 | - Default: Auto detects in linux. `C:\Program Files\Mozilla Firefox` in windows 133 | 134 | - `-f ` _optional_ 135 | 136 | - Set custom Firefox folder path, for example `~/.mozilla/icecat/` 137 | - Default: `~/.mozilla/firefox/` in linux. `%APPDATA%\Mozilla\Firefox` in windows 138 | 139 | - `-p ` _optional_ 140 | 141 | - Set custom profile name, for example `4htgy4pu.app` 142 | - Default: Profile folder name found in `profiles.ini` at -> 143 | 144 | ``` 145 | [Install4F96D1932A9F858E] 146 | Default=1yrah0xg.default-release 147 | Locked=1 148 | ``` 149 | 150 | - `-e` _optional_ 151 | 152 | - Install [`fx-autoconfig`](https://github.com/MrOtherGuy/fx-autoconfig) 153 | - Runs sudo to copy `mozilla.cfg` and `local-settings.js` to Application Binary folder 154 | - Default: True 155 | 156 | - `-h` _optional_ 157 | - Shows help message with flags info 158 |
159 | 160 |
Manual Installation 161 | 162 | 1. Open `about:support` in new tab and click `Open Directory` near `Profile Directory`. 163 | 164 | 2. Open this directory in terminal and clone the repository 165 | 166 | Note: If you already have a `chrome` folder under `Profile Directory`, rename it to `chrome_bak` or anything else to preserve your old theme. 167 | 168 | ```console 169 | $ cd {Your profile directory} 170 | 171 | $ git clone https://github.com/Hakanbaban53/RealFire.git chrome 172 | 173 | $ cd chrome 174 | ``` 175 | 176 |
MacOS
177 | 178 | - `about:support` > `Application Binary` > `{Installation folder}firefox`
179 | Generally `Installation folder` is `/Applications/Firefox.app/Contents/MacOS/` (`Firefox Nightly` for Nightly version) 180 | 181 | For `MacOS`, our destination folder is `/Applications/Firefox.app/Contents/Resources/` 182 | 183 | ```console 184 | $ ln -s "`pwd`/programs/user.js" ../user.js 185 | 186 | $ cp ./programs/mozilla.cfg /Applications/Firefox.app/Contents/Resources/ 187 | 188 | $ cp ./programs/local-settings.js /Applications/Firefox.app/Contents/Resources/defaults/pref/ 189 | ``` 190 | 191 |
192 | 193 |
Windows
194 | 195 | - `about:support` > `Application Binary` > `{Installation folder}firefox.exe`
196 | Generally `Installation folder` is `C:\Program Files\Mozilla Firefox\` 197 | 198 | ```powershell 199 | > mklink ..\user.js "%cd%\programs\user.js" 200 | 201 | > copy .\programs\mozilla.cfg "C:\Program Files\Mozilla Firefox\" 202 | 203 | > copy .\programs\local-settings.js "C:\Program Files\Mozilla Firefox\defaults\pref\" 204 | ``` 205 |
206 | ``` 207 | 208 |
209 | 210 | - 🗑️ If you want to remove the Theme: 211 | 212 | #### GNU/Linux & MacOS 213 | ./programs/uninstall.sh 214 | 215 | #### Windows 216 | ./programs/uninstall.bat 217 | 218 | 219 | #### 🔧 Follow-up changes 220 | 221 | 1. In Firefox 222 | 223 | - Right click hamburger button > `customize toolbar` disable `Title Bar`, `Drag Space`. 224 | - Remove `Flexible Space` from urlbar. 225 | - Set Density to `Compact/Normal/Touch` and Themes to `Dark` or `Light`. 226 | 227 | 2. Open `about:support` > `Clear startup cache...` > `Restart` **_twice_** 228 | 229 | 3. ### **Voilà** 230 | 231 | ## ⚙️ Configuration 232 | 233 | 1. You can use the [ realfire-config.css ](/includes/realfire-config.css) change the a lot of variables. 234 | 235 | 2. If you run the automatic installation script, it will install all the files in the folders where they need to be installed. 236 | 237 | 3. If something breaks on your system then please raise a issue 238 | 239 | 4. If you want to use `vertical tabs`, you may need to edit this line in the [realfire-config.css](/includes/realfire-config.css#L59) file. 240 | 241 | ## 📌 Known issues 242 | 243 | - Adaptive window color with windows not working on preferences page and start page (Windows only). If you want the change it use the [ realfire-config.css ](/includes/realfire-config.css) file. 244 | 245 | ## 📂 Folder structure 246 | 247 | ```css 248 | 🗃 . 249 | ├── 🖿 assets 250 | │ └── 🖻 preview images 251 | ├── 🖿 img 252 | │ └── 🖻 new tab background image 253 | ├── 🖿 includes 254 | │ ├── 🗎 realfire-checkbox.css 255 | │ ├── 🗎 realfire-icons.css 256 | │ ├── 🗎 realfire-config.css 257 | │ └── 🗐 other .css files 258 | ├── 🖿 JS 259 | │ ├── 🗎 aboutUserChrome.sys.mjs 260 | │ ├── 🗎 navbarToolbarButtonSlider.uc.js 261 | │ ├── 🗎 macosTheme.us.js 262 | │ └── 🗐 many script in .uc.js format 263 | ├── 🖿 programs 264 | │ ├── 🗎 install-cfg.sh 265 | │ ├── 🗎 install.sh 266 | │ ├── 🗎 install-curl.sh 267 | │ ├── 🗎 install.bat 268 | │ ├── 🗎 install-curl.bat 269 | │ ├── 🗎 local-settings.js 270 | │ ├── 🗎 mozilla.cfg 271 | │ ├── 🗎 uninstall.bat 272 | │ ├── 🗎 uninstall.sh 273 | │ └── 🗎 user.js 274 | ├── 🖿 resources 275 | │ └── 🖿 icons 276 | │ └── 🗐 many icons in .svg format 277 | ├── 🖿 utils 278 | │ ├── 🗎 .editorconfig 279 | │ ├── 🗎 boot.sys.mjs 280 | │ ├── 🗎 chrome.manifest 281 | │ ├── 🗎 fs.sys.mjs 282 | │ └── 🗎 utils.sys.mjs 283 | ├── 🗎 README.md 284 | ├── 🗎 userChrome.css 285 | └── 🗎 userContent.css 286 | 287 | ``` 288 | 289 | ## Credits 290 | 291 | - I started with this amazing material theme : [Sweet_Pop!](https://github.com/PROxZIMA/Sweet-Pop) by [PROxZIMA](https://github.com/PROxZIMA) 292 | 293 | - One of the best dark theme for Firefox : [ShadowFox](https://overdodactyl.github.io/ShadowFox) by [overdodactyl](https://github.com/overdodactyl) 294 | 295 | - [Theme inspiration](https://www.reddit.com/r/FirefoxCSS/comments/ci7i69/another_oneline_theme/) by [u/SENDMEJUDES](https://www.reddit.com/user/SENDMEJUDES/) 296 | 297 | - [Installation script](https://github.com/rafaelmardojai/firefox-gnome-theme) details. 298 | 299 | --- 300 | 301 | ## Stargazers over time 302 | 303 | [![Stargazers over time](https://starchart.cc/Hakanbaban53/RealFire.svg)](https://starchart.cc/Hakanbaban53/RealFire) 304 | 305 | [Back to top](#RealFire_🔥) 306 | 307 | --- 308 | 309 |

Hakan İSMAİL ❤

310 | -------------------------------------------------------------------------------- /assets/adaptive-tab-bar-extension-support.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/adaptive-tab-bar-extension-support.gif -------------------------------------------------------------------------------- /assets/adaptive.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/adaptive.gif -------------------------------------------------------------------------------- /assets/context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/context.png -------------------------------------------------------------------------------- /assets/hide_scroll_bar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/hide_scroll_bar.gif -------------------------------------------------------------------------------- /assets/library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/library.png -------------------------------------------------------------------------------- /assets/mac_os_theme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/mac_os_theme.gif -------------------------------------------------------------------------------- /assets/navbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/navbar.gif -------------------------------------------------------------------------------- /assets/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/assets/preview.png -------------------------------------------------------------------------------- /img/new_tab_wallpaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hakanbaban53/RealFire/61a2d4d6325d13bbc729a40445bda27acd1c2f59/img/new_tab_wallpaper.jpg -------------------------------------------------------------------------------- /includes/realfire-addons-page.css: -------------------------------------------------------------------------------- 1 | @-moz-document url(about:addons) { 2 | 3 | /* Navigation menu */ 4 | #sidebar { 5 | align-items: center !important; 6 | background-color: var(--uc-base-colour) !important; 7 | border-right: 2px solid var(--settings-color) !important; 8 | -moz-appearance: none !important; 9 | } 10 | 11 | .sticky-container { 12 | border-bottom: 2px solid var(--accent-color) !important; 13 | -moz-appearance: none !important; 14 | } 15 | 16 | .main-heading { 17 | padding: 16px !important; 18 | background-color: var(--uc-base-colour) !important; 19 | border-top: 2px solid var(--accent-color) !important; 20 | border-inline: 2px solid var(--accent-color) !important; 21 | border-radius: var(--uc-border-radius) var(--uc-border-radius) 0 0 !important; 22 | } 23 | 24 | #content { 25 | background: var(--uc-base-colour) !important; 26 | } 27 | 28 | #categories { 29 | width: auto !important; 30 | } 31 | 32 | #categories richlistitem { 33 | color: var(--uc-inverted-colour) !important; 34 | border-radius: var(--uc-border-radius) !important; 35 | margin-inline: 20px !important; 36 | justify-content: center !important; 37 | } 38 | 39 | /* Sidebar footer */ 40 | .sidebar-footer-list { 41 | margin-inline: 0 !important; 42 | margin-inline-start: 0 !important; 43 | } 44 | 45 | /* Selected category color */ 46 | @media not (prefers-contrast) { 47 | #categories > .category[selected], 48 | #categories > .category.selected { 49 | color: var(--settings-color) !important; 50 | } 51 | } 52 | 53 | /* Selected privacy option background */ 54 | .privacy-detailedoption.selected { 55 | border-color: var(--settings-color) !important; 56 | background-color: color-mix(var(--settings-color) 20%, transparent) !important; 57 | } 58 | 59 | /* Links */ 60 | a, 61 | .text-link { 62 | color: var(--settings-color) !important; 63 | } 64 | 65 | a:hover, 66 | .text-link:hover, 67 | .text-link:is(:not([disabled="true"]), :enabled):hover { 68 | color: color-mix(var(--uc-inverted-colour), var(--settings-color)) !important; 69 | } 70 | 71 | /* Addon card hover effect */ 72 | addon-card:not([expanded]) > .addon.card:hover { 73 | box-shadow: 0 0 0 5px var(--accent-field-color) !important; 74 | } 75 | 76 | /* Focus styles */ 77 | tree:focus-visible, 78 | textarea:focus-visible, 79 | search-textbox[focused], 80 | richlistbox:focus-visible, 81 | input:is([type="email"], [type="tel"], [type="text"], [type="password"], [type="url"], [type="number"]):focus, 82 | #searchInput[focused="true"] { 83 | outline: 2px solid var(--settings-color) !important; 84 | } 85 | 86 | /* Search input */ 87 | #searchInput { 88 | border-radius: var(--uc-border-radius) !important; 89 | } 90 | 91 | /* Buttons */ 92 | button, 93 | #row-selector.selector { 94 | color: var(--uc-inverted-colour) !important; 95 | border-radius: var(--uc-border-radius) !important; 96 | } 97 | 98 | button.primary, 99 | button[default], 100 | button[autofocus], 101 | button[type="submit"], 102 | button:not([disabled])[default="true"] { 103 | background-color: var(--accent-color) !important; 104 | border-color: var(--accent-color) !important; 105 | color: var(--button-text-white) !important; 106 | } 107 | 108 | /* Focus styles for controls */ 109 | button:focus-visible, 110 | select:focus-visible, 111 | menulist:focus-visible, 112 | radio[focused="true"] > .radio-check, 113 | tab:focus-visible > .tab-middle > .tab-text, 114 | checkbox:not([native]):focus-visible > .checkbox-check, 115 | input:is([type="checkbox"], [type="color"], [type="radio"]):focus-visible { 116 | outline: 2px solid var(--uc-inverted-colour) !important; 117 | outline-offset: 0 !important; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /includes/realfire-button.css: -------------------------------------------------------------------------------- 1 | button, 2 | #row-selector.selector { 3 | color: var(--uc-inverted-colour) !important; 4 | border-radius: var(--uc-border-radius) !important; 5 | } 6 | 7 | button:focus-visible, 8 | select:focus-visible, 9 | menulist:focus-visible, 10 | radio[focused="true"]>.radio-check, 11 | tab:focus-visible>.tab-middle>.tab-text, 12 | checkbox:not([native]):focus-visible>.checkbox-check, 13 | input:is([type="checkbox"], [type="color"], [type="radio"]):focus-visible { 14 | outline-offset: 0px !important; 15 | outline: var(--uc-inverted-colour) solid 2px !important; 16 | } 17 | 18 | button:not([disabled])[default], 19 | button[data-l10n-id="permission-dialog-btn-open-link"] { 20 | color: var(--button-text-white) !important; 21 | background-color: var(--accent-color) !important; 22 | } -------------------------------------------------------------------------------- /includes/realfire-checkbox.css: -------------------------------------------------------------------------------- 1 | .checkbox-check[checked], 2 | input[type="checkbox"]:checked { 3 | background-size: 14px !important; 4 | fill: var(--uc-inverted-colour) !important; 5 | background-color: var(--accent-color) !important; 6 | } 7 | .checkbox-check { 8 | border-radius: 4px !important; 9 | } 10 | 11 | .radio-check[selected], 12 | input[type="radio"]:checked { 13 | fill: var(--uc-inverted-colour) !important; 14 | background-color: var(--accent-color) !important; 15 | } -------------------------------------------------------------------------------- /includes/realfire-colours.css: -------------------------------------------------------------------------------- 1 | /* ---+---+---+---+---+---+---+ 2 | | C | O | L | O | U | R | S | 3 | +---+---+---+---+---+---+---+ */ 4 | 5 | /* Dark Mode Color Scheme */ 6 | @media (prefers-color-scheme: dark) { 7 | :root { 8 | /* Container Tabs Plugin Colors */ 9 | --uc-identity-colour-red: #fc5c65; 10 | --uc-identity-colour-pink: #f78fb3; 11 | --uc-identity-colour-blue: #0078d7; 12 | --uc-identity-colour-green: #b8e994; 13 | --uc-identity-colour-purple: #786fa6; 14 | --uc-identity-colour-yellow: #f7d794; 15 | --uc-identity-colour-orange: #f19066; 16 | --uc-identity-colour-turquoise: #55e6c1; 17 | 18 | /* RealFire Main Color Scheme */ 19 | --uc-base-colour: #000000; 20 | --uc-muted-colour: #c3c3c3; 21 | --uc-inverted-colour: #fafafc; 22 | --uc-highlight-colour: #191b1c; 23 | --uc-accent-colour: AccentColor; 24 | } 25 | } 26 | 27 | /* Light Mode Color Scheme */ 28 | @media (prefers-color-scheme: light) { 29 | :root { 30 | /* Container Tabs Plugin Colors */ 31 | --uc-identity-colour-red: #fc5c65; 32 | --uc-identity-colour-blue: #1d65f5; 33 | --uc-identity-colour-pink: #ec83d0; 34 | --uc-identity-colour-green: #40a02b; 35 | --uc-identity-colour-purple: #822fee; 36 | --uc-identity-colour-yellow: #e49320; 37 | --uc-identity-colour-orange: #fe640b; 38 | --uc-identity-colour-turquoise: #209fb5; 39 | 40 | /* RealFire Main Color Scheme */ 41 | --uc-base-colour: #fafafc; 42 | --uc-muted-colour: #292929; 43 | --uc-inverted-colour: #1e2021; 44 | --uc-highlight-colour: #dadadc; 45 | --uc-accent-colour: AccentColor; 46 | } 47 | } 48 | 49 | /* Variables for UI Density */ 50 | :root[uidensity="compact"] { 51 | --sidebar-menupopup-height: 29px; 52 | } 53 | 54 | :root[uidensity="touch"] { 55 | --sidebar-menupopup-height: 41px; 56 | } 57 | 58 | /* General UI Variables */ 59 | :root { 60 | --tab-radius: 8px; 61 | --navbar-percent: 32vw; 62 | --tab-border-width: 2px; 63 | --toolbar-percent: 68vw; 64 | --sidebar-menupopup-height: 36px; 65 | --subview-height: var(--tab-min-height); 66 | --bookmark-block-padding: 1px; 67 | --menupopup-height: var(--tab-min-height); 68 | --navbar-margin-top: calc(0px - var(--tab-min-height)); 69 | --toolbarbutton-inner-padding: 6px; 70 | --toolbarbutton-outer-padding: 3px; 71 | --urlbar-icon-padding: 3px; 72 | --urlbar-min-height: calc(var(--tab-min-height) - 3px); 73 | 74 | /* Colors */ 75 | --accent-color: var(--uc-accent-colour); 76 | --settings-color: var(--uc-accent-colour); 77 | --button-text-white: #ffffff; 78 | --accent-field-color: color-mix(in srgb, field 70%, var(--accent-color)); 79 | --accent-hover-color: color-mix(in srgb, var(--accent-color) 90%, var(--uc-inverted-colour) 20%); 80 | 81 | /* Light-weight Themes (LWT) */ 82 | --lwt-frame: var(--uc-base-colour); 83 | --lwt-text-color: var(--uc-inverted-colour); 84 | --toolbar-field-color: var(--uc-inverted-colour); 85 | --toolbar-field-focus-border-color: transparent; 86 | --toolbar-field-focus-color: var(--uc-inverted-colour); 87 | --urlbar-popup-url-color: var(--uc-accent-colour); 88 | --lwt-toolbar-field-highlight: var(--uc-inverted-colour); 89 | --lwt-tab-text: var(--lwt-text-colour); 90 | --toolbar-color: var(--lwt-text-color); 91 | --toolbarseparator-color: var(--uc-accent-colour); 92 | --toolbarbutton-active-background: var(--toolbarbutton-hover-background); 93 | --sidebar-background-color: var(--lwt-sidebar-background-color); 94 | --urlbar-box-text-color: var(--uc-muted-colour); 95 | --urlbar-box-hover-text-color: var(--uc-inverted-colour); 96 | } 97 | -------------------------------------------------------------------------------- /includes/realfire-config.css: -------------------------------------------------------------------------------- 1 | /*---+---+---+---+---+---+---+ 2 | | G | L | O | B | A | L | 3 | +---+---+---+---+---+---+---*/ 4 | 5 | :root { 6 | /* Global Border Radius */ 7 | --uc-border-radius: 8px; 8 | 9 | /* Distance the Statuspanel floats away from the window border */ 10 | --uc-status-panel-spacing: 12px; 11 | 12 | /* Animation Duration */ 13 | --uc-animation-duration: 0.3s; 14 | } 15 | 16 | /* Remove window control buttons */ 17 | /* .titlebar-buttonbox-container { display: none !important; } */ 18 | 19 | #pageActionButton { 20 | display: none !important; 21 | } 22 | 23 | #PanelUI-menu-button { 24 | padding: 8px !important; 25 | } 26 | 27 | #PanelUI-menu-button .toolbarbutton-badge-stack { 28 | padding: 8px !important; 29 | } 30 | 31 | /*---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 32 | | B | O | O | K | M | A | R | S | | T | O | O | L | B | A | R | 33 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ 34 | 35 | :root { 36 | /* Position of the Personal Toolbar (0 - top, 4 - bottom) */ 37 | --uc-toolbar-position: 4; 38 | 39 | /* Darken the Personal Toolbar (0-1) */ 40 | --uc-darken-toolbar: 0.2; 41 | /* Darken by 20% in dark mode */ 42 | } 43 | 44 | @media (prefers-color-scheme: light) { 45 | :root { 46 | --uc-darken-toolbar: 0; 47 | /* No darkening in light mode */ 48 | } 49 | } 50 | 51 | /*---+---+---+---+---+---+---+ 52 | | U | R | L | B | A | R | 53 | +---+---+---+---+---+---+---*/ 54 | 55 | :root { 56 | /* Width of the URL Bar (min-width and max-width) */ 57 | /* If you want to use vertical tabs, you can set the max-width to 100vh */ 58 | --uc-urlbar-min-width: 20vw; 59 | --uc-urlbar-max-width: 40vw; 60 | 61 | /* Position of the URL Bar (1 - tabs on right, 3 - tabs on left) */ 62 | --uc-urlbar-position: 1; 63 | 64 | /* Firefox can be wonky with vertical URL Bar placement */ 65 | --uc-urlbar-top-spacing: 0px; 66 | } 67 | 68 | /* Disable Navigation Buttons */ 69 | /* #back-button, #forward-button { display: none !important; } */ 70 | 71 | /* Disable Tracking Protection Shield */ 72 | #tracking-protection-icon-container { 73 | display: none !important; 74 | } 75 | 76 | /* Hide Encryption and Permissions icons */ 77 | /* #identity-permission-box { display: none !important; } */ 78 | /* #identity-box { display: none !important; } */ 79 | 80 | /* Hide everything BUT the zoom indicator within the URL Bar */ 81 | /* #page-action-buttons > :not(#urlbar-zoom-button) { display: none !important; } */ 82 | 83 | /* Hide the Go-arrow in the URL Bar */ 84 | #urlbar-go-button { 85 | display: none !important; 86 | } 87 | 88 | /* Hide the Extensions Menu Icon */ 89 | /* #unified-extensions-button { display: none !important; } */ 90 | 91 | /*---+---+---+---+---+---+---+ 92 | | T | A | B | B | A | R | 93 | +---+---+---+---+---+---+---*/ 94 | 95 | :root { 96 | /* Active and Inactive Tab Widths */ 97 | --uc-active-tab-width: clamp(100px, 30vw, 300px); 98 | --uc-inactive-tab-width: clamp(100px, 20vw, 200px); 99 | 100 | /* Show Tab Close Button (none - hide, -moz-inline-block - show) */ 101 | --show-tab-close-button: -moz-inline-block; 102 | 103 | /* Show Tab Close Button on Tab Hover (none - hide, -moz-inline-block - show) */ 104 | --show-tab-close-button-hover: -moz-inline-block; 105 | 106 | /*Set the tab position 0px is stuck the bottom */ 107 | --uc-tab-block-margin: 6px; 108 | 109 | /* Hide the all Tabs button from the Tab Bar (show: -moz-box, hide: none) */ 110 | --uc-show-all-tabs-button: -moz-box; 111 | 112 | /* Margin of the Container Tabs Indicator */ 113 | --container-tabs-indicator-margin: 10px; 114 | 115 | /* Glow added to the container indicator */ 116 | --uc-identity-glow: 0 1px 10px 1px; 117 | /* No glow by default */ 118 | } 119 | 120 | /* Hide the secondary Tab Label (e.g., playing indicator) */ 121 | .tab-secondary-label { 122 | display: none !important; 123 | } -------------------------------------------------------------------------------- /includes/realfire-findbar.css: -------------------------------------------------------------------------------- 1 | findbar { 2 | border: none !important; 3 | padding: 6px !important; 4 | background: var(--uc-base-colour) !important; 5 | } 6 | 7 | .findbar-button:hover { 8 | background: var(--uc-highlight-colour) !important; 9 | } 10 | 11 | .textbox-search-sign, 12 | .textbox-search-icon, 13 | .findbar-textbox { 14 | fill: var(--uc-inverted-colour); 15 | padding-inline-start: 28px !important; 16 | background-repeat: no-repeat !important; 17 | background-color: transparent !important; 18 | background-position: 5px center !important; 19 | -moz-context-properties: fill, fill-opacity; 20 | } 21 | 22 | 23 | 24 | .findbar-find-status:not([status="notfound"]) { 25 | display: none !important; 26 | } 27 | 28 | hbox[anonid="findbar-textbox-wrapper"] { 29 | height: 28px !important; 30 | border-radius: var(--uc-border-radius) !important; 31 | background-color: var(--uc-base-colour) !important; 32 | border: 2px solid rgba(217, 217, 217, 0.5) !important; 33 | transition: background-color var(--uc-animation-duration) cubic-bezier(0, -0.74, 0.25, 1) !important; 34 | } 35 | 36 | hbox[anonid="findbar-textbox-wrapper"]:hover { 37 | background-color: var(--uc-highlight-colour) !important; 38 | } 39 | 40 | hbox[anonid="findbar-textbox-wrapper"]:focus-within { 41 | border: 2px solid var(--accent-color) !important; 42 | } 43 | 44 | hbox[anonid="findbar-textbox-wrapper"] toolbarbutton { 45 | border: 0 !important; 46 | margin: 0 !important; 47 | padding: 0 !important; 48 | width: 24px !important; 49 | opacity: 0.5 !important; 50 | height: 24px !important; 51 | display: flex !important; 52 | background: 0 !important; 53 | box-shadow: none !important; 54 | border-radius: 99px !important; 55 | transition: background-color var(--uc-animation-duration) ease !important; 56 | } 57 | 58 | hbox[anonid="findbar-textbox-wrapper"] toolbarbutton[disabled] { 59 | display: none !important; 60 | } 61 | 62 | hbox[anonid="findbar-textbox-wrapper"] toolbarbutton .toolbarbutton-text { 63 | visibility: collapse !important; 64 | } 65 | 66 | hbox[anonid="findbar-textbox-wrapper"] toolbarbutton:not([disabled]):hover { 67 | opacity: 1 !important; 68 | background-color: transparent !important; 69 | } 70 | 71 | hbox[anonid="findbar-textbox-wrapper"] 72 | toolbarbutton:not([disabled]):hover:active { 73 | opacity: 1 !important; 74 | transition-duration: var(--uc-animation-duration) !important; 75 | background-color: transparent !important; 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /includes/realfire-icons.css: -------------------------------------------------------------------------------- 1 | /* menupopup:not(.in-menulist) > menu:not(.menu-iconic), 2 | menupopup:not(.in-menulist, [aria-label]) 3 | > menuitem:not(.menuitem-iconic, [type="checkbox"], [type="radio"]) { 4 | padding-inline-start: calc(2em + 16 px) !important; 5 | } */ 6 | 7 | .subviewbutton .toolbarbutton-icon { 8 | display: -moz-inline-box !important; 9 | } 10 | 11 | input[type="radio"]:checked, 12 | .radio-check[selected], 13 | menuitem[type="radio"][checked="true"] { 14 | background-image: url("chrome://userchrome/content/material/radio-checked.svg"); 15 | } 16 | 17 | input[type="radio"]:not([checked]), 18 | .radio-check, 19 | menuitem[type="radio"]:not([checked="true"]) { 20 | background-image: url("chrome://userchrome/content/material/radio-unchecked.svg") !important; 21 | } 22 | 23 | menuitem[type="checkbox"][checked="true"] { 24 | background-image: url("chrome://userchrome/content/material/checked.svg") !important; 25 | } 26 | 27 | menuitem[type="checkbox"]:not([checked="true"]) { 28 | background-image: url("chrome://userchrome/content/material/unchecked.svg") !important; 29 | } 30 | 31 | .bookmark-item { 32 | list-style-image: url("chrome://userchrome/content/material/bookmark-manage.svg") !important; 33 | } 34 | 35 | #appMenu-translate-button { 36 | list-style-image: url("chrome://userchrome/content/material/translate.svg"); 37 | } 38 | 39 | menuitem[data-l10n-id$="-sync-now"], 40 | #PanelUI-fxa-menu-setup-sync-button { 41 | background-image: url("chrome://browser/skin/sync.svg"); 42 | list-style-image: url("chrome://browser/skin/sync.svg"); 43 | } 44 | 45 | menu.sync-ui-item, 46 | #PanelUI-fxa-menu-sendtab-button { 47 | background-image: url("chrome://userchrome/content/material/send-tab.svg"); 48 | list-style-image: url("chrome://userchrome/content/material/send-tab.svg"); 49 | } 50 | 51 | #menu_browserContentToolbox, 52 | .subviewbutton[label="Browser Content Toolbox"], 53 | .subviewbutton[data-l10n-id$="appmenuitem-more-tools"] { 54 | background-image: url("chrome://userchrome/content/material/toolbox.svg"); 55 | list-style-image: url("chrome://userchrome/content/material/toolbox.svg"); 56 | } 57 | 58 | #menu_preferences, 59 | #openSettingsMenuItem, 60 | .subviewbutton[data-l10n-id$="-settings"] { 61 | background-image: url("chrome://global/skin/icons/settings.svg"); 62 | list-style-image: url("chrome://global/skin/icons/settings.svg"); 63 | } 64 | 65 | #menu_preferences, 66 | #openSettingsMenuItem, 67 | .subviewbutton[id="appMenu-advanced-settings-button"]{ 68 | list-style-image: url("chrome://userchrome/content/material/experiments.svg"); 69 | } 70 | 71 | 72 | #PanelUI-fxa-menu-account-signout-button { 73 | background-image: url("chrome://userchrome/content/material/signout.svg"); 74 | list-style-image: url("chrome://userchrome/content/material/signout.svg"); 75 | } 76 | 77 | #menu_newNavigatorTab, 78 | menuitem[id$="openANewTab"], 79 | #appMenu-new-tab-button2 { 80 | background-image: url("chrome://browser/skin/new-tab.svg"); 81 | list-style-image: url("chrome://browser/skin/new-tab.svg"); 82 | } 83 | 84 | #menu_newNavigator, 85 | #historyUndoWindowMenu, 86 | menuitem[data-l10n-id*="-open-"][data-l10n-id$="-window"], 87 | #context_openTabInWindow, 88 | #appMenu-new-window-button2, 89 | #appMenuRecentlyClosedWindows { 90 | background-image: url("chrome://browser/skin/window.svg"); 91 | list-style-image: url("chrome://browser/skin/window.svg"); 92 | } 93 | 94 | menuitem[data-l10n-id$="-private-window"], 95 | #appMenu-new-private-window-button2 { 96 | background-image: url("chrome://browser/skin/privateBrowsing.svg"); 97 | list-style-image: url("chrome://browser/skin/privateBrowsing.svg"); 98 | } 99 | 100 | .subviewbutton[data-l10n-id="library-bookmarks-menu"], 101 | #panelMenuBookmarkThisPage[starred], 102 | #sidebar-switcher-bookmarks { 103 | background-image: url("chrome://browser/skin/bookmark.svg"); 104 | list-style-image: url("chrome://browser/skin/bookmark.svg"); 105 | } 106 | 107 | menuitem[data-l10n-id*="bookmark-"]:not(.menuitem-iconic), 108 | #context-bookmarkframe, 109 | #placesContext_createBookmark , 110 | #panelMenuBookmarkThisPage { 111 | background-image: url("chrome://browser/skin/bookmark-hollow.svg"); 112 | list-style-image: url("chrome://browser/skin/bookmark-hollow.svg"); 113 | } 114 | 115 | #appMenuSearchHistory, 116 | #menu_find, 117 | .findbar-textbox, 118 | #context-searchselect, 119 | #panelMenu_searchBookmarks, 120 | #appMenu-find-button2, 121 | #allTabsMenu-searchTabs { 122 | background-image: url("chrome://global/skin/icons/search-glass.svg"); 123 | list-style-image: url("chrome://global/skin/icons/search-glass.svg"); 124 | } 125 | 126 | #spell-dictionaries, 127 | #toggle_PersonalToolbar, 128 | #BMB_viewBookmarksToolbar, 129 | #panelMenu_viewBookmarksToolbar { 130 | background-image: url("chrome://browser/skin/bookmarks-toolbar.svg"); 131 | list-style-image: url("chrome://browser/skin/bookmarks-toolbar.svg"); 132 | } 133 | 134 | #menu_historySidebar:not([checked="true"]), 135 | .subviewbutton[id$="-history-button"], 136 | #sidebar-switcher-history { 137 | background-image: url("chrome://browser/skin/history.svg"); 138 | list-style-image: url("chrome://browser/skin/history.svg"); 139 | } 140 | 141 | #historyUndoMenu, 142 | #appMenuRecentlyClosedTabs { 143 | background-image: url("chrome://devtools/skin/images/debugging-tabs.svg"); 144 | list-style-image: url("chrome://devtools/skin/images/debugging-tabs.svg"); 145 | } 146 | 147 | #historyRestoreLastSession, 148 | #appMenuRestoreSession { 149 | background-image: url("chrome://userchrome/content/material/restore-session.svg"); 150 | list-style-image: url("chrome://userchrome/content/material/restore-session.svg"); 151 | } 152 | 153 | #sanitizeItem, 154 | #placesContext_deleteHost, 155 | #appMenuClearRecentHistory { 156 | background-image: url("chrome://browser/skin/forget.svg"); 157 | list-style-image: url("chrome://browser/skin/forget.svg"); 158 | } 159 | 160 | #menu_openDownloads, 161 | .subviewbutton[id$="-downloads-button"] { 162 | background-image: url("chrome://browser/skin/downloads/downloads.svg"); 163 | list-style-image: url("chrome://browser/skin/downloads/downloads.svg"); 164 | } 165 | 166 | #appMenu-passwords-button { 167 | background-image: url("chrome://browser/skin/login.svg"); 168 | list-style-image: url("chrome://browser/skin/login.svg"); 169 | } 170 | 171 | #menu_openAddons, 172 | #appMenu-extensions-themes-button { 173 | background-image: url("chrome://mozapps/skin/extensions/extension.svg"); 174 | list-style-image: url("chrome://mozapps/skin/extensions/extension.svg"); 175 | } 176 | 177 | menuitem[data-l10n-id*="-print"], 178 | #appMenu-print-button2 { 179 | background-image: url("chrome://global/skin/icons/print.svg"); 180 | list-style-image: url("chrome://global/skin/icons/print.svg"); 181 | } 182 | 183 | #context-saveimage, 184 | #context-savelink, 185 | #menu_savePage, 186 | #context-savepage, 187 | #appMenu-save-file-button2 { 188 | background-image: url("chrome://browser/skin/save.svg"); 189 | list-style-image: url("chrome://browser/skin/save.svg"); 190 | } 191 | 192 | menuitem[data-l10n-id*="-customize-toolbar"], 193 | .subviewbutton[command="cmd_CustomizeToolbars"] { 194 | background-image: url("chrome://browser/skin/customize.svg"); 195 | list-style-image: url("chrome://browser/skin/customize.svg"); 196 | } 197 | 198 | #menu_taskManager, 199 | .subviewbutton[label="Task Manager"], 200 | .subviewbutton[oncommand="switchToTabHavingURI('about:performance', true)"] { 201 | background-image: url("chrome://global/skin/icons/performance.svg"); 202 | list-style-image: url("chrome://global/skin/icons/performance.svg"); 203 | } 204 | 205 | #menu_browserToolbox, 206 | .subviewbutton[key="key_browserToolbox"] { 207 | background-image: url("chrome://devtools/skin/images/fox-smiling.svg"); 208 | list-style-image: url("chrome://devtools/skin/images/fox-smiling.svg"); 209 | } 210 | 211 | #menu_responsiveUI:not([checked="true"]), 212 | .subviewbutton[key="key_responsiveDesignMode"]:not([checked="true"]) { 213 | background-image: url("chrome://devtools/skin/images/command-responsivemode.svg"); 214 | list-style-image: url("chrome://devtools/skin/images/command-responsivemode.svg"); 215 | fill-opacity: 0; 216 | } 217 | 218 | .subviewbutton[key="key_responsiveDesignMode"]:not([checked="true"]) 219 | > .menu-iconic-left::before { 220 | opacity: 0 !important; 221 | } 222 | 223 | #menu_eyedropper:not([checked="true"]), 224 | .subviewbutton[key="key_responsiveDesignMode"] + .subviewbutton { 225 | background-image: url("chrome://devtools/skin/images/command-eyedropper.svg"); 226 | list-style-image: url("chrome://devtools/skin/images/command-eyedropper.svg"); 227 | fill-opacity: 0; 228 | } 229 | 230 | #extensionsForDevelopers, 231 | .subviewbutton[data-l10n-id="appmenu-developer-tools-extensions"] { 232 | background-image: url("chrome://activity-stream/content/data/content/assets/glyph-webextension-16.svg"); 233 | list-style-image: url("chrome://activity-stream/content/data/content/assets/glyph-webextension-16.svg"); 234 | } 235 | 236 | #appMenu-help-button2 { 237 | background-image: url("chrome://global/skin/icons/help.svg"); 238 | list-style-image: url("chrome://global/skin/icons/help.svg"); 239 | } 240 | 241 | #appMenu-restart-button2 { 242 | background-image: url("chrome://userchrome/content/material/reload.svg"); 243 | list-style-image: url("chrome://userchrome/content/material/reload.svg"); 244 | } 245 | 246 | #appMenu-userChrome-button { 247 | background-image: url("chrome://browser/skin/trending.svg"); 248 | list-style-image: url("chrome://browser/skin/trending.svg"); 249 | } 250 | 251 | #menu_HelpPopup_reportPhishingtoolmenu, 252 | #appMenu_menu_HelpPopup_reportPhishingtoolmenu { 253 | background-image: url("chrome://global/skin/icons/lightbulb.svg"); 254 | list-style-image: url("chrome://global/skin/icons/lightbulb.svg"); 255 | } 256 | 257 | #aboutName, 258 | #appMenu_aboutName { 259 | background-image: url("chrome://devtools/skin/images/browsers/firefox.svg"); 260 | list-style-image: url("chrome://devtools/skin/images/browsers/firefox.svg"); 261 | } 262 | 263 | #menu_FileQuitItem, 264 | #appMenu-quit-button2 { 265 | background-image: url("chrome://userchrome/content/material/quit.svg"); 266 | list-style-image: url("chrome://userchrome/content/material/quit.svg"); 267 | } 268 | 269 | #menu_newUserContext, 270 | #allTabsMenu-containerTabsButton { 271 | background-image: url("chrome://userchrome/content/material/new-container.svg"); 272 | list-style-image: url("chrome://userchrome/content/material/new-container.svg"); 273 | } 274 | 275 | #PanelUI-fxa-menu-connect-device-button, 276 | #sidebar-switcher-tabs { 277 | background-image: url("chrome://browser/skin/synced-tabs.svg"); 278 | list-style-image: url("chrome://browser/skin/synced-tabs.svg"); 279 | } 280 | 281 | #sidebar-reverse-position[label="Move Sidebar to Right"], 282 | #sidebar-reverse-position[label="Kenar çubuğunu sağa taşı"] { 283 | background-image: url("chrome://browser/skin/sidebars-right.svg"); 284 | list-style-image: url("chrome://browser/skin/sidebars-right.svg"); 285 | } 286 | 287 | #viewSidebarMenuMenu, 288 | #BMB_viewBookmarksSidebar, 289 | #sidebar-reverse-position[label="Move Sidebar to Left"], 290 | #sidebar-reverse-position[label="Kenar çubuğunu sola taşı"] { 291 | background-image: url("chrome://browser/skin/sidebars.svg"); 292 | list-style-image: url("chrome://browser/skin/sidebars.svg"); 293 | } 294 | 295 | #toolbar-context-selectAllTabs[data-l10n-id="toolbar-context-menu-select-all-tabs"] { 296 | background-image: url("chrome://userchrome/content/material/select-all.svg"); 297 | } 298 | 299 | 300 | #context_closeTab, 301 | #orgClose, 302 | menuitem[data-l10n-id="sidebar-menu-close"] { 303 | background-image: url("chrome://global/skin/icons/close.svg"); 304 | list-style-image: url("chrome://global/skin/icons/close.svg"); 305 | } 306 | 307 | #BMB_bookmarksPopup menuitem:not(.menuitem-iconic), 308 | #PlacesToolbar .openintabs-menuitem { 309 | list-style-image: url("chrome://userchrome/content/material/open_new_tabs.svg"); 310 | background-image: url("chrome://userchrome/content/material/open_new_tabs.svg"); 311 | } 312 | 313 | #menu_openFile { 314 | background-image: url("chrome://browser/skin/open.svg"); 315 | } 316 | 317 | menuitem[data-l10n-id*="-email"] { 318 | background-image: url("chrome://browser/skin/mail.svg"); 319 | } 320 | 321 | #menu_importFromAnotherBrowser, 322 | #browserImport { 323 | background-image: url("chrome://browser/skin/import.svg"); 324 | } 325 | 326 | menuitem[data-l10n-id="text-action-undo"], 327 | menuitem[data-l10n-id$="-reopen-closed-tabs"] { 328 | background-image: url("chrome://global/skin/icons/undo.svg"); 329 | } 330 | 331 | menuitem[data-l10n-id="text-action-redo"] { 332 | background-image: url("chrome://userchrome/content/material/redo.svg"); 333 | } 334 | 335 | menuitem[data-l10n-id="text-action-cut"] { 336 | background-image: url("chrome://browser/skin/edit-cut.svg"); 337 | } 338 | 339 | menuitem[data-l10n-id="text-action-copy"], 340 | #syncedTabsCopySelected { 341 | background-image: url("chrome://global/skin/icons/edit-copy.svg"); 342 | } 343 | 344 | menuitem[data-l10n-id="text-action-paste"] { 345 | background-image: url("chrome://browser/skin/edit-paste.svg"); 346 | } 347 | 348 | menuitem[data-l10n-id="text-action-delete"], 349 | menuitem[data-l10n-id="downloads-cmd-clear-list"], 350 | menuitem[data-l10n-id="downloads-cmd-delete-file"], 351 | .customize-context-removeExtension, 352 | menuitem[data-l10n-id="toolbar-context-menu-remove-from-toolbar"], 353 | .downloadRemoveFromHistoryMenuItem, 354 | menuitem[id^="placesContext_delete"] { 355 | background-image: url("chrome://global/skin/icons/delete.svg"); 356 | } 357 | 358 | #menu_bookmarksSidebar:not([checked="true"]), 359 | menuitem[data-l10n-id="menu-bookmark-edit"] { 360 | background-image: url("chrome://browser/skin/bookmark.svg") !important; 361 | } 362 | 363 | #menu_bookmarksSidebar:not([checked="true"]) > .menu-iconic-left::before { 364 | opacity: 0 !important; 365 | } 366 | 367 | #menu_historySidebar:not([checked="true"]) > .menu-iconic-left::before { 368 | opacity: 0 !important; 369 | } 370 | 371 | #menu_tabsSidebar:not([checked="true"]), 372 | #sync-tabs-menuitem { 373 | background-image: url("chrome://browser/skin/tab.svg"); 374 | } 375 | 376 | #menu_tabsSidebar:not([checked="true"]) > .menu-iconic-left::before { 377 | opacity: 0 !important; 378 | } 379 | 380 | #menu_zoomEnlarge { 381 | background-image: url("chrome://browser/skin/add-circle-fill.svg"); 382 | } 383 | 384 | #menu_zoomReduce { 385 | background-image: url("chrome://browser/skin/subtract-circle-fill.svg"); 386 | } 387 | 388 | #repair-text-encoding { 389 | background-image: url("chrome://browser/skin/characterEncoding.svg"); 390 | } 391 | 392 | #fullScreenItem:not([checked="true"]) { 393 | background-image: url("chrome://browser/skin/fullscreen.svg"); 394 | } 395 | 396 | #fullScreenItem:not([checked="true"]) > .menu-iconic-left::before { 397 | opacity: 0 !important; 398 | } 399 | 400 | #menu_readerModeItem { 401 | background-image: url("chrome://browser/skin/reader-mode.svg"); 402 | } 403 | 404 | #sync-setup { 405 | background-image: var(--avatar-image-url); 406 | } 407 | 408 | 409 | #webDeveloperMenu { 410 | background-image: url("chrome://browser/skin/developer.svg"); 411 | } 412 | 413 | #menu_responsiveUI:not([checked="true"]) > .menu-iconic-left::before { 414 | opacity: 0 !important; 415 | } 416 | 417 | #menu_eyedropper:not([checked="true"]) > .menu-iconic-left::before { 418 | opacity: 0 !important; 419 | } 420 | 421 | 422 | #menu_pageInfo, 423 | #context-viewframeinfo { 424 | background-image: url("chrome://global/skin/icons/info.svg"); 425 | } 426 | 427 | 428 | menuitem[data-l10n-id*="reload-"], 429 | #context-reloadframe { 430 | background-image: url("chrome://global/skin/icons/reload.svg"); 431 | } 432 | 433 | menuitem[id^="context_toggleMute"]:not([soundplaying], [muted]), 434 | menuitem[id^="context_toggleMute"][soundplaying]:not([muted]), 435 | #context-media-mute { 436 | background-image: url("chrome://global/skin/media/audio-muted.svg"); 437 | } 438 | 439 | menuitem[id^="context_toggleMute"][muted], 440 | #context-media-unmute { 441 | background-image: url("chrome://global/skin/media/audio.svg"); 442 | } 443 | 444 | menuitem[data-l10n-id^="pin-"], 445 | .customize-context-moveToPanel { 446 | background-image: url("chrome://activity-stream/content/data/content/assets/glyph-pin-16.svg"); 447 | } 448 | 449 | menuitem[data-l10n-id^="unpin-"], 450 | .customize-context-moveToToolbar { 451 | background-image: url("chrome://activity-stream/content/data/content/assets/glyph-unpin-16.svg"); 452 | } 453 | 454 | menuitem[id^="context_duplicateTab"] { 455 | background-image: url("chrome://userchrome/content/material/duplicate-tab.svg"); 456 | } 457 | 458 | #context_moveTabOptions { 459 | background-image: url("chrome://userchrome/content/material/move-tab.svg"); 460 | } 461 | 462 | menuitem.sendtab-target[clientType="desktop"] { 463 | background-image: url("chrome://browser/skin/device-desktop.svg"); 464 | } 465 | 466 | menuitem.sendtab-target[clientType="phone"] { 467 | background-image: url("chrome://browser/skin/device-phone.svg"); 468 | } 469 | 470 | menuitem.sendtab-target[clientType="tablet"] { 471 | background-image: url("chrome://browser/skin/device-tablet.svg"); 472 | } 473 | 474 | menuitem.sendtab-target[clientType="tv"] { 475 | background-image: url("chrome://browser/skin/device-tv.svg"); 476 | } 477 | 478 | menuitem.sendtab-target[clientType="vr"] { 479 | background-image: url("chrome://browser/skin/device-vr.svg"); 480 | } 481 | 482 | .share-tab-url-item { 483 | background-image: url("chrome://userchrome/content/material/share-tab.svg"); 484 | } 485 | 486 | #context-setDesktopBackground { 487 | background-image: url("chrome://userchrome/content/material/desktop-bg.svg"); 488 | } 489 | 490 | #context_reopenInContainer, 491 | #context-openlinkinusercontext-menu { 492 | background-image: url("chrome://userchrome/content/material/move-container.svg"); 493 | } 494 | 495 | #menu_selectAll, 496 | #context-selectall, 497 | #context_selectAllTabs { 498 | background-image: url("chrome://userchrome/content/material/select-all.svg"); 499 | } 500 | 501 | #context-viewsource, 502 | #context-viewpartialsource-selection { 503 | background-image: url("chrome://userchrome/content/material/page-source.svg"); 504 | } 505 | 506 | #context_closeTabOptions { 507 | background-image: url("chrome://userchrome/content/material/close-tab-option.svg"); 508 | } 509 | 510 | #context_moveToStart { 511 | background-image: url("chrome://userchrome/content/material/move-start.svg"); 512 | } 513 | 514 | #context_moveToEnd { 515 | background-image: url("chrome://userchrome/content/material/move-end.svg"); 516 | } 517 | 518 | menuitem[data-l10n-id="full-screen-exit"] { 519 | background-image: url("chrome://browser/skin/fullscreen-exit.svg"); 520 | } 521 | 522 | #paste-and-go { 523 | background-image: url("chrome://browser/skin/forward.svg"); 524 | } 525 | 526 | #appMenu-report-broken-site-button { 527 | list-style-image: url("chrome://global/skin/icons/warning.svg"); 528 | } 529 | 530 | .customize-context-reportExtension { 531 | background-image: url("chrome://global/skin/icons/warning.svg"); 532 | } 533 | 534 | .downloadResumeMenuItem { 535 | background-image: url("chrome://userchrome/content/material/playButton.svg"); 536 | } 537 | 538 | .downloadPauseMenuItem{ 539 | background-image: url("chrome://userchrome/content/material/pause.svg"); 540 | } 541 | 542 | .downloadShowMenuItem { 543 | background-image: url("chrome://global/skin/icons/folder.svg"); 544 | } 545 | 546 | menuitem[id^="context-open"]:is([id$="intab"], [id$="incontainertab"]), 547 | menuitem[data-l10n-id$="-view-new-tab"], 548 | menuitem[data-l10n-id*="-open-in-"][data-l10n-id$="-tab"] { 549 | background-image: url("chrome://global/skin/icons/open-in-new.svg"); 550 | } 551 | 552 | menuitem[oncommand^="Pocket.savePage"] { 553 | background-image: url("chrome://global/skin/icons/pocket-outline.svg"); 554 | } 555 | 556 | menuitem[data-l10n-id$="-screenshot"] { 557 | background-image: url("chrome://browser/skin/screenshot.svg"); 558 | } 559 | 560 | menuitem[data-l10n-id*="-copy-"][data-l10n-id*="-link"] { 561 | background-image: url("chrome://global/skin/icons/link.svg"); 562 | } 563 | 564 | #context-searchselect[label^="Search Google for "] { 565 | background-image: url("chrome://activity-stream/content/data/content/tippytop/favicons/google-com.ico"); 566 | } 567 | 568 | #context-searchselect[label^="Search Bing for "] { 569 | background-image: url("chrome://activity-stream/content/data/content/tippytop/favicons/bing-com.ico"); 570 | } 571 | 572 | #PlacesToolbarItems .openintabs-menuitem 573 | #context-searchselect[label^="Search DuckDuckGo for "] { 574 | background-image: url("chrome://activity-stream/content/data/content/tippytop/favicons/duckduckgo-com.ico"); 575 | } 576 | 577 | #context-inspect-a11y { 578 | background-image: url("chrome://devtools/skin/images/tool-accessibility.svg"); 579 | } 580 | 581 | #appmenu-developer-tools-view .subviewbutton[key="key_viewSource"] { 582 | list-style-image: url("chrome://userchrome/content/material/web-page-source-code.svg"); 583 | } 584 | 585 | #appmenu-developer-tools-view .subviewbutton[key="key_toggleToolbox"], 586 | #context-inspect { 587 | background-image: url("chrome://userchrome/content/material/command-pick.svg"); 588 | list-style-image: url("chrome://userchrome/content/material/command-pick.svg"); 589 | } 590 | 591 | #context-media-play { 592 | background-image: url("chrome://global/skin/media/play-fill.svg"); 593 | } 594 | 595 | #context-media-pause, 596 | #doNotDisturbMenuItem { 597 | background-image: url("chrome://global/skin/media/pause-fill.svg"); 598 | } 599 | 600 | #context-video-fullscreen { 601 | background-image: url("chrome://global/skin/media/fullscreenEnterButton.svg"); 602 | } 603 | 604 | #context-leave-dom-fullscreen { 605 | background-image: url("chrome://global/skin/media/fullscreenExitButton.svg"); 606 | } 607 | 608 | #context-video-pictureinpicture:not([checked="true"]) { 609 | background-image: url("chrome://global/skin/media/picture-in-picture-open.svg"); 610 | } 611 | 612 | #context-video-pictureinpicture:not([checked="true"]) 613 | > .menu-iconic-left::before { 614 | opacity: 0 !important; 615 | } 616 | 617 | #context-video-saveimage { 618 | background-image: url("chrome://devtools/skin/images/command-screenshot.svg"); 619 | } 620 | 621 | #disableForOriginMenuItem { 622 | background-image: url("chrome://browser/skin/notification-icons/desktop-notification-blocked.svg"); 623 | } 624 | 625 | menuitem[data-l10n-id^="places-edit-"] { 626 | background-image: url("chrome://global/skin/icons/edit.svg"); 627 | } 628 | 629 | #appmenu-developer-tools-view .subviewbutton[key="key_aboutProcesses"] { 630 | list-style-image: url("chrome://global/skin/icons/performance.svg"); 631 | background-image: url("chrome://global/skin/icons/performance.svg"); 632 | } 633 | 634 | #context-copyimage-contents { 635 | background-image: url("chrome://devtools/skin/images/copy.svg"); 636 | } 637 | 638 | #menu_openHelp, 639 | #appMenu_menu_openHelp { 640 | background-image: url("chrome://devtools/content/debugger/images/help.svg"); 641 | list-style-image: url("chrome://devtools/content/debugger/images/help.svg"); 642 | } 643 | 644 | #feedbackPage, 645 | #appMenu_feedbackPage { 646 | background-image: url("chrome://userchrome/content/material/ideas.svg"); 647 | list-style-image: url("chrome://userchrome/content/material/ideas.svg"); 648 | } 649 | 650 | #userScriptsMenu { 651 | background-image: url("chrome://userchrome/content/material/userScriptsMenu.svg"); 652 | } 653 | 654 | #menu_devtools_remotedebugging, 655 | .subviewbutton[label="Remote Debugging"] { 656 | background-image: url("chrome://userchrome/content/material/remote-debug.svg"); 657 | list-style-image: url("chrome://userchrome/content/material/remote-debug.svg"); 658 | } 659 | 660 | #menu_browserConsole, 661 | .subviewbutton[key="key_browserConsole"] { 662 | background-image: url("chrome://userchrome/content/material/terminal.svg"); 663 | list-style-image: url("chrome://userchrome/content/material/terminal.svg"); 664 | } 665 | 666 | #placesContext_showAllBookmarks, 667 | #bookmarksShowAll, 668 | #panelMenu_showAllBookmarks { 669 | background-image: url("chrome://userchrome/content/material/bookmark-manage.svg"); 670 | } 671 | 672 | #appMenu-restoreSession{ 673 | list-style-image: url("chrome://userchrome/content/material/restore-session.svg"); 674 | } 675 | 676 | #menu_showAllHistory { 677 | background-image: url("chrome://userchrome/content/material/all-history.svg"); 678 | } 679 | 680 | #menu_zoomEnlarge { 681 | background-image: url("chrome://userchrome/content/material/zoom-in.svg"); 682 | } 683 | 684 | #menu_zoomReduce { 685 | background-image: url("chrome://userchrome/content/material/zoom-out.svg"); 686 | } 687 | 688 | #menu_zoomReset { 689 | background-image: url("chrome://userchrome/content/material/actual-zoom.svg"); 690 | } 691 | -------------------------------------------------------------------------------- /includes/realfire-inputs.css: -------------------------------------------------------------------------------- 1 | /*settings Inputs*/ 2 | tree:hover, 3 | richlistbox:hover, 4 | #searchInput:hover, 5 | search-textbox:hover, 6 | input:is([type="email"], [type="tel"], [type="text"], [type="password"], [type="url"], [type="number"]):hover { 7 | outline: var(--settings-color) solid 1px !important; 8 | } 9 | 10 | tree:focus-visible, 11 | search-textbox[focused], 12 | richlistbox:focus-visible, 13 | #searchInput[focused="true"], 14 | input:is([type="email"], [type="tel"], [type="text"], [type="password"], [type="url"], [type="number"]):focus { 15 | transition: linear var(--uc-animation-duration) !important; 16 | outline: var(--settings-color) solid 2px !important; 17 | } 18 | 19 | #searchInput { 20 | transition: linear var(--uc-animation-duration) !important; 21 | border-radius: var(--uc-border-radius) !important; 22 | } 23 | 24 | /*popups*/ 25 | search-textbox.tabsFilter:hover, 26 | search-textbox#search-box:hover, 27 | search-textbox#search-box:focus-within, 28 | search-textbox.tabsFilter:focus-within { 29 | transition: ease-in var(--uc-animation-duration); 30 | border: 1px solid var(--accent-color) !important; 31 | background-color: var(--uc-highlight-colour) !important; 32 | } 33 | 34 | image.textbox-search-sign { 35 | display: none !important; 36 | } 37 | 38 | search-textbox.tabsFilter, 39 | search-textbox#search-box { 40 | padding: 4px !important; 41 | transition: ease-out var(--uc-animation-duration); 42 | appearance: none !important; 43 | -moz-default-appearance: none !important; 44 | color: var(--uc-inverted-colour) !important; 45 | border-radius: var(--uc-border-radius) !important; 46 | background-color: var(--uc-base-colour) !important; 47 | border: 1px solid var(--uc-muted-colour) !important; 48 | } -------------------------------------------------------------------------------- /includes/realfire-layout.css: -------------------------------------------------------------------------------- 1 | #nav-bar, 2 | #TabsToolbar, 3 | #main-window, 4 | #sidebar-box, 5 | #PersonalToolbar, 6 | #toolbar-menubar, 7 | #navigator-toolbox { 8 | box-shadow: none !important; 9 | border: none !important; 10 | } 11 | 12 | /* remove "padding" left and right from tabs */ 13 | .titlebar-spacer { 14 | display: none !important; 15 | } 16 | 17 | /* fix Shield Icon padding */ 18 | #urlbar-input-container[pageproxystate="valid"] 19 | > #tracking-protection-icon-container 20 | > #tracking-protection-icon-box 21 | > #tracking-protection-icon { 22 | padding-bottom: 1px; 23 | } 24 | 25 | #statuspanel #statuspanel-label { 26 | border: none !important; 27 | border-radius: var(--uc-border-radius) !important; 28 | } 29 | -------------------------------------------------------------------------------- /includes/realfire-library.css: -------------------------------------------------------------------------------- 1 | @-moz-document url(chrome://browser/content/places/places.xhtml) 2 | { 3 | #PopupSearchAutoComplete > * { 4 | border-radius: 0 !important; 5 | } 6 | 7 | #PopupSearchAutoComplete > :first-child { 8 | border-radius: 4px 4px 0 0 !important; 9 | } 10 | 11 | #PopupSearchAutoComplete > :last-child { 12 | border-radius: 0 0 4px 4px !important; 13 | } 14 | 15 | /* autocomplete panel can't overlap the textbox, so shadow can't go up 16 | more than 1px */ 17 | panel[type="autocomplete-richlistbox"] > .autocomplete-richlistbox { 18 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.03), 0 5px 5px -3px rgba(0, 0, 0, 0.2), 19 | 0 8px 10px -0px rgba(0, 0, 0, 0.14), 0 3px 14px -5px rgba(0, 0, 0, 0.12) !important; 20 | } 21 | 22 | /* search panel gets special treatment; it has multiple children */ 23 | #PopupSearchAutoComplete > .autocomplete-richlistbox { 24 | box-shadow: none !important; 25 | } 26 | 27 | #PopupSearchAutoComplete { 28 | filter: drop-shadow(0 8px 6px rgba(0, 0, 0, 0.25)) 29 | drop-shadow(0 1px 1px rgba(0, 0, 0, 0.125)) !important; 30 | } 31 | 32 | /* ============== Menus ============== */ 33 | 34 | /* These change top bar background color */ 35 | #placesToolbar { 36 | color: var(--uc-inverted-colour) !important; 37 | background-color: var(--uc-base-colour) !important; 38 | border-bottom: 1px solid var(--accent-color) !important; 39 | } 40 | 41 | /* These change the lists background color */ 42 | /* This one changes the urlbar star bookmarking folder tree backgrund color */ 43 | #placesView #placesView .scrollbox-innerbox, 44 | #infoPane, 45 | #placesList, 46 | #placeContent, 47 | #editBMPanel_folderTree { 48 | -moz-appearance: none !important; 49 | color: var(--uc-inverted-colour) !important; 50 | background: var(--uc-base-colour) !important; 51 | border-bottom: 1px solid var(--accent-color) !important; 52 | } 53 | 54 | /* These change the list header background and text colors */ 55 | #placeContent treecol { 56 | -moz-appearance: none !important; 57 | color: var(--uc-inverted-colour) !important; 58 | background: var(--uc-base-colour) !important; 59 | } 60 | 61 | #placeContent treecol:hover { 62 | -moz-appearance: none !important; 63 | color: var(--uc-inverted-colour) !important; 64 | background: rgb(255, 255, 255, 0.15) !important; 65 | } 66 | 67 | /* This changes the right border on the left list panel */ 68 | #placesView > splitter { 69 | border-inline-end: 1px solid var(--accent-color) !important; 70 | } 71 | 72 | /* These change the odd rows of the lists */ 73 | #placeContent tree, 74 | treechildren::-moz-tree-row(odd) { 75 | color: var(--uc-inverted-colour) !important; 76 | } 77 | 78 | treechildren::-moz-tree-row(hover), 79 | treechildren::-moz-tree-row(selected, focus) { 80 | outline: none !important; 81 | color: var(--uc-inverted-colour) !important; 82 | background-color: var(--accent-color) !important; 83 | } 84 | 85 | treechildren::-moz-tree-cell { 86 | border-right: 0px dotted rgba(0, 0, 0, 0.4) !important; 87 | } 88 | 89 | #placeContent > splitter { 90 | border: 0px solid red !important; 91 | } 92 | 93 | /* This changes the forward and back buttons opacity when disabled */ 94 | #placesToolbar > toolbarbutton[disabled] > .toolbarbutton-icon { 95 | opacity: 0.25 !important; 96 | } 97 | 98 | /* This changes the forward and back buttons color */ 99 | #back-button > .toolbarbutton-icon, 100 | #forward-button > .toolbarbutton-icon { 101 | opacity: 1 !important; 102 | fill: var(--uc-inverted-colour) !important; 103 | } 104 | 105 | /* This deletes the leftover border when clicking one of the top buttons */ 106 | #placesMenu > menu { 107 | margin-inline: 5px !important; 108 | border-radius: var(--uc-border-radius) !important; 109 | } 110 | 111 | 112 | #placesMenu > menu > .menubar-text { 113 | background: none !important;; 114 | } 115 | 116 | /* This changes the text color of the "clear downloads" button */ 117 | #clearDownloadsButton { 118 | color: var(--uc-inverted-colour) !important; 119 | } 120 | 121 | #clearDownloadsButton[disabled] { 122 | color: var(--uc-base-colour) !important; 123 | } 124 | 125 | /* This themes the search box */ 126 | #searchFilter { 127 | -moz-appearance: none !important; 128 | color: var(--uc-inverted-colour) !important; 129 | transition: all var(--uc-animation-duration) ease-in-out !important; 130 | border-radius: var(--uc-border-radius) !important; 131 | background-color: var(--uc-base-colour) !important; 132 | outline: 1px solid var(--uc-muted-colour) !important; 133 | } 134 | 135 | /* This themes the search box on hover */ 136 | #searchFilter[focused="true"] { 137 | color: var(--uc-inverted-colour) !important; 138 | background-color: var(--uc-base-colour) !important; 139 | outline: 1.5px solid var(--accent-color) !important; 140 | box-shadow: var(--input-field-focus-shadow) !important; 141 | } 142 | 143 | /* This themes the information box on the lower part of the library menu */ 144 | #detailsDeck { 145 | border-top: 2px solid #222 !important; 146 | color: var(--uc-inverted-colour) !important; 147 | background-color: var(--uc-base-colour) !important; 148 | } 149 | 150 | /* This changes the text boxes inside the library bottom information box */ 151 | /* This changes the text boxes on the popup when bookmarking a page from the url box */ 152 | #infoBox textbox, 153 | #infoBox listbox, 154 | #editBMPanel_namePicker, 155 | #editBMPanel_tagsField, 156 | #editBMPanel_tagsSelector, 157 | #editBMPanel_locationField, 158 | #editBMPanel_keywordField { 159 | -moz-appearance: none !important; 160 | color: var(--uc-inverted-colour) !important; 161 | transition: all var(--uc-animation-duration) ease-in-out !important; 162 | border-radius: var(--uc-border-radius) !important; 163 | border: 1px solid var(--uc-muted-colour) !important; 164 | } 165 | 166 | /* A fix for bookmark preferences... so that some boxes won't appear brighter than others */ 167 | #bookmarkproperties #editBMPanel_namePicker, 168 | #bookmarkproperties #editBMPanel_tagsField, 169 | #bookmarkproperties #editBMPanel_tagsSelector { 170 | border: 1px solid var(--accent-color) !important; 171 | border-radius: var(--uc-border-radius) !important; 172 | } 173 | 174 | 175 | 176 | /* This changes the same text boxes on hover */ 177 | /* This changes the same url bookmarking popup text boxes on hover */ 178 | #infoBox textbox:hover, 179 | #infoBox listbox:hover, 180 | #editBMPanel_namePicker:hover, 181 | #editBMPanel_tagsField:hover, 182 | #editBMPanel_locationField:hover, 183 | #editBMPanel_keywordField:hover, 184 | #infoBox #bookmarkproperties #editBMPanel_namePicker:hover, 185 | #infoBox #bookmarkproperties #editBMPanel_tagsField:hover { 186 | color: var(--uc-inverted-colour) !important; 187 | border: 1.5px solid var(--accent-color) !important; 188 | background-color: var(--uc-base-colour) !important; 189 | box-shadow: var(--Input-field-focus-shadow) !important; 190 | } 191 | 192 | /* This changes the buttons inside the bookmarking popup at the url star */ 193 | #editBMPanel_newFolderButton, 194 | #editBookmarkPanelDoneButton, 195 | #editBookmarkPanelRemoveButton, 196 | #identity-popup-popup-menulist, 197 | #tracking-action-unblock-private, 198 | #tracking-action-block, 199 | #tracking-action-unblock { 200 | padding: 0.3em !important; 201 | margin-top: 0.5em !important; 202 | margin-bottom: 0.5em !important; 203 | -moz-appearance: none !important; 204 | background: var(--uc-base-colour) !important; 205 | color: var(--uc-inverted-colour) !important; 206 | } 207 | 208 | #editBMPanel_newFolderButton:hover, 209 | #editBookmarkPanelDoneButton:hover, 210 | #editBookmarkPanelRemoveButton:hover, 211 | #tracking-action-unblock-private:hover, 212 | #identity-popup-popup-menulist:hover, 213 | #tracking-action-block:hover, 214 | #tracking-action-unblock:hover { 215 | color: var(--uc-inverted-colour) !important; 216 | background: var(--uc-muted-colour) !important; 217 | } 218 | 219 | #editBookmarkPanelBottomButtons { 220 | background: transparent !important; 221 | } 222 | 223 | /* These change the expander buttons on the library and bookmarking popup */ 224 | #editBMPanel_folderMenuList, 225 | #editBMPanel_tagsSelectorExpander, 226 | #editBMPanel_foldersExpander, 227 | #detailsDeck button { 228 | -moz-appearance: none !important; 229 | color: var(--uc-inverted-colour) !important; 230 | background: var(--uc-base-colour) !important; 231 | border: 1px solid var(--uc-inverted-colour) !important; 232 | } 233 | 234 | #editBMPanel_folderMenuList:hover, 235 | #editBMPanel_foldersExpander:hover, 236 | #editBMPanel_tagsSelectorExpander:hover, 237 | #detailsDeck button:hover { 238 | background: var(--uc-muted-colour) !important; 239 | border: 1px solid var(--accent-color) !important; 240 | } 241 | 242 | #BMB_bookmarksPopup { 243 | margin-top: -9px !important; 244 | } 245 | 246 | #editBMPanel_folderMenuList { 247 | padding: 1px !important; 248 | color: var(--uc-inverted-colour) !important; 249 | } 250 | 251 | /* These change the downloads history list background */ 252 | #downloadsRichListBox { 253 | color: var(--uc-inverted-colour) !important; 254 | background: var(--uc-base-colour) !important; 255 | } 256 | 257 | #detailsPane { 258 | border-top: none !important; 259 | background-color: var(--uc-base-colour) !important; 260 | } 261 | 262 | 263 | } 264 | -------------------------------------------------------------------------------- /includes/realfire-nav-bar.css: -------------------------------------------------------------------------------- 1 | #navigator-toolbox:not(:-moz-lwtheme), 2 | .sidebar-panel:not(:-moz-lwtheme) { 3 | background: var(--uc-base-colour) !important; 4 | } 5 | 6 | #nav-bar { 7 | padding-block-start: 0px !important; 8 | border: none !important; 9 | box-shadow: none !important; 10 | background: transparent !important; 11 | } 12 | 13 | #nav-bar-toolbarbutton-slider-container { 14 | max-width: 64px !important; 15 | } 16 | 17 | ::-moz-selection { 18 | background-color: var(--accent-color) !important; 19 | } 20 | 21 | 22 | /*Dots in search bar*/ 23 | #urlbar #identity-icon-box, 24 | #urlbar #identity-permission-box { 25 | opacity: 0 !important; 26 | margin-inline-start: calc(-16px - 2 * var(--urlbar-icon-padding)); 27 | transition: margin-inline-start 100ms linear, opacity 200ms linear; 28 | } 29 | 30 | #urlbar #identity-box.notSecureText #identity-icon-box { 31 | margin-inline-start: initial !important; 32 | opacity: 1 !important; 33 | color: #e36f6f !important; 34 | } 35 | 36 | #urlbar #identity-box.extensionPage #identity-icon-box { 37 | margin-inline-start: initial !important; 38 | opacity: 1 !important; 39 | } 40 | 41 | #identity-box:hover #identity-icon-box, 42 | #identity-box:hover #identity-permission-box, 43 | #identity-box #identity-permission-box[open="true"] { 44 | opacity: 1 !important; 45 | margin-inline-start: initial !important; 46 | } 47 | 48 | #urlbar-input-container .urlbar-input-box { 49 | padding-inline-start: 2px !important; 50 | } 51 | 52 | #identity-box:hover~.urlbar-input-box>#urlbar-input { 53 | mask-image: linear-gradient(to right, transparent, black 3ch) !important; 54 | } 55 | 56 | #page-action-buttons { 57 | padding-inline-start: 8px; 58 | } 59 | 60 | #page-action-buttons .urlbar-page-action { 61 | margin-inline-end: calc(-16px - 2 * var(--urlbar-icon-padding)); 62 | opacity: 0; 63 | transition: margin-inline-end 100ms linear, opacity 200ms linear; 64 | } 65 | 66 | #page-action-buttons:hover>.urlbar-page-action, 67 | .urlbar-page-action[open], 68 | .urlbar-page-action[open]~.urlbar-page-action { 69 | opacity: 1; 70 | margin-inline-end: 0px !important; 71 | } 72 | 73 | #identity-box.chromeUI #identity-icon-box { 74 | opacity: 1 !important; 75 | margin-inline-start: initial; 76 | } 77 | 78 | #identity-box.chromeUI::after, 79 | #identity-box.chromeUI:hover::after { 80 | opacity: 0 !important; 81 | } 82 | 83 | #page-action-buttons:not(:hover) #translations-button[translationsactive="true"]:not([open]) { 84 | visibility: collapse !important; 85 | } 86 | 87 | /* Create visual dots on both sides */ 88 | /* left side identity-box dots modification */ 89 | #identity-box::after, 90 | #page-action-buttons::before { 91 | position: relative; 92 | content: "•••"; 93 | pointer-events: none; 94 | transition: opacity 100ms ease; 95 | align-self: center; 96 | font-size: 0.7em; 97 | } 98 | 99 | #identity-box::after, 100 | #page-action-buttons::before { 101 | opacity: 0.2; 102 | } 103 | 104 | #identity-box::after { 105 | transform: rotate(90deg); 106 | left: 4px; 107 | } 108 | 109 | #page-action-buttons::before { 110 | transform: rotate(-90deg); 111 | right: 4px; 112 | } 113 | 114 | #identity-box:hover::after, 115 | #page-action-buttons:hover::before { 116 | opacity: 0.5 !important; 117 | transition: opacity 50ms ease; 118 | pointer-events: none; 119 | } 120 | 121 | #identity-box[pageproxystate="invalid"]::after, 122 | #urlbar-input-container[pageproxystate="invalid"]>#page-action-buttons::before { 123 | opacity: 0 !important; 124 | transition: opacity 50ms ease; 125 | } 126 | 127 | /* Only show dots in search bar when hovered */ 128 | #urlbar #identity-box::after, 129 | #urlbar #page-action-buttons::before { 130 | opacity: 0; 131 | } 132 | 133 | #urlbar:hover #identity-box::after, 134 | #urlbar:hover #page-action-buttons::before { 135 | opacity: 0.5; 136 | transition: opacity 100ms ease; 137 | } 138 | 139 | #urlbar-background { 140 | border: transparent !important; 141 | } 142 | 143 | #urlbar[focused="true"]>#urlbar-background, 144 | #urlbar:not([open])>#urlbar-background { 145 | background: var(--uc-base-colour) !important; 146 | } 147 | 148 | #urlbar[open]>#urlbar-background { 149 | background: var(--uc-base-colour) !important; 150 | } 151 | 152 | .urlbarView-row:hover>.urlbarView-row-inner, 153 | .urlbarView-row[selected]>.urlbarView-row-inner { 154 | background: var(--toolbar-field-focus-background-color) !important; 155 | color: var(--uc-inverted-colour) !important; 156 | } 157 | 158 | .urlbarView-url { 159 | color: var(--accent-color) !important; 160 | } 161 | 162 | .urlbar-icon, 163 | #urlbar-go-button { 164 | margin: auto; 165 | } 166 | 167 | .urlbar-icon[starred='true'] { 168 | fill: var(--accent-color) !important; 169 | } 170 | 171 | .urlbar-page-action { 172 | padding: 0 inherit !important; 173 | } 174 | 175 | #toolbar-menubar { 176 | min-width: 100% !important; 177 | } -------------------------------------------------------------------------------- /includes/realfire-responsive.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 1000px) { 2 | #navigator-toolbox { 3 | display: flex; 4 | flex-wrap: wrap; 5 | flex-direction: row; 6 | align-items: flex-end !important; 7 | } 8 | 9 | #nav-bar { 10 | order: var(--uc-urlbar-position) !important; 11 | width: var(--uc-urlbar-max-width) !important; 12 | } 13 | 14 | #urlbar-container { 15 | padding-left: 2px; 16 | width: auto !important; 17 | margin-inline: 6px !important; 18 | min-width: var(--uc-urlbar-min-width); 19 | max-width: var(--uc-urlbar-max-width) !important; 20 | } 21 | 22 | #TabsToolbar { 23 | order: 2 !important; 24 | } 25 | 26 | #PersonalToolbar { 27 | width: 100% !important; 28 | order: var(--uc-toolbar-position) !important; 29 | } 30 | 31 | :root:not([customizing]) 32 | #nav-bar 33 | .customization-target 34 | > :not(#urlbar-container) { 35 | opacity: 0 !important; 36 | width: 0px !important; 37 | padding: 0px !important; 38 | min-width: 0px !important; 39 | transition: all var(--uc-animation-duration) !important; 40 | } 41 | 42 | :root:not([customizing]) 43 | #nav-bar:hover 44 | .customization-target 45 | > :not(#urlbar-container,#nav-bar-toolbarbutton-slider-container), 46 | :root:not([customizing]) 47 | #nav-bar:focus-within 48 | .customization-target 49 | > :not(#urlbar-container,#nav-bar-toolbarbutton-slider-container) { 50 | opacity: 1 !important; 51 | min-width: 28px !important; 52 | transition: all var(--uc-animation-duration) !important; 53 | } 54 | 55 | :root:not([customizing]) 56 | #nav-bar:hover 57 | .customization-target 58 | > #nav-bar-toolbarbutton-slider-container, 59 | :root:not([customizing]) 60 | #nav-bar:focus-within 61 | .customization-target 62 | > #nav-bar-toolbarbutton-slider-container { 63 | width: 100% !important; 64 | opacity: 1 !important; 65 | transition: all 200ms !important; 66 | } 67 | 68 | #back-button, 69 | #forward-button { 70 | transform: scale(1, 1) !important; 71 | transition: margin-left var(--uc-animation-duration) var(--animation-easing-function), 72 | transform var(--uc-animation-duration) var(--animation-easing-function) !important; 73 | } 74 | 75 | #forward-button[disabled="true"], 76 | #back-button[disabled="true"] { 77 | display: none; 78 | opacity: 0 !important; 79 | pointer-events: none !important; 80 | transform: scale(0.6, 0.6) !important; 81 | } 82 | 83 | #navigator-toolbox:focus-within #titlebar { 84 | width: auto !important; 85 | min-width: calc(100vw - var(--uc-urlbar-max-width) - 1px); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /includes/realfire-settings-page.css: -------------------------------------------------------------------------------- 1 | @-moz-document url(chrome://browser/content/preferences/preferences.xhtml), 2 | url(about:preferences), 3 | url(about:preferences#home), 4 | url(about:preferences#general), 5 | url(about:preferences#search), 6 | url(about:preferences#privacy), 7 | url(about:preferences#sync), 8 | url(about:preferences#experimental), 9 | url(about:preferences#moreFromMozilla) { 10 | 11 | /* Navigation menu */ 12 | .navigation { 13 | align-items: center !important; 14 | background-color: var(--uc-base-colour) !important; 15 | border-right: 2px solid var(--settings-color) !important; 16 | -moz-appearance: none !important; 17 | } 18 | 19 | .sticky-container { 20 | width: 100% !important; 21 | margin-inline: 0 !important; 22 | position: absolute !important; 23 | border-bottom: 2px solid var(--accent-color) !important; 24 | } 25 | 26 | .main-content { 27 | padding: 0 !important; 28 | background-color: var(--uc-base-colour) !important; 29 | -moz-appearance: none !important; 30 | } 31 | 32 | #mainPrefPane { 33 | padding: 90px 0 0 28px !important; 34 | } 35 | 36 | #categories { 37 | width: auto !important; 38 | } 39 | 40 | #categories richlistitem { 41 | color: var(--uc-inverted-colour) !important; 42 | border-radius: var(--uc-border-radius) !important; 43 | margin-inline: 20px !important; 44 | justify-content: center !important; 45 | } 46 | 47 | /* Sidebar footer */ 48 | .sidebar-footer-list { 49 | margin-inline: 0 !important; 50 | margin-inline-start: 0 !important; 51 | } 52 | 53 | /* Selected category color */ 54 | @media not (prefers-contrast) { 55 | #categories > .category[selected], 56 | #categories > .category.selected { 57 | color: var(--settings-color) !important; 58 | } 59 | } 60 | 61 | /* Selected privacy option background */ 62 | .privacy-detailedoption.selected { 63 | border-color: var(--settings-color) !important; 64 | background-color: color-mix(var(--settings-color) 20%, transparent) !important; 65 | } 66 | 67 | /* Links */ 68 | a, 69 | .text-link { 70 | color: var(--settings-color) !important; 71 | } 72 | 73 | a:hover, 74 | .text-link:hover, 75 | .text-link:is(:not([disabled="true"]), :enabled):hover { 76 | color: color-mix(var(--uc-inverted-colour), var(--settings-color)) !important; 77 | } 78 | 79 | /* Focus styles */ 80 | input:is([type="email"], [type="tel"], [type="text"], [type="password"], [type="url"], [type="number"]):focus, 81 | search-textbox[focused], 82 | textarea:focus-visible, 83 | tree:focus-visible, 84 | richlistbox:focus-visible, 85 | #searchInput[focused="true"] { 86 | outline: 2px solid var(--settings-color) !important; 87 | } 88 | 89 | /* Search input */ 90 | #searchInput { 91 | border-radius: var(--uc-border-radius) !important; 92 | } 93 | 94 | /* Buttons */ 95 | button, 96 | #row-selector.selector { 97 | color: var(--uc-inverted-colour) !important; 98 | border-radius: var(--uc-border-radius) !important; 99 | } 100 | 101 | button.primary, 102 | button[default], 103 | button[autofocus], 104 | button[type="submit"], 105 | button:not([disabled])[default="true"] { 106 | color: var(--button-text-white) !important; 107 | border-color: var(--accent-color) !important; 108 | background-color: var(--accent-color) !important; 109 | } 110 | 111 | /* Focus styles for controls */ 112 | select:focus-visible, 113 | button:focus-visible, 114 | menulist:focus-visible, 115 | radio[focused="true"] > .radio-check, 116 | tab:focus-visible > .tab-middle > .tab-text, 117 | checkbox:not([native]):focus-visible > .checkbox-check, 118 | input:is([type="checkbox"], [type="color"], [type="radio"]):focus-visible { 119 | outline: 2px solid var(--uc-inverted-colour) !important; 120 | outline-offset: 0 !important; 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /includes/realfire-side-bar.css: -------------------------------------------------------------------------------- 1 | #sidebar-search-container { 2 | justify-content: center !important; 3 | } 4 | 5 | .content-container { 6 | background-color: var(--uc-base-colour) !important; 7 | } 8 | 9 | .textbox-search-sign, 10 | .textbox-search-icon { 11 | background-repeat: no-repeat !important; 12 | background-color: transparent !important; 13 | background-position: 5px center !important; 14 | background-image: url(../icons/search.svg) !important; 15 | } 16 | 17 | #sidebar-header { 18 | background-color: var(--uc-base-colour) !important; 19 | border-bottom: 1.5px solid var(--accent-color) !important; 20 | } 21 | 22 | #sidebar-icon { 23 | fill: var(--accent-color) !important; 24 | } 25 | -------------------------------------------------------------------------------- /includes/realfire-tabs.css: -------------------------------------------------------------------------------- 1 | /* Hides the list-all-tabs button */ 2 | #alltabs-button { 3 | display: var(--uc-show-all-tabs-button) !important; 4 | } 5 | 6 | /* remove tab shadow */ 7 | .tabbrowser-tab>.tab-stack>.tab-background { 8 | box-shadow: none !important; 9 | border-radius: var(--uc-border-radius) !important; 10 | margin-block: var(--uc-tab-block-margin) !important; 11 | } 12 | 13 | /* multi tab selection */ 14 | #tabbrowser-tabs:not([noshadowfortests]) .tabbrowser-tab:is([multiselected])>.tab-stack>.tab-background:-moz-lwtheme { 15 | outline-color: var(--toolbarseparator-color) !important; 16 | } 17 | 18 | /* tab close button options */ 19 | .tabbrowser-tab:not([pinned]) .tab-close-button { 20 | display: var(--show-tab-close-button) !important; 21 | } 22 | 23 | .tabbrowser-tab:not([pinned]):hover .tab-close-button { 24 | display: var(--show-tab-close-button-hover) !important; 25 | } 26 | 27 | /* Add animation for tab width change */ 28 | .tabbrowser-tab[selected][fadein]:not([pinned]), 29 | .tabbrowser-tab[fadein]:not([selected]):not([pinned]) { 30 | transition: max-width var(--uc-animation-duration) ease-in-out !important; 31 | } 32 | 33 | /* adaptive tab width */ 34 | .tabbrowser-tab[selected][fadein]:not([pinned]) { 35 | max-width: var(--uc-active-tab-width) !important; 36 | } 37 | 38 | .tabbrowser-tab[fadein]:not([selected]):not([pinned]) { 39 | max-width: var(--uc-inactive-tab-width) !important; 40 | } 41 | 42 | /* container tabs indicator */ 43 | .tabbrowser-tab[usercontextid]>.tab-stack>.tab-background>.tab-context-line { 44 | height: 1px !important; 45 | box-shadow: var(--uc-identity-glow) var(--identity-tab-color) !important; 46 | margin: -1px var(--container-tabs-indicator-margin) 0 var(--container-tabs-indicator-margin) !important; 47 | } 48 | 49 | /* show favicon when media is playing but tab is hovered */ 50 | .tab-icon-image:not([pinned]) { 51 | opacity: 1 !important; 52 | } 53 | 54 | /* Makes the speaker icon to always appear if the tab is playing (not only on hover) */ 55 | .tab-icon-overlay:not([crashed]), 56 | .tab-icon-overlay[pinned][crashed][selected] { 57 | top: 5px !important; 58 | z-index: 1 !important; 59 | width: 16px !important; 60 | height: 16px !important; 61 | padding: 1.5px !important; 62 | inset-inline-end: -8px !important; 63 | border-radius: var(--uc-border-radius) !important; 64 | } 65 | 66 | /* style and position speaker icon */ 67 | [muted], 68 | .tab-icon-overlay:not([sharing], [crashed]):is([soundplaying], 69 | [activemedia-blocked]) { 70 | opacity: 1 !important; 71 | fill-opacity: 0.8 !important; 72 | stroke: transparent !important; 73 | color: var(--accent-color) !important; 74 | stroke: var(--toolbar-bgcolor) !important; 75 | } 76 | 77 | /* change the colours of the speaker icon on active tab to match tab colours */ 78 | .tabbrowser-tab[selected] .tab-icon-overlay:not([sharing], [crashed]):is([soundplaying], 79 | [muted], 80 | [activemedia-blocked]) { 81 | stroke: var(--toolbar-bgcolor) !important; 82 | } 83 | 84 | .tab-icon-overlay:not([pinned], [sharing], [crashed]):is([soundplaying], 85 | [muted], 86 | [activemedia-blocked]) { 87 | margin-inline-end: 9.5px !important; 88 | } 89 | 90 | .tabbrowser-tab:not([image]) .tab-icon-overlay:not([pinned], [sharing], [crashed]) { 91 | top: 0 !important; 92 | padding: 0 !important; 93 | inset-inline-end: 0 !important; 94 | margin-inline-end: 5.5px !important; 95 | } 96 | 97 | .tab-icon-overlay:not([crashed])[soundplaying]:hover, 98 | .tab-icon-overlay:not([crashed])[muted]:hover, 99 | .tab-icon-overlay:not([crashed])[activemedia-blocked]:hover { 100 | fill-opacity: 0.95 !important; 101 | color: var(--accent-color) !important; 102 | stroke: var(--toolbar-color) !important; 103 | background-color: var(--toolbar-color) !important; 104 | } 105 | 106 | .tabbrowser-tab[selected] .tab-icon-overlay:not([crashed])[muted]:hover, 107 | .tabbrowser-tab[selected] .tab-icon-overlay:not([crashed])[soundplaying]:hover, 108 | .tabbrowser-tab[selected] .tab-icon-overlay:not([crashed])[activemedia-blocked]:hover { 109 | fill-opacity: 0.95 !important; 110 | color: var(--accent-color) !important; 111 | stroke: var(--toolbar-color) !important; 112 | background-color: var(--toolbar-color) !important; 113 | } 114 | 115 | #PersonalToolbar:not([customizing]) { 116 | background-color: transparent !important; 117 | border-radius: var(--uc-border-radius) !important; 118 | /* border: 1.5px solid var(--accent-color) !important; */ 119 | background-repeat: no-repeat, no-repeat, var(--lwt-background-tiling); 120 | --uc-bg-y: calc(-2 * (var(--tab-block-margin) + var(--toolbarbutton-inner-padding) + var(--toolbarbutton-outer-padding)) - var(--tab-min-height) - 16px - var(--bookmark-block-padding)); 121 | background-position: top left, top left, 122 | var(--lwt-background-alignment, top left); 123 | margin-bottom: 4px; 124 | } 125 | 126 | /* #PersonalToolbar:not([customizing]):-moz-window-inactive { 127 | border: 1.5px solid var(--accent-field-color) !important; 128 | } */ 129 | 130 | .tabbrowser-tab .tab-stack .tab-background:is([selected], [multiselected]) { 131 | outline: 2px solid var(--accent-color) !important; 132 | background-color: var(--uc-base-colour) !important; 133 | } 134 | 135 | /* Border for selected tab in inactive window */ 136 | .tabbrowser-tab .tab-stack .tab-background[selected=]:-moz-window-inactive::after { 137 | content: ""; 138 | display: block; 139 | height: 50%; /* Adjust this value to control the length of the border */ 140 | width: 1.5px; /* Width of the border */ 141 | position: absolute; 142 | right: 0; 143 | top: 25%; /* Adjust this value to control the vertical position */ 144 | background-color: var(--accent-field-color); 145 | } 146 | 147 | /* Fixing Multiselect */ 148 | .tab-background[multiselected="true"]:not([selected="true"])>.tab-background-inner { 149 | background: none !important; 150 | } 151 | -------------------------------------------------------------------------------- /programs/install-curl.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd %TEMP% 4 | 5 | set "FILENAME=RealFire-main.zip" 6 | set "FOLDERPATH=RealFire-main" 7 | 8 | if exist "%FOLDERPATH%"\* ( 9 | rd /s /q %FOLDERPATH% 10 | ) 11 | 12 | curl -LJo %FILENAME% https://github.com/Hakanbaban53/RealFire/archive/refs/heads/main.zip || (echo Failed to fetch RealFire^! theme && echo Exiting... && goto :eof) 13 | 14 | tar -xvf %FILENAME% || echo. 15 | 16 | del %FILENAME% 17 | 18 | call "%FOLDERPATH%\programs\install.bat" %* 19 | 20 | REM if exist "%FOLDERPATH%"\* ( 21 | REM rd /s /q %FOLDERPATH% 22 | REM ) 23 | 24 | REM exit \B 25 | -------------------------------------------------------------------------------- /programs/install-curl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | FILENAME=RealFire-main.zip 4 | FOLDERPATH=$PWD/RealFire-main 5 | 6 | if [ -d "$FOLDERPATH" ]; then rm -Rf $FOLDERPATH; fi 7 | 8 | curl -LJo $FILENAME https://github.com/Hakanbaban53/RealFire/archive/refs/heads/main.zip 9 | 10 | unzip $FILENAME 11 | 12 | rm $FILENAME 13 | 14 | chmod +x "${FOLDERPATH}/programs/install.sh" 15 | 16 | "${FOLDERPATH}/programs/install.sh" "$@" 17 | 18 | # if [ -d "$FOLDERPATH" ]; then rm -Rf $FOLDERPATH; fi 19 | -------------------------------------------------------------------------------- /programs/install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | call :RequestAdminElevation "%~dpfs0" %* || goto:eof 4 | 5 | goto :init 6 | 7 | :header 8 | echo %__NAME% v%__VERSION% 9 | echo This is a sample batch file to install 10 | echo RealFire theme via Command Line Interface 11 | echo. 12 | goto :eof 13 | 14 | :usage 15 | echo USAGE: 16 | echo %__NAME% [ options ... ]" 17 | echo where options include: 18 | echo. 19 | echo. /b, -b ^ (Set custom Firefox binary folder path) 20 | echo. /f, -f ^ (Set custom Firefox folder path) 21 | echo. /p, -p ^ (Set custom profile name) 22 | echo. /e, -e (Default Enabled. Install fx-autoconfig - Runs as admin to copy mozilla.cfg and local-settings.js to Application Binary folder) 23 | echo. /v, -v, --version (Show script version) 24 | echo. /?, -h (Show help message) 25 | goto :eof 26 | 27 | :version 28 | if "%~1"=="full" call :header & goto :eof 29 | echo %__VERSION% 30 | goto :eof 31 | 32 | :init 33 | set "__NAME=%~nx0" 34 | set "__VERSION=4.0.0" 35 | 36 | for %%a in ("%~dp0.") do set "THEMEDIRECTORY=%%~dpa" 37 | 38 | set "APPLICATIONFOLDER=C:\Program Files\Mozilla Firefox" 39 | set "FIREFOXFOLDER=%APPDATA%\Mozilla\Firefox" 40 | set "PROFILENAME=" 41 | set "FXACEXTRAS=yes" 42 | set "CHROMEFOLDER=chrome" 43 | 44 | :parse 45 | if "%~1"=="" goto :main 46 | 47 | if /i "%~1"=="/?" call :header & call :usage "%~2" & goto :end 48 | if /i "%~1"=="-h" call :header & call :usage "%~2" & goto :end 49 | if /i "%~1"=="--help" call :header & call :usage "%~2" & goto :end 50 | 51 | if /i "%~1"=="/v" call :version & goto :end 52 | if /i "%~1"=="-v" call :version & goto :end 53 | if /i "%~1"=="--version" call :version full & goto :end 54 | 55 | if /i "%~1"=="/b" set "APPLICATIONFOLDER=%~2" & shift & shift & goto :parse 56 | if /i "%~1"=="-b" set "APPLICATIONFOLDER=%~2" & shift & shift & goto :parse 57 | 58 | if /i "%~1"=="/f" set "FIREFOXFOLDER=%~2" & shift & shift & goto :parse 59 | if /i "%~1"=="-f" set "FIREFOXFOLDER=%~2" & shift & shift & goto :parse 60 | 61 | if /i "%~1"=="/p" set "PROFILENAME=%~2" & shift & shift & goto :parse 62 | if /i "%~1"=="-p" set "PROFILENAME=%~2" & shift & shift & goto :parse 63 | 64 | if /i "%~1"=="/e" set "FXACEXTRAS=" & shift & goto :parse 65 | if /i "%~1"=="-e" set "FXACEXTRAS=" & shift & goto :parse 66 | 67 | shift 68 | goto :parse 69 | 70 | :main 71 | setlocal enableDelayedExpansion 72 | 73 | REM Check if Firefox profiles.ini is installed or not 74 | set "PROFILES_FILE=%FIREFOXFOLDER%\profiles.ini" 75 | if not exist "%PROFILES_FILE%" ( 76 | echo Failed to locate profiles.ini in %FIREFOXFOLDER% 77 | echo Exiting... 78 | goto :end 79 | ) 80 | echo. 81 | echo Profiles file found... 82 | 83 | for /f "delims=" %%i in ('findstr /rc:"Default=.*" %PROFILES_FILE%') do ( 84 | set "i=%%i" 85 | set "i=!i:/=\!" 86 | set "PROFILENAMEDEF=!i:~8!" 87 | goto :continue 88 | ) 89 | :continue 90 | 91 | REM Define default Profile folder path else use -p option 92 | if defined PROFILENAME set "PROFILEFOLDER=%FIREFOXFOLDER%\%PROFILENAME%" 93 | if not defined PROFILENAME set "PROFILEFOLDER=%FIREFOXFOLDER%\%PROFILENAMEDEF%" 94 | 95 | REM Enter Firefox profile folder if it exists 96 | if not exist "%PROFILEFOLDER%"\* ( 97 | echo Failed to locate Profile folder at %PROFILEFOLDER% 98 | echo Exiting... 99 | goto :end 100 | ) 101 | 102 | cd %PROFILEFOLDER% 103 | 104 | REM Copy theme repository inside chrome folder 105 | echo. 106 | echo Installing RealFire UwU in %cd% 107 | 108 | if exist "%CHROMEFOLDER%"\* ( 109 | echo Moving existing %CHROMEFOLDER% to %CHROMEFOLDER%_bak 110 | move %CHROMEFOLDER% %CHROMEFOLDER%_bak || (echo Rename or move the backup && goto :end) 111 | ) 112 | 113 | mkdir %CHROMEFOLDER% 114 | cd %CHROMEFOLDER% 115 | 116 | robocopy %THEMEDIRECTORY% %cd% /COPY:DATS /E 117 | 118 | echo. 119 | echo Setting configuration user.js file... 120 | 121 | if exist ..\user.js ( 122 | echo Moving existing user.js to user.js.bak 123 | move ..\user.js ..\user.js.bak || (echo Rename or move the user.js file && goto :end) 124 | ) 125 | mklink ..\user.js "%cd%\programs\user.js" 126 | 127 | REM If FXACEXTRAS extras enabled, install necessary files 128 | if not defined FXACEXTRAS ( 129 | goto :done 130 | ) 131 | 132 | echo. 133 | echo Enabling userChrome.js manager (fx-autoconfig)... 134 | curl -sL "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/profile/chrome/utils/boot.sys.mjs" > "utils\boot.sys.mjs" || (echo Failed to fetch fx-autoconfig && echo Exiting... && goto :end) 135 | 136 | echo. 137 | echo Downloading config-pref.js (fx-autoconfig)... 138 | curl -sL "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/defaults/pref/config-prefs.js" > "programs\config-prefs.js" || (echo Failed to fetch fx-autoconfig config-prefs.js && echo Exiting... && goto :end) 139 | curl -sL "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js" > "programs\config.js" || (echo Failed to fetch fx-autoconfig config.js && echo Exiting... && goto :end) 140 | 141 | echo. 142 | echo Copying mozilla.cfg and local-settings.js to %APPLICATIONFOLDER% 143 | copy .\programs\config.js "%APPLICATIONFOLDER%" 144 | copy .\programs\mozilla.cfg "%APPLICATIONFOLDER%" 145 | copy .\programs\config-prefs.js "%APPLICATIONFOLDER%\defaults\pref\" 146 | copy .\programs\local-settings.js "%APPLICATIONFOLDER%\defaults\pref\" 147 | 148 | goto :done 149 | 150 | :done 151 | echo. 152 | echo Done! 153 | echo Note: Restart twice to apply changes 154 | 155 | :end 156 | call :cleanup 157 | pause 158 | exit /B 159 | 160 | :cleanup 161 | REM The cleanup function is only really necessary if you 162 | REM are _not_ using SETLOCAL. 163 | set "__NAME=" 164 | set "__VERSION=" 165 | 166 | set "THEMEDIRECTORY=" 167 | set "APPLICATIONFOLDER=" 168 | set "FIREFOXFOLDER=" 169 | set "PROFILENAME=" 170 | set "FXACEXTRAS=" 171 | set "CHROMEFOLDER=" 172 | 173 | goto :eof 174 | 175 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 176 | :RequestAdminElevation FilePath %* || goto:eof 177 | :: 178 | :: By: Cyberponk, v1.5 - 10/06/2016 - Changed the admin rights test method from cacls to fltmc 179 | :: v1.4 - 17/05/2016 - Added instructions for arguments with ! char 180 | :: v1.3 - 01/08/2015 - Fixed not returning to original folder after elevation successful 181 | :: v1.2 - 30/07/2015 - Added error message when running from mapped drive 182 | :: v1.1 - 01/06/2015 183 | :: 184 | :: Func: opens an admin elevation prompt. If elevated, runs everything after the function call, with elevated rights. 185 | :: Returns: -1 if elevation was requested 186 | :: 0 if elevation was successful 187 | :: 1 if an error occured 188 | :: 189 | :: USAGE: 190 | :: If function is copied to a batch file: 191 | :: call :RequestAdminElevation "%~dpf0" %* || goto:eof 192 | :: 193 | :: If called as an external library (from a separate batch file): 194 | :: set "_DeleteOnExit=0" on Options 195 | :: (call :RequestAdminElevation "%~dpf0" %* || goto:eof) && CD /D %CD% 196 | :: 197 | :: If called from inside another CALL, you must set "_ThisFile=%~dpf0" at the beginning of the file 198 | :: call :RequestAdminElevation "%_ThisFile%" %* || goto:eof 199 | :: 200 | :: If you need to use the ! char in the arguments, the calling must be done like this, and afterwards you must use %args% to get the correct arguments: 201 | :: set "args=%* " 202 | :: call :RequestAdminElevation ..... use one of the above but replace the %* with %args:!={a)% 203 | :: set "args=%args:{a)=!%" 204 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 205 | setlocal ENABLEDELAYEDEXPANSION & set "_FilePath=%~1" 206 | if NOT EXIST "!_FilePath!" (echo/Read RequestAdminElevation usage information) 207 | :: UAC.ShellExecute only works with 8.3 filename, so use %~s1 208 | set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof) 209 | :: Remove parenthesis from the temp filename 210 | set _FN=%_FN:(=% 211 | set _vbspath="%temp:~%\%_FN:)=%.vbs" & set "_batpath=%temp:~%\%_FN:)=%.bat" 212 | 213 | :: Test if we gave admin rights 214 | fltmc >nul 2>&1 || goto :_getElevation 215 | 216 | :: Elevation successful 217 | (if exist %_vbspath% ( del %_vbspath% )) & (if exist %_batpath% ( del %_batpath% )) 218 | :: Set ERRORLEVEL 0, set original folder and exit 219 | endlocal & CD /D "%~dp1" & ver >nul & goto:eof 220 | 221 | :_getElevation 222 | echo/Requesting elevation... 223 | :: Try to create %_vbspath% file. If failed, exit with ERRORLEVEL 1 224 | echo/Set UAC = CreateObject^("Shell.Application"^) > %_vbspath% || (echo/&echo/Unable to create %_vbspath% & endlocal &md; 2>nul &goto:eof) 225 | echo/UAC.ShellExecute "%_batpath%", "", "", "runas", 1 >> %_vbspath% & echo/wscript.Quit(1)>> %_vbspath% 226 | :: Try to create %_batpath% file. If failed, exit with ERRORLEVEL 1 227 | echo/@%* > "%_batpath%" || (echo/&echo/Unable to create %_batpath% & endlocal &md; 2>nul &goto:eof) 228 | echo/@if %%errorlevel%%==9009 (echo/^&echo/Admin user could not read the batch file. If running from a mapped drive or UNC path, check if Admin user can read it.)^&echo/^& @if %%errorlevel%% NEQ 0 pause >> "%_batpath%" 229 | 230 | :: Run %_vbspath%, that calls %_batpath%, that calls the original file 231 | %_vbspath% && (echo/&echo/Failed to run VBscript %_vbspath% &endlocal &md; 2>nul & goto:eof) 232 | 233 | :: Vbscript has been run, exit with ERRORLEVEL -1 234 | echo/&echo/Elevation was requested on a new CMD window &endlocal &fc;: 2>nul & goto:eof 235 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 236 | -------------------------------------------------------------------------------- /programs/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | THEMEDIRECTORY=$(cd `dirname "$0"` && cd .. && pwd); 4 | 5 | os_type=$(uname -s) 6 | 7 | # Set default paths 8 | FIREFOXFOLDER="" 9 | APPLICATIONFOLDER="" 10 | 11 | # Check the operating system and set paths accordingly 12 | if [ "$os_type" == "Darwin" ]; then 13 | FIREFOXFOLDER=~/Library/Application\ Support/Firefox 14 | APPLICATIONFOLDER='/Applications/Firefox.app/Contents/MacOS/Firefox' 15 | else 16 | FIREFOXFOLDER=/home/$USER/.mozilla/firefox 17 | APPLICATIONFOLDER='/usr/lib64/firefox' 18 | fi 19 | 20 | PROFILENAME=""; 21 | FXACEXTRAS=true; 22 | CHROMEFOLDER="chrome"; 23 | 24 | 25 | # Get installation options 26 | while getopts 'b:f:p:eh' flag; do 27 | case "${flag}" in 28 | b) APPLICATIONFOLDER="${OPTARG}" ;; 29 | f) FIREFOXFOLDER="${OPTARG}" ;; 30 | p) PROFILENAME="${OPTARG}" ;; 31 | e) FXACEXTRAS=false ;; 32 | h) 33 | echo "RealFire! Install script usage: ./install.sh [ options ... ]" 34 | echo "where options include:" 35 | echo 36 | echo " -b (Set custom Firefox binary folder path)" 37 | echo " -f (Set custom Firefox folder path)" 38 | echo " -p (Set custom profile name)" 39 | echo " -e (Install fx-autoconfig - Runs sudo to copy mozilla.cfg and local-settings.js to Application Binary folder)" 40 | echo " -h (Show help message)" 41 | exit 0 42 | ;; 43 | esac 44 | done 45 | 46 | 47 | # Check if Firefox profiles.ini is installed or not 48 | PROFILES_FILE="${FIREFOXFOLDER}/profiles.ini" 49 | if [ ! -f "${PROFILES_FILE}" ]; then 50 | >&2 echo "Failed to locate profiles.ini in ${FIREFOXFOLDER} 51 | Exiting..." 52 | exit 1 53 | fi 54 | 55 | echo 56 | echo "Profiles file found..." 57 | 58 | 59 | # Define default Profile folder path else use -p option 60 | if [ -z "$PROFILENAME" ]; then 61 | PROFILEFOLDER="${FIREFOXFOLDER}/$(grep -zoP '\[Install.*?\]\nDefault=\K(.*?)\n' $PROFILES_FILE | tr -d '\0')" 62 | else 63 | PROFILEFOLDER="${FIREFOXFOLDER}/${PROFILENAME}" 64 | fi 65 | 66 | 67 | # Enter Firefox profile folder if it exists 68 | if [ ! -d "$PROFILEFOLDER" ]; then 69 | >&2 echo "Failed to locate Profile folder at ${PROFILEFOLDER} 70 | Exiting..." 71 | exit 1 72 | fi 73 | 74 | cd $PROFILEFOLDER 75 | 76 | 77 | # Copy theme repository inside chrome folder 78 | echo 79 | echo "Installing RealFire! in ${PWD}" 80 | 81 | # Create a chrome directory if it doesn't exist else take a backupold chrome folder 82 | if [ -d "$CHROMEFOLDER" ]; then 83 | echo "Moving existing $CHROMEFOLDER to ${CHROMEFOLDER}_bak" 84 | mv --backup=t $CHROMEFOLDER "${CHROMEFOLDER}_bak" || { exit 1; } 85 | fi 86 | 87 | mkdir -p $CHROMEFOLDER 88 | cd $CHROMEFOLDER 89 | 90 | cp -a "${THEMEDIRECTORY}/." $PWD 91 | 92 | 93 | # Symlink user.js to that of RealFire! 94 | echo 95 | echo "Setting configuration user.js file..." 96 | 97 | if [ -f ../user.js ]; then 98 | echo "Moving existing user.js to user.js.bak" 99 | mv --backup=t ../user.js ../user.js.bak || { exit 1; } 100 | fi 101 | 102 | ln -fs "`pwd`/programs/user.js" ../user.js 103 | 104 | 105 | # If FXACEXTRAS extras enabled, install necessary files 106 | if [ "$FXACEXTRAS" = true ] ; then 107 | echo 108 | 109 | echo "Enabling userChrome.js manager (fx-autoconfig)..." 110 | rm "./utils/boot.sys.mjs" 111 | curl -sL "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/profile/chrome/utils/boot.sys.mjs" > "./utils/boot.sys.mjs" || { echo "Failed to fetch boot.sys.mjs"; echo "Exiting..."; exit 1; } 112 | 113 | echo "Enabling config-prefs.js..." 114 | rm "./programs/config-prefs.js" 115 | curl -sL "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/defaults/pref/config-prefs.js" > "./programs/config-prefs.js" || { echo "Failed to fetch config-prefs.js"; echo "Exiting..."; exit 1; } 116 | echo "Enabling config.js..." 117 | rm "./programs/config.js" 118 | curl -sL "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js" > "./programs/config.js" || { echo "Failed to fetch config.js"; echo "Exiting..."; exit 1; } 119 | 120 | 121 | echo 122 | echo "Copying mozilla.cfg, local-settings.js, config.js and config-pref.js to ${APPLICATIONFOLDER}" 123 | 124 | sudo cp ./programs/mozilla.cfg "${APPLICATIONFOLDER}/" 125 | sudo cp ./programs/config.js "${APPLICATIONFOLDER}/" 126 | 127 | sudo cp ./programs/config-prefs.js "${APPLICATIONFOLDER}/defaults/pref/" 128 | sudo cp ./programs/local-settings.js "${APPLICATIONFOLDER}/defaults/pref/" 129 | fi 130 | 131 | echo 132 | echo "Done!" 133 | echo "Note: Restart twice to apply changes" -------------------------------------------------------------------------------- /programs/local-settings.js: -------------------------------------------------------------------------------- 1 | // 2 | pref("general.config.filename", "mozilla.cfg"); 3 | pref("general.config.obscure_value", 0); 4 | pref("general.config.sandbox_enabled", false); 5 | -------------------------------------------------------------------------------- /programs/mozilla.cfg: -------------------------------------------------------------------------------- 1 | // skip 1st line 2 | try { 3 | 4 | let { 5 | classes: Cc, 6 | interfaces: Ci, 7 | manager: Cm, 8 | utils: Cu 9 | } = Components; 10 | 11 | // set new tab page 12 | // Cu.import("resource:///modules/AboutNewTab.jsm"); 13 | // var newTabURL_ = "file://"; 14 | // AboutNewTab.newTabURL = newTabURL_; 15 | 16 | // set fx-autoconfig 17 | let cmanifest = Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get('UChrm', Ci.nsIFile); 18 | cmanifest.append('utils'); 19 | cmanifest.append('chrome.manifest'); 20 | 21 | if(cmanifest.exists()){ 22 | Cm.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(cmanifest); 23 | Cu.import('chrome://userchromejs/content/boot.jsm'); 24 | } 25 | 26 | } catch(ex) {Cu.reportError(ex)}; // report errors in the Browser Console 27 | -------------------------------------------------------------------------------- /programs/uninstall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | call :RequestAdminElevation "%~dpfs0" %* || goto:eof 4 | 5 | goto :init 6 | 7 | :init 8 | set "__NAME=RealFire Uninstaller" 9 | set "__VERSION=4.0.0" 10 | 11 | call :header 12 | 13 | set "APPLICATIONFOLDER=C:\Program Files\Mozilla Firefox" 14 | set "FIREFOXFOLDER=%APPDATA%\Mozilla\Firefox" 15 | set "CHROMEFOLDER=chrome" 16 | set "PROFILEFOLDER=" 17 | 18 | REM Locate Firefox profiles.ini 19 | set "PROFILES_FILE=%FIREFOXFOLDER%\profiles.ini" 20 | if not exist "%PROFILES_FILE%" ( 21 | echo Failed to locate profiles.ini in %FIREFOXFOLDER% 22 | echo Exiting... 23 | goto :end 24 | ) 25 | 26 | echo. 27 | echo Profiles file found... 28 | for /f "delims=" %%i in ('findstr /rc:"Default=.*" %PROFILES_FILE%') do ( 29 | set "i=%%i" 30 | set "i=!i:/=\!" 31 | set "PROFILENAMEDEF=!i:~8!" 32 | goto :continue 33 | ) 34 | :continue 35 | 36 | REM Set profile folder 37 | set "PROFILEFOLDER=%FIREFOXFOLDER%\%PROFILENAMEDEF%" 38 | 39 | if not exist "%PROFILEFOLDER%" ( 40 | echo Failed to locate Profile folder at %PROFILEFOLDER% 41 | echo Exiting... 42 | goto :end 43 | ) 44 | 45 | cd "%PROFILEFOLDER%" 46 | echo. 47 | echo Uninstalling RealFire UwU from %cd% 48 | 49 | REM Remove chrome folder and restore backup if exists 50 | if exist "%CHROMEFOLDER%_bak" ( 51 | echo Restoring backup folder %CHROMEFOLDER%_bak... 52 | rmdir /s /q "%CHROMEFOLDER%" 53 | move "%CHROMEFOLDER%_bak" "%CHROMEFOLDER%" || ( 54 | echo Failed to restore backup folder %CHROMEFOLDER%_bak. 55 | goto :end 56 | ) 57 | ) else ( 58 | echo Removing %CHROMEFOLDER% folder... 59 | rmdir /s /q "%CHROMEFOLDER%" 60 | ) 61 | 62 | REM Restore user.js backup if exists 63 | if exist "user.js.bak" ( 64 | echo Restoring user.js.bak... 65 | move /y "user.js.bak" "user.js" 66 | ) else ( 67 | echo Removing user.js link... 68 | del "user.js" 69 | ) 70 | 71 | REM Optionally remove fx-autoconfig files 72 | set /p FXACREMOVE="Do you want to remove fx-autoconfig files? (Y/N): " 73 | if /i "%FXACREMOVE%"=="Y" ( 74 | echo Removing fx-autoconfig files... 75 | rmdir /s /q "chrome\utils" 76 | del "programs\config.js" 77 | del "programs\mozilla.cfg" 78 | del "programs\config-prefs.js" 79 | del "programs\local-settings.js" 80 | ) 81 | 82 | REM Optionally remove application files 83 | set /p APPREMOVE="Do you want to remove RealFire application files from %APPLICATIONFOLDER%? (Y/N): " 84 | if /i "%APPREMOVE%"=="Y" ( 85 | echo Removing application files from %APPLICATIONFOLDER%... 86 | del "%APPLICATIONFOLDER%\config.js" 87 | del "%APPLICATIONFOLDER%\mozilla.cfg" 88 | del "%APPLICATIONFOLDER%\defaults\pref\config-prefs.js" 89 | del "%APPLICATIONFOLDER%\defaults\pref\local-settings.js" 90 | ) 91 | 92 | echo. 93 | echo Uninstallation complete! 94 | 95 | :end 96 | pause 97 | exit /B 98 | 99 | :header 100 | echo %__NAME% v%__VERSION% 101 | echo This uninstaller will remove RealFire theme 102 | echo and restore your Firefox profile to its 103 | echo previous state. 104 | echo. 105 | goto :eof 106 | 107 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 108 | :RequestAdminElevation FilePath %* || goto:eof 109 | :: 110 | :: By: Cyberponk, v1.5 - 10/06/2016 - Changed the admin rights test method from cacls to fltmc 111 | :: v1.4 - 17/05/2016 - Added instructions for arguments with ! char 112 | :: v1.3 - 01/08/2015 - Fixed not returning to original folder after elevation successful 113 | :: v1.2 - 30/07/2015 - Added error message when running from mapped drive 114 | :: v1.1 - 01/06/2015 115 | :: 116 | :: Func: opens an admin elevation prompt. If elevated, runs everything after the function call, with elevated rights. 117 | :: Returns: -1 if elevation was requested 118 | :: 0 if elevation was successful 119 | :: 1 if an error occured 120 | :: 121 | :: USAGE: 122 | :: If function is copied to a batch file: 123 | :: call :RequestAdminElevation "%~dpf0" %* || goto:eof 124 | :: 125 | :: If called as an external library (from a separate batch file): 126 | :: set "_DeleteOnExit=0" on Options 127 | :: (call :RequestAdminElevation "%~dpf0" %* || goto:eof) && CD /D %CD% 128 | :: 129 | :: If called from inside another CALL, you must set "_ThisFile=%~dpf0" at the beginning of the file 130 | :: call :RequestAdminElevation "%_ThisFile%" %* || goto:eof 131 | :: 132 | :: If you need to use the ! char in the arguments, the calling must be done like this, and afterwards you must use %args% to get the correct arguments: 133 | :: set "args=%* " 134 | :: call :RequestAdminElevation ..... use one of the above but replace the %* with %args:!={a)% 135 | :: set "args=%args:{a)=!%" 136 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 137 | setlocal ENABLEDELAYEDEXPANSION & set "_FilePath=%~1" 138 | if NOT EXIST "!_FilePath!" (echo/Read RequestAdminElevation usage information) 139 | :: UAC.ShellExecute only works with 8.3 filename, so use %~s1 140 | set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof) 141 | :: Remove parenthesis from the temp filename 142 | set _FN=%_FN:(=% 143 | set _vbspath="%temp:~%\%_FN:)=%.vbs" & set "_batpath=%temp:~%\%_FN:)=%.bat" 144 | 145 | :: Test if we gave admin rights 146 | fltmc >nul 2>&1 || goto :_getElevation 147 | 148 | :: Elevation successful 149 | (if exist %_vbspath% ( del %_vbspath% )) & (if exist %_batpath% ( del %_batpath% )) 150 | :: Set ERRORLEVEL 0, set original folder and exit 151 | endlocal & CD /D "%~dp1" & ver >nul & goto:eof 152 | 153 | :_getElevation 154 | echo/Requesting elevation... 155 | :: Try to create %_vbspath% file. If failed, exit with ERRORLEVEL 1 156 | echo/Set UAC = CreateObject^("Shell.Application"^) > %_vbspath% || (echo/&echo/Unable to create %_vbspath% & endlocal &md; 2>nul &goto:eof) 157 | echo/UAC.ShellExecute "%_batpath%", "", "", "runas", 1 >> %_vbspath% & echo/wscript.Quit(1)>> %_vbspath% 158 | :: Try to create %_batpath% file. If failed, exit with ERRORLEVEL 1 159 | echo/@%* > "%_batpath%" || (echo/&echo/Unable to create %_batpath% & endlocal &md; 2>nul &goto:eof) 160 | echo/@if %%errorlevel%%==9009 (echo/^&echo/Admin user could not read the batch file. If running from a mapped drive or UNC path, check if Admin user can read it.)^&echo/^& @if %%errorlevel%% NEQ 0 pause >> "%_batpath%" 161 | 162 | :: Run %_vbspath%, that calls %_batpath%, that calls the original file 163 | %_vbspath% && (echo/&echo/Failed to run VBscript %_vbspath% &endlocal &md; 2>nul & goto:eof) 164 | 165 | :: Vbscript has been run, exit with ERRORLEVEL -1 166 | echo/&echo/Elevation was requested on a new CMD window &endlocal &fc;: 2>nul & goto:eof 167 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 168 | -------------------------------------------------------------------------------- /programs/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Set theme directory 4 | THEMEDIRECTORY=$(cd `dirname "$0"` && cd .. && pwd); 5 | 6 | # Default paths 7 | FIREFOXFOLDER="" 8 | APPLICATIONFOLDER="" 9 | 10 | # Determine operating system 11 | os_type=$(uname -s) 12 | 13 | # Set paths based on operating system 14 | if [ "$os_type" == "Darwin" ]; then 15 | FIREFOXFOLDER=~/Library/Application\ Support/Firefox 16 | APPLICATIONFOLDER='/Applications/Firefox.app/Contents/MacOS/Firefox' 17 | else 18 | FIREFOXFOLDER=/home/$USER/.mozilla/firefox 19 | APPLICATIONFOLDER='/usr/lib64/firefox' 20 | fi 21 | 22 | CHROMEFOLDER="chrome"; 23 | 24 | # Get installation options 25 | while getopts 'b:f:p:eh' flag; do 26 | case "${flag}" in 27 | b) APPLICATIONFOLDER="${OPTARG}" ;; 28 | f) FIREFOXFOLDER="${OPTARG}" ;; 29 | p) PROFILENAME="${OPTARG}" ;; 30 | e) FXACEXTRAS=false ;; 31 | h) 32 | echo "RealFire! Uninstall script usage: ./uninstall.sh [ options ... ]" 33 | echo "where options include:" 34 | echo 35 | echo " -b (Set custom Firefox binary folder path)" 36 | echo " -f (Set custom Firefox folder path)" 37 | echo " -p (Set custom profile name)" 38 | echo " -e (Install fx-autoconfig - Runs sudo to copy mozilla.cfg and local-settings.js to Application Binary folder)" 39 | echo " -h (Show help message)" 40 | exit 0 41 | ;; 42 | esac 43 | done 44 | 45 | # Check if Firefox profiles.ini is installed or not 46 | PROFILES_FILE="${FIREFOXFOLDER}/profiles.ini" 47 | if [ ! -f "${PROFILES_FILE}" ]; then 48 | >&2 echo "Failed to locate profiles.ini in ${FIREFOXFOLDER} 49 | Exiting..." 50 | exit 1 51 | fi 52 | 53 | echo 54 | echo "Profiles file found..." 55 | 56 | 57 | # Define default Profile folder path else use -p option 58 | if [ -z "$PROFILENAME" ]; then 59 | PROFILEFOLDER="${FIREFOXFOLDER}/$(grep -zoP '\[Install.*?\]\nDefault=\K(.*?)\n' $PROFILES_FILE | tr -d '\0')" 60 | else 61 | PROFILEFOLDER="${FIREFOXFOLDER}/${PROFILENAME}" 62 | fi 63 | 64 | 65 | # Enter Firefox profile folder if it exists 66 | if [ ! -d "$PROFILEFOLDER" ]; then 67 | >&2 echo "Failed to locate Profile folder at ${PROFILEFOLDER} 68 | Exiting..." 69 | exit 1 70 | fi 71 | 72 | cd $PROFILEFOLDER 73 | 74 | # Confirm uninstallation 75 | read -p "This will remove RealFire! theme and associated configuration files. Are you sure? (y/n): " -n 1 -r 76 | echo 77 | if [[ $REPLY =~ ^[Yy]$ ]]; then 78 | 79 | 80 | # Remove RealFire! theme folder if it exists 81 | if [ -d "${CHROMEFOLDER}" ]; then 82 | rm -rf "${CHROMEFOLDER}" 83 | fi 84 | 85 | # Remove user.js symbolic link 86 | if [ -f "../user.js" ]; then 87 | rm "../user.js" 88 | fi 89 | 90 | # Restore backup of user.js if exists 91 | if [ -f "../user.js.bak" ]; then 92 | mv ../user.js.bak ../user.js || { exit 1; } 93 | fi 94 | 95 | echo "Removing mozilla.cfg, local-settings.js, config.js and config-pref.js from ${APPLICATIONFOLDER}" 96 | 97 | sudo rm -f "${APPLICATIONFOLDER}/mozilla.cfg" 98 | sudo rm -f "${APPLICATIONFOLDER}/config.js" 99 | sudo rm -f "${APPLICATIONFOLDER}/defaults/pref/config-prefs.js" 100 | sudo rm -f "${APPLICATIONFOLDER}/defaults/pref/local-settings.js" 101 | 102 | echo "RealFire! theme and associated configuration files have been removed." 103 | else 104 | echo "Uninstallation aborted." 105 | fi 106 | -------------------------------------------------------------------------------- /programs/user.js: -------------------------------------------------------------------------------- 1 | user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); 2 | user_pref("svg.context-properties.content.enabled", true); 3 | user_pref("browser.tabs.tabMinWidth", 76); 4 | user_pref("browser.compactmode.show", true); 5 | user_pref("browser.proton.enabled", false); 6 | user_pref("ui.popup.disable_autohide", false); 7 | user_pref("browser.startup.preXulSkeletonUI", false); 8 | // user_pref("browser.uidensity", 1); 9 | user_pref("userChrome.toolbarSlider.width", 2); 10 | user_pref("layout.css.has-selector.enabled", true); 11 | user_pref("userChromeJS.scriptsDisabled", "macosTheme.uc.js"); 12 | -------------------------------------------------------------------------------- /resources/material/actual-zoom.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/all-history.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/bookmark-manage.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/checked copy.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/checked.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/close-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | close-hover-svg 3 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /resources/material/close-tab-option.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/close.svg: -------------------------------------------------------------------------------- 1 | 2 | close-svg 3 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/command-pick.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/desktop-bg.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/duplicate-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /resources/material/experiments.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/ideas.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/inactive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/material/maximize-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | maximize-hover-svg 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resources/material/maximize-restore.svg: -------------------------------------------------------------------------------- 1 | 2 | maximize-restore-svg 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resources/material/maximize-svg.svg: -------------------------------------------------------------------------------- 1 | 2 | maximize-svg 3 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/maximize.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/material/minimize-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | minimize-hover-svg 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resources/material/minimize.svg: -------------------------------------------------------------------------------- 1 | 2 | minimize-svg 3 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/move-container.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /resources/material/move-end.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/move-start.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/move-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/new-container.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/material/open_new_tabs.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /resources/material/page-source.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/pause.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | -------------------------------------------------------------------------------- /resources/material/playButton.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resources/material/quit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/radio-checked.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/radio-unchecked.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/redo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/reload.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /resources/material/remote-debug.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/restore-session.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/select-all.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/send-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/share-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/signout.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/terminal.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/toolbox.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/material/translate.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /resources/material/unchecked.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/material/userScriptsMenu.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/web-page-source-code.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | -------------------------------------------------------------------------------- /resources/material/zoom-in.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /resources/material/zoom-out.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /userChrome.css: -------------------------------------------------------------------------------- 1 | @import 'includes/realfire-config.css'; 2 | @import 'includes/realfire-colours.css'; 3 | 4 | @import 'includes/realfire-layout.css'; 5 | @import 'includes/realfire-responsive.css'; 6 | 7 | @import "includes/realfire-findbar.css"; 8 | @import "includes/realfire-icons.css"; 9 | @import "includes/realfire-popups.css"; 10 | @import "includes/realfire-checkbox.css"; 11 | 12 | @import 'includes/realfire-nav-bar.css'; 13 | @import 'includes/realfire-tabs.css'; 14 | @import 'includes/realfire-side-bar.css'; 15 | @import 'includes/realfire-library.css'; 16 | @import 'includes/realfire-button.css'; 17 | @import 'includes/realfire-inputs.css'; 18 | 19 | notification-message.infobar { 20 | background:var(--uc-base-colour) !important; 21 | outline: 2px solid var(--accent-color) !important; 22 | border-radius: var(--uc-border-radius) !important; 23 | } 24 | 25 | notification-message.infobar::before { 26 | background-image: none !important; 27 | } -------------------------------------------------------------------------------- /userContent.css: -------------------------------------------------------------------------------- 1 | @import 'includes/realfire-config.css'; 2 | @import 'includes/realfire-colours.css'; 3 | @import 'includes/realfire-settings-page.css'; 4 | @import "includes/realfire-popups.css"; 5 | @import "includes/realfire-checkbox.css"; 6 | @import 'includes/realfire-library.css'; 7 | @import 'includes/realfire-addons-page.css'; 8 | 9 | @-moz-document url(about:home), url(about:newtab), url(about:privatebrowsing) { 10 | 11 | .search-wrapper:not(.search.disabled) .search-handoff-button { 12 | transition: all var(--uc-animation-duration) ease-out; 13 | } 14 | 15 | .search-wrapper.fake-focus:not(.search.disabled) .search-handoff-button { 16 | transition: all var(--uc-animation-duration) ease-in; 17 | } 18 | 19 | div.title span { 20 | background-color: var(--uc-base-colour); 21 | border-radius: var(--uc-border-radius); 22 | white-space: nowrap !important; 23 | padding: 2px 4px !important; 24 | min-height: auto !important; 25 | width: 9vh !important; 26 | } 27 | 28 | .top-site-outer { 29 | transition: all var(--uc-animation-duration) ease-out; 30 | } 31 | 32 | .top-site-outer .top-site-icon, 33 | .outer-wrapper .ds-top-sites .top-sites .top-site-outer .top-site-inner > a .tile { 34 | transition: all var(--uc-animation-duration) ease-out; 35 | background-color: var(--uc-base-colour) !important; 36 | } 37 | 38 | .top-sites-list:not(.dnd-active) .top-site-outer:is(.active, :focus, :hover), 39 | .outer-wrapper .ds-top-sites .top-sites .top-site-outer .top-site-inner > a:is(.active, :focus, :hover) { 40 | transition: all var(--uc-animation-duration) ease-in; 41 | outline: 2px solid var(--accent-color); 42 | } 43 | 44 | .top-sites-list:not(.dnd-active) .top-site-outer:is(.active, :focus, :hover) { 45 | transition: all var(--uc-animation-duration) ease-in; 46 | background: var(--uc-base-colour) !important; 47 | } 48 | 49 | .click-target-container *, 50 | .top-sites-list * { 51 | color: var(--uc-inverted-colour) !important; 52 | } 53 | 54 | body::before { 55 | content: ""; 56 | z-index: -1; 57 | position: fixed; 58 | top: 0; 59 | left: 0; 60 | background: url(img/new_tab_wallpaper.jpg) center no-repeat; 61 | background-size: cover; 62 | width: 100vw; 63 | height: 100vh; 64 | } 65 | 66 | .neterror { 67 | background-color: var(--uc-base-colour) !important; 68 | } 69 | 70 | #neterrorTryAgainButton { 71 | background-color: var(--accent-color) !important; 72 | color: var(--uc-inverted-colour) !important; 73 | } 74 | 75 | #neterrorTryAgainButton:hover { 76 | background-color: var(--accent-hover-color) !important; 77 | } 78 | 79 | .home-section .section input:checked + .slider { 80 | background-color: var(--accent-color) !important; 81 | } 82 | 83 | .home-section .section .slider { 84 | background-color: var(--uc-inverted-colour) !important; 85 | } 86 | .weatherCard { 87 | background-color: var(--uc-base-colour) !important; 88 | border-radius: var(--uc-border-radius); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /utils/boot.sys.mjs: -------------------------------------------------------------------------------- 1 | import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; 2 | import { loaderModuleLink, Pref, FileSystem, windowUtils, showNotification, startupFinished, restartApplication, escapeXUL, toggleScript } from "chrome://userchromejs/content/utils.sys.mjs"; 3 | 4 | const FX_AUTOCONFIG_VERSION = "0.10.4"; 5 | console.warn( "Browser is executing custom scripts via autoconfig" ); 6 | 7 | const APP_VARIANT = (() => { 8 | let is_tb = AppConstants.BROWSER_CHROME_URL.startsWith("chrome://messenger"); 9 | return { 10 | THUNDERBIRD: is_tb, 11 | FIREFOX: !is_tb 12 | } 13 | })(); 14 | const BRAND_NAME = AppConstants.MOZ_APP_DISPLAYNAME_DO_NOT_USE; 15 | 16 | const BROWSERCHROME = (() => { 17 | if(APP_VARIANT.FIREFOX){ 18 | return AppConstants.BROWSER_CHROME_URL 19 | } 20 | return "chrome://messenger/content/messenger.xhtml" 21 | })(); 22 | 23 | const PREF_ENABLED = 'userChromeJS.enabled'; 24 | const PREF_SCRIPTSDISABLED = 'userChromeJS.scriptsDisabled'; 25 | 26 | function getDisabledScripts(){ 27 | return Services.prefs.getStringPref(PREF_SCRIPTSDISABLED,"").split(",") 28 | } 29 | 30 | class ScriptData { 31 | #preCompiledESM; 32 | #preCompileFailed; 33 | #preCompiling; 34 | #preLoadedStyle; 35 | #chromeURI; 36 | #isRunning = false; 37 | #injectionFailed = false; 38 | constructor(leafName, headerText, noExec, isStyle){ 39 | const hasLongDescription = (/^\/\/\ @long-description/im).test(headerText); 40 | this.filename = leafName; 41 | this.name = headerText.match(/\/\/ @name\s+(.+)\s*$/im)?.[1]; 42 | this.charset = headerText.match(/\/\/ @charset\s+(.+)\s*$/im)?.[1]; 43 | this.description = hasLongDescription 44 | ? headerText.match(/\/\/ @description\s+.*?\/\*\s*(.+?)\s*\*\//is)?.[1] 45 | : headerText.match(/\/\/ @description\s+(.+)\s*$/im)?.[1]; 46 | this.version = headerText.match(/\/\/ @version\s+(.+)\s*$/im)?.[1]; 47 | this.author = headerText.match(/\/\/ @author\s+(.+)\s*$/im)?.[1]; 48 | this.icon = headerText.match(/\/\/ @icon\s+(.+)\s*$/im)?.[1]; 49 | this.homepageURL = headerText.match(/\/\/ @homepageURL\s+(.+)\s*$/im)?.[1]; 50 | this.downloadURL = headerText.match(/\/\/ @downloadURL\s+(.+)\s*$/im)?.[1]; 51 | this.updateURL = headerText.match(/\/\/ @updateURL\s+(.+)\s*$/im)?.[1]; 52 | this.optionsURL = headerText.match(/\/\/ @optionsURL\s+(.+)\s*$/im)?.[1]; 53 | this.id = headerText.match(/\/\/ @id\s+(.+)\s*$/im)?.[1] 54 | || `${leafName.split('.uc.js')[0]}@${this.author||'userChromeJS'}`; 55 | this.isESM = this.filename.endsWith(".mjs"); 56 | this.onlyonce = /\/\/ @onlyonce\b/.test(headerText); 57 | this.inbackground = this.filename.endsWith(".sys.mjs") || /\/\/ @backgroundmodule\b/.test(headerText); 58 | this.ignoreCache = /\/\/ @ignorecache\b/.test(headerText); 59 | this.manifest = headerText.match(/\/\/ @manifest\s+(.+)\s*$/im)?.[1]; 60 | this.type = isStyle ? "style" : "script"; 61 | this.styleSheetMode = isStyle 62 | ? headerText.match(/\/\/ @stylemode\s+(.+)\s*$/im)?.[1] === "agent_sheet" 63 | ? "agent" : "author" 64 | : null; 65 | this.useFileURI = /\/\/ @usefileuri\b/.test(headerText); 66 | this.noExec = isStyle || noExec; 67 | 68 | if(this.inbackground || this.styleSheetMode === "agent" || (!isStyle && noExec)){ 69 | this.regex = null; 70 | this.loadOrder = -1; 71 | }else{ 72 | // Construct regular expression to use to match target document 73 | let match, rex = { 74 | include: [], 75 | exclude: [] 76 | }; 77 | let findNextRe = /^\/\/ @(include|exclude)\s+(.+)\s*$/gm; 78 | while (match = findNextRe.exec(headerText)) { 79 | rex[match[1]].push( 80 | match[2].replace(/^main$/i, BROWSERCHROME).replace(/\*/g, '.*?') 81 | ); 82 | } 83 | if (!rex.include.length) { 84 | rex.include.push(BROWSERCHROME); 85 | } 86 | let exclude = rex.exclude.length ? `(?!${rex.exclude.join('$|')}$)` : ''; 87 | this.regex = new RegExp(`^${exclude}(${rex.include.join('|') || '.*'})$`,'i'); 88 | let loadOrder = headerText.match(/\/\/ @loadOrder\s+(\d+)\s*$/im)?.[1]; 89 | this.loadOrder = Number.parseInt(loadOrder) || 10; 90 | } 91 | 92 | Object.freeze(this); 93 | } 94 | get isEnabled() { 95 | return getDisabledScripts().indexOf(this.filename) === -1; 96 | } 97 | get injectionFailed(){ 98 | return this.#injectionFailed 99 | } 100 | get isRunning(){ 101 | return this.#isRunning 102 | } 103 | get chromeURI(){ 104 | if(!this.#chromeURI){ 105 | this.#chromeURI = this.type === "style" 106 | ? Services.io.newURI(`chrome://userstyles/skin/${this.filename}`) 107 | : Services.io.newURI(`chrome://userscripts/content/${this.filename}`) 108 | } 109 | return this.#chromeURI 110 | } 111 | get referenceURI(){ 112 | return this.useFileURI && this.type === "style" 113 | ? FileSystem.convertChromeURIToFileURI(this.chromeURI) 114 | : this.chromeURI 115 | } 116 | get preLoadedStyle(){ 117 | return this.#preLoadedStyle 118 | } 119 | static preCompileMJS(aScript){ 120 | if(aScript.#preCompiledESM){ 121 | return Promise.resolve(aScript.#preCompiledESM) 122 | } 123 | if(aScript.#preCompileFailed){ 124 | return Promise.resolve(null); 125 | } 126 | if(aScript.#preCompiling){ 127 | return aScript.#preCompiling 128 | } 129 | aScript.#preCompiling = new Promise(resolve => { 130 | ChromeUtils.compileScript( 131 | `data:,"use strict"; 132 | import("${aScript.chromeURI.spec}") 133 | .catch(e=>{ throw new Error(e.message,"${aScript.filename}",e.lineNumber) })` 134 | ) 135 | .then( script => { 136 | aScript.#preCompiledESM = script; 137 | resolve(script); 138 | }) 139 | .catch( (ex) => resolve(ScriptData.onCompileRejection(ex,aScript)) ) 140 | .finally(()=>{aScript.#preCompiling = null}) 141 | }); 142 | return aScript.#preCompiling 143 | } 144 | static onCompileRejection(ex,script){ 145 | script.#preCompileFailed = true; 146 | console.error(`@ ${script.filename}: script couldn't be compiled because:`,ex); 147 | return null 148 | } 149 | static preLoadAuthorStyle(aStyle){ 150 | if(aStyle.#injectionFailed){ 151 | console.warn(`ignoring style preload for ${aStyle.filename} because it has already failed`); 152 | return false 153 | } 154 | let sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService); 155 | try{ 156 | // Try to preload the file and store it 157 | aStyle.#preLoadedStyle = sss.preloadSheet(aStyle.referenceURI, sss.AUTHOR_SHEET); 158 | }catch(e){ 159 | console.error(`Could not pre-load ${aStyle.filename}: ${e.name}`) 160 | return false 161 | } 162 | aStyle.#isRunning = true; 163 | return true 164 | } 165 | 166 | static tryLoadScriptIntoWindow(aScript,win){ 167 | if(aScript.regex === null || !aScript.regex.test(win.location.href)){ 168 | return 169 | } 170 | if(aScript.type === "style" && aScript.styleSheetMode === "author"){ 171 | if(!aScript.#preLoadedStyle){ 172 | let success = ScriptData.preLoadAuthorStyle(aScript); 173 | if(!success){ 174 | return 175 | } 176 | } 177 | win.windowUtils.addSheet(aScript.#preLoadedStyle,Ci.nsIDOMWindowUtils.AUTHOR_SHEET); 178 | return 179 | } 180 | if (aScript.inbackground || aScript.noExec) { 181 | return 182 | } 183 | if(aScript.onlyonce && aScript.#isRunning) { 184 | return 185 | } 186 | 187 | const injection = aScript.isESM 188 | ? ScriptData.injectESMIntoGlobal(aScript,win) 189 | : ScriptData.injectClassicScriptIntoGlobal(aScript,win); 190 | injection 191 | .catch(ex => { 192 | console.error(new Error(`@ ${aScript.filename}:${ex.lineNumber}`,{cause:ex})); 193 | }) 194 | } 195 | static markScriptRunning(aScript){ 196 | aScript.#isRunning = true; 197 | } 198 | static injectESMIntoGlobal(aScript,aGlobal){ 199 | return new Promise((resolve,reject) => { 200 | ScriptData.preCompileMJS(aScript) 201 | .then(script => { 202 | if(script){ 203 | script.executeInGlobal(aGlobal); 204 | aScript.#isRunning = true; 205 | } 206 | }) 207 | .then(resolve) 208 | .catch( ex => { 209 | aScript.#injectionFailed = true; 210 | reject(ex) 211 | }) 212 | }) 213 | } 214 | static injectClassicScriptIntoGlobal(aScript,aGlobal){ 215 | try{ 216 | Services.scriptloader.loadSubScriptWithOptions( 217 | aScript.chromeURI.spec, 218 | { 219 | target: aGlobal, 220 | ignoreCache: aScript.ignoreCache 221 | } 222 | ) 223 | aScript.#isRunning = true; 224 | return Promise.resolve(1) 225 | }catch(ex){ 226 | aScript.#injectionFailed = true; 227 | return Promise.reject(ex) 228 | } 229 | } 230 | static registerScriptManifest(aScript){ 231 | if(aScript.#isRunning){ 232 | return 233 | } 234 | let cmanifest = FileSystem.getEntry(FileSystem.convertChromeURIToFileURI(`chrome://userscripts/content/${aScript.manifest}.manifest`)); 235 | if(cmanifest.isFile()){ 236 | Components.manager 237 | .QueryInterface(Ci.nsIComponentRegistrar).autoRegister(cmanifest.entry()); 238 | }else{ 239 | console.warn(`Script '${aScript.filename}' tried to register a manifest but requested file '${aScript.manifest}' doesn't exist`); 240 | } 241 | } 242 | static extractScriptHeader(aFSResult){ 243 | return aFSResult.content() 244 | .match(/^\/\/ ==UserScript==\s*[\n\r]+(?:.*[\n\r]+)*?\/\/ ==\/UserScript==\s*/m)?.[0] || "" 245 | } 246 | static extractStyleHeader(aFSResult){ 247 | return aFSResult.content() 248 | .match(/^\/\* ==UserScript==\s*[\n\r]+(?:.*[\n\r]+)*?\/\/ ==\/UserScript==\s*\*\//m)?.[0] || "" 249 | } 250 | static fromScriptFile(aFile){ 251 | if(aFile.fileSize < 24){ 252 | // Smaller files can't possibly have a valid header 253 | // This also means that we successfully generate a ScriptData for *folders* named "xx.uc.js"... 254 | return new ScriptData(aFile.leafName,"",aFile.fileSize === 0,false) 255 | } 256 | const result = FileSystem.readNSIFileSyncUncheckedWithOptions(aFile,{ metaOnly: true }); 257 | const headerText = this.extractScriptHeader(result); 258 | // If there are less than 2 bytes after the header then we mark the script as non-executable. This means that if the file only has a header then we don't try to inject it to any windows, since it wouldn't do anything. 259 | return new ScriptData(aFile.leafName, headerText, headerText.length > aFile.fileSize - 2,false); 260 | } 261 | static fromStyleFile(aFile){ 262 | if(aFile.fileSize < 24){ 263 | // Smaller files can't possibly have a valid header 264 | return new ScriptData(aFile.leafName,"",true,true) 265 | } 266 | const result = FileSystem.readNSIFileSyncUncheckedWithOptions(aFile,{ metaOnly: true }); 267 | return new ScriptData(aFile.leafName, this.extractStyleHeader(result), true,true); 268 | } 269 | } 270 | 271 | Pref.setIfUnset(PREF_ENABLED,true); 272 | Pref.setIfUnset(PREF_SCRIPTSDISABLED,""); 273 | 274 | // This is called if _previous_ startup was broken 275 | function showgBrowserNotification(){ 276 | Services.prefs.setBoolPref('userChromeJS.gBrowser_hack.enabled',true); 277 | showNotification( 278 | { 279 | label : "fx-autoconfig: Something was broken in last startup", 280 | type : "fx-autoconfig-gbrowser-notification", 281 | priority: "critical", 282 | buttons: [{ 283 | label: "Why am I seeing this?", 284 | callback: (notification) => { 285 | notification.ownerGlobal.openWebLinkIn( 286 | "https://github.com/MrOtherGuy/fx-autoconfig#startup-error", 287 | "tab" 288 | ); 289 | return false 290 | } 291 | }] 292 | } 293 | ) 294 | } 295 | 296 | // This is called if startup somehow takes over 5 seconds 297 | function maybeShowBrokenNotification(window){ 298 | if(window.isFullyOccluded && "gBrowser" in window){ 299 | console.log("Window was fully occluded, no need to panic") 300 | return 301 | } 302 | let aNotificationBox = window.gNotificationBox; 303 | aNotificationBox.appendNotification( 304 | "fx-autoconfig-broken-notification", 305 | { 306 | label: "fx-autoconfig: Startup might be broken", 307 | image: "chrome://browser/skin/notification-icons/popup.svg", 308 | priority: "critical" 309 | } 310 | ); 311 | } 312 | 313 | 314 | 315 | function updateMenuStatus(event){ 316 | const menu = event.target; 317 | if(!menu.id === "menuUserScriptsPopup"){ 318 | return 319 | } 320 | let disabledScripts = getDisabledScripts(); 321 | for(let item of menu.children){ 322 | if(item.getAttribute("type") != "checkbox"){ 323 | continue 324 | } 325 | if (disabledScripts.includes(item.dataset.filename)){ 326 | item.removeAttribute("checked"); 327 | }else{ 328 | item.setAttribute("checked","true"); 329 | } 330 | } 331 | } 332 | 333 | class UserChrome_js{ 334 | constructor(){ 335 | this.scripts = []; 336 | this.styles = []; 337 | this.SESSION_RESTORED = false; 338 | this.IS_ENABLED = Services.prefs.getBoolPref(PREF_ENABLED,false); 339 | this.isInitialWindow = true; 340 | this.initialized = false; 341 | this.init(); 342 | } 343 | registerScript(aScript,isDisabled){ 344 | if(aScript.type === "script"){ 345 | this.scripts.push(aScript); 346 | }else{ 347 | this.styles.push(aScript); 348 | } 349 | if(!isDisabled && aScript.manifest){ 350 | try{ 351 | ScriptData.registerScriptManifest(aScript); 352 | }catch(ex){ 353 | console.error(new Error(`@ ${aScript.filename}`,{cause:ex})); 354 | } 355 | } 356 | return isDisabled 357 | } 358 | init(){ 359 | if(this.initialized){ 360 | return 361 | } 362 | loaderModuleLink.setup(this,FX_AUTOCONFIG_VERSION,AppConstants.MOZ_APP_DISPLAYNAME_DO_NOT_USE,APP_VARIANT,ScriptData); 363 | 364 | if(!this.IS_ENABLED){ 365 | Services.obs.addObserver(this, 'domwindowopened', false); 366 | this.initialized = true; 367 | return 368 | } 369 | // gBrowserHack setup 370 | this.GBROWSERHACK_ENABLED = 371 | (Services.prefs.getBoolPref("userChromeJS.gBrowser_hack.required",false) ? 2 : 0) 372 | + (Services.prefs.getBoolPref("userChromeJS.gBrowser_hack.enabled",false) ? 1 : 0); 373 | this.PERSISTENT_DOMCONTENT_CALLBACK = Services.prefs.getBoolPref("userChromeJS.persistent_domcontent_callback",false); 374 | const disabledScripts = getDisabledScripts(); 375 | // load script data 376 | const scriptDir = FileSystem.getScriptDir(); 377 | if(scriptDir.isDirectory()){ 378 | for(let entry of scriptDir){ 379 | if (/^[A-Za-z0-9]+.*(\.uc\.js|\.uc\.mjs|\.sys\.mjs)$/i.test(entry.leafName)) { 380 | let script = ScriptData.fromScriptFile(entry); 381 | if(this.registerScript(script,disabledScripts.includes(script.filename))){ 382 | continue // script is disabled 383 | } 384 | if(script.inbackground){ 385 | try{ 386 | if(script.isESM){ 387 | ChromeUtils.importESModule( script.chromeURI.spec ); 388 | ScriptData.markScriptRunning(script); 389 | }else{ 390 | console.warn(`Refusing to import legacy jsm style backgroundmodule script: ${script.filename} - convert to ES6 modules instead`); 391 | } 392 | }catch(ex){ 393 | console.error(new Error(`@ ${script.filename}:${ex.lineNumber}`,{cause:ex})); 394 | } 395 | } 396 | if(script.isESM && !script.inbackground){ 397 | ScriptData.preCompileMJS(script); 398 | } 399 | } 400 | } 401 | } 402 | const styleDir = FileSystem.getStyleDir(); 403 | if(styleDir.isDirectory()){ 404 | for(let entry of styleDir){ 405 | if (/^[A-Za-z0-9]+.*\.uc\.css$/i.test(entry.leafName)) { 406 | let style = ScriptData.fromStyleFile(entry); 407 | this.registerScript(style,!disabledScripts.includes(style.filename)); 408 | } 409 | } 410 | this.addAgentStyles(this.styles.filter(style => style.styleSheetMode === "agent" && !disabledScripts.includes(style.filename))); 411 | } 412 | this.scripts.sort((a,b) => a.loadOrder - b.loadOrder); 413 | this.styles.sort((a,b) => a.loadOrder - b.loadOrder); 414 | Services.obs.addObserver(this, 'domwindowopened', false); 415 | this.initialized = true; 416 | 417 | } 418 | addAgentStyles(agentStyles){ 419 | if(agentStyles.length > 0){ 420 | let sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService); 421 | for(let style of agentStyles){ 422 | try{ 423 | sss.loadAndRegisterSheet(style.referenceURI, sss.AGENT_SHEET); 424 | ScriptData.markScriptRunning(style); 425 | }catch(e){ 426 | console.error(`Could not load ${style.filename}: ${e.name}`); 427 | } 428 | } 429 | } 430 | } 431 | onDOMContent(document){ 432 | const window = document.defaultView; 433 | if(!(/^chrome:(?!\/\/global\/content\/(commonDialog|alerts\/alert)\.xhtml)|about:(?!blank)/i).test(window.location.href)){ 434 | // Don't inject scripts to modal prompt windows or notifications 435 | if(this.IS_ENABLED && this.styles.length > 0){ 436 | const disabledScripts = getDisabledScripts(); 437 | for(let style of this.styles){ 438 | if(!disabledScripts.includes(style.filename)){ 439 | ScriptData.tryLoadScriptIntoWindow(style,window) 440 | } 441 | } 442 | } 443 | return 444 | } 445 | ChromeUtils.defineLazyGetter(window,"UC_API",() => 446 | ChromeUtils.importESModule("chrome://userchromejs/content/uc_api.sys.mjs") 447 | ) 448 | if(this.IS_ENABLED){ 449 | document.allowUnsafeHTML = false; // https://bugzilla.mozilla.org/show_bug.cgi?id=1432966 450 | 451 | // This is a hack to make gBrowser available for scripts. 452 | // Without it, scripts would need to check if gBrowser exists and deal 453 | // with it somehow. See bug 1443849 454 | const _gb = APP_VARIANT.FIREFOX && "_gBrowser" in window; 455 | if(this.GBROWSERHACK_ENABLED && _gb){ 456 | window.gBrowser = window._gBrowser; 457 | }else if(_gb && this.isInitialWindow){ 458 | this.isInitialWindow = false; 459 | let timeout = window.setTimeout(() => { 460 | maybeShowBrokenNotification(window); 461 | },5000); 462 | windowUtils.waitWindowLoading(window) 463 | .then(() => { 464 | // startup is fine, clear timeout 465 | window.clearTimeout(timeout); 466 | }) 467 | } 468 | // Inject scripts to window 469 | const disabledScripts = getDisabledScripts(); 470 | for(let script of this.scripts){ 471 | if(script.inbackground || script.injectionFailed){ 472 | continue 473 | } 474 | if(!disabledScripts.includes(script.filename)){ 475 | ScriptData.tryLoadScriptIntoWindow(script,window) 476 | } 477 | } 478 | for(let style of this.styles){ 479 | if(!disabledScripts.includes(style.filename)){ 480 | ScriptData.tryLoadScriptIntoWindow(style,window) 481 | } 482 | } 483 | } 484 | if(window.isChromeWindow){ 485 | const menu = document.querySelector( 486 | APP_VARIANT.FIREFOX ? "#menu_openDownloads" : "menuitem#addressBook"); 487 | if(menu){ 488 | menu.parentNode.addEventListener("popupshown", 489 | (ev) => this.generateScriptMenuItemsIfNeeded(ev.target.ownerDocument), 490 | {once: true} 491 | ); 492 | } 493 | } 494 | } 495 | 496 | // Add simple script menu to menubar tools popup 497 | generateScriptMenuItemsIfNeeded(aDoc){ 498 | { 499 | let menu = aDoc.getElementById("userScriptsMenu"); 500 | if(menu){ 501 | return menu 502 | } 503 | } 504 | const popup = aDoc.querySelector( 505 | APP_VARIANT.FIREFOX ? "#menu_openDownloads" : "menuitem#addressBook")?.parentNode; 506 | 507 | if(aDoc.location.href !== BROWSERCHROME || !popup){ 508 | return null 509 | } 510 | const window = aDoc.ownerGlobal; 511 | 512 | window.MozXULElement.insertFTLIfNeeded("toolkit/about/aboutSupport.ftl"); 513 | let menuFragment = window.MozXULElement.parseXULToFragment(` 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | `); 523 | const itemsFragment = window.MozXULElement.parseXULToFragment(""); 524 | for(let script of this.scripts){ 525 | UserChrome_js.appendScriptMenuitemToFragment(window,itemsFragment,script); 526 | } 527 | if(this.styles.length){ 528 | itemsFragment.append(aDoc.createXULElement("menuseparator")); 529 | for(let style of this.styles){ 530 | UserChrome_js.appendScriptMenuitemToFragment(window,itemsFragment,style); 531 | } 532 | } 533 | if(!this.IS_ENABLED){ 534 | itemsFragment.append(window.MozXULElement.parseXULToFragment('')); 535 | } 536 | let menupopup = menuFragment.getElementById("menuUserScriptsPopup"); 537 | menupopup.prepend(itemsFragment); 538 | popup.prepend(menuFragment); 539 | menupopup.addEventListener("popupshown",updateMenuStatus); 540 | menupopup.addEventListener("command",ev => { 541 | switch(ev.target.id){ 542 | case "userScriptsMenu-OpenFolder": 543 | FileSystem.getScriptDir().showInFileManager(); 544 | break; 545 | case "userScriptsMenu-Restart": 546 | restartApplication(false); 547 | break; 548 | case "userScriptsMenu-ClearCache": 549 | restartApplication(true); 550 | break; 551 | default: 552 | if(ev.target.dataset.filename){ 553 | toggleScript(ev.target.dataset.filename); 554 | } 555 | } 556 | }); 557 | aDoc.l10n.formatValues(["restart-button-label","clear-startup-cache-label","show-dir-label"]) 558 | .then(values => { 559 | let baseTitle = `${values[0]} ${BRAND_NAME}`; 560 | aDoc.getElementById("userScriptsMenu-Restart").setAttribute("label", baseTitle); 561 | aDoc.getElementById("userScriptsMenu-ClearCache").setAttribute("label", values[1].replace("…","") + " & " + baseTitle); 562 | aDoc.getElementById("userScriptsMenu-OpenFolder").setAttribute("label",values[2]) 563 | }); 564 | return popup.querySelector("#userScriptsMenu"); 565 | } 566 | static appendScriptMenuitemToFragment(aWindow,aFragment,aScript){ 567 | aFragment.append( 568 | aWindow.MozXULElement.parseXULToFragment(` 569 | 573 | 574 | `) 575 | ); 576 | return 577 | } 578 | observe(aSubject, aTopic, aData) { 579 | aSubject.addEventListener('DOMContentLoaded', this, {once: !this.PERSISTENT_DOMCONTENT_CALLBACK, capture: true}); 580 | } 581 | 582 | handleEvent(aEvent){ 583 | switch (aEvent.type){ 584 | case "DOMContentLoaded": 585 | this.onDOMContent(aEvent.originalTarget); 586 | break; 587 | default: 588 | console.warn(new Error("unexpected event received",{cause:aEvent})); 589 | } 590 | } 591 | 592 | } 593 | 594 | const _ucjs = !Services.appinfo.inSafeMode && new UserChrome_js(); 595 | _ucjs && startupFinished().then(() => { 596 | _ucjs.SESSION_RESTORED = true; 597 | _ucjs.GBROWSERHACK_ENABLED === 2 && showgBrowserNotification(); 598 | if(Pref.setIfUnset("userChromeJS.firstRunShown",true)){ 599 | showNotification({ 600 | type: "fx-autoconfig-installed", 601 | label: `fx-autoconfig: ${BRAND_NAME} is being modified with custom autoconfig scripting` 602 | }); 603 | } 604 | }); 605 | -------------------------------------------------------------------------------- /utils/chrome.manifest: -------------------------------------------------------------------------------- 1 | content userchromejs ./ 2 | content userscripts ../JS/ 3 | skin userstyles classic/1.0 ../CSS/ 4 | content userchrome ../resources/ 5 | -------------------------------------------------------------------------------- /utils/fs.sys.mjs: -------------------------------------------------------------------------------- 1 | export class FileSystem{ 2 | static RESULT_CONTENT = Symbol("Content"); 3 | static RESULT_DIRECTORY = Symbol("Directory"); 4 | static RESULT_ERROR = Symbol("Error"); 5 | static RESULT_FILE = Symbol("File"); 6 | 7 | static getFileURIForFile(aEntry, type){ 8 | let qi = Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler); 9 | if(type === FileSystem.RESULT_DIRECTORY){ 10 | return qi.getURLSpecFromDir(aEntry) 11 | } 12 | if(type === FileSystem.RESULT_FILE){ 13 | return qi.getURLSpecFromActualFile(aEntry) 14 | } 15 | throw ResultError.fromKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{expected: "FileSystem.RESULT_FILE | FileSystem.RESULT_DIRECTORY"}) 16 | } 17 | 18 | static convertChromeURIToFileURI(aURI){ 19 | const registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry); 20 | return registry.convertChromeURL( 21 | aURI instanceof Ci.nsIURI 22 | ? aURI 23 | : Services.io.newURI(aURI) 24 | ); 25 | } 26 | // Call to .parent is needed because chrome urls get implicit "filename" based on the provider 27 | static #SCRIPT_URI; 28 | static #STYLE_URI; 29 | static #RESOURCE_URI; 30 | static{ 31 | this.#RESOURCE_URI = FileSystem.getFileURIForFile( 32 | FileSystem.convertChromeURIToFileURI('chrome://userchrome/content/') 33 | .QueryInterface(Ci.nsIFileURL).file.parent, 34 | FileSystem.RESULT_DIRECTORY 35 | ); 36 | this.#SCRIPT_URI = FileSystem.getFileURIForFile( 37 | FileSystem.convertChromeURIToFileURI('chrome://userscripts/content/') 38 | .QueryInterface(Ci.nsIFileURL).file.parent, 39 | FileSystem.RESULT_DIRECTORY 40 | ); 41 | this.#STYLE_URI = FileSystem.getFileURIForFile( 42 | FileSystem.convertChromeURIToFileURI('chrome://userstyles/skin/') 43 | .QueryInterface(Ci.nsIFileURL).file.parent, 44 | FileSystem.RESULT_DIRECTORY 45 | ); 46 | } 47 | 48 | static get SCRIPT_URI(){ 49 | return Services.io.newURI(FileSystem.#SCRIPT_URI) 50 | } 51 | 52 | static get STYLE_URI(){ 53 | return Services.io.newURI(FileSystem.#STYLE_URI) 54 | } 55 | 56 | static get RESOURCE_URI(){ 57 | return Services.io.newURI(FileSystem.#RESOURCE_URI) 58 | } 59 | 60 | static getResourceDir(){ 61 | return FileSystemResult.fromNsIFile(FileSystem.RESOURCE_URI.QueryInterface(Ci.nsIFileURL).file) 62 | } 63 | 64 | static getScriptDir(){ 65 | return FileSystemResult.fromNsIFile(FileSystem.SCRIPT_URI.QueryInterface(Ci.nsIFileURL).file) 66 | } 67 | 68 | static getStyleDir(){ 69 | return FileSystemResult.fromNsIFile(FileSystem.STYLE_URI.QueryInterface(Ci.nsIFileURL).file) 70 | } 71 | 72 | static #getEntryFromString(aFilename, baseFileURI){ 73 | let baseDirectory = baseFileURI.QueryInterface(Ci.nsIFileURL).file; 74 | if(typeof aFilename !== "string"){ 75 | return FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{expected:"String"}); 76 | } 77 | const parts = aFilename.replace("\\","/").split("/").filter(a => a.length > 0); 78 | while(parts[0] === ".."){ 79 | baseDirectory = baseDirectory.parent; 80 | parts.shift(); 81 | } 82 | try{ 83 | for(let part of parts){ 84 | baseDirectory.append(part) 85 | } 86 | }catch(ex){ 87 | return FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{type:"Invalid path"}) 88 | } 89 | return FileSystemResult.fromNsIFile(baseDirectory) 90 | } 91 | 92 | static getEntry(aFilename, options = {}){ 93 | if(aFilename instanceof Ci.nsIURI){ 94 | if(aFilename.scheme === "chrome"){ 95 | return FileSystemResult.fromNsIFile(FileSystem.convertChromeURIToFileURI(aFilename).QueryInterface(Ci.nsIFileURL).file) 96 | } 97 | if(aFilename.scheme === "file"){ 98 | return FileSystemResult.fromNsIFile(aFilename.QueryInterface(Ci.nsIFileURL).file) 99 | } 100 | throw new Error("unsupported nsIURI conversion") 101 | } 102 | return FileSystem.#getEntryFromString(aFilename, options.baseDirectory || FileSystem.RESOURCE_URI) 103 | } 104 | static readNSIFileSyncUncheckedWithOptions(aFile,options){ 105 | let stream = Cc['@mozilla.org/network/file-input-stream;1'].createInstance(Ci.nsIFileInputStream); 106 | let cvstream = Cc['@mozilla.org/intl/converter-input-stream;1'].createInstance(Ci.nsIConverterInputStream); 107 | try{ 108 | stream.init(aFile, 0x01, 0, 0); 109 | cvstream.init(stream, 'UTF-8', 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); 110 | }catch(e){ 111 | console.error(e); 112 | cvstream.close(); 113 | stream.close(); 114 | return FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_NOT_READABLE,{cause: e, filename: aFile.leafName}) 115 | } 116 | let rv = {content:'',path: FileSystem.getFileURIForFile(aFile,FileSystem.RESULT_FILE)}; 117 | let data = {}; 118 | const metaOnly = !!options.metaOnly; 119 | while (cvstream.readString(4096, data)) { 120 | rv.content += data.value; 121 | if (metaOnly && rv.content.indexOf('// ==/UserScript==') > 0) { 122 | break; 123 | } 124 | } 125 | cvstream.close(); 126 | stream.close(); 127 | 128 | return FileSystemResult.fromContent(rv) 129 | } 130 | static readFileSync(aFile, options = {}) { 131 | if(typeof aFile === "string"){ 132 | const fsResult = FileSystem.#getEntryFromString(aFile, FileSystem.RESOURCE_URI); 133 | if(fsResult.isFile()){ 134 | return FileSystem.readNSIFileSyncUncheckedWithOptions(fsResult.entry(),options); 135 | } 136 | return fsResult.isError() 137 | ? fsResult 138 | : FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_NOT_FILE,{topic: aFile}) 139 | } 140 | if(aFile instanceof Ci.nsIFile){ 141 | return FileSystem.readNSIFileSyncUncheckedWithOptions(aFile,options); 142 | } 143 | throw ResultError.fromKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{expected: "string | Ci.nsIFile"}) 144 | } 145 | static async readFile(aPath){ 146 | if(typeof aPath !== "string"){ 147 | throw ResultError.fromKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{expected: "string"}) 148 | } 149 | try{ 150 | let path = FileSystem.#appendToBaseURI(aPath); 151 | return FileSystemResult.fromContent({ content: await IOUtils.readUTF8(path), path: PathUtils.toFileURI(path) }) 152 | }catch(ex){ 153 | return FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_NOT_READABLE,{cause: ex}) 154 | } 155 | } 156 | static async readJSON(path){ 157 | try{ 158 | let result = await FileSystem.readFile(path); 159 | return result.isError() 160 | ? null 161 | : JSON.parse(result.content()) 162 | }catch(ex){ 163 | console.error(ex) 164 | } 165 | return null 166 | } 167 | static #appendToBaseURI(aPath,aFileURI){ 168 | // Normally, this API can only write into resources directory 169 | // Writing outside of resources can be enabled using following pref 170 | const disallowUnsafeWrites = !Services.prefs.getBoolPref("userChromeJS.allowUnsafeWrites",false); 171 | 172 | const baseURI = aFileURI || FileSystem.RESOURCE_URI; 173 | let baseParts = PathUtils.split(baseURI.QueryInterface(Ci.nsIFileURL).file.path); 174 | let pathParts = aPath.split(/[\\\/]/); 175 | while(pathParts[0] === ".."){ 176 | baseParts.pop(); 177 | pathParts.shift(); 178 | if(disallowUnsafeWrites){ 179 | throw ResultError.fromKind(FileSystem.ERROR_KIND_NOT_ALLOWED) 180 | } 181 | } 182 | return PathUtils.join(...baseParts.concat(pathParts)) 183 | } 184 | static async writeFile(path, content, options = {}){ 185 | if(!path || typeof path !== "string"){ 186 | throw ResultError.fromKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{expected: "string"}) 187 | } 188 | if(typeof content !== "string"){ 189 | throw ResultError.fromKind(FileSystem.ERROR_KIND_INVALID_ARGUMENT,{expected: "string"}) 190 | } 191 | const fileName = FileSystem.#appendToBaseURI(path); 192 | if(!options.tmpPath){ 193 | options.tmpPath = fileName + ".tmp"; 194 | } 195 | return IOUtils.writeUTF8( fileName, content, options ); 196 | } 197 | static createFileURI(fileName){ 198 | if(!fileName){ 199 | return FileSystem.#RESOURCE_URI 200 | } 201 | return FileSystem.convertChromeURIToFileURI(`chrome://userchrome/content/${fileName}`).spec 202 | } 203 | static chromeDir(){ 204 | return FileSystemResult.fromDirectory(Services.dirsvc.get('UChrm',Ci.nsIFile)) 205 | } 206 | static StringContent(obj){ 207 | return FileSystemResult.fromContent(obj) 208 | } 209 | static ERROR_KIND_NOT_EXIST = 1; 210 | static ERROR_KIND_NOT_DIRECTORY = 2; 211 | static ERROR_KIND_NOT_FILE = 3; 212 | static ERROR_KIND_NOT_CONTENT = 4; 213 | static ERROR_KIND_UNKNOWN_RESULT = 5; 214 | static ERROR_KIND_INVALID_ARGUMENT = 6; 215 | static ERROR_KIND_NOT_READABLE = 7; 216 | static ERROR_KIND_NOT_ALLOWED = 8; 217 | } 218 | 219 | class ResultError extends Error{ 220 | 221 | constructor(kind,options,info = {}){ 222 | super(ResultError.toMessage(kind,info),options); 223 | this.kind = kind; 224 | this.name = "ResultError"; 225 | } 226 | static toMessage(kind,info){ 227 | const strInfo = ResultError.parseInfo(info); 228 | switch(kind){ 229 | case FileSystem.ERROR_KIND_NOT_EXIST: 230 | return `Entry doesn't exist: ${strInfo}` 231 | case FileSystem.ERROR_KIND_NOT_DIRECTORY: 232 | return `Result is not a directory: ${strInfo}` 233 | case FileSystem.ERROR_KIND_NOT_FILE: 234 | return `Result is not a file: ${strInfo}` 235 | case FileSystem.ERROR_KIND_NOT_CONTENT: 236 | return `Result is not content: ${strInfo}` 237 | case FileSystem.ERROR_KIND_UNKNOWN_RESULT: 238 | return `Unknown result type: ${strInfo}` 239 | case FileSystem.ERROR_KIND_INVALID_ARGUMENT: 240 | return `Invalid argument: ${strInfo}` 241 | case FileSystem.ERROR_KIND_NOT_READABLE: 242 | return `File stream is not readable: ${strInfo}` 243 | case FileSystem.ERROR_KIND_NOT_ALLOWED: 244 | return "Writing outside of resources directory is not allowed" 245 | default: 246 | return "Unknown error" 247 | } 248 | } 249 | static parseInfo(aInfo){ 250 | return Object.entries(aInfo).map(a => `${a[0]}: ${a[1]}`).join("; ") 251 | } 252 | static fromKind(aKind,info){ 253 | return info instanceof ResultError 254 | ? info 255 | : new ResultError(aKind,{},info) 256 | } 257 | } 258 | 259 | class FileSystemResult{ 260 | #result; 261 | #type; 262 | #fileuri; 263 | constructor(data,resultType){ 264 | this.#result = data; 265 | this.#type = resultType; 266 | } 267 | 268 | get fileURI(){ 269 | if(this.isError()){ 270 | return null 271 | } 272 | if(!this.#fileuri){ 273 | this.#fileuri = FileSystemResult.#getFileURI(this) 274 | } 275 | return this.#fileuri 276 | } 277 | content(replaceNewlines){ 278 | if(this.isContent()){ 279 | return replaceNewlines 280 | ? this.#result.content.replace(/\r\n?/g, '\n') 281 | : this.#result.content 282 | } 283 | throw ResultError.fromKind(FileSystem.ERROR_KIND_NOT_CONTENT,{type:this.#type.description}) 284 | } 285 | get size(){ 286 | return this.isContent() 287 | ? this.#result.content.length 288 | : this.#result.fileSize 289 | } 290 | entry(){ 291 | if(this.isDirectory() || this.isFile()){ 292 | return this.#result 293 | } 294 | throw ResultError.fromKind(FileSystem.ERROR_KIND_NOT_EXIST,FileSystemResult.#generateErrorInfo(this)) 295 | } 296 | error(){ 297 | return this.isError() 298 | ? this.#result 299 | : null 300 | } 301 | readSync(){ 302 | if(!this.isFile()){ 303 | throw ResultError.fromKind(FileSystem.ERROR_KIND_NOT_FILE,FileSystemResult.#generateErrorInfo(this)) 304 | } 305 | return FileSystem.readNSIFileSyncUncheckedWithOptions(this.#result,{}).content() 306 | } 307 | read(){ 308 | if(!this.isFile()){ 309 | return Promise.reject(ResultError.fromKind(FileSystem.ERROR_KIND_NOT_FILE,FileSystemResult.#generateErrorInfo(this))) 310 | } 311 | return IOUtils.readUTF8(this.#result.path) 312 | } 313 | get type(){ 314 | return this.#type 315 | } 316 | isContent(){ 317 | return this.#type === FileSystem.RESULT_CONTENT 318 | } 319 | isFile(){ 320 | return this.#type === FileSystem.RESULT_FILE 321 | } 322 | isDirectory(){ 323 | return this.#type === FileSystem.RESULT_DIRECTORY 324 | } 325 | isError(){ 326 | return this.#type === FileSystem.RESULT_ERROR 327 | } 328 | [Symbol.iterator](){ 329 | try{ 330 | return this.entries() 331 | }catch(e){ 332 | console.warn(e) 333 | } 334 | return { next() { return { done: true } } } 335 | }; 336 | entries(){ 337 | if(!this.isDirectory()){ 338 | throw ResultError.fromKind(FileSystem.ERROR_KIND_NOT_DIRECTORY,FileSystemResult.#generateErrorInfo(this)) 339 | } 340 | let enumerator = this.#result.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator); 341 | return { 342 | next() { 343 | return enumerator.hasMoreElements() 344 | ? { 345 | value: enumerator.getNext().QueryInterface(Ci.nsIFile), 346 | done: false 347 | } 348 | : { done: true } 349 | }, 350 | [Symbol.iterator]() { 351 | return this; 352 | }, 353 | }; 354 | } 355 | showInFileManager(){ 356 | try{ 357 | if(this.isFile()){ 358 | this.#result.reveal(); 359 | return true 360 | } 361 | if(this.isDirectory()){ 362 | this.#result.launch(); 363 | return true 364 | } 365 | }catch(ex){ 366 | console.error("Could not open file manager for: " + this.#result.leafName); 367 | } 368 | return false 369 | } 370 | static #generateErrorInfo(aResult){ 371 | if(aResult.isError()){ 372 | return aResult.#result 373 | } 374 | return { 375 | topic: aResult.isContent() 376 | ? aResult.#result.path 377 | : aResult.#result.leafName 378 | } 379 | } 380 | static #getFileURI(aResult){ 381 | if(aResult.isContent()){ 382 | return aResult.#result.path 383 | } 384 | return FileSystem.getFileURIForFile(aResult.#result,aResult.#type) 385 | } 386 | static fromDirectory(dir){ 387 | return new FileSystemResult(dir, FileSystem.RESULT_DIRECTORY) 388 | } 389 | static fromContent(content){ 390 | return new FileSystemResult(content, FileSystem.RESULT_CONTENT) 391 | } 392 | static fromErrorKind(aKind,aErrorDescription){ 393 | return new FileSystemResult(ResultError.fromKind(aKind,aErrorDescription), FileSystem.RESULT_ERROR) 394 | } 395 | static fromFile(file){ 396 | return new FileSystemResult(file, FileSystem.RESULT_FILE) 397 | } 398 | static fromNsIFile(entry){ 399 | if(!entry.exists()){ 400 | return FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_NOT_EXIST,{topic: entry.leafName}) 401 | } 402 | if(entry.isDirectory()){ 403 | return FileSystemResult.fromDirectory(entry) 404 | }else if(entry.isFile()){ 405 | return FileSystemResult.fromFile(entry) 406 | } 407 | return FileSystemResult.fromErrorKind(FileSystem.ERROR_KIND_UNKNOWN_RESULT,{topic: entry.leafName}) 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /utils/uc_api.sys.mjs: -------------------------------------------------------------------------------- 1 | const { 2 | Hotkey, 3 | windowUtils, 4 | SharedGlobal, 5 | Pref, 6 | FileSystem, 7 | restartApplication, 8 | startupFinished, 9 | createElement, 10 | createWidget, 11 | escapeXUL, 12 | loadURI, 13 | loaderModuleLink, 14 | getScriptData, 15 | getStyleData, 16 | parseStringAsScriptInfo, 17 | toggleScript, 18 | updateStyleSheet, 19 | showNotification 20 | } = ChromeUtils.importESModule("chrome://userchromejs/content/utils.sys.mjs"); 21 | 22 | export { 23 | FileSystem, 24 | Hotkey as Hotkeys, 25 | Pref as Prefs, 26 | SharedGlobal as SharedStorage, 27 | windowUtils as Windows 28 | } 29 | 30 | export const Runtime = Object.freeze({ 31 | appVariant: loaderModuleLink.variant.THUNDERBIRD 32 | ? "Thunderbird" 33 | : "Firefox", 34 | brandName: loaderModuleLink.brandName, 35 | config: null, 36 | restart: restartApplication, 37 | startupFinished: startupFinished, 38 | loaderVersion: loaderModuleLink.version 39 | }); 40 | 41 | export const Utils = Object.freeze({ 42 | createElement: createElement, 43 | createWidget: createWidget, 44 | escapeXUL: escapeXUL, 45 | loadURI: loadURI 46 | }); 47 | 48 | export const Scripts = Object.freeze({ 49 | getScriptData: getScriptData, 50 | getStyleData: getStyleData, 51 | getScriptMenuForDocument(doc){ 52 | return doc.getElementById("userScriptsMenu") || loaderModuleLink.getScriptMenu(doc) 53 | }, 54 | openScriptDir(){ 55 | FileSystem.getScriptDir().showInFileManager() 56 | }, 57 | openStyleDir(){ 58 | FileSystem.getStyleDir().showInFileManager() 59 | }, 60 | parseStringAsScriptInfo: parseStringAsScriptInfo, 61 | toggleScript: toggleScript, 62 | reloadStyleSheet: updateStyleSheet 63 | }); 64 | 65 | export const Notifications = Object.freeze({ 66 | show(def){ 67 | showNotification(def) 68 | } 69 | }); --------------------------------------------------------------------------------