├── .github ├── ISSUE_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── changelog.md ├── credits.md ├── data ├── alwaysdisplayclose.css ├── chrome │ ├── icon │ │ ├── close.svg │ │ ├── connecting-low-res.png │ │ ├── connecting.png │ │ ├── default-favicon.svg │ │ ├── extension-generic.svg │ │ ├── newtab.svg │ │ ├── readme.md │ │ ├── settings.svg │ │ ├── tab-audio-blocked-white.svg │ │ ├── tab-audio-blocked.svg │ │ ├── tab-audio-muted-white.svg │ │ ├── tab-audio-muted.svg │ │ ├── tab-audio-playing-white.svg │ │ └── tab-audio-playing.svg │ └── tabbrowser.css ├── contextmenu.css ├── icon-128.png ├── icon-16.png ├── icon-32.png ├── icon-96.png ├── icon.png ├── icon │ ├── icon-16-white.png │ ├── icon-32-white.png │ └── icon-48-white.png ├── minifiedpinnedtabs.css ├── template │ └── basic │ │ ├── icons │ │ ├── dark │ │ │ ├── close-active.png │ │ │ ├── close-hover.png │ │ │ └── close-regular.png │ │ ├── light │ │ │ ├── close-active.png │ │ │ ├── close-hover.png │ │ │ └── close-regular.png │ │ ├── readme.md │ │ └── src │ │ │ ├── close-inverted.png │ │ │ ├── close-inverted@2x.png │ │ │ ├── close.png │ │ │ └── close@2x.png │ │ ├── index.css │ │ ├── tab.css │ │ └── tabbrowser.css └── theme │ ├── base.css │ ├── browser_style.css │ ├── dark │ ├── index.css │ └── modifications.css │ ├── darwin │ ├── closetab-white.svg │ ├── closetab.svg │ ├── dropmarker.png │ ├── index.css │ └── modifications.css │ ├── feather │ ├── index.css │ └── modifications.css │ ├── light │ ├── index.css │ └── modifications.css │ └── moonshot │ ├── index.css │ └── modifications.css ├── dev ├── README.md ├── icon │ ├── Icon.svg │ ├── icon_small.svg │ ├── window_500px.png │ └── window_500px_with_sidebar.png └── script │ ├── check_manifest_version_values.py │ ├── create_dev_release.py │ └── prepare_dev_release.py ├── eslint.config.mjs ├── index.js ├── lib ├── arrive.js └── fast-average-color-4.2.0.min.js ├── manifest.json ├── notes ├── assets │ ├── LICENSE-html5up-design.txt │ ├── README-html5up.txt │ ├── css │ │ ├── font-awesome.min.css │ │ ├── images │ │ │ └── overlay.png │ │ ├── main.css │ │ └── vtr.css │ ├── fonts │ │ └── fontawesome-webfont.woff2 │ └── js │ │ └── vtr.js ├── images │ └── banner.png └── index.html ├── options ├── options.css ├── options.html ├── options.js └── options.json ├── sidebar.js ├── utils ├── dom.js ├── log.js ├── namespace-sidebar.js ├── namespace.js ├── options.js ├── tabs.js ├── time.js └── windows.js └── vtr.html /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Add-on version: 4 | Firefox version: 5 | OS + OS-Version: 6 | Other tab + user interface related add-ons: 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | tests: 6 | runs-on: ubuntu-24.04 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | config: 11 | - { MANAGER: "npm", PACKAGE: "web-ext", FLAGS: "", RUN: "npx web-ext", RUNFLAGS: "lint" } 12 | - { MANAGER: "npm", PACKAGE: "eslint", FLAGS: "", RUN: "npx eslint", RUNFLAGS: "." } 13 | - { MANAGER: "pip", PACKAGE: "html5validator", FLAGS: "", RUN: "html5validator", RUNFLAGS: "--show-warnings --root ." } 14 | - { MANAGER: "pip", PACKAGE: "html5validator", FLAGS: "", RUN: "html5validator", RUNFLAGS: "--show-warnings --skip-non-css --root .", ALLOWFAILURE: "true" } 15 | - { MANAGER: "pip", PACKAGE: "html5validator", FLAGS: "", RUN: "html5validator", RUNFLAGS: "--show-warnings --skip-non-svg --root .", ALLOWFAILURE: "true" } 16 | name: ${{ matrix.config.RUN }} ${{ matrix.config.RUNFLAGS }} 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/setup-python@v5 20 | with: 21 | python-version: "3.12" 22 | - uses: actions/setup-node@v4 23 | with: 24 | node-version: "22.x" 25 | - name: Install ${{ matrix.config.PACKAGE }} 26 | run: | 27 | set -e 28 | ${{ matrix.config.MANAGER }} install ${{ matrix.config.PACKAGE }} ${{ matrix.config.FLAGS }} 29 | ${{ matrix.config.RUN }} --version 30 | ${{ matrix.config.RUN }} --help 31 | - name: Run tests 32 | run: | 33 | set -e 34 | if [[ -z "${{ matrix.config.ALLOWFAILURE }}" ]]; then ${{ matrix.config.RUN }} ${{ matrix.config.RUNFLAGS }} | tee test-output.log ; fi; 35 | if [[ -n "${{ matrix.config.ALLOWFAILURE }}" ]]; then ${{ matrix.config.RUN }} ${{ matrix.config.RUNFLAGS }} || true | tee test-output.log ; fi; 36 | - name: Display test results on CI summary 37 | run: | 38 | echo "## Test results for ${{ matrix.config.RUN }} ${{ matrix.config.RUNFLAGS }}" >> $GITHUB_STEP_SUMMARY 39 | cat test-output.log >> $GITHUB_STEP_SUMMARY 40 | echo "" >> $GITHUB_STEP_SUMMARY 41 | deploy: 42 | runs-on: ubuntu-24.04 43 | name: Deploy 44 | needs: tests 45 | steps: 46 | - uses: actions/checkout@v4 47 | with: 48 | fetch-depth: "50" 49 | - uses: actions/setup-python@v5 50 | with: 51 | python-version: "3.12" 52 | - uses: actions/setup-node@v4 53 | with: 54 | node-version: "22.x" 55 | - name: Install web-ext 56 | run: | 57 | set -e 58 | npm install web-ext 59 | npx web-ext --version 60 | - name: Deploy 61 | env: 62 | BOT_USERNAME: ${{ vars.BOT_USERNAME }} 63 | BOT_TOKEN: ${{ secrets.BOT_TOKEN }} 64 | BOT_NAME: ${{ vars.BOT_NAME }} 65 | BOT_EMAIL: ${{ vars.BOT_EMAIL }} 66 | AMO_API_USER: ${{ secrets.AMO_API_USER }} 67 | AMO_API_SECRET: ${{ secrets.AMO_API_SECRET }} 68 | run: | 69 | set -e 70 | if [[ ! "${{ github.ref }}" == "refs/tags"* ]] && [[ "$(git diff --name-only ${{ github.sha }}^ -- manifest.json)" == "" ]]; then echo "Neither tag nor dev release. Exiting ..."; exit 0; fi; 71 | python dev/script/check_manifest_version_values.py ; 72 | if [[ ! "${{ github.ref }}" == "refs/tags"* ]]; then 73 | python dev/script/prepare_dev_release.py ; 74 | npx web-ext sign --api-key=${AMO_API_USER} --api-secret=${AMO_API_SECRET} --channel unlisted --artifacts-dir "artifacts" ; 75 | git clone https://${BOT_USERNAME}:${BOT_TOKEN}@github.com/Croydon/vtr-releases.git vtr-releases ; 76 | mv -v artifacts/* vtr-releases/files/ ; 77 | python dev/script/create_dev_release.py ; 78 | cd vtr-releases ; 79 | git config --global user.name ${BOT_NAME} ; 80 | git config --global user.email ${BOT_EMAIL} ; 81 | git add -A ; 82 | git commit -am "Automatically publish new version" ; 83 | git push ; 84 | else 85 | npx web-ext sign --api-key=${AMO_API_USER} --api-secret=${AMO_API_SECRET} || true ; 86 | fi 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # VTR specific 2 | vtr-releases/* 3 | 4 | build 5 | node_modules 6 | package-lock.json 7 | package.json 8 | web-ext-artifacts 9 | *~ 10 | *.DS_Store 11 | 12 | # IDEs 13 | .idea/ 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # ![](https://github.com/Croydon/vertical-tabs-reloaded/raw/main/data/icon/icon-48-white.png) Contributing to Vertical Tabs Reloaded 2 | 3 | ## Platform Support 4 | 5 | * Firefox only 6 | * only respective latest version 7 | * latest version of [Firefox ESR](https://www.mozilla.org/en-US/firefox/organizations/faq/) is _somewhat_ supported 8 | * this means, compatibility is not getting broken on purpose, but it might be necessary sometimes 9 | * pull requests concerning the latest ESR version are welcome, but if keeping compatibility means introducing major nasty hacks, the chance of merging is low 10 | 11 | If you want to extend the platform support please start first a discussion by creating an issue (and as always search first for an existing one). 12 | 13 | 14 | ## Issues 15 | 16 | * search first for an existing issue addressing your concern 17 | * provide as much relevant information as you can 18 | 19 | 20 | ## Pull Requests 21 | 22 | * you agree to license your code and additional contributions under the terms of the [MPL v2.0](LICENSE.md) 23 | * if you want to make sure to have explicit credits within the project itself, then please add yourself to the [credits.md](credits.md) file within your pull request 24 | * pull requests are requests. There is no guarantee that they will be accepted. Therefore, it might be wise to first start a discussion via opening an issue before starting to implement your idea 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![](https://github.com/Croydon/vertical-tabs-reloaded/raw/main/data/icon/icon-48-white.png) Vertical Tabs Reloaded for Firefox 2 | 3 | 4 | [![](https://img.shields.io/amo/v/vertical-tabs-reloaded.svg?style=flat-square)](https://addons.mozilla.org/firefox/addon/vertical-tabs-reloaded/) [![](https://img.shields.io/amo/d/vertical-tabs-reloaded.svg)](https://addons.mozilla.org/firefox/addon/vertical-tabs-reloaded/statistics/?last=365) [![](https://img.shields.io/amo/users/vertical-tabs-reloaded.svg)](https://addons.mozilla.org/firefox/addon/vertical-tabs-reloaded/statistics/usage/?last=365) [![](https://img.shields.io/amo/rating/vertical-tabs-reloaded.svg)](https://addons.mozilla.org/firefox/addon/vertical-tabs-reloaded/) 5 | 6 | 7 | This Firefox add-on arranges tabs in a vertical rather than horizontal 8 | fashion. Vertical Tabs Reloaded is a fork of [Vertical Tabs](https://addons.mozilla.org/firefox/addon/vertical-tabs/), which was discontinued. The original project is heavily inspired by the Tree Style Tab add-on. 9 | 10 | * source code & issue tracker: https://github.com/Croydon/vertical-tabs-reloaded 11 | * source code repository mirror: https://gitlab.com/Cr0ydon/vertical-tabs-reloaded 12 | 13 | Installation: https://addons.mozilla.org/firefox/addon/vertical-tabs-reloaded/ 14 | 15 | If you like my work you could [buy me a drink. ☕](https://www.paypal.me/cr0ydon/4,99) 16 | 17 | 18 | ## Features 19 | 20 | * arranges tabs vertical 21 | * ships 4 different styles for the tab sidebar 22 | * hide/display manually the tab sidebar with a hotkey (default: Ctrl+Shift+V) or by clicking on the VTR icon 23 | * display the tab toolbar at top, bottom (default) or hide it completely 24 | * show the tab status (unloaded, unready, busy) visually on the tabs 25 | * sync settings across all devices 26 | 27 | 28 | ## Goals 29 | 30 | * Minimalist implementation. 31 | * Native look and feel and ability to customize if wanted. 32 | * Readable, maintainable and robust code. 33 | 34 | 35 | ## Platform Support 36 | 37 | Only the latest Firefox version is fully supported. Compatibility with the latest [ESR version](https://www.mozilla.org/en-US/firefox/organizations/faq/) will not get broken on purpose, but it might be necessary to do so sometimes. Pull requests fixing compatibility with the latest ESR version have a good chance to get accepted. Pull requests concerning other versions as the latest Firefox version or the latest Firefox ESR version will not be accepted. 38 | 39 | ### Firefox ESR 60 support 40 | 41 | Vertical Tabs Reloaded will actively support (i.e. feature updates) ESR 60 for at least 12 weeks (around Firefox 62) up to 18 weeks (around Firefox 63) and bug fixing only support for additional ~ 6 weeks. 42 | 43 | While full support for a year would be nice, it would mean freezing features for too long as the WebExtension API is still rather immature and actively developing. 44 | 45 | ### Firefox ESR 52 users 46 | 47 | Install the version v0.8.2 from here: https://addons.mozilla.org/de/firefox/addon/vertical-tabs-reloaded/versions/?page=1#version-0.8.2 48 | 49 | 50 | ## Building 51 | 52 | You need Node.js and npm installed on your system. Then install web-ext: 53 | > npm install -g web-ext 54 | 55 | After that you can build the add-on by executing in the project's root directory: 56 | > web-ext build 57 | 58 | 59 | ## Developer Version 60 | 61 | You can also install the pre-built [developer version here](https://croydon.github.io/vtr-releases/). By using it you can help me testing new versions before they are getting shipped to everyone. 62 | 63 | 64 | ## Contact 65 | 66 | If you want to have a chat with me you can join #vtr:matrix.org with every Matrix client, e.g. Element: https://app.element.io/#/room/#vtr:matrix.org 67 | 68 | 69 | ## License and Credits 70 | 71 | This project is licensed under the terms of the [Mozilla Public License Version 2.0](LICENSE.md). 72 | 73 | Credits can be found in the [credits.md](credits.md) file. 74 | -------------------------------------------------------------------------------- /credits.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | This project did already got a lot of contribution over time. In fact, this repository is a fork of a fork of a fork of the original project. In the following is a list of contributors, however, it's likely incomplete. Feel free to add your name here within your pull request. 4 | 5 | * [Philipp von Weitershausen](https://github.com/philikon) - Author of the original add-on 6 | * [Croydon](https://github.com/Croydon) - Maintainer of Vertical Tabs Reloaded 7 | * [Vlad Vukicevic](https://github.com/vvuk) - Maintained a fork of the original add-on for some time 8 | * [Darrin Henein](https://github.com/darrinhenein) - Maintained a fork of the original add-on for some time 9 | * [bb10](https://github.com/bb10) - Linux and Windows theme contributions 10 | * [breunigs](https://github.com/breunigs) - fullscreen hiding of the tab bar 11 | * Edward Lee 12 | * Erik Vold 13 | * Frank Yan - various theming fixes 14 | * [Keith94](https://github.com/Keith94) - Improvements of the themes 15 | * Rob Campbell - some UI love 16 | * [YUKI "Piro" Hiroshi](https://github.com/piroor) - Creator of Tree Style Tab, the original add-on used many code from this 17 | * [myBestSoftAndPref](https://github.com/myBestSoftAndPref) - Show tab status (#67) 18 | * [Andy McKay](https://github.com/andymckay/sidebar-tabs) - Experimental WebExtensions Vertical Tabs implementation as a references 19 | * [joanbm](https://github.com/joanbm) - Fixing visibility of audio play symbol (#97) 20 | * [unclechu](https://github.com/unclechu) - Redraw the VTR icons as actually svg files (#133) 21 | * [mmktomato](https://github.com/mmktomato) - Fix for the tab buttons position (#177), show border line when dragging tabs (#141, #199) 22 | 23 | In addition to that a big thank you to all people who provided feedback, suggestions, ideas or who are simply using the add-on. 24 | -------------------------------------------------------------------------------- /data/alwaysdisplayclose.css: -------------------------------------------------------------------------------- 1 | #tabbrowser-tabs .tab-close-button { 2 | display: inline-block !important; 3 | } 4 | -------------------------------------------------------------------------------- /data/chrome/icon/close.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/chrome/icon/connecting-low-res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/chrome/icon/connecting-low-res.png -------------------------------------------------------------------------------- /data/chrome/icon/connecting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/chrome/icon/connecting.png -------------------------------------------------------------------------------- /data/chrome/icon/default-favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /data/chrome/icon/extension-generic.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/chrome/icon/newtab.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/chrome/icon/readme.md: -------------------------------------------------------------------------------- 1 | chrome://browser/skin/tabbrowser/connnecting.png - FF56 2 | chrome://browser/skin/tabbrowser/connnecting@2px.png - FF56 3 | chrome://browser/skin/tabbrowser/newtab.svg 4 | chrome://browser/skin/tabbrowser/tab-audio-playing.svg - FF57 5 | chrome://browser/skin/tabbrowser/tab-audio-muted.svg - FF57 6 | chrome://browser/skin/tabbrowser/tab-audio-blocked.svg - FF57 7 | chrome://global/skin/icons/close.svg - FF57 8 | chrome://browser/skin/settings.svg - FF57 9 | chrome://mozapps/skin/extensions/extensionGeneric-16.svg - extension-generic.svg - FF57 10 | chrome://mozapps/skin/places/defaultFavicon.svg - default-favicon.svg - FF57 11 | -------------------------------------------------------------------------------- /data/chrome/icon/settings.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/chrome/icon/tab-audio-blocked-white.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/chrome/icon/tab-audio-blocked.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/chrome/icon/tab-audio-muted-white.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | c-3.4,0-6.2-2.8-6.2-6.2S4.6,1.8,8,1.8s6.2,2.8,6.2,6.2S11.4,14.2,8,14.2z"/> 7 | 8 | -------------------------------------------------------------------------------- /data/chrome/icon/tab-audio-muted.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | c-3.4,0-6.2-2.8-6.2-6.2S4.6,1.8,8,1.8s6.2,2.8,6.2,6.2S11.4,14.2,8,14.2z"/> 7 | -------------------------------------------------------------------------------- /data/chrome/icon/tab-audio-playing-white.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | c-3.4,0-6.2-2.8-6.2-6.2S4.6,1.8,8,1.8s6.2,2.8,6.2,6.2S11.4,14.2,8,14.2z"/> 7 | 8 | -------------------------------------------------------------------------------- /data/chrome/icon/tab-audio-playing.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | c-3.4,0-6.2-2.8-6.2-6.2S4.6,1.8,8,1.8s6.2,2.8,6.2,6.2S11.4,14.2,8,14.2z"/> 7 | -------------------------------------------------------------------------------- /data/chrome/tabbrowser.css: -------------------------------------------------------------------------------- 1 | /* chrome://browser/content/tabbrowser.css */ 2 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 | 7 | /* 8 | body { 9 | font: 3mm tahoma,arial,helvetica,sans-serif; 10 | } */ 11 | 12 | /* Apply crisp rendering for favicons at exactly 2dppx resolution 13 | @media (resolution: 2dppx) { 14 | .tab-icon-image { 15 | image-rendering: -moz-crisp-edges; 16 | } 17 | } */ 18 | 19 | /* 20 | .tab-sharing-icon-overlay[sharing]:not([selected]), 21 | .tab-icon-overlay[soundplaying][pinned], 22 | .tab-icon-overlay[muted][pinned], 23 | .tab-icon-overlay[blocked][pinned], 24 | .tab-icon-overlay[crashed] { 25 | display: -moz-box; 26 | } 27 | 28 | .tab-label-container { 29 | overflow: hidden; 30 | } 31 | 32 | .tab-label-container[pinned] { 33 | width: 0; 34 | } 35 | 36 | .tab-label-container[textoverflow]:not([pinned]) { 37 | mask-image: linear-gradient(to left, transparent, black 1em); 38 | } 39 | 40 | .tab-label-container[textoverflow]:not([pinned]):-moz-locale-dir(rtl) { 41 | mask-image: linear-gradient(to right, transparent, black 1em); 42 | } 43 | 44 | .tab-stack { 45 | vertical-align: top; for pinned tabs 46 | } 47 | 48 | tabpanels { 49 | background-color: transparent; 50 | } 51 | 52 | .tab-drop-indicator { 53 | position: relative; 54 | z-index: 2; 55 | } 56 | 57 | .closing-tabs-spacer { 58 | pointer-events: none; 59 | } 60 | 61 | .tabbrowser-tabs:not(:hover) > .tabbrowser-arrowscrollbox > .closing-tabs-spacer { 62 | transition: width .15s ease-out; 63 | }*/ 64 | -------------------------------------------------------------------------------- /data/contextmenu.css: -------------------------------------------------------------------------------- 1 | #contextmenu 2 | { 3 | display: none; 4 | position: fixed; 5 | border: 1px solid #B2B2B2; 6 | width: 170px; 7 | background: #F9F9F9; 8 | box-shadow: 0px 1px 1px #E9E9E9; 9 | border-radius: 4px; 10 | z-index: 2; 11 | } 12 | 13 | #contextmenu .contextmenu-items 14 | { 15 | list-style: none; 16 | margin: 0px; 17 | margin-top: 2px; 18 | padding-left: 5px; 19 | padding-right: 3px; 20 | padding-bottom: 2px; 21 | font-size: 13px; 22 | color: #333333; 23 | } 24 | 25 | #contextmenu hr 26 | { 27 | width: 90%; 28 | height: 3px; 29 | background-color: #A8A8A8; 30 | color: #A8A8A8; 31 | margin-bottom: -1px; 32 | margin-top: -1px; 33 | } 34 | 35 | #contextmenu .contextmenu-items li 36 | { 37 | padding: 2px; 38 | padding-left: 10px; 39 | border-bottom: 1px solid #B2B2B2; 40 | } 41 | 42 | #contextmenu .contextmenu-items li:last-child 43 | { 44 | border-bottom: none; 45 | } 46 | 47 | 48 | #contextmenu .contextmenu-items :hover 49 | { 50 | color: white; 51 | background: #284570; 52 | border-radius: 2px; 53 | } 54 | -------------------------------------------------------------------------------- /data/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon-128.png -------------------------------------------------------------------------------- /data/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon-16.png -------------------------------------------------------------------------------- /data/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon-32.png -------------------------------------------------------------------------------- /data/icon-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon-96.png -------------------------------------------------------------------------------- /data/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon.png -------------------------------------------------------------------------------- /data/icon/icon-16-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon/icon-16-white.png -------------------------------------------------------------------------------- /data/icon/icon-32-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon/icon-32-white.png -------------------------------------------------------------------------------- /data/icon/icon-48-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/icon/icon-48-white.png -------------------------------------------------------------------------------- /data/minifiedpinnedtabs.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Minified pinned tabs 3 | **/ 4 | .tabbrowser-tab[pinned] .tab-label { 5 | display: none; 6 | } 7 | 8 | #tabbrowser-tabs-pinned { 9 | display: flex; 10 | flex-wrap: wrap 11 | } 12 | 13 | :root { 14 | --vtr-tab-pinned-border-left-width: 2px !important; 15 | --vtr-tab-pinned-selected-border-left-width: 2px !important; 16 | --vtr-tab-pinned-hover-border-left-width: 2px !important; 17 | } 18 | -------------------------------------------------------------------------------- /data/template/basic/icons/dark/close-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/dark/close-active.png -------------------------------------------------------------------------------- /data/template/basic/icons/dark/close-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/dark/close-hover.png -------------------------------------------------------------------------------- /data/template/basic/icons/dark/close-regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/dark/close-regular.png -------------------------------------------------------------------------------- /data/template/basic/icons/light/close-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/light/close-active.png -------------------------------------------------------------------------------- /data/template/basic/icons/light/close-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/light/close-hover.png -------------------------------------------------------------------------------- /data/template/basic/icons/light/close-regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/light/close-regular.png -------------------------------------------------------------------------------- /data/template/basic/icons/readme.md: -------------------------------------------------------------------------------- 1 | close buttons - FF55 chrome://global/skin/icons/close.png, chrome://global/skin/icons/close@2x.png, chrome://global/skin/icons/close-inverted.png, chrome://global/skin/icons/close-inverted@2x.png 2 | -------------------------------------------------------------------------------- /data/template/basic/icons/src/close-inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/src/close-inverted.png -------------------------------------------------------------------------------- /data/template/basic/icons/src/close-inverted@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/src/close-inverted@2x.png -------------------------------------------------------------------------------- /data/template/basic/icons/src/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/src/close.png -------------------------------------------------------------------------------- /data/template/basic/icons/src/close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/template/basic/icons/src/close@2x.png -------------------------------------------------------------------------------- /data/template/basic/index.css: -------------------------------------------------------------------------------- 1 | @import "tab.css"; 2 | @import "tabbrowser.css"; 3 | 4 | 5 | /* Default template values */ 6 | 7 | :root { 8 | /* Tabbrowser */ 9 | --vtr-tabbrowser-background-color: #FBFBFB; 10 | --vtr-tabbrowser-separation-sidebar-border-color: transparent; 11 | --vtr-tabbrowser-separation-sidebar-border-style: solid; 12 | --vtr-tabbrowser-separation-sidebar-border-width: 0; 13 | 14 | /* Tab Toolbar */ 15 | --vtr-tabbar-height: 24px; 16 | --vtr-tabbar-background-color: #f1f1f1; 17 | --vtr-tabbar-filter: inherit; 18 | --vtr-tabbar-separation-border-color: rgb(160, 160, 160); 19 | --vtr-tabbar-tools-separation-border-color: lightgray; 20 | --vtr-tabbar-tools-separation-border-style: solid; 21 | --vtr-tabbar-tools-separation-border-width: 1px; 22 | --vtr-tabbar-pinned-separation-border-color: transparent; 23 | --vtr-tabbar-pinned-separation-border-style: none; 24 | --vtr-tabbar-pinned-separation-border-width: 0; 25 | 26 | /* Single tab */ 27 | --vtr-tab-text-color: #333333; 28 | --vtr-tab-background-color: #FBFBFB; 29 | --vtr-tab-background: #FBFBFB; 30 | --vtr-tab-font-size: 1em; 31 | --vtr-tab-font-weight: normal; 32 | --vtr-tab-text-shadow: none; 33 | --vtr-tab-height: 28px; 34 | --vtr-tab-min-height: 28px; 35 | --vtr-tab-max-height: 28px; 36 | --vtr-tab-border-radius: 0; 37 | --vtr-tab-border-top-width: 0; 38 | --vtr-tab-border-top-style: solid; 39 | --vtr-tab-border-top-color: transparent; 40 | --vtr-tab-border-right-width: 0; 41 | --vtr-tab-border-right-style: solid; 42 | --vtr-tab-border-right-color: transparent; 43 | --vtr-tab-border-bottom-width: 1px; 44 | --vtr-tab-border-bottom-style: solid; 45 | --vtr-tab-border-bottom-color: #bbc3cc; 46 | --vtr-tab-border-left-width: 4px; 47 | --vtr-tab-border-left-style: solid; 48 | --vtr-tab-border-left-color: transparent; 49 | --vtr-tab-margin-top: 0; 50 | --vtr-tab-margin-right: 0; 51 | --vtr-tab-margin-bottom: 0; 52 | --vtr-tab-margin-left: 0; 53 | --vtr-tab-padding-top: 1px; 54 | --vtr-tab-padding-right: 0; 55 | --vtr-tab-padding-bottom: 1px; 56 | --vtr-tab-padding-left: 0; 57 | 58 | /* Single tab selected */ 59 | --vtr-tab-selected-text-color: var(--vtr-tab-text-color); 60 | --vtr-tab-selected-background-color: #CBCBCB; 61 | --vtr-tab-selected-background: #CBCBCB; 62 | --vtr-tab-selected-font-weight: 600; 63 | --vtr-tab-selected-text-shadow: none; 64 | --vtr-tab-selected-border-radius: 0; 65 | --vtr-tab-selected-border-top-width: var(--vtr-tab-border-top-width); 66 | --vtr-tab-selected-border-top-style: var(--vtr-tab-border-top-style); 67 | --vtr-tab-selected-border-top-color: var(--vtr-tab-border-top-color); 68 | --vtr-tab-selected-border-right-width: var(--vtr-tab-border-right-width); 69 | --vtr-tab-selected-border-right-style: var(--vtr-tab-border-right-style); 70 | --vtr-tab-selected-border-right-color: var(--vtr-tab-border-right-color); 71 | --vtr-tab-selected-border-bottom-width: var(--vtr-tab-border-bottom-width); 72 | --vtr-tab-selected-border-bottom-style: var(--vtr-tab-border-bottom-style); 73 | --vtr-tab-selected-border-bottom-color: var(--vtr-tab-border-bottom-color); 74 | --vtr-tab-selected-border-left-width: 4px; 75 | --vtr-tab-selected-border-left-style: solid; 76 | --vtr-tab-selected-border-left-color: #ff9500; 77 | --vtr-tab-selected-margin-top: 0; 78 | --vtr-tab-selected-margin-right: 0; 79 | --vtr-tab-selected-margin-bottom: 0; 80 | --vtr-tab-selected-margin-left: 0; 81 | --vtr-tab-selected-padding-top: 1px; 82 | --vtr-tab-selected-padding-right: 0; 83 | --vtr-tab-selected-padding-bottom: 1px; 84 | --vtr-tab-selected-padding-left: 0; 85 | 86 | /* Single tab hover */ 87 | --vtr-tab-hover-background-color: #ebebeb; 88 | --vtr-tab-hover-background: #ebebeb; 89 | --vtr-tab-hover-margin-top: var(--vtr-tab-margin-top); 90 | --vtr-tab-hover-margin-right: var(--vtr-tab-margin-right); 91 | --vtr-tab-hover-margin-bottom: var(--vtr-tab-margin-bottom); 92 | --vtr-tab-hover-margin-left: var(--vtr-tab-margin-left); 93 | --vtr-tab-hover-padding-top: var(--vtr-tab-padding-top); 94 | --vtr-tab-hover-padding-right: var(--vtr-tab-padding-right); 95 | --vtr-tab-hover-padding-bottom: var(--vtr-tab-padding-bottom); 96 | --vtr-tab-hover-padding-left: var(--vtr-tab-padding-left); 97 | --vtr-tab-hover-border-top: 2px solid #FFFFFF; 98 | --vtr-tab-hover-border-bottom: 2px solid #FFFFFF; 99 | 100 | /* Single tab pinned */ 101 | --vtr-tab-pinned-text-color: var(--vtr-tab-text-color); 102 | --vtr-tab-pinned-background-color: #CBCBCB; 103 | --vtr-tab-pinned-background: #CBCBCB; 104 | --vtr-tab-pinned-font-weight: 600; 105 | --vtr-tab-pinned-text-shadow: none; 106 | --vtr-tab-pinned-border-radius: 0; 107 | --vtr-tab-pinned-border-top-width: var(--vtr-tab-border-top-width); 108 | --vtr-tab-pinned-border-top-style: var(--vtr-tab-border-top-style); 109 | --vtr-tab-pinned-border-top-color: var(--vtr-tab-border-top-color); 110 | --vtr-tab-pinned-border-right-width: var(--vtr-tab-border-right-width); 111 | --vtr-tab-pinned-border-right-style: var(--vtr-tab-border-right-style); 112 | --vtr-tab-pinned-border-right-color: var(--vtr-tab-border-right-color); 113 | --vtr-tab-pinned-border-bottom-width: var(--vtr-tab-border-bottom-width); 114 | --vtr-tab-pinned-border-bottom-style: var(--vtr-tab-border-bottom-style); 115 | --vtr-tab-pinned-border-bottom-color: var(--vtr-tab-border-bottom-color); 116 | --vtr-tab-pinned-border-left-width: 4px; 117 | --vtr-tab-pinned-border-left-style: solid; 118 | --vtr-tab-pinned-border-left-color: #2292D0; 119 | --vtr-tab-pinned-margin-top: 0; 120 | --vtr-tab-pinned-margin-right: 0; 121 | --vtr-tab-pinned-margin-bottom: 0; 122 | --vtr-tab-pinned-margin-left: 0; 123 | --vtr-tab-pinned-padding-top: 1px; 124 | --vtr-tab-pinned-padding-right: 0; 125 | --vtr-tab-pinned-padding-bottom: 1px; 126 | --vtr-tab-pinned-padding-left: 0; 127 | 128 | /* Single tab pinned selected */ 129 | --vtr-tab-pinned-selected-text-color: var(--vtr-tab-selected-text-color); 130 | --vtr-tab-pinned-selected-background-color: var(--vtr-tab-selected-background-color); 131 | --vtr-tab-pinned-selected-background: var(--vtr-tab-selected-background); 132 | --vtr-tab-pinned-selected-font-weight: var(--vtr-tab-selected-font-weight); 133 | --vtr-tab-pinned-selected-text-shadow: var(--vtr-tab-selected-text-shadow); 134 | --vtr-tab-pinned-selected-border-radius: var(--vtr-tab-selected-border-radius); 135 | --vtr-tab-pinned-selected-border-top-width: var(--vtr-tab-selected-border-top-width); 136 | --vtr-tab-pinned-selected-border-top-style: var(--vtr-tab-selected-border-top-style); 137 | --vtr-tab-pinned-selected-border-top-color: var(--vtr-tab-selected-border-top-color); 138 | --vtr-tab-pinned-selected-border-right-width: var(--vtr-tab-selected-border-right-width); 139 | --vtr-tab-pinned-selected-border-right-style: var(--vtr-tab-selected-border-right-style); 140 | --vtr-tab-pinned-selected-border-right-color: var(--vtr-tab-selected-border-right-color); 141 | --vtr-tab-pinned-selected-border-bottom-width: var(--vtr-tab-selected-border-bottom-width); 142 | --vtr-tab-pinned-selected-border-bottom-style: var(--vtr-tab-selected-border-bottom-style); 143 | --vtr-tab-pinned-selected-border-bottom-color: var(--vtr-tab-selected-border-bottom-color); 144 | --vtr-tab-pinned-selected-border-left-width: var(--vtr-tab-selected-border-left-width); 145 | --vtr-tab-pinned-selected-border-left-style: var(--vtr-tab-selected-border-left-style); 146 | --vtr-tab-pinned-selected-border-left-color: var(--vtr-tab-selected-border-left-color); 147 | --vtr-tab-pinned-selected-margin-top: var(--vtr-tab-selected-margin-top); 148 | --vtr-tab-pinned-selected-margin-right: var(--vtr-tab-selected-margin-right); 149 | --vtr-tab-pinned-selected-margin-bottom: var(--vtr-tab-selected-margin-bottom); 150 | --vtr-tab-pinned-selected-margin-left: var(--vtr-tab-selected-margin-left); 151 | --vtr-tab-pinned-selected-padding-top: var(--vtr-tab-selected-padding-top); 152 | --vtr-tab-pinned-selected-padding-right: var(--vtr-tab-selected-padding-right); 153 | --vtr-tab-pinned-selected-padding-bottom: var(--vtr-tab-selected-padding-bottom); 154 | --vtr-tab-pinned-selected-padding-left: var(--vtr-tab-selected-padding-left); 155 | 156 | /* Single tab pinned hover */ 157 | --vtr-tab-pinned-hover-background-color: var(--vtr-tab-hover-background-color); 158 | --vtr-tab-pinned-hover-background: var(--vtr-tab-hover-background); 159 | --vtr-tab-pinned-hover-margin-top: var(--vtr-tab-hover-margin-top); 160 | --vtr-tab-pinned-hover-margin-right: var(--vtr-tab-hover-margin-right); 161 | --vtr-tab-pinned-hover-margin-bottom: var(--vtr-tab-hover-margin-bottom); 162 | --vtr-tab-pinned-hover-margin-left: var(--vtr-tab-hover-margin-left); 163 | --vtr-tab-pinned-hover-padding-top: var(--vtr-tab-hover-padding-top); 164 | --vtr-tab-pinned-hover-padding-right: var(--vtr-tab-hover-padding-right); 165 | --vtr-tab-pinned-hover-padding-bottom: var(--vtr-tab-hover-padding-bottom); 166 | --vtr-tab-pinned-hover-padding-left: var(--vtr-tab-hover-padding-left); 167 | 168 | /* Favicon */ 169 | --vtr-tab-icon-invert-dark-icons: 0; 170 | 171 | /* Close buttons */ 172 | --vtr-tab-button-close-width: 20px; 173 | --vtr-tab-button-close-height: 20px; 174 | --vtr-tab-button-close-filter: inherit; 175 | --vtr-tab-button-close-regular-background-color: inherit; 176 | --vtr-tab-button-close-regular-background-image: url("../../template/basic/icons/light/close-regular.png"); 177 | --vtr-tab-button-close-hover-background-color: inherit; 178 | --vtr-tab-button-close-regular-border-radius: 0px; 179 | --vtr-tab-button-close-regular-border-color: transparent; 180 | --vtr-tab-button-close-regular-border-style: none; 181 | --vtr-tab-button-close-regular-border-width: 0px; 182 | --vtr-tab-button-close-hover-background-color: inherit; 183 | --vtr-tab-button-close-hover-border-radius: 0px; 184 | --vtr-tab-button-close-hover-border-color: transparent; 185 | --vtr-tab-button-close-hover-border-style: none; 186 | --vtr-tab-button-close-hover-border-width: 0px; 187 | --vtr-tab-button-close-hover-background-image: url("../../template/basic/icons/light/close-hover.png"); 188 | --vtr-tab-button-close-active-background-color: inherit; 189 | --vtr-tab-button-close-active-background-image: url("../../template/basic/icons/light/close-active.png"); 190 | --vtr-tab-button-close-active-border-radius: 0px; 191 | --vtr-tab-button-close-active-border-color: transparent; 192 | --vtr-tab-button-close-active-border-style: none; 193 | --vtr-tab-button-close-active-border-width: 0px; 194 | 195 | /* Sound buttons */ 196 | --vtr-tab-button-sound-width: 18px; 197 | --vtr-tab-button-sound-height: 18px; 198 | --vtr-tab-button-sound-filter: inherit; 199 | --vtr-tab-button-sound-playing-background-image: url("../../chrome/icon/tab-audio-playing.svg"); 200 | --vtr-tab-button-sound-muted-background-image: url("../../chrome/icon/tab-audio-muted.svg"); 201 | 202 | /* Tab status, default: color blind variant */ 203 | --vtr-tab-status-unread-text-decoration: underline; 204 | --vtr-tab-status-busy-text-decoration: underline; 205 | --vtr-tab-status-discarded-text-decoration: line-through; 206 | 207 | /* Splitter/Separation between tabbar and website 208 | --vtr-splitter-background: #ebebeb; 209 | --vtr-splitter-width: 3px; 210 | --vtr-splitter-border-left-size: 0; 211 | --vtr-splitter-border-left-color: #ebebeb; 212 | --vtr-splitter-border-right-size: 0; 213 | --vtr-splitter-border-right-color: #ebebeb; */ 214 | } 215 | -------------------------------------------------------------------------------- /data/template/basic/tab.css: -------------------------------------------------------------------------------- 1 | .tabbrowser-tab { 2 | appearance: none; 3 | background-color: var(--vtr-tab-background-color); 4 | background: var(--vtr-tab-background); 5 | font-size: var(--vtr-tab-font-size); 6 | font-weight: var(--vtr-tab-font-weight); 7 | text-shadow: var(--vtr-tab-text-shadow); 8 | margin: var(--vtr-tab-margin-top) var(--vtr-tab-margin-right) var(--vtr-tab-margin-bottom) var(--vtr-tab-margin-left); 9 | padding: var(--vtr-tab-padding-top) var(--vtr-tab-padding-right) var(--vtr-tab-padding-bottom) var(--vtr-tab-padding-left); 10 | height: var(--vtr-tab-height); 11 | min-height: var(--vtr-tab-min-height); 12 | max-height: var(--vtr-tab-max-height); 13 | color: var(--vtr-tab-text-color); 14 | border-radius: var(--vtr-tab-border-radius); 15 | border-top: var(--vtr-tab-border-top-width) var(--vtr-tab-border-top-style) var(--vtr-tab-border-top-color); 16 | border-right: var(--vtr-tab-border-right-width) var(--vtr-tab-border-right-style) var(--vtr-tab-border-right-color); 17 | border-bottom: var(--vtr-tab-border-bottom-width) var(--vtr-tab-border-bottom-style) var(--vtr-tab-border-bottom-color); 18 | border-left: var(--vtr-tab-border-left-width) var(--vtr-tab-border-left-style) var(--vtr-tab-border-left-color); 19 | } 20 | 21 | .tabbrowser-tab .tab-buttons 22 | { 23 | background-color: var(--vtr-tab-background-color); 24 | } 25 | 26 | /* 27 | * Pinned tabs 28 | */ 29 | .tabbrowser-tab[pinned] { 30 | margin: var(--vtr-tab-pinned-margin-top) var(--vtr-tab-pinned-margin-right) var(--vtr-tab-pinned-margin-bottom) var(--vtr-tab-pinned-margin-left); 31 | padding: var(--vtr-tab-pinned-padding-top) var(--vtr-tab-pinned-padding-right) var(--vtr-tab-pinned-padding-bottom) var(--vtr-tab-pinned-padding-left); 32 | color: var(--vtr-tab-pinned-text-color); 33 | background-color: var(--vtr-tab-pinned-background-color); 34 | background: var(--vtr-tab-pinned-background); 35 | font-weight: var(--vtr-tab-pinned-font-weight); 36 | text-shadow: var(--vtr-tab-pinned-text-shadow); 37 | border-radius: var(--vtr-tab-pinned-border-radius); 38 | border-top: var(--vtr-tab-pinned-border-top-width) var(--vtr-tab-pinned-border-top-style) var(--vtr-tab-pinned-border-top-color); 39 | border-right: var(--vtr-tab-pinned-border-right-width) var(--vtr-tab-pinned-border-right-style) var(--vtr-tab-pinned-border-right-color); 40 | border-bottom: var(--vtr-tab-pinned-border-bottom-width) var(--vtr-tab-pinned-border-bottom-style) var(--vtr-tab-pinned-border-bottom-color); 41 | border-left: var(--vtr-tab-pinned-border-left-width) var(--vtr-tab-pinned-border-left-style) var(--vtr-tab-pinned-border-left-color); 42 | } 43 | 44 | .tabbrowser-tab[pinned] .tab-buttons 45 | { 46 | background-color: var(--vtr-tab-pinned-background-color); 47 | } 48 | 49 | .tabbrowser-tab[pinned][selected="true"] { 50 | margin: var(--vtr-tab-pinned-selected-margin-top) var(--vtr-tab-pinned-selected-margin-right) var(--vtr-tab-pinned-selected-margin-bottom) var(--vtr-tab-pinned-selected-margin-left); 51 | padding: var(--vtr-tab-pinned-selected-padding-top) var(--vtr-tab-pinned-selected-padding-right) var(--vtr-tab-pinned-selected-padding-bottom) var(--vtr-tab-pinned-selected-padding-left); 52 | color: var(--vtr-tab-pinned-selected-text-color); 53 | background-color: var(--vtr-tab-pinned-selected-background-color); 54 | background: var(--vtr-tab-pinned-selected-background); 55 | font-weight: var(--vtr-tab-pinned-selected-font-weight); 56 | text-shadow: var(--vtr-tab-pinned-selected-text-shadow); 57 | border-radius: var(--vtr-tab-pinned-selected-border-radius); 58 | border-top: var(--vtr-tab-pinned-selected-border-top-width) var(--vtr-tab-pinned-selected-border-top-style) var(--vtr-tab-pinned-selected-border-top-color); 59 | border-right: var(--vtr-tab-pinned-selected-border-right-width) var(--vtr-tab-pinned-selected-border-right-style) var(--vtr-tab-pinned-selected-border-right-color); 60 | border-bottom: var(--vtr-tab-pinned-selected-border-bottom-width) var(--vtr-tab-pinned-selected-border-bottom-style) var(--vtr-tab-pinned-selected-border-bottom-color); 61 | border-left: var(--vtr-tab-pinned-selected-border-left-width) var(--vtr-tab-pinned-selected-border-left-style) var(--vtr-tab-pinned-selected-border-left-color); 62 | } 63 | 64 | .tabbrowser-tab[pinned][selected="true"] .tab-buttons 65 | { 66 | background-color: var(--vtr-tab-pinned-selected-background-color); 67 | } 68 | 69 | .tabbrowser-tab[pinned]:not([selected="true"]):hover { 70 | margin: var(--vtr-tab-pinned-hover-margin-top) var(--vtr-tab-pinned-hover-margin-right) var(--vtr-tab-pinned-hover-margin-bottom) var(--vtr-tab-pinned-hover-margin-left); 71 | padding: var(--vtr-tab-pinned-hover-padding-top) var(--vtr-tab-pinned-hover-padding-right) var(--vtr-tab-pinned-hover-padding-bottom) var(--vtr-tab-pinned-hover-padding-left); 72 | background-color: var(--vtr-tab-pinned-hover-background-color); 73 | background: var(--vtr-tab-pinned-hover-background); 74 | } 75 | 76 | .tabbrowser-tab[pinned]:not([selected="true"]):hover .tab-buttons 77 | { 78 | background-color: var(--vtr-tab-pinned-hover-background-color); 79 | } 80 | 81 | .tabbrowser-tab[pinned].hover-before 82 | { 83 | border-top: var(--vtr-tab-hover-border-top); 84 | } 85 | .tabbrowser-tab[pinned].hover-after 86 | { 87 | border-bottom: var(--vtr-tab-hover-border-bottom); 88 | } 89 | 90 | /* 91 | * Selected tabs 92 | */ 93 | .tabbrowser-tab[selected="true"] { 94 | margin: var(--vtr-tab-selected-margin-top) var(--vtr-tab-selected-margin-right) var(--vtr-tab-selected-margin-bottom) var(--vtr-tab-selected-margin-left); 95 | padding: var(--vtr-tab-selected-padding-top) var(--vtr-tab-selected-padding-right) var(--vtr-tab-selected-padding-bottom) var(--vtr-tab-selected-padding-left); 96 | color: var(--vtr-tab-selected-text-color); 97 | background-color: var(--vtr-tab-selected-background-color); 98 | background: var(--vtr-tab-selected-background); 99 | font-weight: var(--vtr-tab-selected-font-weight); 100 | text-shadow: var(--vtr-tab-selected-text-shadow); 101 | border-radius: var(--vtr-tab-selected-border-radius); 102 | border-top: var(--vtr-tab-selected-border-top-width) var(--vtr-tab-selected-border-top-style) var(--vtr-tab-selected-border-top-color); 103 | border-right: var(--vtr-tab-selected-border-right-width) var(--vtr-tab-selected-border-right-style) var(--vtr-tab-selected-border-right-color); 104 | border-bottom: var(--vtr-tab-selected-border-bottom-width) var(--vtr-tab-selected-border-bottom-style) var(--vtr-tab-selected-border-bottom-color); 105 | border-left: var(--vtr-tab-selected-border-left-width) var(--vtr-tab-selected-border-left-style) var(--vtr-tab-selected-border-left-color); 106 | } 107 | 108 | .tabbrowser-tab[selected="true"] .tab-buttons 109 | { 110 | background-color: var(--vtr-tab-selected-background-color); 111 | } 112 | 113 | /* FIXME: Redo, remove? */ 114 | /* .tabbrowser-tab[selected="true"]:-moz-window-inactive { 115 | background-color: InactiveCaption !important; 116 | color: InactiveCaptionText !important; */ 117 | /* gnome/gtk/cleartype doesn't seem to have inactive states for selected items, lets try this */ 118 | /* } */ 119 | 120 | /* 121 | * Hover tabs 122 | */ 123 | .tabbrowser-tab:not([selected="true"]):hover { 124 | margin: var(--vtr-tab-hover-margin-top) var(--vtr-tab-hover-margin-right) var(--vtr-tab-hover-margin-bottom) var(--vtr-tab-hover-margin-left); 125 | padding: var(--vtr-tab-hover-padding-top) var(--vtr-tab-hover-padding-right) var(--vtr-tab-hover-padding-bottom) var(--vtr-tab-hover-padding-left); 126 | background-color: var(--vtr-tab-hover-background-color); 127 | background: var(--vtr-tab-hover-background); 128 | } 129 | 130 | .tabbrowser-tab:not([selected="true"]):hover .tab-buttons 131 | { 132 | background-color: var(--vtr-tab-hover-background-color); 133 | } 134 | 135 | .tabbrowser-tab.hover-before 136 | { 137 | border-top: var(--vtr-tab-hover-border-top); 138 | } 139 | .tabbrowser-tab.hover-after 140 | { 141 | border-bottom: var(--vtr-tab-hover-border-bottom); 142 | } 143 | 144 | /* 145 | * Elementary stuff 146 | */ 147 | .tab-label { 148 | text-align: left; 149 | } 150 | 151 | .tab-label[pinned] { 152 | margin-left: 6px; 153 | position: relative; 154 | } 155 | 156 | .tab-content { 157 | -moz-margin-start: 0px; 158 | margin-top: 1px; 159 | } 160 | 161 | /* .tab-close-button { 162 | border-right: 10px solid var(--vtr-tab-selected-background-color); 163 | } */ 164 | 165 | /* FIXME: tab-icon-image likely to be removed from this section */ 166 | .tab-icon, 167 | .tab-icon-image { 168 | padding: 3px; 169 | background-color: transparent; /* VT Original: f2f2f2 for Dark Theme */ 170 | border-radius: 2px; 171 | /*min-height: 22px !important; 172 | min-width: 22px !important; 173 | max-height: 22px; 174 | max-width: 22px;*/ 175 | opacity: 1; 176 | } 177 | 178 | .tab-icon-image-dark { 179 | filter: invert(var(--vtr-tab-icon-invert-dark-icons)); 180 | } 181 | 182 | .tabbrowser-tab:not(:hover):not([selected="true"]) .tab-close-button { 183 | display: none; 184 | } 185 | 186 | /* Keep the close button at a safe distance from the tab label. */ 187 | .tab-close-button { 188 | /* right: 4px; 189 | margin-left: 3px !important; 190 | margin-right: 1px !important; 191 | background-color: red;*/ 192 | background-position: center center; 193 | width: var(--vtr-tab-button-close-width); 194 | height: var(--vtr-tab-button-close-height); 195 | background-size: var(--vtr-tab-button-close-width) var(--vtr-tab-button-close-height); 196 | filter: var(--vtr-tab-button-close-filter); 197 | } 198 | 199 | 200 | .tabbrowser-tab:not([pinned]) .tab-close-button { 201 | background-color: var(--vtr-tab-button-close-regular-background-color); 202 | background-image: var(--vtr-tab-button-close-regular-background-image); 203 | border-radius: var(--vtr-tab-button-close-regular-border-radius); 204 | border-color: var(--vtr-tab-button-close-regular-border-color); 205 | border-style: var(--vtr-tab-button-close-regular-border-style); 206 | border-width: var(--vtr-tab-button-close-regular-border-width); 207 | } 208 | 209 | .tabbrowser-tab:not([pinned]) .tab-close-button:hover { 210 | background-color: var(--vtr-tab-button-close-hover-background-color); 211 | background-image: var(--vtr-tab-button-close-hover-background-image); 212 | border-radius: var(--vtr-tab-button-close-hover-border-radius); 213 | border-color: var(--vtr-tab-button-close-hover-border-color); 214 | border-style: var(--vtr-tab-button-close-hover-border-style); 215 | border-width: var(--vtr-tab-button-close-hover-border-width); 216 | } 217 | 218 | .tabbrowser-tab:not([pinned]) .tab-close-button:active { 219 | background-color: var(--vtr-tab-button-close-active-background-color); 220 | background-image: var(--vtr-tab-button-close-active-background-image); 221 | border-radius: var(--vtr-tab-button-close-active-border-radius); 222 | border-color: var(--vtr-tab-button-close-active-border-color); 223 | border-style: var(--vtr-tab-button-close-active-border-style); 224 | border-width: var(--vtr-tab-button-close-active-border-width); 225 | } 226 | 227 | /* 228 | .tab-icon-sound[soundplaying] { 229 | background-image: var(--vtr-tab-button-sound-playing-background-image); 230 | -moz-context-properties: fill; 231 | fill: var(--vtr-tab-button-sound-playing-fill); 232 | } 233 | 234 | .tab-icon-sound[muted] { 235 | background-image: var(--vtr-tab-button-sound-muted-background-image); 236 | -moz-context-properties: fill; 237 | fill: var(--vtr-tab-button-sound-muted-fill); 238 | } */ 239 | 240 | .tab-sound-button 241 | { 242 | background-size: var(--vtr-tab-button-sound-width) var(--vtr-tab-button-sound-height); 243 | background-position: center center; 244 | filter: var(--vtr-tab-button-sound-filter); 245 | } 246 | 247 | .tab-sound-button-playing { 248 | background-image: var(--vtr-tab-button-sound-playing-background-image); 249 | } 250 | 251 | .tab-sound-button-muted { 252 | background-image: var(--vtr-tab-button-sound-muted-background-image); 253 | } 254 | 255 | 256 | /* 257 | * Tab Status 258 | */ 259 | 260 | 261 | /* unread */ 262 | body[data-style-tab-status="true"] .tabbrowser-tab[unread="true"]:not([data-discarded="true"]) .tab-label 263 | { 264 | text-decoration: var(--vtr-tab-status-unread-text-decoration); 265 | } 266 | 267 | /* busy */ 268 | body[data-style-tab-status="true"] .tabbrowser-tab[status="loading"] .tab-label 269 | { 270 | text-decoration: var(--vtr-tab-status-busy-text-decoration) !important; 271 | } 272 | 273 | /* unloaded */ 274 | body[data-style-tab-status="true"] .tabbrowser-tab[data-discarded="true"] .tab-label 275 | { 276 | text-decoration: var(--vtr-tab-status-discarded-text-decoration) !important; 277 | } 278 | -------------------------------------------------------------------------------- /data/template/basic/tabbrowser.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | background: transparent; 5 | background-color: var(--vtr-tabbrowser-background-color); 6 | border-right-color: var(--vtr-tabbrowser-separation-sidebar-border-color); 7 | border-right-style: var(--vtr-tabbrowser-separation-sidebar-border-style); 8 | border-right-width: var(--vtr-tabbrowser-separation-sidebar-border-width); 9 | border-left-color: var(--vtr-tabbrowser-separation-sidebar-border-color); 10 | border-left-style: var(--vtr-tabbrowser-separation-sidebar-border-style); 11 | border-left-width: var(--vtr-tabbrowser-separation-sidebar-border-width); 12 | } 13 | 14 | /* Tab toolbar styling */ 15 | #TabsToolbar { 16 | flex: 0 1 var(--vtr-tabbar-height); 17 | height: var(--vtr-tabbar-height); 18 | border-bottom-left-radius: 0px; 19 | box-shadow: none; 20 | appearance: none; 21 | background-color: var(--vtr-tabbar-background-color); 22 | background-image: none; 23 | } 24 | 25 | #TabsToolbar img { 26 | filter: var(--vtr-tabbar-filter); 27 | } 28 | 29 | #TabsToolbar span:not(:last-child) { 30 | border-right-color: var(--vtr-tabbar-tools-separation-border-color); 31 | border-right-style: var(--vtr-tabbar-tools-separation-border-style); 32 | border-right-width: var(--vtr-tabbar-tools-separation-border-width); 33 | } 34 | 35 | #TabsToolbar[data-position="bottom"] 36 | { 37 | border-top: 1px solid var(--vtr-tabbar-separation-border-color); 38 | } 39 | 40 | #TabsToolbar[data-position="top"] 41 | { 42 | border-bottom: 1px solid var(--vtr-tabbar-separation-border-color); 43 | } 44 | 45 | #tabbrowser-tabs-pinned { 46 | border-bottom-color: var(--vtr-tabbar-pinned-separation-border-color); 47 | border-bottom-style: var(--vtr-tabbar-pinned-separation-border-style); 48 | border-bottom-width: var(--vtr-tabbar-pinned-separation-border-width); 49 | } 50 | -------------------------------------------------------------------------------- /data/theme/base.css: -------------------------------------------------------------------------------- 1 | body 2 | { 3 | /* font-family: message-box from the legacy VTR add-on, rest default in Firefox */ 4 | font-family: sans-serif,serif,helvetica; 5 | height: 100vh; 6 | display: flex; 7 | flex-flow: column; 8 | /*overflow-y: hidden;*/ 9 | user-select: none; 10 | } 11 | 12 | #tabbrowser-tabs { 13 | flex: 1 1 auto; 14 | overflow-y: auto; 15 | /* margin-right: 2px; */ 16 | } 17 | 18 | #tabbrowser-tabs-pinned { 19 | flex: 0 1 auto; 20 | } 21 | 22 | #TabsToolbar { 23 | flex: 0 1 24px; 24 | display: flex; 25 | align-items: center; 26 | margin-top: 1px; 27 | } 28 | 29 | #TabsToolbar span:first-child { 30 | margin-left: 2px; 31 | } 32 | 33 | #TabsToolbar span { 34 | padding-left: 6px; 35 | padding-right: 6px; 36 | } 37 | 38 | #TabsToolbar span:hover { 39 | background-color: hsla(240,5%,5%,.1); 40 | } 41 | 42 | .tab-buttons { 43 | white-space: nowrap; 44 | display: flex; 45 | align-items: center; 46 | } 47 | 48 | .tab-close-button { 49 | height: 20px; 50 | width: 24px; 51 | display: inline-block; 52 | background-image: url("../../data/template/basic/icons/light/close-regular.png"); 53 | background-size: 20px 20px; /* contain ? */ 54 | background-position: center center; 55 | background-repeat: no-repeat; 56 | } 57 | 58 | .tab-sound-button { 59 | display: inline-block; 60 | background-size: 20px 20px; 61 | background-position: center center; 62 | background-repeat: no-repeat; 63 | /* mask-repeat: no-repeat; 64 | mask-position: center center; */ 65 | } 66 | 67 | .tab-sound-button-playing { 68 | height: 18px; 69 | width: 24px; 70 | /* background-color: currentColor; */ 71 | background-image: url("../../data/chrome/icon/tab-audio-playing.svg"); 72 | } 73 | 74 | .tab-sound-button-muted { 75 | height: 18px; 76 | width: 24px; 77 | /* background-color: inherit; */ 78 | background-image: url("../../data/chrome/icon/tab-audio-muted.svg"); 79 | } 80 | 81 | .tab-icon-sound { 82 | filter: drop-shadow(1px 1px 1px currentColor); 83 | } 84 | 85 | /* Ensure the tab favicon doesn't stretch. */ 86 | .tab-icon-image { 87 | max-width: 20px; 88 | max-height: 22px; 89 | } 90 | 91 | /* Placeholder: .tab-icon-image-light .tab-icon-image-dark */ 92 | 93 | /* FIXME: This works natively in FF but not here? 94 | .tab-icon-image[src*="data/chrome/icon/"] { 95 | -moz-context-properties: fill !important; 96 | fill: currentColor !important; 97 | }*/ 98 | 99 | 100 | /* Don't show close buttons for pinned tabs */ 101 | .tabbrowser-tab[pinned] .tab-close-button, 102 | .tabbrowser-tab[pinned] .tab-close-button:hover, 103 | .tabbrowser-tab[pinned] .tab-close-button:active { 104 | display: none; 105 | } 106 | 107 | .tabbrowser-tab { 108 | min-height: 20px; 109 | height: 20px; 110 | max-height: 40px; 111 | border-bottom: 1px solid #5E6972; 112 | 113 | display: grid; 114 | grid-gap: 4px; 115 | /* margin: 0.5rem; */ 116 | align-items: center; 117 | } 118 | 119 | .tab-label { 120 | white-space: nowrap; 121 | vertical-align: middle; 122 | text-overflow: clip; 123 | overflow: hidden; 124 | } 125 | 126 | body[data-tab-buttons-position="left"] .tabbrowser-tab { grid-template-columns: min-content 22px auto; } 127 | body[data-tab-buttons-position="left"] .tabbrowser-tab .tab-buttons { order: 1; padding-left: 3px; } 128 | body[data-tab-buttons-position="left"] .tabbrowser-tab .tab-icon { order: 2; } 129 | body[data-tab-buttons-position="left"] .tabbrowser-tab .tab-label { order: 3; } 130 | body[data-tab-buttons-position="left"] .tabbrowser-tab .tab-buttons .tab-close-button { order: -1; } 131 | 132 | body[data-tab-buttons-position="right"] .tabbrowser-tab { grid-template-columns: 22px auto min-content; } 133 | body[data-tab-buttons-position="right"] .tabbrowser-tab .tab-icon { order: 1; } 134 | body[data-tab-buttons-position="right"] .tabbrowser-tab .tab-label { order: 2; } 135 | body[data-tab-buttons-position="right"] .tabbrowser-tab .tab-buttons { order: 3; padding-right: 3px; } 136 | body[data-tab-buttons-position="right"] .tabbrowser-tab .tab-buttons .tab-close-button { order: 999; } 137 | 138 | .tabbrowser-tab:not(:hover):not([selected="true"]) .tab-close-button { display: none; } 139 | 140 | /* FIXME: useful? */ 141 | /* Taken from Firefox's original tabbrowser css */ 142 | /* Apply crisp rendering for favicons at exactly 2dppx resolution */ 143 | @media (resolution: 2dppx) { 144 | .tab-icon-image { 145 | image-rendering: crisp-edges; 146 | image-rendering: -moz-crisp-edges; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /data/theme/browser_style.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | background: transparent; 4 | box-sizing: border-box; 5 | color: #222426; 6 | cursor: default; 7 | display: flex; 8 | flex-direction: column; 9 | font: caption; 10 | margin: 0; 11 | padding: 0; 12 | user-select: none; 13 | } 14 | 15 | body * { 16 | box-sizing: border-box; 17 | text-align: start; 18 | } 19 | -------------------------------------------------------------------------------- /data/theme/dark/index.css: -------------------------------------------------------------------------------- 1 | @import "../../template/basic/index.css"; 2 | @import "modifications.css"; 3 | 4 | :root { 5 | /* Tabbrowser */ 6 | --vtr-tabbrowser-background-color: #424F5A; 7 | 8 | /* Tab Toolbar */ 9 | --vtr-tabbar-height: 24px; 10 | --vtr-tabbar-background-color: #27323B; 11 | --vtr-tabbar-filter: invert(77%) sepia(6%) saturate(55%) hue-rotate(131deg) brightness(97%) contrast(81%); 12 | 13 | /* Single tab */ 14 | --vtr-tab-text-color: #fbfbfb; 15 | --vtr-tab-background-color: #424F5A; 16 | --vtr-tab-background: #424F5A; 17 | --vtr-tab-font-size: 1em; 18 | --vtr-tab-font-weight: normal; 19 | --vtr-tab-text-shadow: none; 20 | --vtr-tab-height: 28px; 21 | --vtr-tab-min-height: 28px; 22 | --vtr-tab-max-height: 28px; 23 | --vtr-tab-border-radius: 0; 24 | --vtr-tab-border-top-width: 0; 25 | --vtr-tab-border-top-style: solid; 26 | --vtr-tab-border-top-color: transparent; 27 | --vtr-tab-border-right-width: 0; 28 | --vtr-tab-border-right-style: solid; 29 | --vtr-tab-border-right-color: transparent; 30 | --vtr-tab-border-bottom-width: 2px; 31 | --vtr-tab-border-bottom-style: solid; 32 | --vtr-tab-border-bottom-color: #5E6972; 33 | --vtr-tab-border-left-width: 4px; 34 | --vtr-tab-border-left-style: solid; 35 | --vtr-tab-border-left-color: transparent; 36 | --vtr-tab-margin-top: 0; 37 | --vtr-tab-margin-right: 0; 38 | --vtr-tab-margin-bottom: 0; 39 | --vtr-tab-margin-left: 0; 40 | --vtr-tab-padding-top: 1px; 41 | --vtr-tab-padding-right: 0; 42 | --vtr-tab-padding-bottom: 1px; 43 | --vtr-tab-padding-left: 0; 44 | 45 | /* Single tab selected */ 46 | --vtr-tab-selected-text-color: #fbfbfb; 47 | --vtr-tab-selected-background-color: #27323B; 48 | --vtr-tab-selected-background: #27323B; 49 | --vtr-tab-selected-font-weight: 600; 50 | --vtr-tab-selected-text-shadow: none; 51 | --vtr-tab-selected-border-radius: 0; 52 | --vtr-tab-selected-border-top-width: var(--vtr-tab-border-top-width); 53 | --vtr-tab-selected-border-top-style: var(--vtr-tab-border-top-style); 54 | --vtr-tab-selected-border-top-color: var(--vtr-tab-border-top-color); 55 | --vtr-tab-selected-border-right-width: var(--vtr-tab-border-right-width); 56 | --vtr-tab-selected-border-right-style: var(--vtr-tab-border-right-style); 57 | --vtr-tab-selected-border-right-color: var(--vtr-tab-border-right-color); 58 | --vtr-tab-selected-border-bottom-width: var(--vtr-tab-border-bottom-width); 59 | --vtr-tab-selected-border-bottom-style: var(--vtr-tab-border-bottom-style); 60 | --vtr-tab-selected-border-bottom-color: var(--vtr-tab-border-bottom-color); 61 | --vtr-tab-selected-border-left-width: 4px; 62 | --vtr-tab-selected-border-left-style: solid; 63 | --vtr-tab-selected-border-left-color: #ff9500; 64 | --vtr-tab-selected-margin-top: 0; 65 | --vtr-tab-selected-margin-right: 0; 66 | --vtr-tab-selected-margin-bottom: 0; 67 | --vtr-tab-selected-margin-left: 0; 68 | --vtr-tab-selected-padding-top: 1px; 69 | --vtr-tab-selected-padding-right: 0; 70 | --vtr-tab-selected-padding-bottom: 1px; 71 | --vtr-tab-selected-padding-left: 0; 72 | 73 | /* Single tab pinned */ 74 | --vtr-tab-pinned-text-color: #fbfbfb; 75 | --vtr-tab-pinned-background-color: #27323B; 76 | --vtr-tab-pinned-background: #27323B; 77 | --vtr-tab-pinned-font-weight: inherit; 78 | --vtr-tab-pinned-text-shadow: none; 79 | --vtr-tab-pinned-border-radius: 0; 80 | --vtr-tab-pinned-border-top-width: var(--vtr-tab-border-top-width); 81 | --vtr-tab-pinned-border-top-style: var(--vtr-tab-border-top-style); 82 | --vtr-tab-pinned-border-top-color: var(--vtr-tab-border-top-color); 83 | --vtr-tab-pinned-border-right-width: var(--vtr-tab-border-right-width); 84 | --vtr-tab-pinned-border-right-style: var(--vtr-tab-border-right-style); 85 | --vtr-tab-pinned-border-right-color: var(--vtr-tab-border-right-color); 86 | --vtr-tab-pinned-border-bottom-width: var(--vtr-tab-border-bottom-width); 87 | --vtr-tab-pinned-border-bottom-style: var(--vtr-tab-border-bottom-style); 88 | --vtr-tab-pinned-border-bottom-color: var(--vtr-tab-border-bottom-color); 89 | --vtr-tab-pinned-border-left-width: 4px; 90 | --vtr-tab-pinned-border-left-style: solid; 91 | --vtr-tab-pinned-border-left-color: #2292D0; 92 | --vtr-tab-pinned-margin-top: 0; 93 | --vtr-tab-pinned-margin-right: 0; 94 | --vtr-tab-pinned-margin-bottom: 0; 95 | --vtr-tab-pinned-margin-left: 0; 96 | --vtr-tab-pinned-padding-top: 1px; 97 | --vtr-tab-pinned-padding-right: 0; 98 | --vtr-tab-pinned-padding-bottom: 1px; 99 | --vtr-tab-pinned-padding-left: 0; 100 | 101 | /* Single tab hover */ 102 | --vtr-tab-hover-background-color: #5E6972; 103 | --vtr-tab-hover-background: #5E6972; 104 | --vtr-tab-hover-margin-top: var(--vtr-tab-margin-top); 105 | --vtr-tab-hover-margin-right: var(--vtr-tab-margin-right); 106 | --vtr-tab-hover-margin-bottom: var(--vtr-tab-margin-bottom); 107 | --vtr-tab-hover-margin-left: var(--vtr-tab-margin-left); 108 | --vtr-tab-hover-padding-top: var(--vtr-tab-padding-top); 109 | --vtr-tab-hover-padding-right: var(--vtr-tab-padding-right); 110 | --vtr-tab-hover-padding-bottom: var(--vtr-tab-padding-bottom); 111 | --vtr-tab-hover-padding-left: var(--vtr-tab-padding-left); 112 | --vtr-tab-hover-border-top: 2px solid #FFFFFF; 113 | --vtr-tab-hover-border-bottom: 2px solid #FFFFFF; 114 | 115 | /* Favicon */ 116 | --vtr-tab-icon-invert-dark-icons: 1; 117 | 118 | /* Close button */ 119 | --vtr-tab-button-close-width: 18px; 120 | --vtr-tab-button-close-height: 18px; 121 | --vtr-tab-button-close-regular-background-image: url("../../template/basic/icons/dark/close-regular.png"); 122 | --vtr-tab-button-close-hover-background-image: url("../../template/basic/icons/dark/close-hover.png"); 123 | --vtr-tab-button-close-active-background-image: url("../../template/basic/icons/dark/close-active.png"); 124 | 125 | /* Sound buttons */ 126 | --vtr-tab-button-sound-width: 18px; 127 | --vtr-tab-button-sound-height: 18px; 128 | --vtr-tab-button-sound-playing-background-image: url("../../chrome/icon/tab-audio-playing-white.svg"); 129 | --vtr-tab-button-sound-muted-background-image: url("../../chrome/icon/tab-audio-muted-white.svg"); 130 | 131 | /* Tab status, default: color blind variant */ 132 | --vtr-tab-status-unread-text-decoration: underline; 133 | --vtr-tab-status-busy-text-decoration: underline; 134 | --vtr-tab-status-discarded-text-decoration: line-through; 135 | 136 | /* Splitter/Separation between tabbar and website 137 | --vtr-splitter-background: #27323B; 138 | --vtr-splitter-width: 3px; 139 | --vtr-splitter-border-left-size: 0; 140 | --vtr-splitter-border-left-color: #27323B; 141 | --vtr-splitter-border-right-size: 0; 142 | --vtr-splitter-border-right-color: #27323B; */ 143 | } 144 | -------------------------------------------------------------------------------- /data/theme/dark/modifications.css: -------------------------------------------------------------------------------- 1 | /* No modifications so far */ 2 | -------------------------------------------------------------------------------- /data/theme/darwin/closetab-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /data/theme/darwin/closetab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /data/theme/darwin/dropmarker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/data/theme/darwin/dropmarker.png -------------------------------------------------------------------------------- /data/theme/darwin/index.css: -------------------------------------------------------------------------------- 1 | @import "../../template/basic/index.css"; 2 | @import "modifications.css"; 3 | 4 | :root { 5 | /* Tabbrowser */ 6 | --vtr-tabbrowser-background-color: #333; 7 | 8 | /* Tab Toolbar */ 9 | --vtr-tabbar-height: 24px; 10 | --vtr-tabbar-background-color: #333; 11 | --vtr-tabbar-filter: invert(98%) sepia(0%) saturate(6559%) hue-rotate(176deg) brightness(123%) contrast(47%); 12 | 13 | /* Single tab */ 14 | --vtr-tab-text-color: #BBB; 15 | --vtr-tab-background-color: #333; 16 | --vtr-tab-background: #333; 17 | --vtr-tab-font-size: 12px; 18 | --vtr-tab-font-weight: normal; 19 | --vtr-tab-text-shadow: none; 20 | --vtr-tab-height: 31px; 21 | --vtr-tab-min-height: 31px; 22 | --vtr-tab-max-height: 31px; 23 | --vtr-tab-border-radius: 0; 24 | --vtr-tab-border-top-width: 1px; 25 | --vtr-tab-border-top-style: solid; 26 | --vtr-tab-border-top-color: rgba(255, 255, 255,0.05); 27 | --vtr-tab-border-right-width: 0; 28 | --vtr-tab-border-right-style: solid; 29 | --vtr-tab-border-right-color: transparent; 30 | --vtr-tab-border-bottom-width: 1px; 31 | --vtr-tab-border-bottom-style: solid; 32 | --vtr-tab-border-bottom-color: rgba(0,0,0,0.15); 33 | --vtr-tab-border-left-width: 2px; 34 | --vtr-tab-border-left-style: solid; 35 | --vtr-tab-border-left-color: transparent; 36 | --vtr-tab-margin-top: 0; 37 | --vtr-tab-margin-right: 3px; 38 | --vtr-tab-margin-bottom: 0; 39 | --vtr-tab-margin-left: 0; 40 | --vtr-tab-padding-top: 0; 41 | --vtr-tab-padding-right: 0; 42 | --vtr-tab-padding-bottom: 0; 43 | --vtr-tab-padding-left: 0; 44 | 45 | /* Single tab selected */ 46 | --vtr-tab-selected-text-color: #DDD; 47 | --vtr-tab-selected-background-color: #222; 48 | --vtr-tab-selected-background: #222; 49 | --vtr-tab-selected-font-weight: bold; 50 | --vtr-tab-selected-text-shadow: 0 1px #404040; 51 | --vtr-tab-selected-border-radius: 0; 52 | --vtr-tab-selected-border-top-width: var(--vtr-tab-border-top-width); 53 | --vtr-tab-selected-border-top-style: var(--vtr-tab-border-top-style); 54 | --vtr-tab-selected-border-top-color: var(--vtr-tab-border-top-color); 55 | --vtr-tab-selected-border-right-width: var(--vtr-tab-border-right-width); 56 | --vtr-tab-selected-border-right-style: var(--vtr-tab-border-right-style); 57 | --vtr-tab-selected-border-right-color: var(--vtr-tab-border-right-color); 58 | --vtr-tab-selected-border-bottom-width: var(--vtr-tab-border-bottom-width); 59 | --vtr-tab-selected-border-bottom-style: var(--vtr-tab-border-bottom-style); 60 | --vtr-tab-selected-border-bottom-color: var(--vtr-tab-border-bottom-color); 61 | --vtr-tab-selected-border-left-width: 3px; 62 | --vtr-tab-selected-border-left-style: solid; 63 | --vtr-tab-selected-border-left-color: #D47C00; 64 | --vtr-tab-selected-margin-top: 0; 65 | --vtr-tab-selected-margin-right: 3px; 66 | --vtr-tab-selected-margin-bottom: 1px; 67 | --vtr-tab-selected-margin-left: 0; 68 | --vtr-tab-selected-padding-top: 0; 69 | --vtr-tab-selected-padding-right: 3px; 70 | --vtr-tab-selected-padding-bottom: 0; 71 | --vtr-tab-selected-padding-left: 3px; 72 | 73 | /* Single tab pinned */ 74 | --vtr-tab-pinned-text-color: #fbfbfb; 75 | --vtr-tab-pinned-background-color: #27323B; 76 | --vtr-tab-pinned-background: #27323B; 77 | --vtr-tab-pinned-font-weight: inherit; 78 | --vtr-tab-pinned-text-shadow: none; 79 | --vtr-tab-pinned-border-radius: 0; 80 | --vtr-tab-pinned-border-top-width: var(--vtr-tab-border-top-width); 81 | --vtr-tab-pinned-border-top-style: var(--vtr-tab-border-top-style); 82 | --vtr-tab-pinned-border-top-color: var(--vtr-tab-border-top-color); 83 | --vtr-tab-pinned-border-right-width: var(--vtr-tab-border-right-width); 84 | --vtr-tab-pinned-border-right-style: var(--vtr-tab-border-right-style); 85 | --vtr-tab-pinned-border-right-color: var(--vtr-tab-border-right-color); 86 | --vtr-tab-pinned-border-bottom-width: var(--vtr-tab-border-bottom-width); 87 | --vtr-tab-pinned-border-bottom-style: var(--vtr-tab-border-bottom-style); 88 | --vtr-tab-pinned-border-bottom-color: var(--vtr-tab-border-bottom-color); 89 | --vtr-tab-pinned-border-left-width: 3px; 90 | --vtr-tab-pinned-border-left-style: solid; 91 | --vtr-tab-pinned-border-left-color: #2292D0; 92 | --vtr-tab-pinned-margin-top: 0; 93 | --vtr-tab-pinned-margin-right: 3px; 94 | --vtr-tab-pinned-margin-bottom: 0; 95 | --vtr-tab-pinned-margin-left: 0; 96 | --vtr-tab-pinned-padding-top: 0; 97 | --vtr-tab-pinned-padding-right: 3px; 98 | --vtr-tab-pinned-padding-bottom: 0; 99 | --vtr-tab-pinned-padding-left: 3px; 100 | 101 | /* Single tab hover */ 102 | /* Transparent causes troubles with the way icon buttons are getting handled rgba(0,0,0,0.15); */ 103 | --vtr-tab-hover-background-color: #2b2b2b; 104 | --vtr-tab-hover-background: #2b2b2b; 105 | --vtr-tab-hover-padding-top: var(--vtr-tab-padding-top); 106 | --vtr-tab-hover-margin-top: var(--vtr-tab-margin-top); 107 | --vtr-tab-hover-margin-right: var(--vtr-tab-margin-right); 108 | --vtr-tab-hover-margin-bottom: var(--vtr-tab-margin-bottom); 109 | --vtr-tab-hover-margin-left: var(--vtr-tab-selected-margin-left); 110 | --vtr-tab-hover-padding-right: var(--vtr-tab-padding-right); 111 | --vtr-tab-hover-padding-bottom: var(--vtr-tab-padding-bottom); 112 | --vtr-tab-hover-padding-left: var(--vtr-tab-selected-padding-left); 113 | --vtr-tab-hover-border-top: 2px solid #FFFFFF; 114 | --vtr-tab-hover-border-bottom: 2px solid #FFFFFF; 115 | 116 | /* Favicon */ 117 | --vtr-tab-icon-invert-dark-icons: 1; 118 | 119 | /* Close buttons */ 120 | --vtr-tab-button-close-width: 14px; 121 | --vtr-tab-button-close-height: 14px; 122 | --vtr-tab-button-close-regular-background-image: url("../../theme/darwin/closetab.svg"); 123 | --vtr-tab-button-close-hover-background-image: url("../../theme/darwin/closetab-white.svg"); 124 | --vtr-tab-button-close-active-background-image: url("../../theme/darwin/closetab-white.svg"); 125 | 126 | /* Sound buttons */ 127 | --vtr-tab-button-sound-width: 18px; 128 | --vtr-tab-button-sound-height: 18px; 129 | --vtr-tab-button-sound-playing-background-image: url("../../chrome/icon/tab-audio-playing-white.svg"); 130 | --vtr-tab-button-sound-muted-background-image: url("../../chrome/icon/tab-audio-muted-white.svg"); 131 | 132 | /* Tab status, default: color blind variant */ 133 | --vtr-tab-status-unread-text-decoration: underline; 134 | --vtr-tab-status-busy-text-decoration: underline; 135 | --vtr-tab-status-discarded-text-decoration: line-through; 136 | 137 | /* Splitter/Separation between tabbar and website 138 | --vtr-splitter-background: none; 139 | --vtr-splitter-width: 3px; 140 | --vtr-splitter-border-left-size: 0; 141 | --vtr-splitter-border-left-color: #404040; 142 | --vtr-splitter-border-right-size: 0; 143 | --vtr-splitter-border-right-color: #404040; */ 144 | } 145 | -------------------------------------------------------------------------------- /data/theme/darwin/modifications.css: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | .tab-icon-sound { 4 | filter: drop-shadow(1px 1px 1px white) !important; 5 | } */ 6 | 7 | 8 | /* Keep the close button at a safe distance from the tab label. */ 9 | /*.tab-close-button { 10 | margin-left: 3px; 11 | margin-top: 1px; 12 | background-position: center right; 13 | background-size: contain; */ 14 | 15 | /* background-position: center center; 16 | background-size: 14px 14px; */ 17 | /*opacity: 0.7; turn black into #b9b9b9 18 | }*/ 19 | 20 | .tab-close-button:active { 21 | opacity: 0.75; /* turn black into #8a8a8a */ 22 | } 23 | 24 | .tabbrowser-tab[selected="true"] .tab-close-button { 25 | opacity: 0.8; 26 | } 27 | 28 | .tabbrowser-tab[selected="true"] .tab-close-button:hover { 29 | opacity: 1; 30 | } 31 | 32 | 33 | /* Always display the favicon at 100% opacity */ 34 | /* .tabbrowser-tab .tab-icon-image { 35 | opacity: 1.0 !important; 36 | } */ 37 | 38 | /* Tab label is without special decoration except when selected: then 39 | the text is white and bold. */ 40 | /* .tab-text { 41 | margin-bottom: 1px; FIXME: This margin-bottom or the 6px from the variables? */ 42 | /* text-align: left !important; 43 | } */ 44 | 45 | /* Ensure app tab labels are not too close to the icon. 46 | .tab-label[pinned] { 47 | margin: 2px 6px !important; 48 | position: relative !important; 49 | } */ 50 | 51 | /* 52 | .tabbrowser-tab[pinned]:before { 53 | position: relative !important; 54 | } 55 | 56 | .tabbrowser-tab[pinned][titlechanged] > .tab-stack > .tab-content { 57 | background-image: none !important; 58 | } 59 | 60 | .tabbrowser-tab[pinned][titlechanged] .tab-text { 61 | color: #F1F1F1 !important; 62 | } 63 | 64 | .tabbrowser-tab[pinned][titlechanged]:after { 65 | content: '●' !important; 66 | width: 18px; 67 | height: 10px; 68 | position: absolute !important; 69 | color: #29B4FF; 70 | line-height: 15px; 71 | font-size: 150% !important; 72 | } */ 73 | -------------------------------------------------------------------------------- /data/theme/feather/index.css: -------------------------------------------------------------------------------- 1 | @import "../../template/basic/index.css"; 2 | @import "modifications.css"; 3 | 4 | :root { 5 | /* Tabbrowser */ 6 | --vtr-tabbrowser-background-color: #F9F9FA; 7 | 8 | /* Tab Toolbar */ 9 | --vtr-tabbar-height: 22px; 10 | --vtr-tabbar-background-color: rgb(207,219,236); 11 | 12 | /* Single tab */ 13 | --vtr-tab-text-color: #333333; 14 | --vtr-tab-background-color: #F9F9FA; 15 | --vtr-tab-background: #F9F9FA; 16 | --vtr-tab-font-size: 1em; 17 | --vtr-tab-font-weight: normal; 18 | --vtr-tab-text-shadow: none; 19 | --vtr-tab-height: 25px; 20 | --vtr-tab-min-height: 25px; 21 | --vtr-tab-max-height: 25px; 22 | --vtr-tab-border-radius: 2.67px 0 0 2.67px; 23 | --vtr-tab-border-top-width: 0; 24 | --vtr-tab-border-top-style: solid; 25 | --vtr-tab-border-top-color: transparent; 26 | --vtr-tab-border-right-width: 0px; /* FIXME: Border right 1px wanted from original draft? */ 27 | --vtr-tab-border-right-style: solid; 28 | --vtr-tab-border-right-color: #5E6972; 29 | --vtr-tab-border-bottom-width: 1px; 30 | --vtr-tab-border-bottom-style: solid; 31 | --vtr-tab-border-bottom-color: #bbc3cc; 32 | --vtr-tab-border-left-width: 4px; 33 | --vtr-tab-border-left-style: solid; 34 | --vtr-tab-border-left-color: transparent; 35 | --vtr-tab-margin-top: 0; 36 | --vtr-tab-margin-right: 0; 37 | --vtr-tab-margin-bottom: 0; 38 | --vtr-tab-margin-left: 0; 39 | --vtr-tab-padding-top: 1px; 40 | --vtr-tab-padding-right: 0; 41 | --vtr-tab-padding-bottom: 1px; 42 | --vtr-tab-padding-left: 0; 43 | 44 | /* Single tab selected */ 45 | --vtr-tab-selected-text-color: HighlightText; 46 | --vtr-tab-selected-background-color: Highlight; 47 | --vtr-tab-selected-background: Highlight; 48 | --vtr-tab-selected-font-weight: bold; 49 | --vtr-tab-selected-text-shadow: none; 50 | --vtr-tab-selected-border-radius: 0; 51 | --vtr-tab-selected-border-top-width: var(--vtr-tab-border-top-width); 52 | --vtr-tab-selected-border-top-style: var(--vtr-tab-border-top-style); 53 | --vtr-tab-selected-border-top-color: var(--vtr-tab-border-top-color); 54 | --vtr-tab-selected-border-right-width: var(--vtr-tab-border-right-width); 55 | --vtr-tab-selected-border-right-style: var(--vtr-tab-border-right-style); 56 | --vtr-tab-selected-border-right-color: var(--vtr-tab-border-right-color); 57 | --vtr-tab-selected-border-bottom-width: var(--vtr-tab-border-bottom-width); 58 | --vtr-tab-selected-border-bottom-style: var(--vtr-tab-border-bottom-style); 59 | --vtr-tab-selected-border-bottom-color: var(--vtr-tab-border-bottom-color); 60 | --vtr-tab-selected-border-left-width: 3px; 61 | --vtr-tab-selected-border-left-style: solid; 62 | --vtr-tab-selected-border-left-color: #002A8A; 63 | --vtr-tab-selected-margin-top: 1px; 64 | --vtr-tab-selected-margin-right: 0; 65 | --vtr-tab-selected-margin-bottom: 1px; 66 | --vtr-tab-selected-margin-left: 0; 67 | --vtr-tab-selected-padding-top: 0; 68 | --vtr-tab-selected-padding-right: 0; 69 | --vtr-tab-selected-padding-bottom: 0; 70 | --vtr-tab-selected-padding-left: 0; 71 | 72 | /* Single tab pinned */ 73 | --vtr-tab-pinned-text-color: #333333; 74 | --vtr-tab-pinned-background-color: rgb(207,219,236); 75 | --vtr-tab-pinned-background: rgb(207,219,236); 76 | --vtr-tab-pinned-font-weight: normal; 77 | --vtr-tab-pinned-text-shadow: none; 78 | --vtr-tab-pinned-border-radius: 0; 79 | --vtr-tab-pinned-border-top-width: var(--vtr-tab-border-top-width); 80 | --vtr-tab-pinned-border-top-style: var(--vtr-tab-border-top-style); 81 | --vtr-tab-pinned-border-top-color: var(--vtr-tab-border-top-color); 82 | --vtr-tab-pinned-border-right-width: var(--vtr-tab-border-right-width); 83 | --vtr-tab-pinned-border-right-style: var(--vtr-tab-border-right-style); 84 | --vtr-tab-pinned-border-right-color: var(--vtr-tab-border-right-color); 85 | --vtr-tab-pinned-border-bottom-width: var(--vtr-tab-border-bottom-width); 86 | --vtr-tab-pinned-border-bottom-style: var(--vtr-tab-border-bottom-style); 87 | --vtr-tab-pinned-border-bottom-color: var(--vtr-tab-border-bottom-color); 88 | --vtr-tab-pinned-border-left-width: 2px; 89 | --vtr-tab-pinned-border-left-style: solid; 90 | --vtr-tab-pinned-border-left-color: #2292D0; 91 | --vtr-tab-pinned-margin-top: 0; 92 | --vtr-tab-pinned-margin-right: 0; 93 | --vtr-tab-pinned-margin-bottom: 0; 94 | --vtr-tab-pinned-margin-left: 0; 95 | --vtr-tab-pinned-padding-top: 1px; 96 | --vtr-tab-pinned-padding-right: 0; 97 | --vtr-tab-pinned-padding-bottom: 1px; 98 | --vtr-tab-pinned-padding-left: 0; 99 | 100 | /* Single tab hover */ 101 | --vtr-tab-hover-background-color: #ebebeb; 102 | --vtr-tab-hover-background: #ebebeb; 103 | --vtr-tab-hover-margin-top: var(--vtr-tab-margin-top); 104 | --vtr-tab-hover-margin-right: var(--vtr-tab-margin-right); 105 | --vtr-tab-hover-margin-bottom: var(--vtr-tab-margin-bottom); 106 | --vtr-tab-hover-margin-left: var(--vtr-tab-margin-left); 107 | --vtr-tab-hover-padding-top: var(--vtr-tab-padding-top); 108 | --vtr-tab-hover-padding-right: var(--vtr-tab-padding-right); 109 | --vtr-tab-hover-padding-bottom: var(--vtr-tab-padding-bottom); 110 | --vtr-tab-hover-padding-left: var(--vtr-tab-padding-left); 111 | --vtr-tab-hover-border-top: 2px solid #000000; 112 | --vtr-tab-hover-border-bottom: 2px solid #000000; 113 | 114 | /* Close buttons */ 115 | --vtr-tab-button-close-width: 18px; 116 | --vtr-tab-button-close-height: 18px; 117 | --vtr-tab-button-close-regular-background-image: url("../../template/basic/icons/light/close-regular.png"); 118 | --vtr-tab-button-close-hover-background-image: url("../../template/basic/icons/light/close-hover.png"); 119 | --vtr-tab-button-close-active-background-image: url("../../template/basic/icons/light/close-active.png"); 120 | 121 | /* Sound buttons */ 122 | --vtr-tab-button-sound-width: 17px; 123 | --vtr-tab-button-sound-height: 17px; 124 | --vtr-tab-button-sound-playing-background-image: url("../../chrome/icon/tab-audio-playing.svg"); 125 | --vtr-tab-button-sound-muted-background-image: url("../../chrome/icon/tab-audio-muted.svg"); 126 | 127 | /* Tab status, default: color blind variant */ 128 | --vtr-tab-status-unread-text-decoration: underline; 129 | --vtr-tab-status-busy-text-decoration: underline; 130 | --vtr-tab-status-discarded-text-decoration: line-through; 131 | 132 | /* Splitter/Separation between tabbar and website 133 | --vtr-splitter-background: #d6e5f5; 134 | --vtr-splitter-width: 3px; 135 | --vtr-splitter-border-left-size: 1px; 136 | --vtr-splitter-border-left-color: #fcfcfc; 137 | --vtr-splitter-border-right-size: 1px; 138 | --vtr-splitter-border-right-color: #fcfcfc; */ 139 | } 140 | -------------------------------------------------------------------------------- /data/theme/feather/modifications.css: -------------------------------------------------------------------------------- 1 | /* No modifications so far */ 2 | 3 | /* From the former Linux theme: */ 4 | 5 | body { 6 | /* margin: 1px 0 0 0; 7 | padding: 0; */ 8 | border: 1px solid ButtonShadow; 9 | } 10 | 11 | /* FIXME: redo, remove? */ 12 | /* 13 | .tabbrowser-tab[selected="true"]:-moz-window-inactive { 14 | background-color: InactiveCaption !important; 15 | color: InactiveCaptionText !important; */ 16 | /* gnome/gtk/cleartype doesn't seem to have inactive states for selected items, lets try this */ 17 | /* } */ 18 | 19 | 20 | /* From the former Windows theme: */ 21 | 22 | /* .tabbrowser-tab:hover:not(:-moz-lwtheme) { 23 | border-color: gray; 24 | background: linear-gradient(to bottom, #fafbfd, #ebf3fd) repeat-x !important; 25 | } 26 | 27 | .tabbrowser-tab[pinned] { 28 | position: inherit; 29 | border-left: 4px solid #2292D0 !important; 30 | } 31 | 32 | .tabbrowser-tab[pinned]:not(:-moz-lwtheme) { 33 | background: linear-gradient(to right, gray, #ebf3fd) repeat-y !important; 34 | } 35 | 36 | .tabbrowser-tab[selected="true"] { 37 | margin: 0 !important; 38 | padding: 0 0 0 3px !important; 39 | } 40 | 41 | .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) { 42 | border-color: gray; 43 | background: linear-gradient(to bottom, #ebf4fe, #cfe4fe) repeat-x; 44 | 45 | font-weight: normal; 46 | text-shadow: none; 47 | } 48 | 49 | .tabbrowser-tab[selected="true"]:-moz-window-inactive{ 50 | border: 1px solid !important; 51 | -moz-border-top-colors: #d9d9d9 #fafafb !important; 52 | -moz-border-bottom-colors: #d9d9d9 #f0f0f0 !important; 53 | -moz-border-left-colors: #d9d9d9 #f8f8f8 !important; 54 | -moz-border-right-colors: #d9d9d9 #f8f8f8 !important; 55 | background: linear-gradient(to bottom, #f8f8f8, #e5e5e5) repeat-x !important; 56 | } */ 57 | -------------------------------------------------------------------------------- /data/theme/light/index.css: -------------------------------------------------------------------------------- 1 | @import "../../template/basic/index.css"; 2 | @import "modifications.css"; 3 | 4 | :root { 5 | /* Tabbrowser */ 6 | --vtr-tabbrowser-background-color: #FBFBFB; 7 | 8 | /* Tab Toolbar */ 9 | --vtr-tabbar-height: 24px; 10 | --vtr-tabbar-background-color: #f1f1f1; 11 | 12 | /* Single tab */ 13 | --vtr-tab-text-color: #333333; 14 | --vtr-tab-background-color: #FBFBFB; 15 | --vtr-tab-background: #FBFBFB; 16 | --vtr-tab-font-size: 1em; 17 | --vtr-tab-font-weight: normal; 18 | --vtr-tab-text-shadow: none; 19 | --vtr-tab-height: 28px; 20 | --vtr-tab-min-height: 28px; 21 | --vtr-tab-max-height: 28px; 22 | --vtr-tab-border-radius: 0; 23 | --vtr-tab-border-top-width: 0; 24 | --vtr-tab-border-top-style: solid; 25 | --vtr-tab-border-top-color: transparent; 26 | --vtr-tab-border-right-width: 0; 27 | --vtr-tab-border-right-style: solid; 28 | --vtr-tab-border-right-color: transparent; 29 | --vtr-tab-border-bottom-width: 2px; 30 | --vtr-tab-border-bottom-style: solid; 31 | --vtr-tab-border-bottom-color: #bbc3cc; 32 | --vtr-tab-border-left-width: 4px; 33 | --vtr-tab-border-left-style: solid; 34 | --vtr-tab-border-left-color: transparent; 35 | --vtr-tab-margin-top: 0; 36 | --vtr-tab-margin-right: 0; 37 | --vtr-tab-margin-bottom: 0; 38 | --vtr-tab-margin-left: 0; 39 | --vtr-tab-padding-top: 1px; 40 | --vtr-tab-padding-right: 0; 41 | --vtr-tab-padding-bottom: 1px; 42 | --vtr-tab-padding-left: 0; 43 | 44 | /* Single tab selected */ 45 | --vtr-tab-selected-text-color: #333333; 46 | --vtr-tab-selected-background-color: #CBCBCB; --vtr-tab-selected-background: #CBCBCB; 47 | --vtr-tab-selected-font-weight: 600; 48 | --vtr-tab-selected-text-shadow: none; 49 | --vtr-tab-selected-border-radius: 0; 50 | --vtr-tab-selected-border-top-width: var(--vtr-tab-border-top-width); 51 | --vtr-tab-selected-border-top-style: var(--vtr-tab-border-top-style); 52 | --vtr-tab-selected-border-top-color: var(--vtr-tab-border-top-color); 53 | --vtr-tab-selected-border-right-width: var(--vtr-tab-border-right-width); 54 | --vtr-tab-selected-border-right-style: var(--vtr-tab-border-right-style); 55 | --vtr-tab-selected-border-right-color: var(--vtr-tab-border-right-color); 56 | --vtr-tab-selected-border-bottom-width: var(--vtr-tab-border-bottom-width); 57 | --vtr-tab-selected-border-bottom-style: var(--vtr-tab-border-bottom-style); 58 | --vtr-tab-selected-border-bottom-color: var(--vtr-tab-border-bottom-color); 59 | --vtr-tab-selected-border-left-width: 4px; 60 | --vtr-tab-selected-border-left-style: solid; 61 | --vtr-tab-selected-border-left-color: #ff9500; 62 | --vtr-tab-selected-margin-top: 0; 63 | --vtr-tab-selected-margin-right: 0; 64 | --vtr-tab-selected-margin-bottom: 0; 65 | --vtr-tab-selected-margin-left: 0; 66 | --vtr-tab-selected-padding-top: 1px; 67 | --vtr-tab-selected-padding-right: 0; 68 | --vtr-tab-selected-padding-bottom: 1px; 69 | --vtr-tab-selected-padding-left: 0; 70 | 71 | /* Single tab pinned */ 72 | --vtr-tab-pinned-text-color: #333333; 73 | --vtr-tab-pinned-background-color: #CBCBCB; 74 | --vtr-tab-pinned-background: #CBCBCB; 75 | --vtr-tab-pinned-font-weight: 600; 76 | --vtr-tab-pinned-text-shadow: none; 77 | --vtr-tab-pinned-border-radius: 0; 78 | --vtr-tab-pinned-border-top-width: var(--vtr-tab-border-top-width); 79 | --vtr-tab-pinned-border-top-style: var(--vtr-tab-border-top-style); 80 | --vtr-tab-pinned-border-top-color: var(--vtr-tab-border-top-color); 81 | --vtr-tab-pinned-border-right-width: var(--vtr-tab-border-right-width); 82 | --vtr-tab-pinned-border-right-style: var(--vtr-tab-border-right-style); 83 | --vtr-tab-pinned-border-right-color: var(--vtr-tab-border-right-color); 84 | --vtr-tab-pinned-border-bottom-width: var(--vtr-tab-border-bottom-width); 85 | --vtr-tab-pinned-border-bottom-style: var(--vtr-tab-border-bottom-style); 86 | --vtr-tab-pinned-border-bottom-color: var(--vtr-tab-border-bottom-color); 87 | --vtr-tab-pinned-border-left-width: 4px; 88 | --vtr-tab-pinned-border-left-style: solid; 89 | --vtr-tab-pinned-border-left-color: #2292D0; 90 | --vtr-tab-pinned-margin-top: 0; 91 | --vtr-tab-pinned-margin-right: 0; 92 | --vtr-tab-pinned-margin-bottom: 0; 93 | --vtr-tab-pinned-margin-left: 0; 94 | --vtr-tab-pinned-padding-top: 1px; 95 | --vtr-tab-pinned-padding-right: 0; 96 | --vtr-tab-pinned-padding-bottom: 1px; 97 | --vtr-tab-pinned-padding-left: 0; 98 | 99 | /* Single tab hover */ 100 | --vtr-tab-hover-background-color: #ebebeb; 101 | --vtr-tab-hover-background: #ebebeb; 102 | --vtr-tab-hover-margin-top: var(--vtr-tab-margin-top); 103 | --vtr-tab-hover-margin-right: var(--vtr-tab-margin-right); 104 | --vtr-tab-hover-margin-bottom: var(--vtr-tab-margin-bottom); 105 | --vtr-tab-hover-margin-left: var(--vtr-tab-margin-left); 106 | --vtr-tab-hover-padding-top: var(--vtr-tab-padding-top); 107 | --vtr-tab-hover-padding-right: var(--vtr-tab-padding-right); 108 | --vtr-tab-hover-padding-bottom: var(--vtr-tab-padding-bottom); 109 | --vtr-tab-hover-padding-left: var(--vtr-tab-padding-left); 110 | --vtr-tab-hover-border-top: 2px solid #000000; 111 | --vtr-tab-hover-border-bottom: 2px solid #000000; 112 | 113 | /* Close buttons */ 114 | --vtr-tab-button-close-width: 18px; 115 | --vtr-tab-button-close-height: 18px; 116 | --vtr-tab-button-close-regular-background-image: url("../../template/basic/icons/light/close-regular.png"); 117 | --vtr-tab-button-close-hover-background-image: url("../../template/basic/icons/light/close-hover.png"); 118 | --vtr-tab-button-close-active-background-image: url("../../template/basic/icons/light/close-active.png"); 119 | 120 | /* Sound buttons */ 121 | --vtr-tab-button-sound-width: 18px; 122 | --vtr-tab-button-sound-height: 18px; 123 | --vtr-tab-button-sound-playing-background-image: url("../../chrome/icon/tab-audio-playing.svg"); 124 | --vtr-tab-button-sound-muted-background-image: url("../../chrome/icon/tab-audio-muted.svg"); 125 | 126 | /* Tab status, default: color blind variant */ 127 | --vtr-tab-status-unread-text-decoration: underline; 128 | --vtr-tab-status-busy-text-decoration: underline; 129 | --vtr-tab-status-discarded-text-decoration: line-through; 130 | 131 | /* Splitter/Separation between tabbar and website 132 | --vtr-splitter-background: #ebebeb; 133 | --vtr-splitter-width: 3px; 134 | --vtr-splitter-border-left-size: 0; 135 | --vtr-splitter-border-left-color: #ebebeb; 136 | --vtr-splitter-border-right-size: 0; 137 | --vtr-splitter-border-right-color: #ebebeb; */ 138 | } 139 | -------------------------------------------------------------------------------- /data/theme/light/modifications.css: -------------------------------------------------------------------------------- 1 | /* No modifications so far */ 2 | -------------------------------------------------------------------------------- /data/theme/moonshot/index.css: -------------------------------------------------------------------------------- 1 | @import "../../template/basic/index.css"; 2 | @import "modifications.css"; 3 | 4 | :root { 5 | /* Tabbrowser */ 6 | --vtr-tabbrowser-background-color: #222; 7 | --vtr-tabbrowser-separation-sidebar-border-color: var(--vtr-tab-selected-background-color); 8 | --vtr-tabbrowser-separation-sidebar-border-style: solid; 9 | --vtr-tabbrowser-separation-sidebar-border-width: 1px; 10 | 11 | /* Tab Toolbar */ 12 | --vtr-tabbar-height: 28px; 13 | --vtr-tabbar-background-color: #222; 14 | --vtr-tabbar-filter: invert(77%) sepia(6%) saturate(55%) hue-rotate(131deg) brightness(97%) contrast(81%); 15 | --vtr-tabbar-separation-border-color: var(--vtr-tab-selected-background-color); 16 | --vtr-tabbar-tools-separation-border-color: var(--vtr-tab-border-bottom-color); 17 | --vtr-tabbar-tools-separation-border-style: solid; 18 | --vtr-tabbar-tools-separation-border-width: 1px; 19 | --vtr-tabbar-pinned-separation-border-color: var(--vtr-tab-selected-background-color); 20 | --vtr-tabbar-pinned-separation-border-style: solid; 21 | --vtr-tabbar-pinned-separation-border-width: 1px; 22 | 23 | /* Single tab */ 24 | --vtr-tab-text-color: #dbdbdb; 25 | --vtr-tab-background-color: #222; 26 | --vtr-tab-background: #222; 27 | --vtr-tab-font-size: 1em; 28 | --vtr-tab-font-weight: normal; 29 | --vtr-tab-text-shadow: none; 30 | --vtr-tab-height: 28px; 31 | --vtr-tab-min-height: 28px; 32 | --vtr-tab-max-height: 28px; 33 | --vtr-tab-border-radius: 0; 34 | --vtr-tab-border-top-width: 0; 35 | --vtr-tab-border-top-style: solid; 36 | --vtr-tab-border-top-color: transparent; 37 | --vtr-tab-border-right-width: 0; 38 | --vtr-tab-border-right-style: solid; 39 | --vtr-tab-border-right-color: transparent; 40 | --vtr-tab-border-bottom-width: 1px; 41 | --vtr-tab-border-bottom-style: solid; 42 | --vtr-tab-border-bottom-color: #171717; 43 | --vtr-tab-border-left-width: 0; 44 | --vtr-tab-border-left-style: solid; 45 | --vtr-tab-border-left-color: transparent; 46 | --vtr-tab-margin-top: 0; 47 | --vtr-tab-margin-right: 0; 48 | --vtr-tab-margin-bottom: 0; 49 | --vtr-tab-margin-left: 0; 50 | --vtr-tab-padding-top: 1px; 51 | --vtr-tab-padding-right: 0; 52 | --vtr-tab-padding-bottom: 1px; 53 | --vtr-tab-padding-left: 0; 54 | 55 | /* Single tab selected */ 56 | --vtr-tab-selected-text-color: #ddd; 57 | --vtr-tab-selected-background-color: #0d456a; 58 | --vtr-tab-selected-background: #0d456a; 59 | --vtr-tab-selected-font-weight: normal; 60 | --vtr-tab-selected-text-shadow: none; 61 | --vtr-tab-selected-border-radius: 0; 62 | --vtr-tab-selected-border-top-width: var(--vtr-tab-border-top-width); 63 | --vtr-tab-selected-border-top-style: var(--vtr-tab-border-top-style); 64 | --vtr-tab-selected-border-top-color: var(--vtr-tab-border-top-color); 65 | --vtr-tab-selected-border-right-width: var(--vtr-tab-border-right-width); 66 | --vtr-tab-selected-border-right-style: var(--vtr-tab-border-right-style); 67 | --vtr-tab-selected-border-right-color: var(--vtr-tab-border-right-color); 68 | --vtr-tab-selected-border-bottom-width: var(--vtr-tab-border-bottom-width); 69 | --vtr-tab-selected-border-bottom-style: var(--vtr-tab-border-bottom-style); 70 | --vtr-tab-selected-border-bottom-color: var(--vtr-tab-border-bottom-color); 71 | --vtr-tab-selected-border-left-width: 0px; 72 | --vtr-tab-selected-border-left-style: solid; 73 | --vtr-tab-selected-border-left-color: transparent; 74 | --vtr-tab-selected-margin-top: 0; 75 | --vtr-tab-selected-margin-right: 0; 76 | --vtr-tab-selected-margin-bottom: 0; 77 | --vtr-tab-selected-margin-left: 0; 78 | --vtr-tab-selected-padding-top: 1px; 79 | --vtr-tab-selected-padding-right: 0; 80 | --vtr-tab-selected-padding-bottom: 1px; 81 | --vtr-tab-selected-padding-left: 0; 82 | 83 | /* Single tab pinned */ 84 | --vtr-tab-pinned-text-color: #fbfbfb; 85 | --vtr-tab-pinned-background-color: var(--vtr-tab-background-color); 86 | --vtr-tab-pinned-background: var(--vtr-tab-background-color); 87 | --vtr-tab-pinned-font-weight: inherit; 88 | --vtr-tab-pinned-text-shadow: none; 89 | --vtr-tab-pinned-border-radius: 0; 90 | --vtr-tab-pinned-border-top-width: var(--vtr-tab-border-top-width); 91 | --vtr-tab-pinned-border-top-style: var(--vtr-tab-border-top-style); 92 | --vtr-tab-pinned-border-top-color: var(--vtr-tab-border-top-color); 93 | --vtr-tab-pinned-border-right-width: var(--vtr-tab-border-right-width); 94 | --vtr-tab-pinned-border-right-style: var(--vtr-tab-border-right-style); 95 | --vtr-tab-pinned-border-right-color: var(--vtr-tab-border-right-color); 96 | --vtr-tab-pinned-border-bottom-width: var(--vtr-tab-border-bottom-width); 97 | --vtr-tab-pinned-border-bottom-style: var(--vtr-tab-border-bottom-style); 98 | --vtr-tab-pinned-border-bottom-color: var(--vtr-tab-border-bottom-color); 99 | --vtr-tab-pinned-border-left-width: 1px; 100 | --vtr-tab-pinned-border-left-style: solid; 101 | --vtr-tab-pinned-border-left-color: #171717; 102 | --vtr-tab-pinned-margin-top: 0; 103 | --vtr-tab-pinned-margin-right: 0; 104 | --vtr-tab-pinned-margin-bottom: 0; 105 | --vtr-tab-pinned-margin-left: 0; 106 | --vtr-tab-pinned-padding-top: 1px; 107 | --vtr-tab-pinned-padding-right: 0; 108 | --vtr-tab-pinned-padding-bottom: 1px; 109 | --vtr-tab-pinned-padding-left: 0; 110 | 111 | /* Single tab hover */ 112 | --vtr-tab-hover-background-color: #4b4a4a; /*#5E6972;*/ 113 | --vtr-tab-hover-background: #4b4a4a; /*#5E6972;*/ 114 | --vtr-tab-hover-margin-top: var(--vtr-tab-margin-top); 115 | --vtr-tab-hover-margin-right: var(--vtr-tab-margin-right); 116 | --vtr-tab-hover-margin-bottom: var(--vtr-tab-margin-bottom); 117 | --vtr-tab-hover-margin-left: var(--vtr-tab-margin-left); 118 | --vtr-tab-hover-padding-top: var(--vtr-tab-padding-top); 119 | --vtr-tab-hover-padding-right: var(--vtr-tab-padding-right); 120 | --vtr-tab-hover-padding-bottom: var(--vtr-tab-padding-bottom); 121 | --vtr-tab-hover-padding-left: var(--vtr-tab-padding-left); 122 | --vtr-tab-hover-border-top: 2px solid #FFFFFF; 123 | --vtr-tab-hover-border-bottom: 2px solid #FFFFFF; 124 | 125 | /* Favicon */ 126 | --vtr-tab-icon-invert-dark-icons: 0.8; 127 | 128 | /* Close button */ 129 | --vtr-tab-button-close-width: 18px; 130 | --vtr-tab-button-close-height: 18px; 131 | --vtr-tab-button-close-filter: inherit; 132 | --vtr-tab-button-close-regular-background-image: url("../../template/basic/icons/dark/close-regular.png"); 133 | --vtr-tab-button-close-hover-background-color: transparent; 134 | --vtr-tab-button-close-hover-border-radius: 6px; 135 | --vtr-tab-button-close-hover-border-color: var(--vtr-tab-text-color); 136 | --vtr-tab-button-close-hover-border-style: solid; 137 | --vtr-tab-button-close-hover-border-width: 1px; 138 | --vtr-tab-button-close-hover-background-image: url("../../template/basic/icons/dark/close-regular.png"); 139 | --vtr-tab-button-close-active-background-image: url("../../template/basic/icons/dark/close-regular.png"); 140 | --vtr-tab-button-close-active-background-color: #0d166a; 141 | --vtr-tab-button-close-active-border-radius: 6px; 142 | 143 | /* Sound buttons */ 144 | --vtr-tab-button-sound-width: 18px; 145 | --vtr-tab-button-sound-height: 18px; 146 | --vtr-tab-button-sound-filter: brightness(0) saturate(100%) invert(99%) sepia(65%) saturate(1032%) hue-rotate(180deg) brightness(106%) contrast(96%); 147 | --vtr-tab-button-sound-playing-background-image: url("../../chrome/icon/tab-audio-playing-white.svg"); 148 | --vtr-tab-button-sound-muted-background-image: url("../../chrome/icon/tab-audio-muted-white.svg"); 149 | 150 | /* Tab status, default: color blind variant */ 151 | --vtr-tab-status-unread-text-decoration: underline; 152 | --vtr-tab-status-busy-text-decoration: underline; 153 | --vtr-tab-status-discarded-text-decoration: line-through; 154 | } 155 | -------------------------------------------------------------------------------- /data/theme/moonshot/modifications.css: -------------------------------------------------------------------------------- 1 | /* No modifications so far */ 2 | -------------------------------------------------------------------------------- /dev/README.md: -------------------------------------------------------------------------------- 1 | # Source Files 2 | 3 | Working files. Not needed for the execution of the add-on. 4 | -------------------------------------------------------------------------------- /dev/icon/Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 48 | 50 | 51 | 53 | image/svg+xml 54 | 56 | 57 | 58 | 59 | 60 | 65 | 74 | 106 | 126 | VTR 142 | 143 | -------------------------------------------------------------------------------- /dev/icon/icon_small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 48 | 50 | 51 | 53 | image/svg+xml 54 | 56 | 57 | 58 | 59 | 60 | 65 | 97 | 117 | VTR 141 | 142 | 143 | -------------------------------------------------------------------------------- /dev/icon/window_500px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/dev/icon/window_500px.png -------------------------------------------------------------------------------- /dev/icon/window_500px_with_sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/dev/icon/window_500px_with_sidebar.png -------------------------------------------------------------------------------- /dev/script/check_manifest_version_values.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import os 5 | import sys 6 | 7 | manifest = None 8 | manifestfile = os.path.join("manifest.json") 9 | 10 | with open(manifestfile, "r") as manifest_file: 11 | manifest = json.load(manifest_file) 12 | 13 | 14 | version_three_digits = ".".join(manifest["version"].split(".")[:3]) 15 | if version_three_digits != manifest["version_name"]: 16 | print("Error in manifest.json: The first three digit parts of `version` have to be identical to `version_schema`") 17 | print(f"Error in manifest.json: The first three digit parts of `version` are: {version_three_digits}") 18 | print(f"Error in manifest.json: `version_schema` is: {manifest['version_name']}") 19 | sys.exit(1) 20 | -------------------------------------------------------------------------------- /dev/script/create_dev_release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import os 5 | 6 | manifest = None 7 | updates = None 8 | manifestfile = os.path.join("manifest.json") 9 | updatefile = os.path.join("vtr-releases", "updates.json") 10 | webpage = os.path.join("vtr-releases", "index.html") 11 | 12 | with open(manifestfile, "r") as manifest_file: 13 | manifest = json.load(manifest_file) 14 | 15 | with open(updatefile, "r") as update_file: 16 | updates = json.load(update_file) 17 | 18 | new_version_filename = f"vtr_developer_version-{manifest['version']}_{manifest['version_name']}.xpi" 19 | 20 | os.rename( 21 | os.path.join("vtr-releases", "files", f"vtr_developer_version-{manifest['version']}.xpi"), 22 | os.path.join("vtr-releases", "files", new_version_filename), 23 | ) 24 | 25 | download_url = f"https://croydon.github.io/vtr-releases/files/{new_version_filename}" 26 | 27 | with open(updatefile, "w") as update_file: 28 | new_version = { 29 | "version": manifest["version"], 30 | "update_link": download_url 31 | } 32 | updates["addons"]["vtrbeta@go-dev.de"]["updates"] += [new_version] 33 | 34 | updates = json.dumps(updates, indent=4) 35 | update_file.write("{}\n".format(updates)) 36 | 37 | 38 | with open(webpage, "w") as update_file: 39 | data = """ 40 | 41 | 42 | 43 | VTR (DEVELOPER VERSION) 44 | 45 | 46 |
47 | If you don't know what this page is about, go to https://github.com/Croydon/vertical-tabs-reloaded instead. 48 | 49 |


50 | 51 | Install VTR DEVELOPER VERSION 52 |
53 | 54 | """.format(download_url) 55 | update_file.write("{}\n".format(data)) 56 | -------------------------------------------------------------------------------- /dev/script/prepare_dev_release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import os 5 | 6 | manifest = None 7 | manifestfile = os.path.join("manifest.json") 8 | 9 | with open(manifestfile, "r") as manifest_file: 10 | manifest = json.load(manifest_file) 11 | 12 | version_three_digits = ".".join(manifest["version"].split(".")[:3]) 13 | version_fourth_digit = ".".join(manifest["version"].split(".")[3:]) 14 | 15 | with open(manifestfile, "w") as manifest_file: 16 | manifest["name"] = "VTR (DEVELOPER VERSION)" 17 | manifest["version_name"] = f"{version_three_digits}-alpha.{version_fourth_digit}" 18 | manifest["sidebar_action"]["default_title"] = "VTR (DEVELOPER VERSION)" 19 | manifest["browser_specific_settings"]["gecko"]["id"] = "vtrbeta@go-dev.de" 20 | manifest["browser_specific_settings"]["gecko"]["update_url"] = "https://croydon.github.io/vtr-releases/updates.json" 21 | 22 | manifest = json.dumps(manifest, indent=4) 23 | manifest_file.write("{}\n".format(manifest)) 24 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils */ 4 | 5 | var sidebarPorts = {}; 6 | 7 | function manage_installation(details) 8 | { 9 | utils.options.get_options_file().then(() => 10 | { 11 | if(details.reason == "install") 12 | { 13 | // FIXME 14 | // browser.tabs.create({url: "install-notes.html"}); 15 | // browser.sidebarAction.open(); 16 | } 17 | 18 | if(details.reason == "update") 19 | { 20 | utils.log.debug("VTR update!"); 21 | 22 | utils.options.get_setting("theme").then(value => 23 | { 24 | if(value == "none") 25 | { 26 | utils.options.save_setting("theme", "dark"); // This is likely irrelvant, but could prevent some race conditions 27 | utils.options.restore_default_setting_of("theme"); 28 | } 29 | 30 | if(value == "windows" || value == "linux") 31 | { 32 | utils.options.save_setting("theme", "feather"); 33 | } 34 | }); 35 | 36 | // Migrate toggleDisplayHotkey from legacy (pre-WebExtension format) to WebExtension FF60+ format 37 | utils.options.get_setting("toggleDisplayHotkey").then(value => 38 | { 39 | // While this only replaces the - with + it triggers an option change which in turns triggers the default 40 | // hotkey validation check in utils/options.js; if it's invalid we reset to default hotkey 41 | utils.options.save_setting("toggleDisplayHotkey", value.replace(/-/g, "+")); 42 | }); 43 | 44 | utils.options.get_setting("runtime.vtr.installedVersion").then((installedVersion) => 45 | { 46 | let previousVersion; 47 | if(installedVersion == undefined) 48 | { 49 | previousVersion = details.previousVersion.split("."); 50 | if(typeof browser.sidebarAction != "undefined" && typeof browser.sidebarAction.open != "undefined") 51 | { 52 | browser.sidebarAction.open(); 53 | } 54 | browser.tabs.create({url: "notes/index.html"}); 55 | } 56 | else 57 | { 58 | previousVersion = installedVersion.split("."); 59 | } 60 | 61 | utils.log.debug(previousVersion); 62 | let major = parseInt(previousVersion[0], 10); 63 | let minor = parseInt(previousVersion[1], 10); 64 | let patch; 65 | if(previousVersion[2].includes("a")) 66 | { 67 | patch = -1; // lets make alpha versions comparable in a more easy way 68 | } 69 | else 70 | { 71 | patch = parseInt(previousVersion[2], 10); 72 | } 73 | 74 | if(installedVersion != undefined && (major < 0 || (major == 0 && minor < 13) || (major == 0 && minor == 13 && patch < 0))) 75 | { 76 | if(typeof browser.sidebarAction != "undefined" && typeof browser.sidebarAction.open != "undefined") 77 | { 78 | browser.sidebarAction.open(); 79 | } 80 | browser.tabs.create({url: "notes/index.html"}); 81 | } 82 | }); 83 | } 84 | 85 | let manifest = browser.runtime.getManifest(); 86 | utils.log.debug("manifest version" + manifest.version); 87 | utils.options.save_setting("runtime.vtr.installedVersion", manifest.version); 88 | 89 | utils.log.debug("manage_installation called"); 90 | }); 91 | } 92 | 93 | // Set up listener 94 | 95 | browser.runtime.onInstalled.addListener(manage_installation); 96 | 97 | browser.runtime.onConnect.addListener((port) => 98 | { 99 | sidebarPorts[port.name] = port; 100 | 101 | if(port.sender.id == browser.runtime.id) 102 | { 103 | port.onDisconnect.addListener((port) => 104 | { 105 | delete sidebarPorts[port.name]; 106 | let portInfo = port.name.split("-"); 107 | if(portInfo[0] == "sidebarAction") 108 | { 109 | utils.windows.setSidebarOpenedStatus(portInfo[1], false); 110 | } 111 | }); 112 | 113 | port.onMessage.addListener((message) => 114 | { 115 | if(message["message"]["type"] == "sidebarAction") 116 | { 117 | utils.windows.setSidebarOpenedStatus(message["message"]["windowID"], true); 118 | } 119 | }); 120 | } 121 | }); 122 | 123 | browser.storage.onChanged.addListener(utils.options.on_options_change); 124 | 125 | browser.windows.onCreated.addListener((window) => 126 | { 127 | utils.windows.add(window.id); 128 | }); 129 | 130 | browser.windows.onRemoved.addListener((windowID) => 131 | { 132 | utils.windows.remove(windowID); 133 | }); 134 | 135 | browser.windows.getAll({windowTypes: ["normal", "popup"]}).then((windowInfoArray) => 136 | { 137 | for (let windowInfo of windowInfoArray) 138 | { 139 | utils.windows.add(windowInfo.id); 140 | } 141 | }); 142 | 143 | browser.windows.onFocusChanged.addListener((windowID) => 144 | { 145 | utils.windows.setCurrentWindow(windowID); 146 | }); 147 | 148 | browser.windows.getCurrent().then((currentWindow) => 149 | { 150 | utils.windows.setCurrentWindow(currentWindow.id); 151 | }); 152 | 153 | /* browser.commands.onCommand.addListener((command) => 154 | { 155 | if (command == "toggleTabbrowser") 156 | { 157 | // FIREFIX: FIXME: Firefox dones't count hotkeys as "user input" therefore dones't allow us here to toggle the sidebar... stupid. 158 | if(utils.windows.getSidebarOpenedStatus(utils.windows.getCurrentWindow()) == false) 159 | { 160 | utils.windows.setSidebarOpenedStatus(utils.windows.getCurrentWindow(), true); 161 | browser.sidebarAction.open(); 162 | } 163 | else 164 | { 165 | utils.windows.setSidebarOpenedStatus(utils.windows.getCurrentWindow(), false); 166 | browser.sidebarAction.close(); 167 | } 168 | } 169 | }); */ 170 | 171 | 172 | browser.browserAction.onClicked.addListener(() => 173 | { 174 | if(utils.windows.getSidebarOpenedStatus(utils.windows.getCurrentWindow()) == false) 175 | { 176 | utils.windows.setSidebarOpenedStatus(utils.windows.getCurrentWindow(), true); 177 | // FIXME: Create "does function exists utils module" to tackle different browsers+versions 178 | if(typeof browser.sidebarAction == "undefined" || typeof browser.sidebarAction.open == "undefined") 179 | { 180 | return; 181 | } 182 | browser.sidebarAction.open(); 183 | } 184 | else 185 | { 186 | utils.windows.setSidebarOpenedStatus(utils.windows.getCurrentWindow(), false); 187 | if(typeof browser.sidebarAction == "undefined" || typeof browser.sidebarAction.close == "undefined") 188 | { 189 | return; 190 | } 191 | browser.sidebarAction.close(); 192 | } 193 | }); 194 | 195 | if(typeof browser.runtime.getBrowserInfo == "undefined") 196 | { 197 | // This likely means we are running in Opera, set same setting as in Firefox Nightly 198 | utils.options.set_alpha_settings(); 199 | } 200 | else 201 | { 202 | browser.runtime.getBrowserInfo().then((browserInfo) => 203 | { 204 | let version = browserInfo.version; 205 | 206 | // Enforce debugging, hidden settings and experiment flag to true for Firefox Nightly 207 | if(version.includes("a")) 208 | { 209 | utils.options.set_alpha_settings(); 210 | } 211 | 212 | // Enforce debugging and hidden settings for Firefox Beta 213 | if(version.includes("b")) 214 | { 215 | utils.options.set_beta_settings(); 216 | } 217 | }); 218 | } 219 | 220 | // FIXME: Once we are removing FF 60 (ESR) support and the legacy hotkey import, we can just use utils.options.update_hotkey() here 221 | // Setting hotkey for toggeling the sidebar 222 | utils.options.get_setting("toggleDisplayHotkey").then((value) => 223 | { 224 | browser.commands.update({"name": "_execute_sidebar_action", "shortcut": value}); 225 | }); 226 | -------------------------------------------------------------------------------- /lib/arrive.js: -------------------------------------------------------------------------------- 1 | /* 2 | * arrive.js 3 | * v2.4.1 4 | * https://github.com/uzairfarooq/arrive 5 | * MIT licensed 6 | * 7 | * Copyright (c) 2014-2017 Uzair Farooq 8 | */ 9 | 10 | var Arrive=function(e,t,n){"use strict";function r(e,t,n){l.addMethod(t,n,e.unbindEvent),l.addMethod(t,n,e.unbindEventWithSelectorOrCallback),l.addMethod(t,n,e.unbindEventWithSelectorAndCallback)}function i(e){e.arrive=f.bindEvent,r(f,e,"unbindArrive"),e.leave=d.bindEvent,r(d,e,"unbindLeave")}if(e.MutationObserver&&"undefined"!=typeof HTMLElement){var o=0,l=function(){var t=HTMLElement.prototype.matches||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector;return{matchesSelector:function(e,n){return e instanceof HTMLElement&&t.call(e,n)},addMethod:function(e,t,r){var i=e[t];e[t]=function(){return r.length==arguments.length?r.apply(this,arguments):"function"==typeof i?i.apply(this,arguments):n}},callCallbacks:function(e,t){t&&t.options.onceOnly&&1==t.firedElems.length&&(e=[e[0]]);for(var n,r=0;n=e[r];r++)n&&n.callback&&n.callback.call(n.elem,n.elem);t&&t.options.onceOnly&&1==t.firedElems.length&&t.me.unbindEventWithSelectorAndCallback.call(t.target,t.selector,t.callback)},checkChildNodesRecursively:function(e,t,n,r){for(var i,o=0;i=e[o];o++)n(i,t,r)&&r.push({callback:t.callback,elem:i}),i.childNodes.length>0&&l.checkChildNodesRecursively(i.childNodes,t,n,r)},mergeArrays:function(e,t){var n,r={};for(n in e)e.hasOwnProperty(n)&&(r[n]=e[n]);for(n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);return r},toElementsArray:function(t){return n===t||"number"==typeof t.length&&t!==e||(t=[t]),t}}}(),c=function(){var e=function(){this._eventsBucket=[],this._beforeAdding=null,this._beforeRemoving=null};return e.prototype.addEvent=function(e,t,n,r){var i={target:e,selector:t,options:n,callback:r,firedElems:[]};return this._beforeAdding&&this._beforeAdding(i),this._eventsBucket.push(i),i},e.prototype.removeEvent=function(e){for(var t,n=this._eventsBucket.length-1;t=this._eventsBucket[n];n--)if(e(t)){this._beforeRemoving&&this._beforeRemoving(t);var r=this._eventsBucket.splice(n,1);r&&r.length&&(r[0].callback=null)}},e.prototype.beforeAdding=function(e){this._beforeAdding=e},e.prototype.beforeRemoving=function(e){this._beforeRemoving=e},e}(),a=function(t,r){var i=new c,o=this,a={fireOnAttributesModification:!1};return i.beforeAdding(function(n){var i,l=n.target;(l===e.document||l===e)&&(l=document.getElementsByTagName("html")[0]),i=new MutationObserver(function(e){r.call(this,e,n)});var c=t(n.options);i.observe(l,c),n.observer=i,n.me=o}),i.beforeRemoving(function(e){e.observer.disconnect()}),this.bindEvent=function(e,t,n){t=l.mergeArrays(a,t);for(var r=l.toElementsArray(this),o=0;o0?l.checkChildNodesRecursively(n,t,r,o):"attributes"===e.type&&r(i,t,o)&&o.push({callback:t.callback,elem:i}),l.callCallbacks(o,t)})}function r(e,t){return l.matchesSelector(e,t.selector)&&(e._id===n&&(e._id=o++),-1==t.firedElems.indexOf(e._id))?(t.firedElems.push(e._id),!0):!1}var i={fireOnAttributesModification:!1,onceOnly:!1,existing:!1};f=new a(e,t);var c=f.bindEvent;return f.bindEvent=function(e,t,r){n===r?(r=t,t=i):t=l.mergeArrays(i,t);var o=l.toElementsArray(this);if(t.existing){for(var a=[],s=0;s0&&l.checkChildNodesRecursively(n,t,r,i),l.callCallbacks(i,t)})}function r(e,t){return l.matchesSelector(e,t.selector)}var i={};d=new a(e,t);var o=d.bindEvent;return d.bindEvent=function(e,t,r){n===r?(r=t,t=i):t=l.mergeArrays(i,t),o.call(this,e,t,r)},d},f=new s,d=new u;t&&i(t.fn),i(HTMLElement.prototype),i(NodeList.prototype),i(HTMLCollection.prototype),i(HTMLDocument.prototype),i(Window.prototype);var h={};return r(f,h,"unbindAllArrive"),r(d,h,"unbindAllLeave"),h}}(window,"undefined"==typeof jQuery?null:jQuery,void 0); 11 | -------------------------------------------------------------------------------- /lib/fast-average-color-4.2.0.min.js: -------------------------------------------------------------------------------- 1 | /*! Fast Average Color | © 2018 Denis Seleznev | MIT License | https://github.com/hcodes/fast-average-color/ */ 2 | /* VTR MODIFICATIONS: - Trashhold when a color counts as bright decreased from 128 to 108 */ 3 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.FastAverageColor=e()}(this,function(){"use strict";var _=function(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return function(t,e){var r=[],n=!0,i=!1,o=void 0;try{for(var a,s=t[Symbol.iterator]();!(n=(a=s.next()).done)&&(r.push(a.value),!e||r.length!==e);n=!0);}catch(t){i=!0,o=t}finally{try{!n&&s.return&&s.return()}finally{if(i)throw o}}return r}(t,e);throw new TypeError("Invalid attempt to destructure non-iterable instance")},e=function(){function n(t,e){for(var r=0;r 4 | { 5 | browser.runtime.openOptionsPage(); 6 | }); 7 | -------------------------------------------------------------------------------- /notes/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Croydon/vertical-tabs-reloaded/eea29dc0f66be749f179c07c39cd4d9e785d6d8a/notes/images/banner.png -------------------------------------------------------------------------------- /notes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vertical Tabs Reloaded 6 | 7 | 8 | 9 | 10 | 11 | 12 | 38 | 39 |
40 | 41 |
42 |
43 | 44 |
45 |

Hi! Vertical Tabs Reloaded just got updated.

46 |

You can open the tab sidebar via hotkey (default: Ctrl+Shift+V) or the VTR icon next to the navigation bar.

47 |
48 |
49 |
50 | 51 |
52 |
53 | 54 |
55 |

Changelog Summary for 0.13.0 - Current release

56 |
57 |
58 |
59 |
    60 |
  1. 61 |

    Minified pinned tabs 62 | Pinned tabs are now getting displayed as favicon-only (opt-out). This saves a lot of space for people with many pinned tabs.

    63 |
  2. 64 |
65 | 66 |
    67 |
  1. 68 |

    Improved visibility of favicons 69 | While using a dark theme, dark favicons are now getting inverted for better accessibility.

    70 |
  2. 71 |
72 |
73 |
74 |
    75 |
  1. 76 |

    Further improvements 77 | Tabs can now be dragged & dropped to the bookmark bar to create a new bookmark.
    78 | Tab buttons, like the sound control and the close button, can now be displayed on the left instead of the right side.

    79 |
  2. 80 |
81 |
82 |
83 |
84 |
85 | 86 |
87 |
88 |
    89 |
  1. 90 |

    Visual comparision between version 0.13.0 and 0.12.1

    92 |
  2. 93 |
94 |
95 |
96 |
    97 |
  1. 98 |

    Visual comparision between version 0.13.0 and 0.12.1

    100 |
  2. 101 |
102 |
103 |
104 |
105 |
106 | 107 |
108 |
109 | 110 |
111 |

Changelog Summary for 0.10.0 - 0.12.1

112 |
113 |
114 |
115 |
    116 |
  1. New Context Menu Choices 117 | The context menu now includes: Move tab to new window, reload all tabs, close all tabs below, close all tabs above, close all other tabs, bookmark all (visible) tabs, unload tab, duplicate tab and restore last closed tab.

  2. 118 | 119 |
  3. Better Interoperability 120 | Support of the tab hide API empowers you to use tab group add-ons or similar add-ons seamless with VTR. Also, VTR settings are getting synchronized via Firefox Sync across devices (opt-out).

  4. 121 |
122 |
123 |
124 |
    125 |
  1. Performance Improvements 126 | Opening the sidebar with several thousand tabs could take several minutes with previous versions, now we are talking about several seconds. You can look at some benchmark results here.

  2. 127 | 128 |
  3. More Mouse Gestures 129 | Middle clicks on free space within the sidebar opens now a new tab. There is also a new option which enables to close tabs by middle clicking them (opt-in).

  4. 130 |
131 |
132 |
133 |
    134 |
  1. Further improvements 135 | The tab context menu closes now automatically, when leaving the sidebar with the mouse and on scrolling. The close button can be displayed now on every tab. Tab tooltip can be configured. Many fixes regarding the private mode, multiple windows, tab closing, context menu and sidebar toggling. Also, it is possible again to change the hotkey which toggles the sidebar. Visual help for drag & drop got added.

  2. 136 |
137 |
138 |
139 |
140 |
141 | 142 |
143 |
144 | 145 |
146 |

Important changes in 0.9

147 |
148 | 149 |

With the release of Firefox Quantum 57 all add-ons were required to be re-written from scratch.

150 |

Due to technical changes, Vertical Tabs Reloaded may look and behave differently now. While many things did improve with this update, unfortunately, some functionality was required to be left behind, due to limitations from Firefox itself.
Luckily, most lost features will come back in the future.

151 | 152 |
153 |
154 |
155 |
156 |

Themes

157 |
158 |

All themes got updates.
159 | The Dark and the Light themes got some fine turning, Darwin got a stronger identity, while the Linux and Windows themes got merged into a new theme named Feather. Feather is a bright, minimalistic theme.

160 | Also finally: Pinned tabs are always visible.

161 |
162 |
163 | 164 |
165 |
166 |
167 |

More stable

168 |
169 |

Vertical Tabs Reloaded got a lot more stable overall.
170 | No more crazy behavior. No more errors when opening tabs in fullscreen, disabling Vertical Tabs Reloaded temporary doesn't leave the tab browser broken. Clicks on tabs don't accidentally close them anymore. Overall, a lot of unwanted side effects are gone. 171 |

172 |
173 |
174 | 175 |
176 |
177 |
178 |

Lost features

179 |
180 |

Some features are not available anymore, due to technical limitations from Firefox:
181 | * compact mode (tab icon only)
182 | * tab sidebar can't be shown when in fullscreen
183 | * horizontal tab browser can't be hidden
184 | * no "native" theme
185 | * tab toolbar can't be customized via Firefox customization page
186 | * not compatible with many other add-ons like Tab Mix Plus
187 | 188 |

189 |
190 |
191 |
192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 |
200 |

Roadmap

201 |
202 | 203 |

Many new features are on the road ahead, as well as re-adding removed features:

204 | 214 | 215 |
216 |
217 | 218 |
219 |
220 | 221 |
222 |

Contributing & Donating

223 |
224 | 225 |

Maintaining and supporting this add-on, as well as trying to improve it on the way, requires quite some time.

226 |

I really appreciate anyone, who is contributing code or content, who is donating or helping out in any other way.

227 |

Contributing is saving me time, while donating is supporting me as a person, so that I'm able to invest more time in the development of Vertical Tabs Reloaded myself.
228 | You can also support me by reporting bugs, suggesting improvements on GitHub, share the word about this add-on or by rating Vertical Tabs Reloaded on Mozilla's Add-on page.

229 | 230 |

Thank you!

231 |
232 |
233 | 234 |
235 | 236 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /options/options.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | background-color: initial; 4 | box-sizing: border-box; 5 | color: #222426; 6 | cursor: default; 7 | display: flex; 8 | flex-direction: column; 9 | font: caption; 10 | margin: 0; 11 | padding: 0; 12 | user-select: none; 13 | 14 | } 15 | 16 | body * { 17 | box-sizing: border-box; 18 | text-align: start; 19 | } 20 | 21 | body { 22 | font-size: 1.25em; 23 | } 24 | 25 | @media (prefers-color-scheme: dark) { 26 | * { 27 | color: #fbfbfe; 28 | background-color: #1c1b22; 29 | } 30 | } 31 | 32 | #settings { 33 | width: 100%; 34 | margin-top: 5px; 35 | padding-left: 5px; 36 | } 37 | 38 | table { 39 | border-collapse: collapse; 40 | } 41 | 42 | tr td { 43 | border-top: 1px solid #c1c1c1; 44 | } 45 | 46 | .preferences-description { 47 | font-size: 90.9%; 48 | color: graytext; 49 | /*margin-top: -3px;*/ 50 | white-space: pre-wrap; 51 | } 52 | 53 | a, a:visited, a:hover { 54 | color: inherit; 55 | text-decoration: underline; 56 | } 57 | 58 | a:hover { 59 | color: rgb(10, 141, 255); 60 | text-decoration: underline; 61 | } 62 | 63 | .hidden-setting, 64 | .experimental-setting { 65 | display: none; 66 | } 67 | 68 | button, input, select { 69 | font-size: 0.9em; 70 | min-width: 160px; 71 | } 72 | 73 | input[type="checkbox"], #options-actions-show-notes { 74 | min-width: unset; 75 | } 76 | 77 | /* 78 | select, input { 79 | margin-left: 2px; 80 | } 81 | 82 | button { 83 | padding-right: 10px !important; 84 | padding-left: 10px !important; 85 | } 86 | 87 | select { 88 | padding: 0.1em 3.5em 0.1em 1em !important; 89 | background-image: url("chrome://global/skin/arrow/arrow-dn.gif") !important; 90 | background-position: 91 | calc(100% - 20px) calc(1em + 2px), 92 | calc(100% - 15px) calc(1em + 2px), 93 | 100% 0 !important; 94 | background-size: 95 | 5px 5px, 96 | 5px 5px, 97 | 2.5em 2.5em !important; 98 | background-repeat: no-repeat !important; 99 | box-sizing: border-box !important; 100 | } 101 | 102 | select option { 103 | font-size: 1em; 104 | padding-top: 0.2em; 105 | padding-bottom: 0.2em; 106 | padding-inline-start: 10px; 107 | padding-inline-end: 30px; 108 | }*/ 109 | -------------------------------------------------------------------------------- /options/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vertical Tabs Reloaded Options 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |

17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /options/options.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | if(browser.extension.getBackgroundPage() == null) 4 | { 5 | document.getElementById("settings").insertAdjacentHTML("beforebegin", "

Please open the options page in a regular, non-private window.

"); 6 | } 7 | 8 | var main = browser.extension.getBackgroundPage(); 9 | var utils = main.utils; 10 | var log = utils.log; /* exported log */ 11 | var options = utils.options; 12 | 13 | var blockSaveEvent = false; 14 | 15 | var settings = options.get_options_object(); 16 | 17 | /* exported setDefaultPrefs */ 18 | function setDefaultPrefs() 19 | { 20 | options.restore_default_settings(); 21 | } 22 | 23 | function save_setting(event) 24 | { 25 | if(blockSaveEvent == true) { return; } 26 | 27 | let input = document.getElementById(event.target.id); 28 | let value; 29 | 30 | if(input.type == "checkbox") 31 | { 32 | value = input.checked; 33 | } 34 | else 35 | { 36 | value = input.value; 37 | } 38 | 39 | // main.debug_log(event.target.id + " new value: " + value); 40 | options.save_setting(event.target.id, value); 41 | } 42 | 43 | function build() 44 | { 45 | // This builds the entire setting list from the JSON object 46 | let settingsHTML = ""; 47 | 48 | Object.keys(settings).forEach((k) => 49 | { 50 | let setting = settings[k]; 51 | 52 | let description = "", classHidden = "", addition = ""; 53 | 54 | if(setting.description != undefined) 55 | { 56 | description = '
' + setting.description + ""; 57 | } 58 | 59 | if(setting.hidden == true) 60 | { 61 | classHidden = "hidden-setting"; 62 | } 63 | 64 | if(setting.experimental == true) 65 | { 66 | classHidden += " experimental-setting"; 67 | } 68 | 69 | if(setting.readonly == true) 70 | { 71 | addition = " disabled"; 72 | } 73 | 74 | if(setting.type == "bool") 75 | { 76 | settingsHTML += '
" + description + '
"; 77 | } 78 | 79 | if(setting.type == "string") 80 | { 81 | if(setting.placeholder == undefined) { setting.placeholder = ""; } 82 | 83 | settingsHTML += '' + setting.title + description + ' "; 84 | } 85 | 86 | if(setting.type == "integer") 87 | { 88 | if(setting.placeholder == undefined) { setting.placeholder = ""; } 89 | 90 | settingsHTML += '' + setting.title + description + ' "; 91 | } 92 | 93 | if(setting.type == "menulist") 94 | { 95 | settingsHTML += '' + setting.title + description + ' "; 104 | } 105 | 106 | if(setting.type == "control") 107 | { 108 | settingsHTML += '' + setting.title + description + ' "; 109 | } 110 | }); 111 | 112 | document.getElementById("settings").insertAdjacentHTML("beforeend", settingsHTML); 113 | } 114 | 115 | function load_value(input) 116 | { 117 | // buttons don't have values 118 | if(input.type != "button") 119 | { 120 | options.get_setting(input.id).then(value => 121 | { 122 | if(input.type == "checkbox") 123 | { 124 | document.getElementById(input.id).checked = value; 125 | } 126 | else 127 | { 128 | document.getElementById(input.id).value = value; 129 | } 130 | }); 131 | } 132 | 133 | // main.debug_log("found element:" + input.id); 134 | } 135 | 136 | 137 | function add_events(input) 138 | { 139 | if(input.type == "button") 140 | { 141 | // id of element equals the function which is getting executed on click 142 | input.addEventListener("click", window[input.id]); 143 | } 144 | else 145 | { 146 | input.addEventListener("change", save_setting); 147 | } 148 | } 149 | 150 | /* function all_forms_helper(functionName) 151 | { 152 | var inputs = document.querySelectorAll("input, select, button"); 153 | for (var i = 0; i < inputs.length; i++) 154 | { 155 | let params = [inputs[i]]; 156 | let funcObject = this[functionName]; 157 | funcObject.apply(this, params); 158 | } 159 | } */ 160 | 161 | function update_all_inputs() 162 | { 163 | blockSaveEvent = true; 164 | // all_forms_helper(load_value); 165 | 166 | let inputs = document.querySelectorAll("input, select"); 167 | for (let anInput of inputs) 168 | { 169 | load_value(anInput); 170 | } 171 | 172 | blockSaveEvent = false; 173 | 174 | options.get_setting("showHiddenSettings").then(value => 175 | { 176 | let newDisplay = ""; // see default CSS 177 | 178 | if(value != false) 179 | { 180 | newDisplay = "table-row"; 181 | } 182 | 183 | let elements = document.getElementsByClassName("hidden-setting"); 184 | for(let anElement of elements) 185 | { 186 | // main.debug_log(elements[i]); 187 | anElement.style.display = newDisplay; 188 | } 189 | }); 190 | 191 | options.get_setting("showHiddenSettings").then(value => 192 | { 193 | if(value == false) { return; } 194 | 195 | options.get_setting("experiment").then(value => 196 | { 197 | let newDisplay = ""; // see default CSS 198 | 199 | if(value != false) 200 | { 201 | newDisplay = "table-row"; 202 | } 203 | 204 | let elements = document.getElementsByClassName("experimental-setting"); 205 | for(let anElement of elements) 206 | { 207 | anElement.style.display = newDisplay; 208 | } 209 | }); 210 | }); 211 | } 212 | 213 | /* function oncontentmenu_show_hidden_options() 214 | { 215 | options.save_setting("showHiddenSettings", true); 216 | } */ 217 | 218 | document.addEventListener("DOMContentLoaded", () => 219 | { 220 | document.getElementById("options-actions-show-notes").addEventListener("click", () => 221 | { 222 | browser.tabs.update({url: browser.runtime.getURL("notes/index.html")}); 223 | }); 224 | 225 | options.get_options_file().then(() => 226 | { 227 | build(); 228 | 229 | update_all_inputs(); 230 | 231 | let inputs = document.querySelectorAll("input, select, button"); 232 | for (let anInput of inputs) 233 | { 234 | add_events(anInput); 235 | } 236 | 237 | // document.getElementById("contextmenu-show-hidden-options").onclick = oncontentmenu_show_hidden_options; 238 | 239 | browser.storage.onChanged.addListener(update_all_inputs); 240 | }); 241 | }); 242 | -------------------------------------------------------------------------------- /options/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "style.tab.status": { 3 | "name": "style.tab.status", 4 | "type": "bool", 5 | "title": "Show tab status on text label", 6 | "description": "Unloaded: strike-through; Unread/busy: underline", 7 | "value": false 8 | }, 9 | "events.tab.close.mouse.middleclick": { 10 | "name": "events.tab.close.mouse.middleclick", 11 | "type": "bool", 12 | "title": "Close tabs with mouse middle click", 13 | "description": "This prevents auto-scrolling via middle click", 14 | "value": false 15 | }, 16 | "style.tab.button.close.displayalways": { 17 | "name": "style.tab.button.close.displayalways", 18 | "type": "bool", 19 | "title": "Display the close button on all tabs", 20 | "description": "All tabs except pinned tabs", 21 | "value": false 22 | }, 23 | "style.tab.pinned.minified": { 24 | "name": "style.tab.pinned.minified", 25 | "type": "bool", 26 | "title": "Enable minified pinned tabs", 27 | "description": "Icon-only view", 28 | "value": true 29 | }, 30 | "style.tab.buttons.position": { 31 | "name": "style.tab.buttons.position", 32 | "type": "menulist", 33 | "title": "Position of tab buttons", 34 | "description": "Sound control and close button", 35 | "value": "right", 36 | "options": [ 37 | { 38 | "value": "right", 39 | "label": "Right" 40 | }, 41 | { 42 | "value": "left", 43 | "label": "Left" 44 | } 45 | ] 46 | }, 47 | "style.tab.showUrlInTooltip": { 48 | "name": "style.tab.showUrlInTooltip", 49 | "type": "menulist", 50 | "title": "Configure tab tooltip on mouse over", 51 | "value": "title", 52 | "options": [ 53 | { 54 | "value": "title", 55 | "label": "Title only" 56 | }, 57 | { 58 | "value": "title-url", 59 | "label": "Title - URL" 60 | }, 61 | { 62 | "value": "url-title", 63 | "label": "URL - Title" 64 | }, 65 | { 66 | "value": "url", 67 | "label": "URL only" 68 | } 69 | ] 70 | }, 71 | "menu.context.bookmarks.create.place": { 72 | "name": "menu.context.bookmarks.create.place", 73 | "type": "menulist", 74 | "title": "Choose place for bookmark folders", 75 | "value": "toolbar_____", 76 | "options": [ 77 | { 78 | "value": "toolbar_____", 79 | "label": "Bookmark toolbar" 80 | }, 81 | { 82 | "value": "unfiled_____", 83 | "label": "Unfiled Bookmarks" 84 | } 85 | ] 86 | }, 87 | "theme": { 88 | "name": "theme", 89 | "type": "menulist", 90 | "title": "Theme", 91 | "value": "dark", 92 | "options": [ 93 | { 94 | "value": "dark", 95 | "label": "Dark (recommended)" 96 | }, 97 | { 98 | "value": "light", 99 | "label": "Light (recommended)" 100 | }, 101 | { 102 | "value": "darwin", 103 | "label": "Darwin" 104 | }, 105 | { 106 | "value": "feather", 107 | "label": "Feather" 108 | }, 109 | { 110 | "value": "moonshot", 111 | "label": "Moonshot" 112 | } 113 | ] 114 | }, 115 | "tabtoolbarPosition": { 116 | "name": "tabtoolbarPosition", 117 | "type": "menulist", 118 | "title": "Toolbar Position", 119 | "value": "top", 120 | "options": [ 121 | { 122 | "value": "bottom", 123 | "label": "Bottom" 124 | }, 125 | { 126 | "value": "top", 127 | "label": "Top" 128 | }, 129 | { 130 | "value": "hide", 131 | "label": "Hide" 132 | } 133 | ] 134 | }, 135 | "toggleDisplayHotkey": { 136 | "name": "toggleDisplayHotkey", 137 | "type": "string", 138 | "title": "Hotkey for hiding/showing tab sidebar", 139 | "description": "Learn which values are excepted here", 140 | "value": "Ctrl+Shift+V" 141 | }, 142 | "setDefaultPrefs": { 143 | "name": "setDefaultPrefs", 144 | "type": "control", 145 | "title": "Reset preferences of VTR", 146 | "label": "Restore default preferences" 147 | }, 148 | "options.sync.enabled": { 149 | "name": "options.sync.enabled", 150 | "type": "bool", 151 | "title": "Sync options across all devices", 152 | "description": "You need to have Firefox Sync enabled", 153 | "value": true 154 | }, 155 | "showHiddenSettings": { 156 | "name": "showHiddenSettings", 157 | "type": "bool", 158 | "title": "Display advanced settings", 159 | "value": false, 160 | "hidden": false 161 | }, 162 | "debug": { 163 | "name": "debug", 164 | "type": "bool", 165 | "title": "Enable console logging for debugging", 166 | "value": false, 167 | "hidden": true 168 | }, 169 | "experiment": { 170 | "name": "experiment", 171 | "type": "bool", 172 | "title": "Enable VTR experimental features (**unstable!**)", 173 | "value": false, 174 | "hidden": true 175 | }, 176 | "events.tab.change.on": { 177 | "name": "events.tab.change.on", 178 | "type": "menulist", 179 | "title": "Experimental: Change the active tab on...", 180 | "value": "click", 181 | "hidden": true, 182 | "experimental": true, 183 | "options": [ 184 | { 185 | "value": "click", 186 | "label": "Click only" 187 | }, 188 | { 189 | "value": "hover", 190 | "label": "Hover over tabs" 191 | }, 192 | { 193 | "value": "click-scroll", 194 | "label": "Click or scroll wheel" 195 | } 196 | ] 197 | }, 198 | 199 | "meta.options.time.lastsaved": { 200 | "name": "meta.options.time.lastsaved", 201 | "type": "integer", 202 | "title": "Timestamp, last change of options", 203 | "value": 0, 204 | "hidden": true, 205 | "readonly": true 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /utils/dom.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils */ 4 | 5 | utils["dom"] = class DomUtils 6 | { 7 | static isElementInVisibleArea(DOMElement) 8 | { 9 | let rect = DOMElement.getBoundingClientRect(); 10 | 11 | if(rect.top >= 0 12 | && rect.left >= 0 13 | && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) 14 | && rect.right <= (window.innerWidth || document.documentElement.clientWidth)) 15 | { 16 | return true; 17 | } 18 | 19 | return false; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /utils/log.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils */ 4 | /* exported log */ 5 | 6 | utils["log"] = {}; 7 | var log = utils["log"]; 8 | 9 | utils["log"]["debugEnabled"] = false; 10 | 11 | // Set inital value for debug logging enabled 12 | browser.storage.local.get("debug").then(results => 13 | { 14 | if (results.hasOwnProperty("debug")) 15 | { 16 | utils.log.debugEnabled = results.debug; 17 | } 18 | }); 19 | 20 | utils["log"]["debug"] = function debug_log(output) 21 | { 22 | if(utils["log"]["debugEnabled"] == true) 23 | { 24 | console.log(output); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /utils/namespace-sidebar.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | var main; 5 | var utils; 6 | var log; 7 | // var options; 8 | 9 | if(browser.extension.getBackgroundPage() != null) 10 | { 11 | // REGULAR WINDOWS 12 | main = browser.extension.getBackgroundPage(); 13 | // options = main.utils.options; // see sidebar.js 14 | } 15 | else 16 | { 17 | // PRIVATE WINDOWS 18 | // options = utils.options; // see sidebar.js 19 | } 20 | 21 | // for all windows 22 | utils = {}; 23 | log = utils.log; 24 | -------------------------------------------------------------------------------- /utils/namespace.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var utils = {}; 4 | -------------------------------------------------------------------------------- /utils/options.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils log */ 4 | 5 | // 6 | // Handle addon settings 7 | // 8 | var OptionsUtils = class OptionsUtils 9 | { 10 | constructor() 11 | { 12 | this.settings = {}; 13 | this.initalized = false; 14 | 15 | this.get_options_file(); 16 | } 17 | 18 | get_options_file() 19 | { 20 | return new Promise((fulfill) => 21 | { 22 | if(this.initalized == true) 23 | { 24 | fulfill(true); 25 | } 26 | 27 | var xhr = new XMLHttpRequest(); 28 | xhr.onreadystatechange = () => 29 | { 30 | if(xhr.readyState == 4) // 4 == DONE 31 | { 32 | this.settings = xhr.response; 33 | this.initalized = true; 34 | fulfill(true); 35 | } 36 | }; 37 | 38 | xhr.overrideMimeType("json"); 39 | xhr.responseType = "json"; 40 | 41 | xhr.open("GET", "options/options.json", true); 42 | xhr.send(); 43 | }); 44 | } 45 | 46 | /* exported get_options_object */ 47 | get_options_object() 48 | { 49 | return this.settings; 50 | } 51 | 52 | /* exported restore_default_settings */ 53 | restore_default_settings() 54 | { 55 | Object.keys(this.settings).forEach((optionsElement) => 56 | { 57 | this.restore_default_setting_of(optionsElement); 58 | }); 59 | } 60 | 61 | reset_experimental_features() 62 | { 63 | Object.keys(this.settings).forEach((optionsElement) => 64 | { 65 | if(this.settings[optionsElement]["experimental"] == true) 66 | { 67 | this.restore_default_setting_of(optionsElement); 68 | } 69 | }); 70 | } 71 | 72 | restore_default_setting_of(optionsElement) 73 | { 74 | this.save_setting(this.settings[optionsElement]["name"], this.settings[optionsElement]["value"]); 75 | } 76 | 77 | on_options_change(changes, area) 78 | { 79 | if(area == "sync") 80 | { 81 | Object.keys(changes).forEach((name) => 82 | { 83 | if(name == "meta.options.time.lastsaved" || name == "options.sync.enabled") { return; } 84 | 85 | browser.storage.sync.get("meta.options.time.lastsaved").then(results => 86 | { 87 | if (results.hasOwnProperty("meta.options.time.lastsaved")) 88 | { 89 | // This entire function is a callback, use the globally acccessible utils.options call instead of this 90 | utils.options.get_setting("meta.options.time.lastsaved").then(lastSavedLocal => 91 | { 92 | if(results["meta.options.time.lastsaved"] > lastSavedLocal) 93 | { 94 | let settingsObject = {}; 95 | settingsObject[name] = changes[name]["newValue"]; 96 | browser.storage.local.set(settingsObject).then(error => 97 | { 98 | if(error) 99 | { 100 | log.debug("VTR received sync setting: Could not save option:" + name); 101 | return false; 102 | } 103 | 104 | log.debug("received sync setting: " + name + " => " + changes[name]["newValue"]); 105 | }); 106 | } 107 | }); 108 | } 109 | }); 110 | }); 111 | } 112 | 113 | if(area == "local") 114 | { 115 | Object.keys(changes).forEach(name => 116 | { 117 | if(name == "debug") 118 | { 119 | utils.log.debugEnabled = changes[name]["newValue"]; 120 | } 121 | 122 | if(name == "toggleDisplayHotkey") 123 | { 124 | utils.options.update_hotkey("sidebar.toggling", changes[name]["newValue"]); 125 | } 126 | }); 127 | } 128 | } 129 | 130 | save_setting(name, value) 131 | { 132 | let settingsObject = {}; 133 | settingsObject[name] = value; 134 | 135 | log.debug("save: " + name + " " + value); 136 | 137 | if(name == "experiment" && value == false) 138 | { 139 | this.reset_experimental_features(); 140 | } 141 | 142 | if(name != "meta.options.time.lastsaved" && name != "options.sync.enabled") 143 | { 144 | this.save_setting("meta.options.time.lastsaved", utils.time.getTimestamp()); 145 | } 146 | 147 | browser.storage.local.set(settingsObject).then(error => 148 | { 149 | if(error) 150 | { 151 | return false; 152 | } 153 | }); 154 | 155 | if(name != "options.sync.enabled") 156 | { 157 | this.get_setting("options.sync.enabled").then(syncEnabled => 158 | { 159 | if(syncEnabled != true) { return; } 160 | 161 | browser.storage.sync.set(settingsObject).then(error => 162 | { 163 | if(error) 164 | { 165 | log.debug("VTR sync error!"); 166 | return false; 167 | } 168 | }); 169 | 170 | log.debug("sync setting saved: " + name + " => " + value); 171 | }); 172 | } 173 | 174 | // If sync gets enabled, all values should be copied once 175 | if(name == "options.sync.enabled" && value == true) 176 | { 177 | browser.storage.sync.get("meta.options.time.lastsaved").then(results => 178 | { 179 | if (!results.hasOwnProperty("meta.options.time.lastsaved")) 180 | { 181 | results["meta.options.time.lastsaved"] = -1; 182 | // No sync data exists, copy from local to sync 183 | } 184 | 185 | this.get_setting("meta.options.time.lastsaved").then(lastSavedLocal => 186 | { 187 | log.debug("VTR sync: sync.lastsaved: " + results["meta.options.time.lastsaved"] + " local.lastsaved: " + lastSavedLocal); 188 | 189 | let allStorageSettings; 190 | // Sync is newer then local, copy from sync to local 191 | if(results["meta.options.time.lastsaved"] > lastSavedLocal) 192 | { 193 | allStorageSettings = browser.storage.sync.get(null); 194 | } 195 | 196 | // Local is newer then sync, copy from local to sync 197 | if(results["meta.options.time.lastsaved"] < lastSavedLocal) 198 | { 199 | allStorageSettings = browser.storage.local.get(null); 200 | } 201 | 202 | allStorageSettings.then(storageResults => 203 | { 204 | Object.keys(storageResults).forEach((storageName) => 205 | { 206 | if(name == "meta.options.time.lastsaved" || name == "options.sync.enabled") { return; } 207 | 208 | let settingsObject = {}; 209 | settingsObject[storageName] = storageResults[storageName]; 210 | 211 | if(results["meta.options.time.lastsaved"] > lastSavedLocal) 212 | { 213 | browser.storage.local.set(settingsObject); 214 | 215 | log.debug("VTR sync inital setting from sync to local saved: " + name + " => " + value); 216 | } 217 | 218 | if(results["meta.options.time.lastsaved"] < lastSavedLocal) 219 | { 220 | browser.storage.sync.set(settingsObject); 221 | 222 | log.debug("VTR sync inital setting from local to sync saved: " + name + " => " + value); 223 | } 224 | }); 225 | }); 226 | }); 227 | }); 228 | } 229 | 230 | return true; 231 | } 232 | 233 | get_all_settings() 234 | { 235 | // This is necessary to not only get all actually saved values, but also the default values for unsaved attributes 236 | return new Promise((fulfill, reject) => 237 | { 238 | let allSettings = {}; 239 | 240 | let forEachSetting = (name) => 241 | { 242 | return new Promise((fulfill) => 243 | { 244 | this.get_setting(name).then((value) => 245 | { 246 | let newValue = {}; 247 | newValue[name] = value; 248 | Object.assign(allSettings, newValue); 249 | fulfill(true); 250 | }); 251 | }); 252 | }; 253 | 254 | let allPromises = Object.keys(this.settings).map(forEachSetting); 255 | 256 | Promise.all(allPromises).then(() => 257 | { 258 | fulfill(allSettings); 259 | }); 260 | }).catch( 261 | (reason) => 262 | { 263 | log.debug(reason); 264 | } 265 | ); 266 | } 267 | 268 | get_setting(name) 269 | { 270 | if(name == undefined) 271 | { 272 | return this.get_all_settings(); 273 | } 274 | 275 | return new Promise((fulfill, reject) => 276 | { 277 | browser.storage.local.get(name).then(results => 278 | { 279 | let localDebugOutput = "VTR option '" + name + "': "; 280 | let localDebug = false; 281 | let localDebugWorthwhile = false; 282 | 283 | if (!results.hasOwnProperty(name)) 284 | { 285 | // Debug output for "debug" is causing potentially an endless loop to the extend that browser doesn't react anymore 286 | // if(name != "debug") { localDebug = true; localDebugOutput += "No user value, use default value. "; } 287 | if(this.settings.hasOwnProperty(name)) 288 | { 289 | if(name != "debug") { localDebug = true; localDebugOutput += "No user value; default value is '" + this.settings[name]["value"] + "'. "; } 290 | results[name] = this.settings[name]["value"]; 291 | } 292 | else 293 | { 294 | localDebugWorthwhile = true; 295 | if(name != "debug") { localDebug = true; localDebugOutput += "No default value found."; } 296 | } 297 | } 298 | 299 | if(localDebug == true && localDebugWorthwhile == true) { log.debug(localDebugOutput); } 300 | 301 | fulfill(results[name]); 302 | }).catch( 303 | (reason) => 304 | { 305 | log.debug(reason); 306 | } 307 | ); 308 | }); 309 | } 310 | 311 | set_alpha_settings() 312 | { 313 | // Enforce debugging, hidden settings and experiment flag to true for Firefox Nightly / Opera 314 | this.save_setting("showHiddenSettings", true); 315 | this.save_setting("debug", true); 316 | this.save_setting("experiment", true); 317 | } 318 | 319 | set_beta_settings() 320 | { 321 | // Enforce debugging and hidden settings for Firefox Beta 322 | this.save_setting("showHiddenSettings", true); 323 | this.save_setting("debug", true); 324 | } 325 | 326 | async update_hotkey(name, value) 327 | { 328 | if(name == "sidebar.toggling") 329 | { 330 | try 331 | { 332 | await browser.commands.update({"name": "_execute_sidebar_action", "shortcut": value}); 333 | } 334 | catch (error) 335 | { 336 | this.restore_default_setting_of("toggleDisplayHotkey"); 337 | log.debug(error); 338 | } 339 | } 340 | } 341 | }; 342 | 343 | utils["options"] = new OptionsUtils(); 344 | -------------------------------------------------------------------------------- /utils/tabs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils log */ 4 | 5 | utils["tabs"] = class tabutils 6 | { 7 | static getTargetID(e) 8 | { 9 | // This returns the tabID of a tab, which is always the last element in a HTML ID tag 10 | return parseInt(this.getIDFromHTMLID(e.target.id), 10); 11 | } 12 | 13 | static getIDFromHTMLID(target) 14 | { 15 | let targetArray = target.split("-"); 16 | return parseInt(targetArray[targetArray.length - 1], 10); 17 | } 18 | 19 | static getIndexFrom(tabID) 20 | { 21 | tabID = this._convertIDtoInt(tabID); 22 | 23 | return parseInt(window.document.getElementById("tab-" + tabID).getAttribute("data-index"), 10); 24 | } 25 | 26 | static updateTabIndexes() 27 | { 28 | let index = 0; 29 | for(let tab of window.document.querySelectorAll(".tabbrowser-tab")) 30 | { 31 | tab.setAttribute("data-index", index); 32 | // window.document.getElementById("tab-title-" + utils.tabs.getIDFromHTMLID(tab.id)).innerHTML = index; 33 | index++; 34 | } 35 | } 36 | 37 | static close(tabID) 38 | { 39 | tabID = this._convertIDtoInt(tabID); 40 | 41 | browser.tabs.remove(tabID); 42 | } 43 | 44 | static reload(tabID) 45 | { 46 | tabID = this._convertIDtoInt(tabID); 47 | 48 | browser.tabs.reload(tabID); 49 | } 50 | 51 | // Toggles pinning status 52 | static pin(tabID) 53 | { 54 | tabID = this._convertIDtoInt(tabID); 55 | 56 | browser.tabs.get(tabID).then((tabInfo) => 57 | { 58 | browser.tabs.update(tabID, {"pinned": !tabInfo.pinned}); 59 | }); 60 | } 61 | 62 | // Duplicates a tab 63 | static duplicate(tabID) 64 | { 65 | tabID = this._convertIDtoInt(tabID); 66 | 67 | browser.tabs.duplicate(tabID); 68 | } 69 | 70 | // Toggles muting status 71 | static mute(tabID) 72 | { 73 | tabID = this._convertIDtoInt(tabID); 74 | 75 | browser.tabs.get(tabID).then((tabInfo) => 76 | { 77 | log.debug("muted: " + !tabInfo.mutedInfo.muted); 78 | browser.tabs.update(tabID, {"muted": !tabInfo.mutedInfo.muted}); 79 | }); 80 | } 81 | 82 | // Discard a single tab 83 | static discard(tabID) 84 | { 85 | tabID = this._convertIDtoInt(tabID); 86 | 87 | browser.tabs.discard(tabID); 88 | } 89 | 90 | static moveToNewWindow(tabID) 91 | { 92 | tabID = this._convertIDtoInt(tabID); 93 | 94 | browser.tabs.update(tabID, {active: true}).then(() => 95 | { 96 | browser.windows.create({"tabId": tabID}); 97 | }); 98 | } 99 | 100 | static setIndex(tabID, newIndex) 101 | { 102 | tabID = this._convertIDtoInt(tabID); 103 | 104 | if(typeof newIndex == "string") 105 | { 106 | newIndex = parseInt(newIndex, 10); 107 | } 108 | 109 | browser.tabs.move(tabID, {index: newIndex}); 110 | } 111 | 112 | static async isPinned(tabID) 113 | { 114 | return await this._isTabSomething(tabID, "pinned"); 115 | } 116 | 117 | static async isMuted(tabID) 118 | { 119 | return await this._isTabSomething(tabID, "mutedInfo.muted"); 120 | } 121 | 122 | static reloadAllVisibleTabs() 123 | { 124 | browser.windows.getCurrent({"windowTypes": ["normal"], "populate": true}).then((windowInfo) => 125 | { 126 | for(let tab of windowInfo.tabs) 127 | { 128 | if(tab.hidden == true) { continue; } 129 | 130 | browser.tabs.reload(tab.id); 131 | } 132 | }); 133 | } 134 | 135 | static bookmarkAllVisibleTabs(e, name) 136 | { 137 | if(name == null) 138 | { 139 | name = "tabs"; 140 | } 141 | 142 | utils.options.get_setting("menu.context.bookmarks.create.place").then((bookmarkCreatePlace) => 143 | { 144 | browser.bookmarks.create({"title": name, "type": "folder", "parentId": bookmarkCreatePlace}).then((bookmarkTreeNode) => 145 | { 146 | browser.windows.getCurrent({"windowTypes": ["normal"], "populate": true}).then((windowInfo) => 147 | { 148 | let index = 0; 149 | for(let tab of windowInfo.tabs.reverse()) 150 | { 151 | if(tab.hidden == true) { return; } 152 | browser.bookmarks.create({"title": tab.title, "url": tab.url, "index": index, "type": "bookmark", "parentId": bookmarkTreeNode.id}); 153 | index++; 154 | } 155 | }); 156 | }); 157 | }); 158 | } 159 | 160 | static selectNextToActiveTab(windowID, direction) 161 | { 162 | browser.tabs.query({"windowId": windowID, "active": true}).then((tabs) => 163 | { 164 | if(tabs.length == 0) { return; } 165 | 166 | let newActiveIndex; 167 | 168 | if(direction == "down") 169 | { 170 | newActiveIndex = tabs[0].index + 1; 171 | } 172 | else if(direction == "up") 173 | { 174 | newActiveIndex = tabs[0].index - 1; 175 | } 176 | 177 | let foundNextVisibleTab = false; 178 | while(foundNextVisibleTab == false) 179 | { 180 | browser.tabs.query({"windowId": windowID, "index": newActiveIndex}).then((tabs) => 181 | { 182 | if(tabs.length == 0) { return; } 183 | 184 | if(tabs[0].hidden == false) { foundNextVisibleTab = true; } 185 | 186 | browser.tabs.update(tabs[0].id, {active: true}); 187 | }); 188 | } 189 | }); 190 | } 191 | 192 | static closeTabsRelativeTo(tabID, relativeTyp) 193 | { 194 | let tabIndex = this.getIndexFrom(tabID); 195 | log.debug("Close tabs " + relativeTyp + " from tab index " + tabIndex); 196 | 197 | let closeTheseTabs = []; 198 | for(let tab of window.document.querySelectorAll(".tabbrowser-tab")) 199 | { 200 | if(tab.style.display == "none") { continue; } 201 | 202 | let currentTabID = this.getIDFromHTMLID(tab.id); 203 | let currentTabIndex = this.getIndexFrom(currentTabID); 204 | 205 | if((relativeTyp == "below" && currentTabIndex > tabIndex) 206 | || (relativeTyp == "above" && currentTabIndex < tabIndex) 207 | || (relativeTyp == "others" && currentTabID != tabID)) 208 | { 209 | closeTheseTabs.push(currentTabID); 210 | } 211 | } 212 | 213 | this.updateTabIndexes(); 214 | log.debug(closeTheseTabs); 215 | this.close(closeTheseTabs); 216 | } 217 | 218 | static async restoreLastClosedTab() 219 | { 220 | let lastSession = await browser.sessions.getRecentlyClosed({maxResults: 1}); 221 | if(typeof lastSession[0].tab != "undefined") 222 | { 223 | browser.sessions.restore(lastSession[0].tab.sessionId); 224 | } 225 | } 226 | 227 | static async isActive(tabID) 228 | { 229 | return await this._isTabSomething(tabID, "active"); 230 | } 231 | 232 | static async isDiscarded(tabID) 233 | { 234 | return await this._isTabSomething(tabID, "discarded"); 235 | } 236 | 237 | static isTabElement(HTMLElement) 238 | { 239 | if(HTMLElement == null || typeof HTMLElement.classList == "undefined") 240 | { 241 | return false; 242 | } 243 | 244 | if(HTMLElement.classList.contains("tabbrowser-tab")) 245 | { 246 | return true; 247 | } 248 | 249 | return false; 250 | } 251 | 252 | static async _isTabSomething(tabID, key) 253 | { 254 | tabID = this._convertIDtoInt(tabID); 255 | 256 | let somethingInfo; 257 | 258 | await browser.tabs.get(tabID).then((tabInfo) => 259 | { 260 | if(!key.includes(".")) 261 | { 262 | somethingInfo = tabInfo[key]; 263 | } 264 | else 265 | { 266 | for(let singleKey of key.split(".")) 267 | { 268 | if(somethingInfo == null) 269 | { 270 | somethingInfo = tabInfo[singleKey]; 271 | } 272 | else 273 | { 274 | somethingInfo = somethingInfo[singleKey]; 275 | } 276 | } 277 | } 278 | }); 279 | 280 | return somethingInfo; 281 | } 282 | 283 | static _convertIDtoInt(tabID) 284 | { 285 | if(typeof tabID == "string") 286 | { 287 | tabID = parseInt(tabID, 10); 288 | } 289 | 290 | return tabID; 291 | } 292 | 293 | static removeClassAll(className) 294 | { 295 | const elements = document.querySelectorAll(`.tabbrowser-tab.${className}`); 296 | Array.from(elements).forEach(element => element.classList.remove(className)); 297 | } 298 | }; 299 | -------------------------------------------------------------------------------- /utils/time.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils */ 4 | 5 | // Time & Date Helpers 6 | utils["time"] = class timesutils 7 | { 8 | /* Returns the current UNIX timestamp */ 9 | static getTimestamp() 10 | { 11 | return Math.floor(Date.now() / 1000); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /utils/windows.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* global utils log */ 4 | 5 | let managedWindows = {}; 6 | 7 | // Windows Management 8 | // FIREFIX: FIXME: Not yet able to read the status of the sidebar. Try to workaround #134 9 | utils["windows"] = class windowsutils 10 | { 11 | static add(windowID) 12 | { 13 | log.debug("add window " + windowID); 14 | managedWindows[windowID] = {"sidebarOpened": false}; 15 | } 16 | 17 | static remove(windowID) 18 | { 19 | delete managedWindows[windowID]; 20 | } 21 | 22 | static setSidebarOpenedStatus(windowID, newSidebarOpenedStatus) 23 | { 24 | log.debug("set window status " + windowID + " status: " + newSidebarOpenedStatus); 25 | 26 | if(typeof managedWindows[windowID] == "undefined") 27 | { 28 | this.add(windowID); 29 | } 30 | managedWindows[windowID]["sidebarOpened"] = newSidebarOpenedStatus; 31 | } 32 | 33 | static getSidebarOpenedStatus(windowID) 34 | { 35 | return managedWindows[windowID]["sidebarOpened"]; 36 | } 37 | 38 | static getCurrentWindow() 39 | { 40 | return managedWindows["currentWindow"]; 41 | } 42 | 43 | static setCurrentWindow(windowID) 44 | { 45 | managedWindows["currentWindow"] = windowID; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /vtr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vertical Tabs Reloaded 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | ➕ 14 | ⚙️ 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
    25 |
  • Reload Tab
  • 26 |
  • Unload Tab
  • 27 |
  • Pin/Unpin Tab
  • 28 |
  • Duplicate Tab
  • 29 |
  • Mute/Unmute Tab
  • 30 |
  • Move to New Window
  • 31 |
32 |
33 |
    34 |
  • Reload All Tabs
  • 35 |
  • Bookmark All Tabs
  • 36 |
  • Close All Tabs Above
  • 37 |
  • Close All Tabs Below
  • 38 |
  • Close All Other Tabs
  • 39 |
40 |
41 |
    42 |
  • Restore Closed Tab
  • 43 |
  • Close Tab
  • 44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | --------------------------------------------------------------------------------