1
0
mirror of https://github.com/XFox111/TabsAsideExtension.git synced 2026-07-02 19:52:47 +03:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Michael Gordeev 3e60583427 Minor 1.8 (#34)
- Ability to rename Tab Groups #33
- Added collections view switch #35
2020-08-29 18:39:51 +03:00
Michael Gordeev 10edf4f975 Repo documentation link typos fixed 2020-08-14 14:43:49 +03:00
Michael Gordeev cc854fbd25 Updated README.md 2020-08-11 19:04:20 +03:00
Michael Gordeev ad9acb6208 Create ci.yaml 2020-08-11 18:56:30 +03:00
Michael Gordeev f74eeb5759 [v1.7.3] Firefox compability patch (#32)
- Added Firefox support (#28)
- Updated settings defaults
- Updated `about:` protocol behavior
- Fixed collections header becoming the old one on a tab removing
- Added VS Code debugging config
- Removed trailing whitespaces
2020-08-10 23:46:37 +03:00
Michael Gordeev 80c9dbe1a5 HOTFIX: Chinese language pack path typo fixed 2020-08-05 12:29:01 +03:00
Michael Gordeev c777f1a60a Minor 1.7 (#31)
- Complete UI/UX overhaul
- Updated default hotkeys (#27)
- Added option to disable deletion confirmation (#29)
- Added Chinese translation
- Fixed font artifacts on Windows

Co-authored-by: Dustin-Jiang <56217843+Dustin-Jiang@users.noreply.github.com>
Co-Authored-By: Michael Gordeev <michael@xfox111.net>
2020-08-05 12:07:11 +03:00
Michael Gordeev 1b7b419168 Patch 1.6.1
One tab remove button removes whole collection fixed (#25)
2020-07-18 21:39:15 +03:00
Michael Gordeev 39f7cd391a Minor 1.6 (#24)
- Added localization system (#23)
- Added Russian locale (#23)
- Feedback button link is now based on the extension download source (#20)
- Added badge counter to the extension icon
- Added keyboard shortcuts (#22)
- Added action items to the extension icon context menu (#22)
- Added ability to change primary extension icon action to save tabs instead of opening the pane (#22)
2020-07-15 16:54:50 +03:00
Michael Gordeev 2eae09583c Minor 1.5 (#18)
- Updated repository documentation: added contribution guidelines, Code of Conduct, GitHub templates
- Updated README
- Added confirmation dialog for tabs and collections deletion (#17)
- Complete code refactoring (HTML/JS/CSS)
- Implemented <iframe> base for embedded pane (#13) (Fixed CSS instability on some websites)
- Improved dark theme
- Added opensource fonts to replace Segoe UI on Unix systems (#11, #17)
- Fixed invisible vertical scrollbar
- Code polish and improvement

Co-authored-by: Amine A. <15179425+AmineI@users.noreply.github.com>
Co-Authored-By: Michael Gordeev <michael@xfox111.net>
2020-07-06 10:14:02 +03:00
Michael Gordeev cb45f1a7b3 Minor 1.4 (#16)
- Added ability to disable tabs loading on restoring (#10)
- Extension optimization
- Added "Contributors" page link
- Updated README.md

Co-authored-by: Amine A. <15179425+AmineI@users.noreply.github.com>
Co-Authored-By: Michael Gordeev <michael@xfox111.net>
2020-06-27 12:56:54 +03:00
Michael Gordeev 2b83f3bd60 Patch 1.3.1
Fixed version number
Fixed browser closing
Hid elements of unimplemented features
Added code for issue #10 (help wanted)
2020-06-20 20:38:30 +03:00
Michael Gordeev 386b4f57d9 Minor 1.3 (#9)
* Empty tabs are now ignored (#8)

* Empty collections can't be saved now
2020-06-11 14:13:22 +03:00
26 changed files with 1833 additions and 785 deletions
+33
View File
@@ -0,0 +1,33 @@
---
name: Bug report
about: Create a report to help us improve the extension
title: ''
labels: bug
assignees: ''
---
### Description
A clear and concise description of what the bug is.
### Reproduction steps
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
### Expected behavior
A clear and concise description of what you expected to happen.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Environment
Please provide the following information:
- Operating System: [e.g. Windows 10 Pro 1909 (10.0.18363)]
- Browser: [e.g. Microsoft Edge 83.0.478.56]
- Extension version: [e.g. 1.5]
### Additional context
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when '...'
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+9
View File
@@ -0,0 +1,9 @@
Implements following issues:
## Changelog
- Item 1
- Item 2
- Item 3
## PR Checklist
- [ ] Change extension version in the manifest
+73
View File
@@ -0,0 +1,73 @@
name: CI
on:
workflow_dispatch:
push:
branches: [ master ]
paths:
# Trigger deploy on manifest change
- 'manifest.json'
jobs:
Firefox:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Extension for Firefox
id: web-ext-build
uses: kewisch/action-web-ext@v1
with:
cmd: build
- name: Sign build
id: web-ext-sign
uses: kewisch/action-web-ext@v1
with:
cmd: sign
source: ${{ steps.web-ext-build.outputs.target }}
apiKey: ${{ secrets.FIREFOX_API_KEY }}
apiSecret: ${{ secrets.FIREFOX_CLIENT_SECRET }}
- name: Publish to Firefox Webstore
uses: trmcnvn/firefox-addon@v1
with:
uuid: tabsaside@xfox111.net
xpi: ${{ steps.web-ext-sign.outputs.target }}
manifest: ./manifest.json
api-key: ${{ secrets.FIREFOX_API_KEY }}
api-secret: ${{ secrets.FIREFOX_CLIENT_SECRET }}
- name: Drop artifacts
uses: actions/upload-artifact@v2
with:
name: 'Firefox Artefacts'
path: ${{ steps.web-ext-sign.outputs.target }}
Chrome:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Pack extension
uses: TheDoctor0/zip-release@0.4.1
with:
filename: ./TabsAside.zip
exclusions: '.git/* .vscode/* .github/* *.md'
- name: Publish to Chrome Webstore
uses: SebastienGllmt/chrome-addon@v3
with:
extension: mgmjbodjgijnebfgohlnjkegdpbdjgin
zip: ./TabsAside.zip
client-id: ${{ secrets.CHROME_CLIENT_ID }}
client-secret: ${{ secrets.CHROME_CLIENT_SECRET }}
refresh-token: ${{ secrets.CHROME_REFRESH_TOKEN }}
- name: Drop artifacts
uses: actions/upload-artifact@v2
with:
name: 'Chrome Artifacts'
path: ./TabsAside.zip
+13
View File
@@ -0,0 +1,13 @@
{
"version": "0.2.0",
"configurations":
[
{
"name": "Debug",
"type": "firefox",
"request": "launch",
"reAttach": true,
"addonPath": "${workspaceFolder}"
}
]
}
+76
View File
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at opensource@xfox111.net. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+204
View File
@@ -0,0 +1,204 @@
# Contribution Guidelines
Welcome, and thank you for your interest in contributing to my project!
There are many ways in which you can contribute, beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved.
## Table of Contents
- [Contribution Guidelines](#contribution-guidelines)
- [Table of Contents](#table-of-contents)
- [Asking Questions](#asking-questions)
- [Providing Feedback](#providing-feedback)
- [Reporting Issues](#reporting-issues)
- [Look For an Existing Issue](#look-for-an-existing-issue)
- [Writing Good Bug Reports and Feature Requests](#writing-good-bug-reports-and-feature-requests)
- [Final Checklist](#final-checklist)
- [Follow Your Issue](#follow-your-issue)
- [Contributing to codebase](#contributing-to-codebase)
- [Deploy test version on your browser](#deploy-test-version-on-your-browser)
- [Development workflow](#development-workflow)
- [Release](#release)
- [Coding guidelines](#coding-guidelines)
- [Indentation](#indentation)
- [Names](#names)
- [Comments](#comments)
- [Strings](#strings)
- [Style](#style)
- [Finding an issue to work on](#finding-an-issue-to-work-on)
- [Contributing to translations](#contributing-to-translations)
- [Submitting pull requests](#submitting-pull-requests)
- [Spell check errors](#spell-check-errors)
- [Thank You!](#thank-you)
- [Attribution](#attribution)
## Asking Questions
Have a question? Rather than opening an issue, please ask me directly on opensource@xfox111.net.
## Providing Feedback
Your comments and feedback are welcome.
You can leave your feedbak on feedback@xfox111.net or do it on [Microsoft Edge Add-ons Webstore](https://microsoftedge.microsoft.com/addons/detail/tabs-aside/kmnblllmalkiapkfknnlpobmjjdnlhnd), [Chrome Extensions Webstore](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin) or [Mozilla Add-ons Webstore](https://addons.mozilla.org/firefox/addon/ms-edge-tabs-aside/)
## Reporting Issues
Have you identified a reproducible problem in the extension? Have a feature request? I'd like to hear it! Here's how you can make reporting your issue as effective as possible.
### Look For an Existing Issue
Before you create a new issue, please do a search in [open issues](https://github.com/xfox111/TabsAsideExtension/issues) to see if the issue or feature request has already been filed.
Be sure to scan through the [feature requests](https://github.com/XFox111/TabsAsideExtension/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement).
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment:
* 👍 - upvote
* 👎 - downvote
If you cannot find an existing issue that describes your bug or feature, create a new issue using the guidelines below.
### Writing Good Bug Reports and Feature Requests
File a single issue per problem and feature request. Do not enumerate multiple bugs or feature requests in the same issue.
Do not add your issue as a comment to an existing issue unless they are the same ones. Many issues look similar, but have different causes.
The more information you can provide, the more likely someone will be successful at reproducing the issue and finding a solution.
Please include the following with each issue:
- Current version of the extension
- Your current browser and OS name
- Reproducible steps (1... 2... 3...) that cause the issue
- What you expected to see, versus what you actually saw
- Images, animations, or a link to a video showing the issue occurring
### Final Checklist
Please remember to do the following:
- [ ] Search the issue repository to ensure your report is a new issue
- [ ] Separate issues reports
- [ ] Include as much information as you can to your report
Don't feel bad if the developers can't reproduce the issue right away. They will simply ask for more information!
### Follow Your Issue
Once your report is submitted, be sure to stay in touch with the devs in case they need more help from you.
## Contributing to codebase
If you are interested in writing code to fix issues or implement new awesome features you can follow this guidelines to get a better result
### Deploy test version on your browser
1. Clone repository to local storage using [Git](https://guides.github.com/introduction/git-handbook/)
```
git clone https://github.com/xfox111/TabsAsideExtension.git
```
2. Enable Developers mode on your browser extensions page
3. Click "Load unpacked" button and navigate to the extension root folder (contains `manifest.json`)
4. Done!
Next time you make any changes to the codebase, reload extension by toggling it off and on or by pressing "Reload" button on extensions list page
### Development workflow
This section represents how contributors should interact with codebase implementing features and fixing bugs
1. Getting assigned to the issue
2. Creating a repository fork
3. Making changes to codebase
5. Creating a pull request to `master`
6. Reviewing & completing PR
7. Done
#### Release
Next stage is release. Release performs on every push to master (which makes functional changes to the source code). Release performs manually by @XFox111 into: Chrome webstore, Edge webstore and GitHub releases
### Coding guidelines
#### Indentation
We use tabs, not spaces.
#### Names
The project naming rules inherit [.NET Naming Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines). Nevertheless there'is some distinction with the guidelines as well as additions to the one:
- Use `camelCase` for variables instead of `CamelCase` stated in [Capitalization Conventions](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions#capitalization-rules-for-identifiers)
- Use `snake_case` for file names
#### Comments
Leave as more comments as you can. Remember: the more detailed documentation your code has the less programmers will curse you in the future
#### Strings
Use "double quotes" wherever it's possible
#### Style
- Prefer to use lambda functions
- Put curly braces on new lines
- Wrong:
```
if (condition) {
...
}
```
- Correct:
```
if (condition)
{
...
}
```
- Put spaces between operators and before braces in methods declarations, conditionals and loops
- Wrong:
- `y=k*x+b`
- `function FunctionName()`
- Correct:
- `y = k * x + b`
- `function FunctionName ()`
- Use ternary conditionals wherever it's possible
- Wrong:
```
var s;
if (condition)
s = "Life";
else
s = "Death"
```
- Correct:
```
var s = condition ? "Life" : "Death";
```
- Do not surround loop and conditional bodies with curly braces if they can be avoided
- Wrong:
```
if (condition)
{
console.log("Hello, World!");
}
else
{
return;
}
```
- Correct
```
if (condition)
console.log("Hello, World!");
else
return;
```
### Finding an issue to work on
Check out the [full issues list](https://github.com/XFox111/TabsAsideExtension/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue) for a list of all potential areas for contributions. **Note** that just because an issue exists in the repository does not mean we will accept a contribution. There are several reasons we may not accept a pull request like:
- Performance - One of Tabs Aside core values is to deliver a lightweight extension, that means it should perform well in both real and test environments.
- User experience - Since we want to deliver a lightweight extension, the UX should feel lightweight as well and not be cluttered. Most changes to the UI should go through the issue owner and project owner (@XFox111).
- Architectural - Project owner needs to agree with any architectural impact a change may make. Such things must be discussed with and agreed upon by the project owner.
To improve the chances to get a pull request merged you should select an issue that is labelled with the `help-wanted` or `bug` labels. If the issue you want to work on is not labelled with `help-wanted` or `bug`, you can start a conversation with the project owner asking whether an external contribution will be considered.
To avoid multiple pull requests resolving the same issue, let others know you are working on it by saying so in a comment.
### Contributing to translations
If you want to help us to translate this extension into other languages, please read [this article](https://developer.chrome.com/extensions/i18n)
**Note** that whatever you want to contribute to the codebase, you should do it only after you got assigned on an issue
### Submitting pull requests
To enable us to quickly review and accept your pull requests, always create one pull request per issue and [link the issue in the pull request](https://github.com/blog/957-introducing-issue-mentions). Never merge multiple requests in one unless they have the same root cause. Be sure to follow our [Coding Guidelines](#coding-guidelines) and keep code changes as small as possible. Avoid pure formatting changes to code that has not been modified otherwise. Pull requests should contain tests whenever possible. Fill pull request content according to its template. Deviations from template are not recommended
#### Spell check errors
Pull requests that fix typos are welcomed but please make sure it doesn't touch multiple feature areas, otherwise it will be difficult to review. Pull requests only fixing spell check errors in source code are not recommended.
## Thank You!
Your contributions to open source, large or small, make great projects like this possible. Thank you for taking the time to contribute.
## Attribution
This Contribution Guidelines are adapted from the [Contributing to VS Code](https://github.com/microsoft/vscode/blob/master/CONTRIBUTING.md)
+38 -12
View File
@@ -1,39 +1,65 @@
# Tabs aside for Google Chrome # Tabs aside
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/xfox111/TabsAsideExtension)](https://github.com/xfox111/TabsAsideExtension/releases/latest)
![CI](https://github.com/XFox111/TabsAsideExtension/workflows/CI/badge.svg)
[![Chrome Web Store](https://img.shields.io/chrome-web-store/users/mgmjbodjgijnebfgohlnjkegdpbdjgin?label=Chrome%20Web%20Store%20downloads)](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin) [![Chrome Web Store](https://img.shields.io/chrome-web-store/users/mgmjbodjgijnebfgohlnjkegdpbdjgin?label=Chrome%20Webstore%20downloads)](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin)
[![Chrome Web Store](https://img.shields.io/chrome-web-store/rating/mgmjbodjgijnebfgohlnjkegdpbdjgin)](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin) [![Chrome Web Store](https://img.shields.io/chrome-web-store/rating/mgmjbodjgijnebfgohlnjkegdpbdjgin)](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/xfox111/chromiumtabsaside)](https://github.com/xfox111/chromiumtabsaside/releases/latest)
[![GitHub issues](https://img.shields.io/github/issues/xfox111/chromiumtabsaside)](https://github.com/xfox111/ChromiumTabsAside/issues) [![Mozilla Add-on](https://img.shields.io/amo/users/ms-edge-tabs-aside?label=Firefox%20Webstore%20downloads)](https://addons.mozilla.org/firefox/addon/ms-edge-tabs-aside/)
[![GitHub last commit](https://img.shields.io/github/last-commit/xfox111/chromiumtabsaside)](https://github.com/xfox111/ChromiumTabsAside/commits/master) [![Mozilla Add-on](https://img.shields.io/amo/rating/ms-edge-tabs-aside)](https://addons.mozilla.org/firefox/addon/ms-edge-tabs-aside/)
[![GitHub repo size](https://img.shields.io/github/repo-size/xfox111/chromiumtabsaside?label=repo%20size)](https://github.com/xfox111/ChromiumTabsAside) [![Mozilla Add-on](https://img.shields.io/amo/dw/ms-edge-tabs-aside)](https://addons.mozilla.org/firefox/addon/ms-edge-tabs-aside/)
[![MIT License](https://img.shields.io/github/license/xfox111/chromiumtabsaside)](https://opensource.org/licenses/MIT)
[![GitHub issues](https://img.shields.io/github/issues/xfox111/TabsAsideExtension)](https://github.com/xfox111/TabsAsideExtension/issues)
[![GitHub last commit](https://img.shields.io/github/last-commit/xfox111/TabsAsideExtension)](https://github.com/xfox111/TabsAsideExtension/commits/master)
[![GitHub repo size](https://img.shields.io/github/repo-size/xfox111/TabsAsideExtension?label=repo%20size)](https://github.com/xfox111/TabsAsideExtension)
[![MIT License](https://img.shields.io/github/license/xfox111/TabsAsideExtension)](https://opensource.org/licenses/MIT)
[![Twitter Follow](https://img.shields.io/twitter/follow/xfox111?style=social)](https://twitter.com/xfox111) [![Twitter Follow](https://img.shields.io/twitter/follow/xfox111?style=social)](https://twitter.com/xfox111)
[![GitHub followers](https://img.shields.io/github/followers/xfox111?label=Follow%20@xfox111&style=social)](https://github.com/xfox111) [![GitHub followers](https://img.shields.io/github/followers/xfox111?label=Follow%20@xfox111&style=social)](https://github.com/xfox111)
[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-%40xfox111-orange)](https://buymeacoffee.com/xfox111)
![Tabs aside](https://xfox111.net/images/TabsAside.png) ![Tabs aside](https://xfox111.net/y7xk3z)
If youre like me, you often find yourself with a bunch of open tabs. Youd like to get those tabs out of the way sometimes, but theyre maybe not worth saving as actual bookmarks. If youre like me, you often find yourself with a bunch of open tabs. Youd like to get those tabs out of the way sometimes, but theyre maybe not worth saving as actual bookmarks.
In the Edge browser, Microsoft has introduced a new feature called "Tabs aside" (or Tab groups) which lets you set tabs aside in a sort of temporary workspace so that you can call them back up later. In the Edge browser, Microsoft has introduced a new feature called "Tabs aside" (or Tab groups) which lets you set tabs aside in a sort of temporary workspace so that you can call them back up later.
Unfortunately, in new Chromium-based Microsoft Edge, the devs decided not to implement this must-have-feature. So I've decided to create a browser extension which replicates this awesome feature in Chromium-based browsers Unfortunately, in new Chromium-based Microsoft Edge, the devs decided not to implement this must-have-feature. So I've decided to create a browser extension which replicates this awesome feature
## Features ## Features
- Familiar UI inherited from legacy Microsoft Edge with some improvements - Familiar UI inherited from legacy Microsoft Edge with some improvements
- Auto Dark mode - Auto Dark mode
- Now you can restore one tab from collection without removing - Now you can restore one tab from collection without removing
- Now you can choose if you want to load restored tabs only when you're navigating onto them
- **Now available for Firefox!**
## Download ## Download
- [Google Chrome Webstore](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin) - [Google Chrome Webstore](https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin)
- [Microsoft Edge Add-ons Webstore](https://microsoftedge.microsoft.com/addons/detail/kmnblllmalkiapkfknnlpobmjjdnlhnd) - [Microsoft Edge Add-ons Webstore](https://microsoftedge.microsoft.com/addons/detail/kmnblllmalkiapkfknnlpobmjjdnlhnd)
- [GitHub Releases](https://github.com/xfox111/chromiumtabsaside/releases/latest) - [Firefox Add-ons](https://addons.mozilla.org/firefox/addon/ms-edge-tabs-aside/)
- [GitHub Releases](https://github.com/xfox111/TabsAsideExtension/releases/latest)
## Project roadmap ## Project roadmap
You can go to the project's [roadmap kanban board](https://github.com/XFox111/ChromiumTabsAside/projects/1) and see what have we planned and watch our progress in realtime You can go to the project's [roadmap kanban board](https://github.com/XFox111/TabsAsideExtension/projects/1) and see what have we planned and watch our progress in realtime
## Contributing
There are many ways in which you can participate in the project, for example:
- [Submit bugs and feature requests](https://github.com/xfox111/TabsAsideExtension/issues), and help us verify as they are checked in
- Review [source code changes](https://github.com/xfox111/TabsAsideExtension/pulls)
- Review documentation and make pull requests for anything from typos to new content
If you are interested in fixing issues and contributing directly to the code base, please see the [Contribution Guidelines](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md), which covers the following:
- [How to deploy the extension on your browser](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md#deploy-test-version-on-your-browser)
- [The development workflow](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md#development-workflow), including debugging and running tests
- [Coding guidelines](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md#coding-guidelines)
- [Submitting pull requests](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md#submitting-pull-requests)
- [Finding an issue to work on](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md#finding-an-issue-to-work-on)
- [Contributing to translations](https://github.com/XFox111/TabsAsideExtension/blob/master/CONTRIBUTING.md#contributing-to-translations)
## Code of Conduct
This project has adopted the Contributor Covenant. For more information see the [Code of Conduct](https://github.com/XFox111/TabsAsideExtension/blob/master/CODE_OF_CONDUCT.md)
## Copyrights ## Copyrights
> ©2020 Michael "XFox" Gordeev > ©2020 Michael "XFox" Gordeev
Licensed under [MIT License](https://opensource.org/licenses/MIT) Licensed under [MIT License](https://opensource.org/licenses/MIT)
+49 -33
View File
@@ -2,56 +2,72 @@
<html> <html>
<head> <head>
<title>Tabs aside</title> <title loc="name">Tabs aside</title>
<link id="icon" rel="shortcut icon" type="image/png" href="icons/light/empty/16.png" /> <link id="icon" rel="shortcut icon" type="image/png" href="icons/light/empty/16.png" />
<link rel="stylesheet" type="text/css" href="css/style.css" /> <link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="stylesheet" type="text/css" href="css/style.generic.css" /> <link rel="stylesheet" type="text/css" href="css/style.generic.css" />
<link rel="stylesheet" type="text/css" href="css/style.dark.css" /> <link rel="stylesheet" type="text/css" href="css/style.dark.css" />
<link rel="stylesheet" type="text/css" href="css/style.listview.css" />
<style type="text/css"> <meta charset="utf-8" />
body {
margin: 0px;
overflow: hidden;
}
aside {
transform: none !important;
left: 0px;
width: initial !important;
}
</style>
</head> </head>
<body class="tabsAside"> <body>
<aside class="tabsAside pane"> <div class="tabsAside background">
<header> <aside class="tabsAside pane">
<div> <header>
<h1>Tabs aside</h1> <h1 loc="name">Tabs aside</h1>
<button title="Options">&#xE10C;</button> <button loc_alt="options" class="btn more" title="Options"></button>
<nav> <nav>
<p>
<input type="checkbox" id="loadOnRestore" />
<label loc="loadOnRestore" for="loadOnRestore">Load tabs on restore</label>
</p>
<p>
<input type="checkbox" id="swapIconAction" />
<label loc="swapIconAction" for="swapIconAction">Set tabs aside on extension icon click (Alt+P or right-click to open the pane)</label>
</p>
<p>
<input type="checkbox" id="showDeleteDialog" />
<label loc="showDeleteDialog" for="showDeleteDialog">Show confirmation dialog before deleting an item</label>
</p>
<hr />
<div> <div>
<button value="https://github.com/xfox111/ChromiumTabsAside">Visit GitHub page</button> <button loc="github" value="https://github.com/xfox111/TabsAsideExtension">Visit GitHub page</button>
<button value="https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin">Leave feedback</button> <button loc="contributors" value="https://github.com/XFox111/TabsAsideExtension/graphs/contributors">Project contributors</button>
<button value="https://buymeacoffee.com/xfox111">Buy me a coffee!</button> <button loc="feedback" feedback-button>Leave feedback</button>
<button hidden>Backup saved tabs</button> <button loc="buyMeACoffee" value="https://buymeacoffee.com/xfox111">Buy me a coffee!</button>
</div> </div>
<hr />
<p> <p>
<small>v1.0</small><br /> <small>v1.0</small><br />
Developed by Michael Gordeev (<a href="https://twitter.com/xfox111" <span loc="credits">Developed by Michael Gordeev</span> (<a href="https://twitter.com/xfox111" target="_blank">@xfox111</a>)
target="_blank">@xfox111</a>)
</p> </p>
</nav> </nav>
</div>
<a class="saveTabs">&#xE0AB; Set current tabs aside</a>
<hr />
</header>
<section> <button loc_alt="closePanel" class="btn remove" title="Close panel"></button>
<h2>You have no aside tabs</h1> <a class="saveTabs"><span class="iconArrowRight"></span> <span loc="setAside">Set current tabs aside</span></a>
</section>
</aside> <div class="listviewSwitch tile">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="listviewSwitch list">
<div></div>
<div></div>
<div></div>
</div>
</header>
<section>
<h2 loc="nothingSaved">You have no aside tabs</h2>
</section>
</aside>
</div>
<script type="text/javascript" src="js/aside-script.js"></script> <script type="text/javascript" src="js/aside-script.js"></script>
</body> </body>
+127
View File
@@ -0,0 +1,127 @@
{
"name":
{
"message": "Tabs aside",
"description": "Extension name. Displayed in the manifest and pane header"
},
"description":
{
"message": "Classic Microsoft Edge \"Tabs Aside\" feature",
"description": "Extension description"
},
"author":
{
"message": "Michael \"XFox\" Gordeev",
"description": "Author name"
},
"options":
{
"message": "Options",
"description": "Alternative text for options button in the pane"
},
"closePanel":
{
"message": "Close",
"description": "Alternative text for close panel button"
},
"loadOnRestore":
{
"message": "Load tabs on restore",
"description": "Label for option"
},
"showDeleteDialog":
{
"message": "Show confirmation dialog before deleting an item",
"description": "Label for option"
},
"swapIconAction":
{
"message": "Set tabs aside on extension icon click (%TOGGLE_SHORTCUT% or right-click to open the pane)",
"description": "Label for option"
},
"github":
{
"message": "Visit GitHub page",
"description": "Link title"
},
"contributors":
{
"message": "Project contributors",
"description": "Link title"
},
"feedback":
{
"message": "Leave feedback",
"description": "Link title"
},
"buyMeACoffee":
{
"message": "Buy me a coffee!",
"description": "Link title"
},
"credits":
{
"message": "Developed by Michael 'XFox' Gordeev",
"description": "Options menu credits"
},
"setAside":
{
"message": "Set current tabs aside",
"description": "Save collection action name. Used in the pane, extension context menu and manifest shortcuts"
},
"nothingSaved":
{
"message": "You have no aside tabs",
"description": "Placeholder for empty pane"
},
"removeTab":
{
"message": "Remove tab from collection",
"description": "Button hint on a tab card"
},
"restoreTabs":
{
"message": "Restore tabs",
"description": "Collection restore action link name"
},
"more":
{
"message": "More...",
"description": "Collections' more button title"
},
"restoreNoRemove":
{
"message": "Restore without removing",
"description": "Context action item name"
},
"removeCollection":
{
"message": "Remove collection",
"description": "Collection remove action name"
},
"removeCollectionConfirm":
{
"message": "Are you sure you want to delete this collection?",
"description": "Prompt dialog content on collection deletion"
},
"removeTabConfirm":
{
"message": "Are you sure you want to delete this tab?",
"description": "Prompt dialog content on one tab deletion"
},
"togglePaneContext":
{
"message": "Toggle tabs aside pane",
"description": "Context action name. Used in extension context menu and manifest shortcuts"
},
"noTabsToSave":
{
"message": "No tabs available to save",
"description": "Alert dialog message when there's no tabs to save"
},
"tabs":
{
"message": "items",
"description": "Collection tabs counter label (e.g. 8 items)"
}
}
+127
View File
@@ -0,0 +1,127 @@
{
"name":
{
"message": "Отложенные вкладки",
"description": "Extension name. Displayed in the manifest and pane header"
},
"description":
{
"message": "Функиця отложенных вкладок классического Microsoft Edge",
"description": "Extension description"
},
"author":
{
"message": "Михаил \"XFox\" Гордеев",
"description": "Author name"
},
"options":
{
"message": "Настройки",
"description": "Alternative text for options button in the pane"
},
"closePanel":
{
"message": "Закрыть",
"description": "Alternative text for close panel button"
},
"loadOnRestore":
{
"message": "Загружать вкладки после открытия",
"description": "Label for option"
},
"showDeleteDialog":
{
"message": "Показывать окно подтверждения перед удалением элемента",
"description": "Label for option"
},
"swapIconAction":
{
"message": "Откладывать вкладки при нажатии на иконку расширения (%TOGGLE_SHORTCUT% или правая кнопка мыши для открытия панели)",
"description": "Label for option"
},
"github":
{
"message": "Страница GitHub",
"description": "Link title"
},
"contributors":
{
"message": "Свой вклад вложили",
"description": "Link title"
},
"feedback":
{
"message": "Оставить отзыв",
"description": "Link title"
},
"buyMeACoffee":
{
"message": "Купить мне кофе!",
"description": "Link title"
},
"credits":
{
"message": "Разработано: Михаил 'XFox' Гордеев",
"description": "Options menu credits"
},
"setAside":
{
"message": "Отложить открытые вкладки",
"description": "Save collection action name. Used in the pane, extension context menu and manifest shortcuts"
},
"nothingSaved":
{
"message": "У вас нет отложенных вкладок",
"description": "Placeholder for empty pane"
},
"removeTab":
{
"message": "Удалить вкладку из коллекции",
"description": "Button hint on a tab card"
},
"restoreTabs":
{
"message": "Восстановить вкладки",
"description": "Collection restore action link name"
},
"more":
{
"message": "Больше...",
"description": "Collections' more button title"
},
"restoreNoRemove":
{
"message": "Восстановить без удаления",
"description": "Context action item name"
},
"removeCollection":
{
"message": "Удалить коллекцию",
"description": "Collection remove action name"
},
"removeCollectionConfirm":
{
"message": "Вы уверены, что хотите удалить эту коллекцию?",
"description": "Prompt dialog content on collection deletion"
},
"removeTabConfirm":
{
"message": "Вы уверены, что хотите удалить эту вкладку из коллекции?",
"description": "Prompt dialog content on one tab deletion"
},
"togglePaneContext":
{
"message": "Открыть/закрыть панель",
"description": "Context action name. Used in extension context menu and manifest shortcuts"
},
"noTabsToSave":
{
"message": "Нет доступных для сохранения вкладок",
"description": "Alert dialog message when there's no tabs to save"
},
"tabs":
{
"message": "вкладок",
"description": "Collection tabs counter label (e.g. 8 items)"
}
}
+127
View File
@@ -0,0 +1,127 @@
{
"name":
{
"message": "搁置的标签页",
"description": "Extension name. Displayed in the manifest and pane header"
},
"description":
{
"message": "为Chromium浏览器提供旧版 Microsoft Edge 中的\"搁置标签页\" 功能",
"description": "Extension description"
},
"author":
{
"message": "Michael \"XFox\" Gordeev",
"description": "Author name"
},
"options":
{
"message": "设置",
"description": "Alternative text for options button in the pane"
},
"closePanel":
{
"message": "关闭",
"description": "Alternative text for close panel button"
},
"loadOnRestore":
{
"message": "在重新打开时加载页面",
"description": "Label for option"
},
"showDeleteDialog":
{
"message": "在删除项目之前显示确认对话框",
"description": "Label for option"
},
"swapIconAction":
{
"message": "点击拓展图标来搁置所有标签页 (按%TOGGLE_SHORTCUT%或右键来打开侧栏)",
"description": "Label for option"
},
"github":
{
"message": "查看GitHub页面",
"description": "Link title"
},
"contributors":
{
"message": "项目贡献者",
"description": "Link title"
},
"feedback":
{
"message": "给我们反馈",
"description": "Link title"
},
"buyMeACoffee":
{
"message": "给我买杯咖啡!",
"description": "Link title"
},
"credits":
{
"message": "由Michael 'XFox' Gordeev开发",
"description": "Options menu credits"
},
"setAside":
{
"message": "搁置当前的所有标签页",
"description": "Save collection action name. Used in the pane, extension context menu and manifest shortcuts"
},
"nothingSaved":
{
"message": "你目前没有搁置的标签页",
"description": "Placeholder for empty pane"
},
"removeTab":
{
"message": "从标签页集中移除标签页",
"description": "Button hint on a tab card"
},
"restoreTabs":
{
"message": "恢复标签页",
"description": "Collection restore action link name"
},
"more":
{
"message": "更多...",
"description": "Collections' more button title"
},
"restoreNoRemove":
{
"message": "恢复但不移除标签页",
"description": "Context action item name"
},
"removeCollection":
{
"message": "移除标签页集",
"description": "Collection remove action name"
},
"removeCollectionConfirm":
{
"message": "你确定要移除这个标签页集吗?",
"description": "Prompt dialog content on collection deletion"
},
"removeTabConfirm":
{
"message": "你确定要移除这个标签页吗?",
"description": "Prompt dialog content on one tab deletion"
},
"togglePaneContext":
{
"message": "打开或关闭侧栏",
"description": "Context action name. Used in extension context menu and manifest shortcuts"
},
"noTabsToSave":
{
"message": "没有可以搁置的标签页",
"description": "Alert dialog message when there's no tabs to save"
},
"tabs":
{
"message": "项",
"description": "Collection tabs counter label (e.g. 8 items)"
}
}
-57
View File
@@ -1,57 +0,0 @@
<div class="tabsAside background">
<aside class="tabsAside pane">
<header>
<div>
<h1>Tabs aside</h1>
<button title="Options">&#xE10C;</button>
<nav>
<div>
<button value="https://github.com/xfox111/ChromiumTabsAside">Visit GitHub page</button>
<button value="https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin">Leave feedback</button>
<button value="https://buymeacoffee.com/xfox111">Buy me a coffee!</button>
<!--<button hidden>Backup saved tabs</button>-->
</div>
<p>
<small>v1.0</small><br />
Developed by Michael Gordeev (<a href="https://twitter.com/xfox111" target="_blank">@xfox111</a>)
</p>
</nav>
</div>
<a class="saveTabs">&#xE0AB; Set current tabs aside</a>
<hr />
</header>
<section>
<h2>You have no aside tabs</h1>
<!--<div>
<div>
<span>Tabs: $(tabsCount)</span>
<small>$(timestamp)</small>
<a>Restore tabs</a>
<div>
<button title="More...">&#xE10C;</button>
<nav>
<button>Add tabs to favorites</button>
<button>Share tabs</button>
</nav>
</div>
<button title="Remove collection">&#xE106;</button>
</div>
<div>
<div title="Tab title caption">
<div>
<div></div>
<span>$(title)</span>
<button title="Remove tab from collection">&#xE106;</button>
</div>
</div>
</div>
</div>-->
</section>
</aside>
</div>
+189 -168
View File
@@ -1,260 +1,281 @@
.tabsAside.background .tabsAside.background
{ {
z-index: 9999 !important; background-color: rgba(255, 255, 255, .5);
background-color: rgba(255, 255, 255, .5) !important; position: fixed;
position: fixed !important; top: 0;
top: 0 !important; bottom: 0;
bottom: 0 !important; right: 0;
right: 0 !important; left: 0;
left: 0 !important; transition: .2s;
transition: .2s !important; color: black;
opacity: 0;
color: black !important;
} }
.tabsAside.pane .tabsAside.pane
{ {
font-family: 'Segoe UI', 'Segoe MDL2 Assets' !important; user-select: none;
user-select: none !important; position: fixed;
position: fixed !important;
right: 0px !important; right: 0px;
top: 0px !important; top: 0px;
bottom: 0px !important; bottom: 0px;
overflow: auto !important; overflow: hidden;
display: grid;
width: 40%; grid-template-rows: auto 1fr;
min-width: 500px !important;
background-color: #f7f7f7 !important; width: 100%;
border: 1px solid rgba(100, 100, 100, .5) !important; min-width: 500px;
border-width: 0px 0px 0px 1px !important;
box-sizing: border-box !important;
box-shadow: 6px 0px 12px black !important;
font-size: small !important; background-color: #f7f7f7;
border: 1px solid rgba(100, 100, 100, .5);
border-width: 0px 0px 0px 1px;
box-shadow: 6px 0px 12px black;
transform: translateX(110%); /* Pane is hidden */ font-size: 13px;
transition: .2s !important;
text-align: initial !important; transform: translateX(110%); /* pane is hidded */
transition: .2s;
} }
aside[embedded]
{
width: 500px !important;
}
.tabsAside.pane[opened] .tabsAside.pane[opened]
{ {
transform: translateX(0px) !important; transform: translateX(0px);
} }
/* Pane header*/ /* Pane header*/
.tabsAside.pane > header .tabsAside.pane > header
{ {
margin: 20px 40px !important; z-index: 1;
line-height: initial !important; padding: 14px 20px 16px 20px;
height: initial !important; box-shadow: 0px 0px 5px rgba(0,0,0,.5);
background-color: white;
display: grid;
grid-template-columns: 1fr auto auto;
grid-column-gap: 10px;
grid-row-gap: 30px;
} }
.tabsAside.pane > header > div
{
display: grid !important;
grid-template-columns: 1fr auto !important;
}
.tabsAside.pane > header > div > h1 .tabsAside.pane > header > h1
{ {
margin: 10px 0px !important; margin: 0px 5px;
font-weight: normal !important; font-weight: 500;
font-size: 21pt !important; font-size: 15pt;
direction: initial !important;
color: inherit !important;
line-height: initial !important;
font-family: inherit !important;
} }
.tabsAside.pane > header > div > button .tabsAside.pane > header > nav
{ {
margin: auto !important; top: 45px;
} right: 55px;
.tabsAside.pane > header > div > nav
{
top: 70px !important;
right: 40px !important;
} }
.tabsAside.pane > header > div > nav > div .tabsAside.pane > header nav > p
{ {
box-shadow: 0px 4px 5px -2px rgba(100, 100, 100, .5) !important; margin: 10px;
cursor: initial !important;
overflow: hidden !important;
} }
.tabsAside.pane > header > div > nav > p .tabsAside.pane > header nav > p > a
{
margin: 10px !important;
font-family: inherit !important;
font-size: inherit !important;
line-height: initial !important;
}
.tabsAside.pane > header > div > nav > p > small
{
font-size: inherit !important;
font-family: inherit !important;
}
.tabsAside.pane > header > div > nav > p > a
{ {
text-decoration: none; text-decoration: none;
font-size: inherit !important;
border: none !important;
} }
.tabsAside.pane > header > a .saveTabs
{ {
font-size: inherit; display: inline-grid;
grid-template-columns: 16px auto;
grid-column-gap: 15px;
font-weight: 600;
margin-right: auto;
} }
.tabsAside.pane > header > hr .iconArrowRight
{ {
border: 1px solid #8a8a8a !important; width: 16px;
direction: initial !important; height: 16px;
color: inherit !important; display: inline-block;
height: initial !important; background-repeat: no-repeat;
margin: 6.5px 0px !important; background-size: 16px;
background-position: center;
background-image: url("chrome-extension://__MSG_@@extension_id__/icons/arrowRight.svg"),
url("moz-extension://__MSG_@@extension_id__/icons/arrowRight.svg");
margin: 2px;
} }
.tabsAside.pane section
{
overflow: auto;
}
.tabsAside.pane > section > h2 .tabsAside.pane > section > h2
{ {
color: inherit !important; margin: 20px;
margin: 0px 40px !important; font-weight: normal;
font-weight: normal !important;
font-size: 1.5em !important;
line-height: normal !important;
} }
/* Collection header */ /* Collection header */
.tabsAside.pane > section > div .tabsAside.pane > section > div
{ {
transition: .2s !important; transition: .2s;
} }
.tabsAside.pane > section > div > div:first-child .collectionSet
{ {
margin: 0px 20px !important; background-color: white;
display: grid !important; margin: 10px;
grid-template-columns: auto 1fr auto auto auto !important; border-radius: 5px;
grid-column-gap: 10px !important; border: 1px solid #eee;
align-items: center !important;
} }
.tabsAside.pane > section > div > div:first-child > small .collectionSet:hover
{
box-shadow: 0px 0px 5px rgba(0, 0, 0, .25);
}
.collectionSet .header > *
{
visibility: hidden;
}
.collectionSet:hover .header > *
{
visibility: visible;
}
.collectionSet > .header
{
margin: 10px 10px 0px 20px;
display: grid;
grid-template-columns: 1fr auto auto auto;
grid-column-gap: 10px;
align-items: center;
}
.collectionSet > .header > small
{ {
color: gray !important; color: gray;
font-size: smaller !important; visibility: visible !important;
}
.tabsAside.pane > section > div > div:first-child > span
{
font-weight: 600 !important;
}
.tabsAside.pane > section > div > div:first-child > a
{
font-size: 11pt !important;
line-height: initial !important;
} }
.tabsAside.pane > section > div > div:first-child > div > nav .collectionSet > .header > input
{ {
width: 250px !important; margin: 0px;
margin-top: 40px !important; visibility: visible !important;
right: 50px !important; font-weight: 500;
} border: none;
background: transparent;
}
.collectionSet > .header > input:hover
{
border: 1px solid black;
}
.collectionSet > .header > a
{
font-size: 11pt;
}
.collectionSet > .header > div > nav
{
width: 250px;
right: 60px;
}
/* Tabs collection */ /* Tabs collection */
.tabsAside.pane > section > div > div:last-child .collectionSet > .set
{ {
margin: 0px 0px 0px 20px !important; padding: 5px 10px;
padding: 10px 40px 10px 20px !important; white-space: nowrap;
white-space: nowrap !important; overflow: auto;
overflow: auto !important;
} }
.tabsAside.pane > section > div > div:last-child:hover::-webkit-scrollbar-thumb .collectionSet > .set::-webkit-scrollbar-thumb
{ {
visibility: visible !important; visibility: hidden;
} }
.tabsAside.pane > section > div > div:last-child > div .collectionSet > .set:hover::-webkit-scrollbar-thumb
{ {
width: 175px !important; visibility: visible;
height: 148px !important;
margin: 5px !important;
background-color: #c2c2c2 !important;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail.png");
background-size: cover !important;
background-position-x: center !important;
display: inline-grid !important;
grid-template-rows: 1fr auto !important;
box-shadow: 0px 0px 5px rgba(100, 100, 100, .5) !important;
transition: .25s !important;
cursor: pointer !important;
} }
.tabsAside.pane > section > div > div:last-child > div:hover
.collectionSet > .set > div
{
width: 175px;
height: 148px;
margin: 5px;
background-color: #c2c2c2;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail.png"),
url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail.png");
background-size: cover;
background-position-x: center;
display: inline-grid;
grid-template-rows: 1fr auto;
transition: .25s;
cursor: pointer;
border: 1px solid #eee;
border-radius: 5px;
}
.collectionSet > .set > div:hover
{ {
filter: brightness(120%) !important; box-shadow: 0px 0px 5px rgba(100, 100, 100, .5);
box-shadow: 0px 0px 15px rgba(100, 100, 100, .5) !important;
} }
.tabsAside.pane > section > div > div:last-child > div > div .collectionSet > .set > div > div
{ {
background-color: rgba(233, 233, 233, .75) !important; background-color: rgba(233, 233, 233, .75);
grid-row: 2 !important; grid-row: 2;
display: grid !important; display: grid;
grid-template-columns: auto 1fr auto !important; grid-template-columns: auto 1fr auto;
} }
.tabsAside.pane > section > div > div:last-child > div > div > button .collectionSet > .set > div > div > button
{ {
margin: auto !important; margin: auto;
margin-right: 5px !important; margin-right: 5px;
display: none !important; display: none;
} }
.tabsAside.pane > section > div > div:last-child > div:hover > div > button .collectionSet > .set > div:hover > div > button
{ {
display: initial !important; display: initial;
} }
.tabsAside.pane > section > div > div:last-child > div > div > div .collectionSet > .set > div > div > div
{ {
width: 20px !important; width: 20px;
height: 20px !important; height: 20px;
margin: 10px !important; margin: 8px;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon.png"); background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon.png"),
background-size: 20px !important; url("moz-extension://__MSG_@@extension_id__/images/tab_icon.png");
background-size: 20px;
} }
.tabsAside.pane > section > div > div:last-child > div > div > span .collectionSet > .set > div > div > span
{ {
overflow: hidden !important; overflow: hidden;
margin: auto 0px !important; margin: auto 0px;
margin-right: 10px !important; margin-right: 10px;
line-height: initial !important;
} }
.tabsAside.pane > section > div > div:last-child > div:hover > div > span .collectionSet > .set > div:hover > div > span
{ {
margin-right: 5px !important; margin-right: 5px;
} }
@media only screen and (max-width: 500px) @media only screen and (max-width: 500px)
{ {
.tabsAside.pane .tabsAside.pane
{ {
width: initial !important; width: 100% !important;
left: 0px !important; min-width: initial;
min-width: initial !important;
} }
} }
+69 -19
View File
@@ -1,59 +1,109 @@
.tabsAside[darkmode].background .tabsAside[darkmode].background
{ {
background-color: rgba(0, 0, 0, .5) !important; background-color: rgba(0, 0, 0, .5);
} }
.tabsAside[darkmode] .pane .tabsAside[darkmode] .pane
{ {
background-color: #333333 !important; background-color: #333333;
color: white !important; color: white;
} }
.tabsAside[darkmode] .pane header .iconArrowRight
{
filter: invert();
}
.tabsAside[darkmode] .pane header
{
background-color: #3b3b3b;
}
.tabsAside[darkmode] .saveTabs > div
{
filter: invert();
}
/* Button style */
.tabsAside[darkmode] .pane button .tabsAside[darkmode] .pane button
{ {
color: white !important; filter: invert();
} }
.tabsAside[darkmode] .pane button:hover .tabsAside[darkmode] .pane button:hover
{ {
background-color: gray !important; background-color: gray;
} }
.tabsAside[darkmode] .pane button:active .tabsAside[darkmode] .pane button:active
{ {
background-color: dimgray !important; background-color: dimgray;
} }
.tabsAside[darkmode] .pane > section > div > div:first-child > div:first-child > small .tabsAside[darkmode] .collectionSet > .header > input
{
color: white;
}
.tabsAside[darkmode] .collectionSet > .header > input:hover
{
border: 1px solid dimgray;
}
.tabsAside[darkmode] .collectionSet > .header > input:focus
{
background: white;
color: black;
}
.tabsAside[darkmode] a
{
color: #48adff;
}
/* Timestamp label */
.tabsAside[darkmode] > .pane > section small
{ {
color: lightgray !important; color: lightgray !important;
} }
/* Scrollbar style */
.tabsAside[darkmode] .pane ::-webkit-scrollbar-thumb .tabsAside[darkmode] .pane ::-webkit-scrollbar-thumb
{ {
background: gray !important; background: gray;
border-radius: 3px !important; border-radius: 3px;
} }
.tabsAside[darkmode] .pane ::-webkit-scrollbar-thumb:hover .tabsAside[darkmode] .pane ::-webkit-scrollbar-thumb:hover
{ {
background: dimgray !important; background: dimgray;
} }
.tabsAside[darkmode] .pane > section > div > div:last-child > div .tabsAside[darkmode] .pane .collectionSet
{ {
background-color: #0c0c0c !important; background-color: #3b3b3b;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail_dark.png"); border-color: #444;
} }
.tabsAside[darkmode] .pane > section > div > div:last-child > div > div /* Tab style */
.tabsAside[darkmode] .pane .collectionSet > .set > div
{
background-color: #0c0c0c;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail_dark.png"),
url("moz-extension://__MSG_@@extension_id__/images/tab_thumbnail_dark.png");
border-color: #444;
}
.tabsAside[darkmode] .pane .collectionSet > .set > div > div
{ {
background-color: rgba(50, 50, 50, .75) !important; background-color: rgba(50, 50, 50, .75);
} }
.tabsAside[darkmode] .pane > section > div > div:last-child > div > div > div .tabsAside[darkmode] .pane .collectionSet > .set > div > div > div
{ {
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon_dark.png"); background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon_dark.png"),
url("moz-extension://__MSG_@@extension_id__/images/tab_icon_dark.png");
} }
/* Context menu style */
.tabsAside[darkmode] .pane nav .tabsAside[darkmode] .pane nav
{ {
background-color: #3f3f3f !important; background-color: #3f3f3f;
} }
+87 -76
View File
@@ -1,126 +1,137 @@
/* Custom scrollbar */ /* Custom scrollbar */
.tabsAside ::-webkit-scrollbar .tabsAside ::-webkit-scrollbar
{ {
height: 6px !important; height: 6px;
width: 6px;
} }
.tabsAside ::-webkit-scrollbar-thumb .tabsAside ::-webkit-scrollbar-thumb
{ {
visibility: hidden !important; background: darkgray;
background: darkgray !important; border-radius: 3px;
border-radius: 3px !important;
} }
.tabsAside ::-webkit-scrollbar-thumb:hover .tabsAside ::-webkit-scrollbar-thumb:hover
{ {
background: gray !important; background: gray;
} }
.tabsAside::-webkit-scrollbar .tabsAside
{ {
width: 6px !important; font-family: 'Segoe UI' ,'DefaultFont';
font-size: 14px;
user-select: none;
} }
.tabsAside::-webkit-scrollbar-thumb
{
background: gray !important;
border-radius: 3px !important;
}
.tabsAside::-webkit-scrollbar-thumb:hover
{
background: darkgray !important;
}
/* Links style */ /* Links style */
.tabsAside a .tabsAside a
{ {
font-family: 'Segoe UI', 'Segoe MDL2 Assets' !important; color: #0078d7;
color: #0078d7 !important;
font-weight: 400 !important;
} }
.tabsAside a:hover .tabsAside a:hover
{ {
text-decoration: underline !important; text-decoration: underline;
cursor: pointer !important; cursor: pointer;
} }
.tabsAside a:visited .tabsAside a:visited
{ {
color: #0078d7 !important; color: #0078d7;
} }
/* Buttons style */ /* Buttons style */
.tabsAside button .tabsAside button
{ {
font-family: 'Segoe MDL2 Assets' !important; width: 28px;
width: 32px !important; height: 28px;
height: 32px !important; background-color: transparent;
background-color: transparent !important; border: none;
border: none !important; cursor: pointer;
cursor: pointer !important;
box-shadow: initial !important;
font-size: inherit !important;
padding: initial !important;
position: initial !important;
box-sizing: initial !important;
line-height: initial !important;
text-align: center !important;
border-radius: 2px !important;
min-height: initial !important;
display: initial !important;
min-width: initial !important;
} }
.tabsAside button:hover .tabsAside button:hover
{ {
background-color: #c6c6c6 !important; background-color: #f2f2f2;
} }
.tabsAside button:active .tabsAside button:active
{ {
background-color: gray !important; background-color: gray;
} }
/* Context menus style */ /* Context menus style */
.tabsAside nav .tabsAside nav
{ {
font-family: 'Segoe UI' !important; user-select: none;
user-select: none !important;
position: absolute !important; position: absolute;
width: 250px !important; width: 290px;
box-shadow: 0px 0px 10px black !important; box-shadow: 0px 0px 10px rgba(0,0,0,.5);
background-color: white !important; background-color: white;
border-radius: 5px !important; border-radius: 5px;
z-index: 10 !important; z-index: 10;
visibility: hidden !important; visibility: hidden;
padding: 4px 0px;
display: initial !important;
left: initial !important;
bottom: initial !important;
padding: initial !important;
min-height: initial !important;
font-size: inherit !important;
} }
.tabsAside nav button .tabsAside nav hr
{ {
font-family: 'Segoe UI' !important; border: none;
cursor: pointer !important; height: 1px;
background-color: transparent !important; background-color: lightgray;
border: none !important;
box-sizing: border-box !important;
font-size: medium !important;
text-align: start !important;
padding: 10px !important;
width: 100% !important;
height: initial !important;
} }
.tabsAside button + nav:active, .tabsAside nav button
.tabsAside button:focus + nav
{ {
visibility: visible !important; text-align: start;
}
padding: 0px 10px;
width: 100%;
height: 32px;
font-family: 'Segoe UI' ,'DefaultFont';
}
.tabsAside nav button:hover
{
background-color: #eeee;
}
.tabsAside button + nav:active,
.tabsAside button:focus + nav
{
visibility: visible;
}
/* Icon buttons style */
.btn
{
background-repeat: no-repeat;
background-size: 12px;
background-position: center;
}
.btn.more
{
background-image: url("chrome-extension://__MSG_@@extension_id__/icons/more.svg"),
url("moz-extension://__MSG_@@extension_id__/icons/more.svg");
}
.btn.remove
{
background-image: url("chrome-extension://__MSG_@@extension_id__/icons/cancel.svg"),
url("moz-extension://__MSG_@@extension_id__/icons/cancel.svg");
}
@font-face
{
font-family: 'DefaultFont';
src: local("Segoe UI"),
url("chrome-extension://__MSG_@@extension_id__/fonts/WeblySleekUI/weblysleekuisemilight.ttf") format("truetype"),
url("chrome-extension://__MSG_@@extension_id__/fonts/WeblySleekUI/weblysleekuisemilight.woff") format("woff"),
url("chrome-extension://__MSG_@@extension_id__/fonts/WeblySleekUI/weblysleekuisemilight.woff2") format("woff2"),
url("moz-extension://__MSG_@@extension_id__/fonts/WeblySleekUI/weblysleekuisemilight.ttf") format("truetype"),
url("moz-extension://__MSG_@@extension_id__/fonts/WeblySleekUI/weblysleekuisemilight.woff") format("woff"),
url("moz-extension://__MSG_@@extension_id__/fonts/WeblySleekUI/weblysleekuisemilight.woff2") format("woff2");
}
+58
View File
@@ -0,0 +1,58 @@
.tabsAside[listview] .collectionSet > .header
{
margin-bottom: 5px;
}
.tabsAside[listview] .collectionSet > .set
{
max-height: 250px;
}
.tabsAside[listview] .collectionSet > .set > div
{
width: initial;
height: initial;
background-image: none !important;
display: block;
}
.listviewSwitch
{
width: 20px;
height: 20px;
display: grid;
grid-row-gap: 2px;
grid-column-gap: 2px;
cursor: pointer;
}
.listviewSwitch.tile
{
grid-template-columns: 1fr 1fr;
}
.listviewSwitch > div
{
border-radius: 1px;
background-color: #c2c2c2;
}
.listviewSwitch:hover > div
{
background-color: #a0a0aa;
}
.tabsAside .listviewSwitch.tile > div
{
background-color: gray;
}
.tabsAside[listview] .listviewSwitch.tile > div
{
background-color: #c2c2c2;
}
.tabsAside[listview] .listviewSwitch.list > div
{
background-color: gray;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
<!-- Exported by Character Map UWP -->
<svg height="100%" viewBox="0 42 1021 941" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M1021,512L550.5,982.5L505.5,937.5L899,544L0,544L0,480L899,480L505.5,86.5L550.5,41.5Z" fill="#000000" fill-opacity="1">
</path>
</svg>

After

Width:  |  Height:  |  Size: 320 B

+5
View File
@@ -0,0 +1,5 @@
<!-- Exported by Character Map UWP -->
<svg height="100%" viewBox="122 122 781 781" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M557.5,512L902.5,857.5L857.5,902.5L512,557.5L166.5,902.5L121.5,857.5L466.5,512L121.5,166.5L166.5,121.5L512,466.5L857.5,121.5L902.5,166.5Z" fill="#000000" fill-opacity="1">
</path>
</svg>

After

Width:  |  Height:  |  Size: 375 B

+5
View File
@@ -0,0 +1,5 @@
<!-- Exported by Character Map UWP -->
<svg height="100%" viewBox="64 448 896 128" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M128,448C137,448 145.333,449.667 153,453C160.667,456.333 167.417,460.917 173.25,466.75C179.083,472.583 183.667,479.333 187,487C190.333,494.667 192,503 192,512C192,521 190.333,529.333 187,537C183.667,544.667 179.083,551.417 173.25,557.25C167.417,563.083 160.667,567.667 153,571C145.333,574.333 137,576 128,576C119,576 110.667,574.333 103,571C95.3333,567.667 88.5833,563.083 82.75,557.25C76.9167,551.417 72.3333,544.667 69,537C65.6667,529.333 64,521 64,512C64,503 65.6667,494.667 69,487C72.3333,479.333 76.9167,472.583 82.75,466.75C88.5833,460.917 95.3333,456.333 103,453C110.667,449.667 119,448 128,448ZM512,448C521,448 529.333,449.667 537,453C544.667,456.333 551.417,460.917 557.25,466.75C563.083,472.583 567.667,479.333 571,487C574.333,494.667 576,503 576,512C576,521 574.333,529.333 571,537C567.667,544.667 563.083,551.417 557.25,557.25C551.417,563.083 544.667,567.667 537,571C529.333,574.333 521,576 512,576C503,576 494.667,574.333 487,571C479.333,567.667 472.583,563.083 466.75,557.25C460.917,551.417 456.333,544.667 453,537C449.667,529.333 448,521 448,512C448,503 449.667,494.667 453,487C456.333,479.333 460.917,472.583 466.75,466.75C472.583,460.917 479.333,456.333 487,453C494.667,449.667 503,448 512,448ZM896,448C905,448 913.333,449.667 921,453C928.667,456.333 935.417,460.917 941.25,466.75C947.083,472.583 951.667,479.333 955,487C958.333,494.667 960,503 960,512C960,521 958.333,529.333 955,537C951.667,544.667 947.083,551.417 941.25,557.25C935.417,563.083 928.667,567.667 921,571C913.333,574.333 905,576 896,576C887,576 878.667,574.333 871,571C863.333,567.667 856.583,563.083 850.75,557.25C844.917,551.417 840.333,544.667 837,537C833.667,529.333 832,521 832,512C832,503 833.667,494.667 837,487C840.333,479.333 844.917,472.583 850.75,466.75C856.583,460.917 863.333,456.333 871,453C878.667,449.667 887,448 896,448Z" fill="#000000" fill-opacity="1">
</path>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+288 -264
View File
@@ -1,94 +1,68 @@
if (document.location.protocol == "chrome-extension:") if (window.location === window.parent.location && !window.location.protocol.includes("-extension:")) // For open/close call
InitializeStandalone();
else
{ {
setTimeout(function () var iframe = document.querySelector("iframe.tabsAsideIframe");
if (!iframe)
{ {
var pane = document.querySelector(".tabsAside.pane"); iframe = document.createElement('iframe');
if (pane == null) iframe.setAttribute("class", "tabsAsideIframe");
iframe.style.position = "fixed";
iframe.style.zIndex = "2147483647";
iframe.style.height = "100%";
iframe.style.width = "100%";
iframe.style.top = "0px";
iframe.style.right = "0px";
iframe.style.left = "0px";
iframe.style.bottom = "0px";
iframe.style.border = "none";
iframe.style.background = "transparent";
iframe.style.opacity = 0;
var bodyStyle = document.body.getAttribute("style");
document.body.setAttribute("style", "overflow: hidden !important");
iframe.onload = () => setTimeout(() => iframe.style.opacity = 1, 100);
iframe.src = chrome.extension.getURL("TabsAside.html");
document.body.appendChild(iframe);
}
else
{
iframe.contentWindow.postMessage({ target: "TabsAside", command: "TogglePane" }, "*");
setTimeout(() =>
{ {
var xhr = new XMLHttpRequest(); iframe.remove();
xhr.open('GET', chrome.extension.getURL("collections.html"), true); document.body.setAttribute("style", bodyStyle);
xhr.onreadystatechange = function () }, 250);
{ }
if (this.status !== 200 || document.querySelector("#aside-pane") != null)
return;
if (document.querySelector(".tabsAside.pane") == null)
{
document.body.innerHTML += this.responseText;
chrome.runtime.sendMessage({ command: "loadData" }, function (collections)
{
if (document.querySelector(".tabsAside.pane section div") == null)
collections.forEach(i =>
{
AddCollection(i);
});
});
}
setTimeout(function ()
{
pane = document.querySelector(".tabsAside.pane");
if (window.matchMedia("(prefers-color-scheme: dark)").matches)
pane.parentElement.setAttribute("darkmode", "");
document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside;
document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i =>
{
i.onclick = function () { window.open(i.value, '_blank'); };
});
document.querySelector(".tabsAside.background").addEventListener("click", function (event)
{
if (event.target == pane.parentElement)
{
pane.removeAttribute("opened");
pane.parentElement.style.opacity = 0;
document.body.style.overflow = "";
setTimeout(function ()
{
pane.parentElement.remove();
}, 300);
}
});
pane.setAttribute("opened", "");
pane.parentElement.style.opacity = 1;
document.body.style.overflow = "hidden";
}, 50);
};
xhr.send();
}
else
{
if (pane.hasAttribute("opened"))
{
pane.removeAttribute("opened");
pane.parentElement.style.opacity = 0;
document.body.style.overflow = "";
setTimeout(function ()
{
if (!pane.hasAttribute("opened"))
pane.parentElement.remove();
}, 300);
}
else
{
pane.setAttribute("opened", "");
pane.parentElement.style.opacity = 1;
}
}
}, 50);
} }
else // For init call
Initialize();
function InitializeStandalone() function Initialize()
{ {
pane = document.querySelector(".tabsAside.pane"); var pane = document.querySelector(".tabsAside.pane");
if (!pane)
return;
if (window.location !== window.parent.location)
{
pane.setAttribute("embedded", "");
window.addEventListener('message', event =>
{
if (event.data.target == "TabsAside")
{
pane.parentElement.style.opacity = 0;
pane.removeAttribute("opened");
}
});
}
UpdateLocale();
if (window.matchMedia("(prefers-color-scheme: dark)").matches) if (window.matchMedia("(prefers-color-scheme: dark)").matches)
{ {
@@ -97,20 +71,141 @@ function InitializeStandalone()
} }
document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside; document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside;
document.querySelector(".tabsAside header .btn.remove").addEventListener("click", () =>
chrome.runtime.sendMessage({ command: "togglePane" })
);
document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i => document.querySelector("nav > p > small").textContent = chrome.runtime.getManifest()["version"];
// Tabs dismiss option
var loadOnRestoreCheckbox = document.querySelector("#loadOnRestore");
chrome.storage.sync.get(
{ "loadOnRestore": true },
values => loadOnRestoreCheckbox.checked = values?.loadOnRestore ?? true
);
chrome.storage.onChanged.addListener((changes, namespace) =>
{ {
i.onclick = function () { window.open(i.value, '_blank'); }; if (namespace == 'sync')
for (key in changes)
if (key === 'loadOnRestore')
loadOnRestoreCheckbox.checked = changes[key].newValue
});
loadOnRestoreCheckbox.addEventListener("click", () =>
chrome.storage.sync.set(
{
"loadOnRestore": loadOnRestoreCheckbox.checked
})
);
// Exntension browser icon action
var swapIconAction = document.querySelector("#swapIconAction");
chrome.storage.sync.get(
{ "setAsideOnClick": false },
values => swapIconAction.checked = values?.setAsideOnClick ?? false
);
chrome.storage.onChanged.addListener((changes, namespace) =>
{
if (namespace == 'sync')
for (key in changes)
if (key === 'setAsideOnClick')
swapIconAction.checked = changes[key].newValue
});
swapIconAction.addEventListener("click", () =>
chrome.storage.sync.set(
{
"setAsideOnClick": swapIconAction.checked
})
);
// Deletion confirmation dialog
var showDeleteDialog = document.querySelector("#showDeleteDialog");
chrome.storage.sync.get(
{ "showDeleteDialog": true },
values => showDeleteDialog.checked = values.showDeleteDialog
);
chrome.storage.onChanged.addListener((changes, namespace) =>
{
if (namespace == 'sync')
for (key in changes)
if (key === 'showDeleteDialog')
showDeleteDialog.checked = changes[key].newValue
});
showDeleteDialog.addEventListener("click", () =>
chrome.storage.sync.set(
{
"showDeleteDialog": showDeleteDialog.checked
})
);
// Collections view switch
chrome.storage.sync.get(
{ "listview": false },
values =>
{
if (values?.listview)
pane.setAttribute("listview", "");
}
);
document.querySelectorAll(".listviewSwitch").forEach(i =>
{
i.onclick = (args) =>
{
if (args.currentTarget.classList[1] == "list")
{
pane.setAttribute("listview", "");
chrome.storage.sync.set({ "listview": true });
}
else
{
pane.removeAttribute("listview");
chrome.storage.sync.set({ "listview": false });
}
}
});
chrome.storage.onChanged.addListener((changes, namespace) =>
{
if (namespace == 'sync')
for (key in changes)
if (key === 'listview')
if (changes[key].newValue)
pane.setAttribute("listview", "");
else
pane.removeAttribute("listview");
}); });
chrome.runtime.sendMessage({ command: "loadData" }, function (collections) document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i =>
i.onclick = () =>
{
if (i.hasAttribute("feedback-button"))
{
if (chrome.runtime.getManifest()["update_url"] && chrome.runtime.getManifest()["update_url"].includes("edge.microsoft.com"))
window.open("https://microsoftedge.microsoft.com/addons/detail/tabs-aside/kmnblllmalkiapkfknnlpobmjjdnlhnd", "_blank")
else
window.open("https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin", "_blank")
}
else
window.open(i.value, "_blank");
});
chrome.runtime.sendMessage({ command: "loadData" }, (collections) =>
{ {
if (document.querySelector(".tabsAside.pane section div") == null) if (document.querySelector(".tabsAside.pane section div") == null)
collections.forEach(i => collections.forEach(i =>
{ AddCollection(i));
AddCollection(i);
});
}); });
setTimeout(() => pane.setAttribute("opened", ""), 100);
}
function UpdateLocale()
{
document.querySelectorAll("*[loc]").forEach(i => i.textContent = chrome.i18n.getMessage(i.getAttribute("loc")));
document.querySelectorAll("*[loc_alt]").forEach(i => i.title = chrome.i18n.getMessage(i.getAttribute("loc_alt")));
var swapActionsLabel = document.querySelector("label[loc=swapIconAction]");
chrome.runtime.sendMessage({ command: "getShortcuts" }, (shortcuts) =>
swapActionsLabel.textContent = swapActionsLabel.textContent.replace("%TOGGLE_SHORTCUT%", shortcuts.filter(i => i.name == "toggle-pane")[0].shortcut)
);
} }
function AddCollection(collection) function AddCollection(collection)
@@ -123,75 +218,63 @@ function AddCollection(collection)
for (var i = 0; i < collection.links.length; i++) for (var i = 0; i < collection.links.length; i++)
{ {
rawTabs += rawTabs +=
"<div title='" + collection.titles[i] + "'" + ((collection.thumbnails && collection.thumbnails[i]) ? " style='background-image: url(" + collection.thumbnails[i] + ")'" : "") + ">" + "<div title='" + collection.titles[i] + "'" + ((collection.thumbnails && collection.thumbnails[i]) ? " style='background-image: url(" + collection.thumbnails[i] + ")'" : "") + " value='" + collection.links[i] + "'>" +
"<span value='" + collection.links[i] + "'></span>" + //"<span class='openTab' value='" + collection.links[i] + "'></span>" +
"<div>" + "<div>" +
"<div" + ((collection.icons[i] == 0 || collection.icons[i] == null) ? "" : " style='background-image: url(\"" + collection.icons[i] + "\")'") + "></div>" + "<div" + ((collection.icons[i] == 0 || collection.icons[i] == null) ? "" : " style='background-image: url(\"" + collection.icons[i] + "\")'") + "></div>" +
"<span>" + collection.titles[i] + "</span>" + "<span>" + collection.titles[i] + "</span>" +
"<button title='Remove tab from collection'>&#xE106;</button>" + "<button loc_alt='removeTab' class='btn remove' title='Remove tab from collection'></button>" +
"</div>" + "</div>" +
"</div>"; "</div>";
} }
list.innerHTML += "<div>" + list.innerHTML +=
"<div>" + "<div class='collectionSet'>" +
"<span>Tabs: " + collection.links.length + "</span>" + "<div class='header'>" +
"<small>" + GetAgo(collection.timestamp) + "</small>" + "<input type='text' value='" + (collection.name ?? new Date(collection.timestamp).toDateString()) + "'/>" +
"<a>Restore tabs</a>" + "<a loc='restoreTabs' class='restoreCollection'>Restore tabs</a>" +
"<div>" + "<div>" +
"<button title='More...'>&#xE10C;</button>" + "<button loc_alt='more' class='btn more' title='More...'></button>" +
"<nav>" + "<nav>" +
"<button>Restore without removing</button>" + "<button loc='restoreNoRemove' class='restoreCollection noDelete'>Restore without removing</button>" +
"<button hidden>Add tabs to favorites</button>" + "</nav>" +
"<button hidden>Share tabs</button>" + "</div>" +
"</nav>" + "<button loc_alt='removeCollection' class='btn remove' title='Remove collection'></button>" +
"</div>" + "<small>" + collection.links.length + " " + chrome.i18n.getMessage("tabs") +"</small>" +
"<button title='Remove collection'>&#xE106;</button>" + "</div>" +
"</div>" +
"<div>" + rawTabs + "</div>" + "<div class='set' class='tabsList'>" + rawTabs + "</div>" +
"</div>" "</div>";
list.querySelectorAll("a").forEach(i => UpdateLocale();
{
i.onclick = function () { RestoreTabs(i.parentElement.parentElement) };
});
list.querySelectorAll("nav button:first-child").forEach(i => list.querySelectorAll("input").forEach(i =>
{ i.oninput = (event) => RenameCollection(i.parentElement.parentElement, event.target.value));
i.onclick = function () { RestoreTabs(i.parentElement.parentElement.parentElement.parentElement, false) };
});
list.querySelectorAll("div > div:last-child > div > span").forEach(i => list.querySelectorAll(".restoreCollection").forEach(i =>
{ i.onclick = () => RestoreTabs(i.parentElement.parentElement));
i.onclick = function () {
chrome.runtime.sendMessage(
{
command: "openTab",
url: i.getAttribute("value")
}
);
};
})
document.querySelectorAll(".tabsAside.pane > section > div > div:first-child > button").forEach(i => list.querySelectorAll(".restoreCollection.noDelete").forEach(i =>
{ i.onclick = () => RestoreTabs(i.parentElement.parentElement.parentElement.parentElement, false));
i.onclick = function () { RemoveTabs(i.parentElement.parentElement) };
});
/*document.querySelectorAll(".tabsAside.pane > section > div > div:first-child > div > nav > button:first-child").forEach(i => list.querySelectorAll(".set > div").forEach(i =>
{ i.onclick = (args) =>
i.onclick = function () { AddToFavorites(i.parentElement.parentElement.parentElement.parentElement) }; {
}); if (args.target.localName != "button")
document.querySelectorAll(".tabsAside.pane > section > div > div:first-child > div > nav > button:last-child").forEach(i => chrome.runtime.sendMessage(
{ {
i.onclick = function () { ShareTabs(i.parentElement.parentElement.parentElement.parentElement) }; command: "openTab",
});*/ url: i.getAttribute("value")
}
);
});
document.querySelectorAll(".tabsAside.pane > section > div > div:last-child > div > div > button").forEach(i => document.querySelectorAll(".header .btn.remove").forEach(i =>
{ i.onclick = () => RemoveTabs(i.parentElement.parentElement));
i.onclick = function () { RemoveOneTab(i.parentElement.parentElement) };
}); document.querySelectorAll(".set .btn.remove").forEach(i =>
i.onclick = (args) =>
RemoveOneTab(i.parentElement.parentElement));
} }
function SetTabsAside() function SetTabsAside()
@@ -199,6 +282,16 @@ function SetTabsAside()
chrome.runtime.sendMessage({ command: "saveTabs" }); chrome.runtime.sendMessage({ command: "saveTabs" });
} }
function RenameCollection(collectionData, name)
{
chrome.runtime.sendMessage(
{
command: "renameCollection",
newName: name,
collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1
});
}
function RestoreTabs(collectionData, removeCollection = true) function RestoreTabs(collectionData, removeCollection = true)
{ {
chrome.runtime.sendMessage( chrome.runtime.sendMessage(
@@ -207,137 +300,68 @@ function RestoreTabs(collectionData, removeCollection = true)
removeCollection: removeCollection, removeCollection: removeCollection,
collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1
}, },
function () () =>
{ {
if (!removeCollection) if (removeCollection)
return; RemoveCollectionElement(collectionData);
if (collectionData.parentElement.children.length < 3)
{
RemoveElement(collectionData);
setTimeout(function ()
{
document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden");
}, 250);
}
else
RemoveElement(collectionData);
} }
); );
} }
function RemoveTabs(collectionData) function RemoveTabs(collectionData)
{ {
chrome.runtime.sendMessage( chrome.storage.sync.get({ "showDeleteDialog": true }, values =>
{ {
command: "deleteTabs", if (values.showDeleteDialog && !confirm(chrome.i18n.getMessage("removeCollectionConfirm")))
collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 return;
},
function () chrome.runtime.sendMessage(
{
if (collectionData.parentElement.children.length < 3)
{ {
RemoveElement(collectionData); command: "deleteTabs",
setTimeout(function () collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1
{ },
document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"); () => RemoveCollectionElement(collectionData)
}, 250); );
} });
else
RemoveElement(collectionData);
}
);
}
function AddToFavorites(collectionData)
{
chrome.runtime.sendMessage(
{
command: "toFavorites",
collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1
});
}
function ShareTabs(collectionData)
{
chrome.runtime.sendMessage(
{
command: "share",
collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1
});
} }
function RemoveOneTab(tabData) function RemoveOneTab(tabData)
{ {
chrome.runtime.sendMessage( chrome.storage.sync.get({ "showDeleteDialog": true }, values =>
{ {
command: "removeTab", if (values.showDeleteDialog && !confirm(chrome.i18n.getMessage("removeTabConfirm")))
collectionIndex: Array.prototype.slice.call(tabData.parentElement.parentElement.parentElement.children).indexOf(tabData.parentElement.parentElement) - 1, return;
tabIndex: Array.prototype.slice.call(tabData.parentElement.children).indexOf(tabData)
}, chrome.runtime.sendMessage(
function ()
{
tabData.parentElement.previousElementSibling.children[0].textContent = "Tabs: " + tabData.parentElement.children.length - 1;
if (tabData.parentElement.children.length < 2)
{ {
RemoveElement(tabData.parentElement.parentElement); command: "removeTab",
if (document.querySelector("tabsAside.pane > section").children.length < 2) collectionIndex: Array.prototype.slice.call(tabData.parentElement.parentElement.parentElement.children).indexOf(tabData.parentElement.parentElement) - 1,
setTimeout(function () tabIndex: Array.prototype.slice.call(tabData.parentElement.children).indexOf(tabData)
{ },
document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"); () =>
}, 250); {
} tabData.parentElement.previousElementSibling.querySelector("small").textContent = (tabData.parentElement.children.length - 1) + " " + chrome.i18n.getMessage("tabs");
else if (tabData.parentElement.children.length < 2)
RemoveElement(tabData); {
}); RemoveElement(tabData.parentElement.parentElement);
} if (document.querySelector("tabsAside.pane > section").children.length < 2)
setTimeout(() => document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"), 250);
function GetAgo(timestamp) }
{ else
var minutes = (Date.now() - timestamp) / 60000; RemoveElement(tabData);
});
if (minutes < 1) });
return "Just now";
else if (Math.floor(minutes) == 1)
return "1 minute ago";
else if (minutes < 60)
return Math.floor(minutes) + " minutes ago";
else if (Math.floor(minutes / 60) == 1)
return "1 hour ago";
else if (minutes < 24 * 60)
return Math.floor(minutes / 60) + " hours ago";
else if (Math.floor(minutes / 24 / 60) == 1)
return "1 day ago";
else if (minutes < 7 * 24 * 60)
return Math.floor(minutes / 24 / 60) + " days ago";
else if (Math.floor(minutes / 7 / 24 / 60) == 1)
return "1 week ago";
else if (minutes < 30 * 24 * 60)
return Math.floor(minutes / 7 / 24 / 60) + " weeks ago";
else if (Math.floor(minutes / 30 / 24 / 60) == 1)
return "1 month ago";
else if (minutes < 365 * 24 * 60)
return Math.floor(minutes / 30 / 24 / 60) + " months ago";
else if (Math.floor(minutes / 24 / 60) == 365)
return "1 year ago";
else
return Math.floor(minutes / 365 / 24 / 60) + "years ago";
} }
function RemoveElement(el) function RemoveElement(el)
{ {
el.style.opacity = 0; el.style.opacity = 0;
setTimeout(function () setTimeout(() => el.remove(), 200);
{
el.remove();
}, 200);
} }
// TODO: Add more actions function RemoveCollectionElement(el)
// TODO: Make backup system {
if (el.parentElement.children.length < 3)
setTimeout(() => document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"), 250);
RemoveElement(el);
}
+160 -145
View File
@@ -1,28 +1,10 @@
chrome.browserAction.onClicked.addListener(function (tab) function TogglePane(tab)
{ {
if (tab.url.startsWith("http") if (tab.url.startsWith("http")
&& !tab.url.includes("chrome.google.com") && !tab.url.includes("chrome.google.com")
&& !tab.url.includes("microsoftedge.microsoft.com")) && !tab.url.includes("addons.mozilla.org")
&& !tab.url.includes("microsoftedge.microsoft.com"))
{ {
chrome.tabs.insertCSS(
{
file: "css/style.css",
allFrames: true,
runAt: "document_idle"
});
chrome.tabs.insertCSS(
{
file: "css/style.generic.css",
allFrames: true,
runAt: "document_idle"
});
chrome.tabs.insertCSS(
{
file: "css/style.dark.css",
allFrames: true,
runAt: "document_idle"
});
chrome.tabs.executeScript(tab.id, chrome.tabs.executeScript(tab.id,
{ {
file: "js/aside-script.js", file: "js/aside-script.js",
@@ -30,92 +12,89 @@ chrome.browserAction.onClicked.addListener(function (tab)
runAt: "document_idle" runAt: "document_idle"
}); });
} }
else if (tab.url.startsWith("chrome-extension") && tab.url.endsWith("TabsAside.html")) else if (tab.url == chrome.runtime.getURL("TabsAside.html"))
chrome.tabs.remove(tab.id); chrome.tabs.remove(tab.id);
else else
{ {
chrome.tabs.create({ chrome.tabs.create(
url: chrome.extension.getURL("TabsAside.html"),
active: true
});
}
});
chrome.tabs.onActivated.addListener(function (activeInfo)
{
chrome.tabs.query({ url: chrome.extension.getURL("TabsAside.html") }, function (result)
{
if (result.length)
setTimeout(function ()
{ {
result.forEach(i => url: chrome.extension.getURL("TabsAside.html"),
active: true
},
(activeTab) =>
chrome.tabs.onActivated.addListener(function TabsAsideCloser(activeInfo)
{ {
if (activeInfo.tabId != i.id) chrome.tabs.query({ url: chrome.extension.getURL("TabsAside.html") }, (result) =>
chrome.tabs.remove(i.id);
});
}, 200);
});
});
function UpdateTheme()
{
if (window.matchMedia("(prefers-color-scheme: dark)").matches)
{
if (collections.length)
chrome.browserAction.setIcon(
{
path:
{ {
"128": "icons/dark/full/128.png", if (result.length)
"48": "icons/dark/full/48.png", setTimeout(() =>
"32": "icons/dark/full/32.png", {
"16": "icons/dark/full/16.png" result.forEach(i =>
} {
}); if (activeInfo.tabId != i.id)
else chrome.tabs.remove(i.id);
chrome.browserAction.setIcon( });
{ }, 200);
path: else chrome.tabs.onActivated.removeListener(TabsAsideCloser);
{ });
"128": "icons/dark/empty/128.png", }));
"48": "icons/dark/empty/48.png",
"32": "icons/dark/empty/32.png",
"16": "icons/dark/empty/16.png"
}
});
}
else
{
if (collections.length)
chrome.browserAction.setIcon(
{
path:
{
"128": "icons/light/full/128.png",
"48": "icons/light/full/48.png",
"32": "icons/light/full/32.png",
"16": "icons/light/full/16.png"
}
});
else
chrome.browserAction.setIcon(
{
path:
{
"128": "icons/light/empty/128.png",
"48": "icons/light/empty/48.png",
"32": "icons/light/empty/32.png",
"16": "icons/light/empty/16.png"
}
});
} }
} }
var collections = JSON.parse(localStorage.getItem("sets")); function ProcessCommand(command)
if (collections == null) {
collections = []; switch(command)
{
case "set-aside":
SaveCollection();
break;
case "toggle-pane":
chrome.tabs.query(
{
active: true,
currentWindow: true
},
(tabs) => TogglePane(tabs[0])
)
break;
}
}
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) chrome.browserAction.onClicked.addListener((tab) =>
{
chrome.storage.sync.get({ "setAsideOnClick": false }, values =>
{
if (values?.setAsideOnClick)
SaveCollection();
else
TogglePane(tab);
});
});
// Adding context menu options
chrome.contextMenus.create(
{
id: "toggle-pane",
contexts: ['all'],
title: chrome.i18n.getMessage("togglePaneContext")
}
);
chrome.contextMenus.create(
{
id: "set-aside",
contexts: ['all'],
title: chrome.i18n.getMessage("setAside")
}
);
var collections = JSON.parse(localStorage.getItem("sets")) || [];
var shortcuts;
chrome.commands.getAll((commands) => shortcuts = commands);
chrome.commands.onCommand.addListener(ProcessCommand);
chrome.contextMenus.onClicked.addListener((info) => ProcessCommand(info.menuItemId));
chrome.runtime.onMessage.addListener((message, sender, sendResponse) =>
{ {
switch (message.command) switch (message.command)
{ {
@@ -140,39 +119,69 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse)
RemoveTab(message.collectionIndex, message.tabIndex); RemoveTab(message.collectionIndex, message.tabIndex);
sendResponse(); sendResponse();
break; break;
case "toFavorites": case "renameCollection":
AddTabsToFavorites(message.collectionIndex); collections[message.collectionIndex].name = message.newName;
localStorage.setItem("sets", JSON.stringify(collections));
break; break;
case "share": case "togglePane":
ShareTabs(message.collectionIndex); chrome.tabs.query(
{
active: true,
currentWindow: true
},
(tabs) => TogglePane(tabs[0])
)
break;
case "getShortcuts":
sendResponse(shortcuts);
break; break;
} }
}); });
// This function updates the extension's toolbar icon
function UpdateTheme()
{
// Updating badge counter
chrome.browserAction.setBadgeText({ text: collections.length < 1 ? "" : collections.length.toString() });
if (chrome.theme) // Firefox sets theme automatically
return;
var theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
var iconStatus = collections.length ? "full" : "empty";
var basePath = "icons/" + theme + "/" + iconStatus + "/";
chrome.browserAction.setIcon(
{
path:
{
"128": basePath + "128.png",
"48": basePath + "48.png",
"32": basePath + "32.png",
"16": basePath + "16.png"
}
});
}
UpdateTheme(); UpdateTheme();
chrome.windows.onCreated.addListener(UpdateTheme);
chrome.windows.onRemoved.addListener(UpdateTheme);
chrome.windows.onFocusChanged.addListener(UpdateTheme); chrome.windows.onFocusChanged.addListener(UpdateTheme);
chrome.tabs.onUpdated.addListener(UpdateTheme); chrome.tabs.onUpdated.addListener(UpdateTheme);
chrome.tabs.onCreated.addListener(UpdateTheme);
chrome.tabs.onMoved.addListener(UpdateTheme);
chrome.tabs.onSelectionChanged.addListener(UpdateTheme);
chrome.tabs.onActiveChanged.addListener(UpdateTheme);
chrome.tabs.onActivated.addListener(UpdateTheme); chrome.tabs.onActivated.addListener(UpdateTheme);
chrome.tabs.onHighlightChanged.addListener(UpdateTheme);
chrome.tabs.onHighlighted.addListener(UpdateTheme);
chrome.tabs.onDetached.addListener(UpdateTheme);
chrome.tabs.onAttached.addListener(UpdateTheme);
chrome.tabs.onRemoved.addListener(UpdateTheme);
chrome.tabs.onReplaced.addListener(UpdateTheme);
// Set current tabs aside
function SaveCollection() function SaveCollection()
{ {
chrome.tabs.query({ currentWindow: true }, function (tabs) chrome.tabs.query({ currentWindow: true }, (rawTabs) =>
{ {
tabs = tabs.filter(i => !i.url.startsWith("chrome-extension") && !i.url.endsWith("TabsAside.html") && !i.pinned); var tabs = rawTabs.filter(i => i.url != chrome.runtime.getURL("TabsAside.html") && !i.pinned && !i.url.includes("//newtab") && !i.url.includes("about:blank") && !i.url.includes("about:home"));
if (tabs.length < 1)
{
alert(chrome.i18n.getMessage("noTabsToSave"));
return;
}
var collection = var collection =
{ {
timestamp: Date.now(), timestamp: Date.now(),
@@ -196,11 +205,15 @@ function SaveCollection()
collections = JSON.parse(localStorage.getItem("sets")); collections = JSON.parse(localStorage.getItem("sets"));
chrome.tabs.create({}); var newTabId;
chrome.tabs.remove(tabs.map(tab => tab.id)); chrome.tabs.create({}, (tab) =>
}); {
newTabId = tab.id;
chrome.tabs.remove(rawTabs.filter(i => !i.pinned && i.id != newTabId).map(tab => tab.id));
});
UpdateTheme(); UpdateTheme();
});
} }
function DeleteCollection(collectionIndex) function DeleteCollection(collectionIndex)
@@ -213,12 +226,28 @@ function DeleteCollection(collectionIndex)
function RestoreCollection(collectionIndex, removeCollection) function RestoreCollection(collectionIndex, removeCollection)
{ {
collections[collectionIndex].links.forEach(i => collections[collectionIndex].links.forEach(i =>
{ {
chrome.tabs.create( chrome.tabs.create(
{ {
url: i, url: i,
active: false active: false
},
(createdTab) =>
{
chrome.storage.sync.get({ "loadOnRestore" : true }, values =>
{
if (!(values?.loadOnRestore))
chrome.tabs.onUpdated.addListener(function DiscardTab(updatedTabId, changeInfo, updatedTab)
{
if (updatedTabId === createdTab.id) {
chrome.tabs.onUpdated.removeListener(DiscardTab);
if (!updatedTab.active) {
chrome.tabs.discard(updatedTabId);
}
}
});
});
}); });
}); });
@@ -231,24 +260,6 @@ function RestoreCollection(collectionIndex, removeCollection)
UpdateTheme(); UpdateTheme();
} }
function AddTabsToFavorites(collectionIndex)
{
alert("Adding to favorites");
/*for (var i = 0; i < collections[collectionIndex].links.length; i++)
{
chrome.bookmarks.create(
{
title: collections[collectionIndex].titles[i],
url: collections[collectionIndex].links[i],
});
}*/
}
function ShareTabs(collectionId)
{
alert("Sharing");
}
function RemoveTab(collectionIndex, tabIndex) function RemoveTab(collectionIndex, tabIndex)
{ {
var set = collections[collectionIndex]; var set = collections[collectionIndex];
@@ -286,7 +297,7 @@ function RemoveTab(collectionIndex, tabIndex)
var thumbnails = []; var thumbnails = [];
function AppendThumbnail(tabId, cahngeInfo, tab) function AppendThumbnail(tabId, tab)
{ {
if (!tab.active || !tab.url.startsWith("http")) if (!tab.active || !tab.url.startsWith("http"))
return; return;
@@ -296,9 +307,9 @@ function AppendThumbnail(tabId, cahngeInfo, tab)
format: "jpeg", format: "jpeg",
quality: 1 quality: 1
}, },
function (dataUrl) (dataUrl) =>
{ {
if(!dataUrl) if (!dataUrl)
{ {
console.log("Failed to retrieve thumbnail"); console.log("Failed to retrieve thumbnail");
return; return;
@@ -319,4 +330,8 @@ function AppendThumbnail(tabId, cahngeInfo, tab)
); );
} }
chrome.tabs.onUpdated.addListener(AppendThumbnail); chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) =>
{
if (changeInfo.status === "complete")
AppendThumbnail(tabId, tab)
});
+71 -11
View File
@@ -1,29 +1,89 @@
{ {
"name": "Tabs Aside", "name": "__MSG_name__",
"version": "1.2.2", "version": "1.8",
"manifest_version": 2, "manifest_version": 2,
"description": "Classic Microsoft Edge \"Tabs Aside\" feature for Chromium browsers", "description": "__MSG_description__",
"author": "Michael \"XFox\" Gordeev", "author": "__MSG_author__",
"permissions": "default_locale": "en",
"permissions":
[ [
"tabs", "tabs",
"unlimitedStorage", "unlimitedStorage",
"<all_urls>" "storage",
"<all_urls>",
"contextMenus"
], ],
"icons": "icons":
{ {
"128": "icons/light/empty/128.png", "128": "icons/light/empty/128.png",
"48": "icons/light/empty/48.png", "48": "icons/light/empty/48.png",
"32": "icons/light/empty/32.png", "32": "icons/light/empty/32.png",
"16": "icons/light/empty/16.png" "16": "icons/light/empty/16.png"
}, },
"browser_action": { "default_icon": "icons/light/empty/32.png" }, "browser_action":
{
"default_icon": "icons/light/empty/32.png",
"theme_icons":
[
{
"size": 128,
"dark": "icons/light/full/128.png",
"light": "icons/dark/full/128.png"
},
{
"size": 48,
"dark": "icons/light/full/48.png",
"light": "icons/dark/full/48.png"
},
{
"size": 32,
"dark": "icons/light/full/32.png",
"light": "icons/dark/full/32.png"
},
{
"size": 16,
"dark": "icons/light/full/16.png",
"light": "icons/dark/full/16.png"
}
]
},
"web_accessible_resources": [ "*" ], "web_accessible_resources": [ "*" ],
"background": "background":
{ {
"scripts": [ "js/background.js" ], "scripts": [ "js/background.js" ],
"persistent": true "persistent": false
},
"commands":
{
"set-aside":
{
"description": "__MSG_setAside__",
"suggested_key":
{
"default": "Alt+Left",
"mac": "MacCtrl+T"
}
},
"toggle-pane":
{
"description": "__MSG_togglePaneContext__",
"suggested_key":
{
"default": "Alt+P",
"mac": "Command+Shift+P"
}
}
},
"browser_specific_settings":
{
"gecko":
{
"id": "tabsaside@xfox111.net",
"strict_min_version": "58.0"
}
} }
} }