Bug 1908431 - add basic support for tab groups in overflow menu. r=dao,fluent-reviewers,desktop-theme-reviewers,tabbrowser-reviewers,bolsson
Differential Revision: https://phabricator.services.mozilla.com/D232389
This commit is contained in:
132
browser/components/tabbrowser/GroupsList.sys.mjs
Normal file
132
browser/components/tabbrowser/GroupsList.sys.mjs
Normal file
@@ -0,0 +1,132 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
export class GroupsPanel {
|
||||
constructor({ view, containerNode }) {
|
||||
this.view = view;
|
||||
|
||||
this.containerNode = containerNode;
|
||||
this.win = containerNode.ownerGlobal;
|
||||
this.doc = containerNode.ownerDocument;
|
||||
this.panelMultiView = null;
|
||||
this.view.addEventListener("ViewShowing", this);
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "ViewShowing":
|
||||
if (event.target == this.view) {
|
||||
this.panelMultiView = this.view.panelMultiView;
|
||||
this.#populate(event);
|
||||
}
|
||||
break;
|
||||
case "PanelMultiViewHidden":
|
||||
if ((this.panelMultiView = event.target)) {
|
||||
this.#cleanup();
|
||||
this.panelMultiView = null;
|
||||
}
|
||||
|
||||
break;
|
||||
case "command":
|
||||
this.#handleCommand(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#handleCommand(event) {
|
||||
let groupId = event.target.closest("toolbaritem").groupId;
|
||||
|
||||
switch (event.target.dataset.command) {
|
||||
case "allTabsGroupView_selectGroup":
|
||||
let group = this.win.gBrowser.getTabGroupById(groupId);
|
||||
group.select();
|
||||
group.ownerGlobal.focus();
|
||||
|
||||
break;
|
||||
case "allTabsGroupView_restoreGroup":
|
||||
this.win.SessionStore.openSavedTabGroup(groupId, this.win);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#setupListeners() {
|
||||
this.view.addEventListener("command", this);
|
||||
this.view.panelMultiView.addEventListener("PanelMultiViewHidden", this);
|
||||
}
|
||||
|
||||
#cleanup() {
|
||||
this.containerNode.innerHTML = "";
|
||||
this.view.removeEventListener("command", this);
|
||||
}
|
||||
|
||||
#populate() {
|
||||
let fragment = this.doc.createDocumentFragment();
|
||||
let otherWindowGroups = this.win.gBrowser
|
||||
.getAllTabGroups()
|
||||
.filter(group => {
|
||||
return group.ownerGlobal !== this.win;
|
||||
});
|
||||
let savedGroups = this.win.SessionStore.savedGroups;
|
||||
|
||||
if (savedGroups.length + otherWindowGroups.length > 0) {
|
||||
let header = this.doc.createElement("h2");
|
||||
header.setAttribute("class", "subview-subheader");
|
||||
this.doc.l10n.setAttributes(header, "tab-group-menu-header");
|
||||
fragment.appendChild(header);
|
||||
}
|
||||
for (let groupData of otherWindowGroups) {
|
||||
fragment.appendChild(this.#createRow(groupData));
|
||||
}
|
||||
for (let groupData of savedGroups) {
|
||||
fragment.appendChild(this.#createRow(groupData, "closed"));
|
||||
}
|
||||
this.containerNode.appendChild(fragment);
|
||||
this.#setupListeners();
|
||||
}
|
||||
|
||||
#createRow(group, kind = "open") {
|
||||
let { doc } = this;
|
||||
let row = doc.createXULElement("toolbaritem");
|
||||
row.setAttribute("class", "all-tabs-item all-tabs-group-item");
|
||||
row.setAttribute("context", "tabContextMenu");
|
||||
row.style.setProperty(
|
||||
"--tab-group-color",
|
||||
`var(--tab-group-color-${group.color})`
|
||||
);
|
||||
row.style.setProperty(
|
||||
"--tab-group-color-invert",
|
||||
`var(--tab-group-color-${group.color}-invert)`
|
||||
);
|
||||
row.style.setProperty(
|
||||
"--tab-group-color-pale",
|
||||
`var(--tab-group-color-${group.color}-pale)`
|
||||
);
|
||||
row.groupId = group.id;
|
||||
let button = doc.createXULElement("toolbarbutton");
|
||||
button.setAttribute(
|
||||
"class",
|
||||
"all-tabs-button subviewbutton subviewbutton-iconic all-tabs-group-action-button"
|
||||
);
|
||||
if (kind != "open") {
|
||||
button.classList.add("all-tabs-group-saved-group");
|
||||
button.dataset.command = "allTabsGroupView_restoreGroup";
|
||||
} else {
|
||||
button.dataset.command = "allTabsGroupView_selectGroup";
|
||||
}
|
||||
button.setAttribute("flex", "1");
|
||||
button.setAttribute("crop", "end");
|
||||
|
||||
if (group.name) {
|
||||
button.setAttribute("label", group.name);
|
||||
} else {
|
||||
doc.l10n
|
||||
.formatValues([{ id: "tab-group-name-default" }])
|
||||
.then(([msg]) => {
|
||||
button.setAttribute("label", msg);
|
||||
});
|
||||
}
|
||||
row.appendChild(button);
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -102,9 +102,14 @@ class TabsListBase {
|
||||
*/
|
||||
_populate() {
|
||||
let fragment = this.doc.createDocumentFragment();
|
||||
let currentGroupId;
|
||||
|
||||
for (let tab of this.gBrowser.tabs) {
|
||||
if (this.filterFn(tab)) {
|
||||
if (tab.group && tab.group.id != currentGroupId) {
|
||||
fragment.appendChild(this._createGroupRow(tab.group));
|
||||
currentGroupId = tab.group.id;
|
||||
}
|
||||
fragment.appendChild(this._createRow(tab));
|
||||
}
|
||||
}
|
||||
@@ -121,6 +126,10 @@ class TabsListBase {
|
||||
* Remove the menuitems from the DOM, cleanup internal state and listeners.
|
||||
*/
|
||||
_cleanup() {
|
||||
this.doc
|
||||
.querySelectorAll(".all-tabs-group-button")
|
||||
.forEach(node => node.remove());
|
||||
|
||||
for (let item of this.rows) {
|
||||
item.remove();
|
||||
}
|
||||
@@ -262,6 +271,9 @@ export class TabsPanel extends TabsListBase {
|
||||
this.gBrowser.removeTab(event.target.tab);
|
||||
break;
|
||||
}
|
||||
if (event.target.classList.contains("all-tabs-group-button")) {
|
||||
this.gBrowser.getTabGroupById(event.target.groupId).select();
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
super.handleEvent(event);
|
||||
@@ -275,9 +287,12 @@ export class TabsPanel extends TabsListBase {
|
||||
// The loading throbber can't be set until the toolbarbutton is rendered,
|
||||
// so set the image attributes again now that the elements are in the DOM.
|
||||
for (let row of this.rows) {
|
||||
// Ensure this isn't a group label
|
||||
if (row.tab) {
|
||||
this._setImageAttributes(row, row.tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_selectTab(tab) {
|
||||
super._selectTab(tab);
|
||||
@@ -324,6 +339,10 @@ export class TabsPanel extends TabsListBase {
|
||||
});
|
||||
}
|
||||
|
||||
if (tab.group) {
|
||||
row.classList.add("grouped");
|
||||
}
|
||||
|
||||
row.appendChild(button);
|
||||
|
||||
let muteButton = doc.createXULElement("toolbarbutton");
|
||||
@@ -352,6 +371,49 @@ export class TabsPanel extends TabsListBase {
|
||||
return row;
|
||||
}
|
||||
|
||||
_createGroupRow(group) {
|
||||
let { doc } = this;
|
||||
let row = doc.createXULElement("toolbaritem");
|
||||
row.setAttribute("class", "all-tabs-item all-tabs-group-item");
|
||||
row.setAttribute("context", "none");
|
||||
row.style.setProperty(
|
||||
"--tab-group-color",
|
||||
`var(--tab-group-color-${group.color})`
|
||||
);
|
||||
row.style.setProperty(
|
||||
"--tab-group-color-invert",
|
||||
`var(--tab-group-color-${group.color}-invert)`
|
||||
);
|
||||
row.style.setProperty(
|
||||
"--tab-group-color-pale",
|
||||
`var(--tab-group-color-${group.color}-pale)`
|
||||
);
|
||||
row.addEventListener("command", this);
|
||||
let button = doc.createXULElement("toolbarbutton");
|
||||
button.setAttribute(
|
||||
"class",
|
||||
"all-tabs-button all-tabs-group-button subviewbutton subviewbutton-iconic"
|
||||
);
|
||||
button.setAttribute("flex", "1");
|
||||
button.setAttribute("crop", "end");
|
||||
button.group = group;
|
||||
button.groupId = group.id;
|
||||
|
||||
if (group.label) {
|
||||
button.label = group.label;
|
||||
} else {
|
||||
doc.l10n
|
||||
.formatValues([{ id: "tab-group-name-default" }])
|
||||
.then(([msg]) => {
|
||||
button.label = msg;
|
||||
});
|
||||
}
|
||||
|
||||
button.image = "chrome://browser/skin/tabbrowser/tab-group-chicklet.svg";
|
||||
row.appendChild(button);
|
||||
return row;
|
||||
}
|
||||
|
||||
_setRowAttributes(row, tab) {
|
||||
setAttributes(row, { selected: tab.selected });
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
class="subviewbutton subviewbutton-nav"
|
||||
closemenu="none"
|
||||
data-l10n-id="all-tabs-menu-hidden-tabs"/>
|
||||
<toolbarseparator id="allTabsMenu-groupsSeparator"/>
|
||||
<vbox id="allTabsMenu-groupsView" class="panel-subview-body">
|
||||
</vbox>
|
||||
<toolbarseparator id="allTabsMenu-tabsSeparator"/>
|
||||
<vbox id="allTabsMenu-dropIndicatorHolder">
|
||||
<vbox id="allTabsMenu-dropIndicator" collapsed="true"/>
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.sys.mjs",
|
||||
GroupsPanel: "resource:///modules/GroupsList.sys.mjs",
|
||||
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
||||
TabsPanel: "resource:///modules/TabsList.sys.mjs",
|
||||
});
|
||||
|
||||
@@ -19,6 +21,7 @@ var gTabsPanel = {
|
||||
containerTabsView: "allTabsMenu-containerTabsView",
|
||||
hiddenTabsButton: "allTabsMenu-hiddenTabsButton",
|
||||
hiddenTabsView: "allTabsMenu-hiddenTabsView",
|
||||
groupsView: "allTabsMenu-groupsView",
|
||||
},
|
||||
_initialized: false,
|
||||
_initializedElements: false,
|
||||
@@ -60,6 +63,11 @@ var gTabsPanel = {
|
||||
containerNode: this.allTabsViewTabs,
|
||||
filterFn: tab => !tab.hidden,
|
||||
dropIndicator: this.dropIndicator,
|
||||
showGroups: true,
|
||||
});
|
||||
this.groupsPanel = new GroupsPanel({
|
||||
view: this.allTabsView,
|
||||
containerNode: this.groupsView,
|
||||
});
|
||||
|
||||
this.allTabsView.addEventListener("ViewShowing", () => {
|
||||
|
||||
@@ -138,6 +138,15 @@
|
||||
this.#updateLabelAriaAttributes();
|
||||
}
|
||||
|
||||
// alias for label
|
||||
get name() {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
set name(newName) {
|
||||
this.label = newName;
|
||||
}
|
||||
|
||||
get collapsed() {
|
||||
return this.hasAttribute("collapsed");
|
||||
}
|
||||
@@ -224,6 +233,19 @@
|
||||
on_TabSelect() {
|
||||
this.collapsed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If one of this group's tabs is the selected tab, this will do nothing.
|
||||
* Otherwise, it will expand the group if collapsed, and select the first
|
||||
* tab in its list.
|
||||
*/
|
||||
select() {
|
||||
this.collapsed = false;
|
||||
if (gBrowser.selectedTab.group == this) {
|
||||
return;
|
||||
}
|
||||
gBrowser.selectedTab = this.tabs[0];
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("tab-group", MozTabbrowserTabGroup);
|
||||
|
||||
@@ -9,6 +9,7 @@ JAR_MANIFESTS += ["jar.mn"]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
"AsyncTabSwitcher.sys.mjs",
|
||||
"GroupsList.sys.mjs",
|
||||
"NewTabPagePreloading.sys.mjs",
|
||||
"OpenInTabsUtils.sys.mjs",
|
||||
"TabsList.sys.mjs",
|
||||
|
||||
@@ -495,6 +495,9 @@ tags = "vertical-tabs"
|
||||
["browser_tab_manager_drag.js"]
|
||||
tags = "vertical-tabs"
|
||||
|
||||
["browser_tab_manager_groups.js"]
|
||||
tags = "vertical-tabs"
|
||||
|
||||
["browser_tab_manager_keyboard_access.js"]
|
||||
tags = "vertical-tabs"
|
||||
|
||||
|
||||
@@ -590,6 +590,33 @@ add_task(async function test_moveTabBetweenGroups() {
|
||||
await removeTabGroup(group2);
|
||||
});
|
||||
|
||||
add_task(async function test_tabGroupSelect() {
|
||||
let tab1 = BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
let tab3 = BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
let tab1Added = BrowserTestUtils.waitForEvent(tab1, "TabGrouped");
|
||||
let tab2Added = BrowserTestUtils.waitForEvent(tab2, "TabGrouped");
|
||||
let group = gBrowser.addTabGroup([tab1, tab2]);
|
||||
await Promise.allSettled([tab1Added, tab2Added]);
|
||||
gBrowser.selectTabAtIndex(tab3._tPos);
|
||||
Assert.ok(tab3.selected, "Tab 3 is selected");
|
||||
group.select();
|
||||
Assert.ok(group.tabs[0].selected, "First tab is selected");
|
||||
gBrowser.selectTabAtIndex(group.tabs[1]._tPos);
|
||||
Assert.ok(group.tabs[1].selected, "Second tab is selected");
|
||||
group.select();
|
||||
Assert.ok(group.tabs[1].selected, "Second tab is still selected");
|
||||
group.collapsed = true;
|
||||
Assert.ok(group.collapsed, "Group is collapsed");
|
||||
Assert.ok(tab3.selected, "Tab 3 is selected");
|
||||
group.select();
|
||||
Assert.ok(!group.collapsed, "Group is no longer collapsed");
|
||||
Assert.ok(group.tabs[0].selected, "First tab in group is selected");
|
||||
|
||||
await removeTabGroup(group);
|
||||
BrowserTestUtils.removeTab(tab3);
|
||||
});
|
||||
|
||||
// Context menu tests
|
||||
// ---
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.tabs.groups.enabled", true]],
|
||||
});
|
||||
|
||||
const tabGroups = SessionStore.getSavedTabGroups();
|
||||
tabGroups.forEach(tabGroup => SessionStore.forgetSavedTabGroup(tabGroup.id));
|
||||
|
||||
window.gTabsPanel.init();
|
||||
});
|
||||
|
||||
async function openTabsMenu(win = window) {
|
||||
return new Promise(resolve => {
|
||||
BrowserTestUtils.waitForEvent(
|
||||
win.document.getElementById("allTabsMenu-allTabsView"),
|
||||
"ViewShown"
|
||||
).then(event => resolve(event.target));
|
||||
win.document.getElementById("alltabs-button").click();
|
||||
});
|
||||
}
|
||||
|
||||
async function closeTabsMenu(win = window) {
|
||||
return new Promise(resolve => {
|
||||
let panel = win.document
|
||||
.getElementById("allTabsMenu-allTabsView")
|
||||
.closest("panel");
|
||||
BrowserTestUtils.waitForPopupEvent(panel, "hidden").then(event =>
|
||||
resolve(event.target)
|
||||
);
|
||||
panel.hidePopup();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that grouped tabs in alltabsmenu are prepended by
|
||||
* a group indicator
|
||||
*/
|
||||
add_task(async function test_allTabsView() {
|
||||
let tabs = [];
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
tabs.push(
|
||||
await addTab(`data:text/plain,tab${i}`, {
|
||||
skipAnimation: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
gBrowser.addTabGroup([tabs[0], tabs[1]], {
|
||||
label: "Test Group",
|
||||
});
|
||||
gBrowser.addTabGroup([tabs[2], tabs[3]]);
|
||||
|
||||
let allTabsMenu = await openTabsMenu();
|
||||
|
||||
let tabButtons = allTabsMenu.querySelectorAll(
|
||||
"#allTabsMenu-allTabsView-tabs .all-tabs-button"
|
||||
);
|
||||
let expectedLabels = [
|
||||
"New Tab",
|
||||
"data:text/plain,tab5",
|
||||
"Test Group",
|
||||
"data:text/plain,tab1",
|
||||
"data:text/plain,tab2",
|
||||
"Unnamed Group",
|
||||
"data:text/plain,tab3",
|
||||
"data:text/plain,tab4",
|
||||
];
|
||||
tabButtons.forEach((button, i) => {
|
||||
Assert.equal(
|
||||
button.label,
|
||||
expectedLabels[i],
|
||||
`Expected: ${expectedLabels[i]}`
|
||||
);
|
||||
});
|
||||
|
||||
await closeTabsMenu();
|
||||
for (let tab of tabs) {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that groups appear in the supplementary group menu
|
||||
* when they are saved (and closed,) or open in another window.
|
||||
* Clicking an open group in this menu focuses it,
|
||||
* and clicking on a saved group restores it.
|
||||
*/
|
||||
add_task(async function test_tabGroupsView() {
|
||||
let tabs = [];
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
tabs.push(
|
||||
await addTab(`data:text/plain,tab${i}`, {
|
||||
skipAnimation: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
let group1 = gBrowser.addTabGroup([tabs[0], tabs[1]], {
|
||||
id: "test-saved-group",
|
||||
label: "Test Saved Group",
|
||||
});
|
||||
let group2 = gBrowser.addTabGroup([tabs[2], tabs[3]], {
|
||||
label: "Test Open Group",
|
||||
});
|
||||
|
||||
let newWindow = await BrowserTestUtils.openNewBrowserWindow();
|
||||
newWindow.gTabsPanel.init();
|
||||
|
||||
let allTabsMenu = await openTabsMenu(newWindow);
|
||||
Assert.equal(
|
||||
allTabsMenu.querySelectorAll("#allTabsMenu-groupsView .all-tabs-button")
|
||||
.length,
|
||||
2,
|
||||
"Both groups shown in groups list"
|
||||
);
|
||||
Assert.ok(
|
||||
!allTabsMenu.querySelector(
|
||||
"#allTabsMenu-groupsView .all-tabs-button.all-tabs-group-saved-group"
|
||||
),
|
||||
"Neither group is shown as saved"
|
||||
);
|
||||
|
||||
await closeTabsMenu(newWindow);
|
||||
|
||||
group1.save();
|
||||
await removeTabGroup(group1);
|
||||
|
||||
Assert.ok(!gBrowser.getTabGroupById("test-saved-group"), "Group 1 removed");
|
||||
|
||||
allTabsMenu = await openTabsMenu(newWindow);
|
||||
Assert.equal(
|
||||
allTabsMenu.querySelectorAll("#allTabsMenu-groupsView .all-tabs-button")
|
||||
.length,
|
||||
2,
|
||||
"Both groups shown in groups list"
|
||||
);
|
||||
let savedGroupButton = allTabsMenu.querySelector(
|
||||
"#allTabsMenu-groupsView .all-tabs-button.all-tabs-group-saved-group"
|
||||
);
|
||||
Assert.equal(
|
||||
savedGroupButton.label,
|
||||
"Test Saved Group",
|
||||
"Saved group appears as saved"
|
||||
);
|
||||
|
||||
// Clicking on an open group should select that group in the origin window
|
||||
let openGroupButton = allTabsMenu.querySelector(
|
||||
"#allTabsMenu-groupsView .all-tabs-button:not(.all-tabs-group-saved-group)"
|
||||
);
|
||||
openGroupButton.click();
|
||||
Assert.equal(
|
||||
gBrowser.selectedTab.group.id,
|
||||
group2.id,
|
||||
"Tab in group 2 is selected"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWindow, { animate: false });
|
||||
|
||||
// Clicking on a saved group should restore the group to the current window
|
||||
allTabsMenu = await openTabsMenu();
|
||||
savedGroupButton = allTabsMenu.querySelector(
|
||||
"#allTabsMenu-groupsView .all-tabs-button.all-tabs-group-saved-group"
|
||||
);
|
||||
savedGroupButton.click();
|
||||
group1 = gBrowser.getTabGroupById("test-saved-group");
|
||||
Assert.ok(group1, "Group 1 has been restored");
|
||||
allTabsMenu = await openTabsMenu();
|
||||
Assert.ok(
|
||||
!allTabsMenu.querySelector("#allTabsMenu-groupsView .all-tabs-button"),
|
||||
"Groups list is now empty for this window"
|
||||
);
|
||||
|
||||
await closeTabsMenu();
|
||||
for (let tab of tabs) {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
await removeTabGroup(group1);
|
||||
});
|
||||
@@ -191,6 +191,7 @@ tabbrowser-manager-close-tab =
|
||||
|
||||
## Tab Groups
|
||||
|
||||
tab-group-name-default = Unnamed Group
|
||||
tab-group-editor-title-create = Create tab group
|
||||
tab-group-editor-title-edit = Manage tab group
|
||||
tab-group-editor-name-label = Name
|
||||
@@ -200,6 +201,8 @@ tab-group-editor-cancel =
|
||||
.label = Cancel
|
||||
.accesskey = C
|
||||
|
||||
tab-group-menu-header = Tab groups
|
||||
|
||||
tab-context-unnamed-group =
|
||||
.label = Unnamed group
|
||||
|
||||
|
||||
@@ -1465,8 +1465,22 @@ toolbar:not(#TabsToolbar) #firefox-view-button {
|
||||
}
|
||||
}
|
||||
|
||||
#allTabsMenu-groupsView {
|
||||
flex: auto;
|
||||
flex-grow: 0;
|
||||
|
||||
&:empty,
|
||||
&:empty + toolbarseparator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.all-tabs-item {
|
||||
margin-inline: var(--arrowpanel-menuitem-margin-inline);
|
||||
|
||||
&.grouped {
|
||||
margin-inline-start: calc(var(--arrowpanel-menuitem-margin-inline) * 2);
|
||||
}
|
||||
border-radius: var(--arrowpanel-menuitem-border-radius);
|
||||
|
||||
&[selected] {
|
||||
@@ -1497,6 +1511,19 @@ toolbar:not(#TabsToolbar) #firefox-view-button {
|
||||
}
|
||||
}
|
||||
|
||||
.all-tabs-group-item {
|
||||
> .subviewbutton-iconic > .toolbarbutton-icon {
|
||||
list-style-image: url("chrome://browser/skin/tabbrowser/tab-group-chicklet.svg");
|
||||
fill: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
|
||||
}
|
||||
|
||||
> .all-tabs-group-saved-group > .toolbarbutton-icon {
|
||||
-moz-context-properties: fill, stroke;
|
||||
fill: transparent;
|
||||
stroke: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
|
||||
}
|
||||
}
|
||||
|
||||
.all-tabs-button {
|
||||
list-style-image: url("chrome://global/skin/icons/defaultFavicon.svg");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user