Bug 1946523 - STG - Step 1 UI migration r=fluent-reviewers,desktop-theme-reviewers,tabbrowser-reviewers,dao,bolsson

Adding additional UI elements and filling out state machine with actualy UI updates. Some functions are stubbed out while waiting on ML to have API up on central. These UI changes should have no change to current UI if pref is turned off.

Differential Revision: https://phabricator.services.mozilla.com/D237277
This commit is contained in:
Nick Grato
2025-02-14 23:37:56 +00:00
parent 06446e1ecf
commit 6cf0bc44df
7 changed files with 677 additions and 78 deletions

View File

@@ -100,6 +100,7 @@
<link rel="localization" href="browser/sidebar.ftl"/>
<link rel="localization" href="browser/profiles.ftl"/>
<link rel="localization" href="preview/onboarding.ftl"/>
<link rel="localization" href="preview/smartTabGroups.ftl"/>
<link rel="localization" href="preview/tabUnload.ftl"/>
<title data-l10n-id="browser-main-window-default-title"></title>

View File

@@ -252,7 +252,7 @@ export class SmartTabGroupingManager {
* This function will terminate a grouping or label generation in progress
* It is currently not implemented.
*/
terminateProcesses() {
terminateProcess() {
// TODO - teminate AI processes, This method will be
// called when tab grouping panel is closed.
}
@@ -382,13 +382,11 @@ export class SmartTabGroupingManager {
) {
this.embeddingEngine = await this._createMLEngine(this.config.embedding);
}
const result = [];
for (let runArg of inputData.inputArgs) {
const request = { args: [[runArg]], options: inputData.runOptions };
let embeddingsPerTab = await this.embeddingEngine.run(request);
result.push(Object.values(embeddingsPerTab.ort_tensor.cpuData));
}
return result;
const request = {
args: [inputData.inputArgs],
options: inputData.runOptions,
};
return await this.embeddingEngine.run(request);
}
/**

View File

@@ -99,6 +99,7 @@
this.tabContainer = document.getElementById("tabbrowser-tabs");
this.tabGroupMenu = document.getElementById("tab-group-editor");
this.tabbox = document.getElementById("tabbrowser-tabbox");
this.tabGroupNameField = document.getElementById("tab-group-name");
this.tabpanels = document.getElementById("tabbrowser-tabpanels");
this.verticalPinnedTabsContainer = document.getElementById(
"vertical-pinned-tabs-container"
@@ -2948,6 +2949,13 @@
return null;
}
gBrowser.getGroupTitleForTabs(tabs).then(newLabel => {
group.label = newLabel;
if (this.tabGroupMenu.panel.state !== "closed") {
this.tabGroupNameField.value = newLabel;
}
});
group.dispatchEvent(
new CustomEvent("TabGroupCreate", {
bubbles: true,

View File

@@ -30,15 +30,8 @@
"gray",
"red",
];
static markup = `
<panel
type="arrow"
class="panel tab-group-editor-panel"
orient="vertical"
role="dialog"
ignorekeys="true"
norolluponanchor="true">
static headerSection = /*html*/ `
<html:div class="panel-header">
<html:h1
id="tab-group-editor-title-create"
@@ -51,46 +44,9 @@
data-l10n-id="tab-group-editor-title-edit">
</html:h1>
</html:div>
`;
<toolbarseparator />
<html:div
class="panel-body
tab-group-editor-name">
<html:label
for="tab-group-name"
data-l10n-id="tab-group-editor-name-label">
</html:label>
<html:input
id="tab-group-name"
type="text"
name="tab-group-name"
value=""
data-l10n-id="tab-group-editor-name-field"
/>
</html:div>
<html:div
class="panel-body tab-group-editor-swatches"
role="radiogroup"
data-l10n-id="tab-group-editor-color-selector"
/>
<html:moz-button-group
class="panel-body tab-group-create-actions tab-group-create-mode-only">
<html:moz-button
id="tab-group-editor-button-cancel"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
<html:moz-button
type="primary"
id="tab-group-editor-button-create"
data-l10n-id="tab-group-editor-done">
</html:moz-button>
</html:moz-button-group>
<toolbarseparator class="tab-group-edit-mode-only" />
static editActions = /*html*/ `
<html:div
class="panel-body tab-group-edit-actions tab-group-edit-mode-only">
<toolbarbutton
@@ -118,7 +74,7 @@
data-l10n-id="tab-group-editor-action-ungroup">
</toolbarbutton>
</html:div>
<toolbarseparator class="tab-group-edit-mode-only" />
<html:div class="tab-group-edit-mode-only panel-body tab-group-delete">
@@ -129,7 +85,163 @@
data-l10n-id="tab-group-editor-action-delete">
</toolbarbutton>
</html:div>
`;
static suggestionsHeader = /*html*/ `
<html:div id="tab-group-suggestions-heading" hidden="true">
<html:div class="panel-header">
<html:h1 data-l10n-id="tab-group-editor-title-suggest"></html:h1>
</html:div>
<toolbarseparator />
</html:div>
`;
static suggestionsSection = /*html*/ `
<html:div id="tab-group-suggestions-container" hidden="true">
<html:div
id="tab-group-suggestions-header"
data-l10n-id="tab-group-editor-suggestions-header">
</html:div>
<html:div id="tab-group-suggestions"></html:div>
<html:moz-button
id="tab-group-select-toggle"
data-l10n-id="tab-group-editor-deselect-suggestions"
size="small"
data-state="deselect">
</html:moz-button>
<html:moz-button-group class="panel-body tab-group-create-actions">
<html:moz-button
id="tab-group-cancel-suggestions-button"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
<html:moz-button
type="primary"
id="tab-group-create-suggestions-button"
data-l10n-id="tab-group-editor-done">
</html:moz-button>
</html:moz-button-group>
</html:div>
`;
static suggestionsButton = /*html*/ `
<html:moz-button
hidden="true"
id="tab-group-suggestion-button"
type="icon ghost"
data-l10n-id="tab-group-editor-smart-suggest-button-create">
</html:moz-button>
`;
static loadingSection = /*html*/ `
<html:div id="tab-group-suggestions-loading" hidden="true">
<html:div
class="tab-group-suggestions-loading-header"
data-l10n-id="tab-group-suggestions-loading-header">
</html:div>
<html:div class="tab-group-suggestions-loading-block"></html:div>
<html:div class="tab-group-suggestions-loading-block"></html:div>
<html:div class="tab-group-suggestions-loading-block"></html:div>
</html:div>
`;
static defaultActions = /*html*/ `
<html:moz-button-group
class="panel-body tab-group-create-actions tab-group-create-mode-only"
id="tab-group-default-actions">
<html:moz-button
id="tab-group-editor-button-cancel"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
<html:moz-button
type="primary"
id="tab-group-editor-button-create"
data-l10n-id="tab-group-editor-done">
</html:moz-button>
</html:moz-button-group>
`;
static loadingActions = /*html*/ `
<html:moz-button-group id="tab-group-suggestions-load-actions" hidden="true">
<html:moz-button
id="tab-group-suggestions-load-cancel"
data-l10n-id="tab-group-editor-cancel">
</html:moz-button>
</html:moz-button-group>
`;
static markup = /*html*/ `
<panel
type="arrow"
class="panel tab-group-editor-panel"
orient="vertical"
role="dialog"
ignorekeys="true"
norolluponanchor="true">
<html:div id="tab-group-main">
${this.headerSection}
<toolbarseparator />
<html:div
class="panel-body
tab-group-editor-name">
<html:label
for="tab-group-name"
data-l10n-id="tab-group-editor-name-label">
</html:label>
<html:input
id="tab-group-name"
type="text"
name="tab-group-name"
value=""
data-l10n-id="tab-group-editor-name-field"
/>
</html:div>
<html:div
class="panel-body tab-group-editor-swatches"
role="radiogroup"
data-l10n-id="tab-group-editor-color-selector"
/>
<toolbarseparator class="tab-group-edit-mode-only"/>
${this.editActions}
<toolbarseparator id="tab-group-suggestions-separator" hidden="true"/>
${this.suggestionsButton}
<html:p
hidden="true"
id="tab-group-suggestions-disclaimer"
data-l10n-id="tab-group-suggestions-disclaimer">
<a data-l10n-name="support" href="#"></a>
</html:p>
<html:moz-button
hidden="true"
disabled="true"
type="icon ghost"
id="tab-group-suggestions-message"
data-l10n-id="tab-group-editor-no-tabs-found">
</html:moz-button>
${this.defaultActions}
</html:div>
${this.suggestionsHeader}
${this.loadingSection}
${this.loadingActions}
${this.suggestionsSection}
</panel>
`;
@@ -158,6 +270,7 @@
ERROR: 11,
};
#tabGroupMain;
#activeGroup;
#cancelButton;
#createButton;
@@ -167,7 +280,25 @@
#panel;
#swatches;
#swatchesContainer;
#defaultActions;
#suggestionState = MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL;
#suggestionsHeading;
#suggestionsHeader;
#suggestionsContainer;
#suggestions;
#suggestionButton;
#cancelSuggestionsButton;
#createSuggestionsButton;
#suggestionsLoading;
#selectSuggestionsToggle;
#suggestionsMessage;
#suggestionsDisclaimer;
#selectedSuggestedTabs = [];
#suggestedTabs = [];
#suggestionsLoadActions;
#suggestionsLoadCancel;
#suggestionsSeparator;
#smartTabGroupingManager;
constructor() {
super();
@@ -195,6 +326,11 @@
this.#swatchesContainer = this.querySelector(
".tab-group-editor-swatches"
);
this.#defaultActions = this.querySelector("#tab-group-default-actions");
this.#tabGroupMain = this.querySelector("#tab-group-main");
this.#initSuggestions();
this.#populateSwatches();
this.#cancelButton.addEventListener("click", () => {
@@ -211,6 +347,22 @@
}
});
/**
* Check if the smart suggest button should be shown
* If there are no ungrouped tabs, the button should be hidden
*/
this.canShowAIUserInterface = () => {
const { tabs } = gBrowser;
let show = false;
tabs.forEach(tab => {
if (tab.group === null) {
show = true;
}
});
return show;
};
document
.getElementById("tabGroupEditor_addNewTabInGroup")
.addEventListener("command", () => {
@@ -247,6 +399,78 @@
this.#swatchesContainer.addEventListener("change", this);
}
#initSuggestions() {
const AI_ICON = "chrome://global/skin/icons/highlights.svg";
const { SmartTabGroupingManager } = ChromeUtils.importESModule(
"resource:///modules/SmartTabGrouping.sys.mjs"
);
this.#smartTabGroupingManager = new SmartTabGroupingManager();
// Init Suggestion Button
this.#suggestionButton = this.querySelector(
"#tab-group-suggestion-button"
);
this.#suggestionButton.iconSrc = AI_ICON;
this.#suggestionButton.addEventListener("click", () => {
this.#handleSmartSuggest();
});
// Init Suggestions UI
this.#suggestionsHeading = this.querySelector(
"#tab-group-suggestions-heading"
);
this.#suggestionsHeader = this.querySelector(
"#tab-group-suggestions-header"
);
this.#suggestionsContainer = this.querySelector(
"#tab-group-suggestions-container"
);
this.#suggestions = this.querySelector("#tab-group-suggestions");
this.#selectSuggestionsToggle = this.querySelector(
"#tab-group-select-toggle"
);
this.#selectSuggestionsToggle.addEventListener("click", () => {
this.#handleSelectToggle();
});
this.#suggestionsMessage = this.querySelector(
"#tab-group-suggestions-message"
);
this.#suggestionsMessage.iconSrc = AI_ICON;
this.#suggestionsDisclaimer = this.querySelector(
"#tab-group-suggestions-disclaimer"
);
this.#createSuggestionsButton = this.querySelector(
"#tab-group-create-suggestions-button"
);
this.#createSuggestionsButton.addEventListener("click", () => {
this.activeGroup.addTabs(this.#selectedSuggestedTabs);
this.close(true);
});
this.#cancelSuggestionsButton = this.querySelector(
"#tab-group-cancel-suggestions-button"
);
this.#cancelSuggestionsButton.addEventListener("click", () => {
this.close();
});
this.#suggestionsSeparator = this.querySelector(
"#tab-group-suggestions-separator"
);
// Init Loading UI
this.#suggestionsLoading = this.querySelector(
"#tab-group-suggestions-loading"
);
this.#suggestionsLoadActions = this.querySelector(
"#tab-group-suggestions-load-actions"
);
this.#suggestionsLoadCancel = this.querySelector(
"#tab-group-suggestions-load-cancel"
);
this.#suggestionsLoadCancel.addEventListener("click", () => {
this.#handleLoadSuggestionsCancel();
});
}
#populateSwatches() {
this.#clearSwatches();
for (let colorCode of MozTabbrowserTabGroupMenu.COLORS) {
@@ -348,11 +572,10 @@
openCreateModal(group) {
this.activeGroup = group;
this.createMode = true;
this.suggestionState =
MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL;
if (lazy.smartTabGroupsEnabled) {
//TODO: set appropriate state
}
this.suggestionState = lazy.smartTabGroupsEnabled
? MozTabbrowserTabGroupMenu.State.CREATE_AI_INITIAL
: MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL;
this.#panel.openPopup(group.firstChild, {
position: this.#panelPosition,
});
@@ -361,11 +584,10 @@
openEditModal(group) {
this.activeGroup = group;
this.createMode = false;
this.suggestionState =
MozTabbrowserTabGroupMenu.State.EDIT_STANDARD_INITIAL;
if (lazy.smartTabGroupsEnabled) {
//TODO: set appropriate state
}
this.suggestionState = lazy.smartTabGroupsEnabled
? MozTabbrowserTabGroupMenu.State.EDIT_AI_INITIAL
: MozTabbrowserTabGroupMenu.State.EDIT_STANDARD_INITIAL;
this.#panel.openPopup(group.firstChild, {
position: this.#panelPosition,
});
@@ -419,6 +641,7 @@
}
}
this.activeGroup = null;
this.#smartTabGroupingManager.terminateProcess();
}
on_keypress(event) {
@@ -487,8 +710,192 @@
this.#renderSuggestionState();
}
#handleLoadSuggestionsCancel() {
// TODO look into actually canceling any processes
this.suggestionState = this.createMode
? MozTabbrowserTabGroupMenu.State.CREATE_AI_INITIAL
: MozTabbrowserTabGroupMenu.State.EDIT_AI_INITIAL;
}
#handleSelectToggle() {
const currentState =
this.#selectSuggestionsToggle.getAttribute("data-state");
const isDeselect = currentState === "deselect";
isDeselect ? this.#handleDeselectAll() : this.#handleSelectAll();
const newState = isDeselect ? "select" : "deselect";
this.#setSelectToggleState(newState);
}
#handleSelectAll() {
document
.querySelectorAll(".tab-group-suggestion-checkbox")
.forEach(checkbox => {
checkbox.checked = true;
});
// Reset selected tabs to all suggested tabs
this.#selectedSuggestedTabs = this.#suggestedTabs;
}
#handleDeselectAll() {
document
.querySelectorAll(".tab-group-suggestion-checkbox")
.forEach(checkbox => {
checkbox.checked = false;
});
this.#selectedSuggestedTabs = [];
}
async #handleSmartSuggest() {
// Loading
this.suggestionState = MozTabbrowserTabGroupMenu.State.LOADING;
const tabs = await this.#smartTabGroupingManager.smartTabGroupingForGroup(
this.activeGroup,
gBrowser.tabs
);
if (!tabs.length) {
// No un-grouped tabs found
this.suggestionState = this.#createMode
? MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_NO_SUGGESTIONS
: MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_NO_SUGGESTIONS;
return;
}
this.#selectedSuggestedTabs = tabs;
this.#suggestedTabs = tabs;
tabs.forEach((tab, index) => {
this.#createRow(tab, index);
});
this.suggestionState = this.#createMode
? MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_SUGGESTIONS
: MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_SUGGESTIONS;
}
#createRow(tab, index) {
// Create Row
let row = document.createXULElement("toolbaritem");
row.setAttribute("context", "tabContextMenu");
row.setAttribute("id", `tab-bar-${index}`);
// Create Checkbox
let checkbox = document.createXULElement("checkbox");
checkbox.value = tab;
checkbox.setAttribute("checked", true);
checkbox.classList.add("tab-group-suggestion-checkbox");
checkbox.addEventListener("CheckboxStateChange", e => {
const isChecked = e.target.checked;
const currentTab = e.target.value;
if (isChecked) {
this.#selectedSuggestedTabs.push(currentTab);
} else {
this.#selectedSuggestedTabs = this.#selectedSuggestedTabs.filter(
t => t != currentTab
);
}
});
row.appendChild(checkbox);
// Create Row Label
let label = document.createXULElement("toolbarbutton");
label.classList.add(
"all-tabs-button",
"subviewbutton",
"subviewbutton-iconic",
"tab-group-suggestion-label"
);
label.setAttribute("flex", "1");
label.setAttribute("crop", "end");
label.label = tab.label;
label.image = tab.image;
label.disabled = true;
row.appendChild(label);
// Apply Row to Suggestions
this.#suggestions.appendChild(row);
}
/**
* Set the state of the select toggle button
* @param {string} "select" | "deselect"
*/
#setSelectToggleState(state) {
this.#selectSuggestionsToggle.setAttribute("data-state", state);
this.#selectSuggestionsToggle.setAttribute(
"data-l10n-id",
`tab-group-editor-${state}-suggestions`
);
}
/**
* Element visibility utility function.
* Toggles the `hidden` attribute of a DOM element.
*
* @param {HTMLElement|XULElement} element - The DOM element to show/hide.
* @param {boolean} shouldShow - Whether the element should be shown (true) or hidden (false).
*/
#setElementVisibility(element, shouldShow) {
element.hidden = !shouldShow;
}
#showDefaultTabGroupActions(value) {
this.#setElementVisibility(this.#defaultActions, value);
}
#showSmartSuggestionsContainer(value) {
this.#setElementVisibility(this.#suggestionsContainer, value);
}
#showSuggestionButton(value) {
this.#setElementVisibility(this.#suggestionButton, value);
}
#showSuggestionMessage(value) {
this.#setElementVisibility(this.#suggestionsMessage, value);
}
#showSuggestionsDisclaimer(value) {
this.#setElementVisibility(this.#suggestionsDisclaimer, value);
}
#showSuggestionsSeparator(value) {
this.#setElementVisibility(this.#suggestionsSeparator, value);
}
#setLoadingState(value) {
this.#setElementVisibility(this.#suggestionsLoadActions, value);
this.#setElementVisibility(this.#suggestionsLoading, value);
}
#setSuggestionsButtonCreateModeState(value) {
const translationString = value
? "tab-group-editor-smart-suggest-button-create"
: "tab-group-editor-smart-suggest-button-edit";
this.#suggestionButton.setAttribute("data-l10n-id", translationString);
}
/**
* Unique state setter for a "3rd" panel state while in Edit Mode
* that just shows suggestions and hides the majority of the panel
* @param {boolean} value
*/
#setEditModeSuggestionState(value) {
this.#setElementVisibility(this.#suggestionsHeader, !value);
this.#setElementVisibility(this.#tabGroupMain, !value);
this.#setElementVisibility(this.#suggestionsHeading, value);
}
#resetCommonUI() {
// TODO - has commun UI reset logic
this.#setLoadingState(false);
this.#setEditModeSuggestionState(false);
this.#suggestedTabs = [];
this.#selectedSuggestedTabs = [];
this.#suggestions.innerHTML = "";
this.#showSmartSuggestionsContainer(false);
}
#renderSuggestionState() {
@@ -496,64 +903,111 @@
// CREATE STANDARD INITIAL
case MozTabbrowserTabGroupMenu.State.CREATE_STANDARD_INITIAL:
this.#resetCommonUI();
//TODO
this.#showDefaultTabGroupActions(true);
this.#showSuggestionButton(false);
this.#showSuggestionMessage(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionsSeparator(false);
break;
//CREATE AI INITIAL
case MozTabbrowserTabGroupMenu.State.CREATE_AI_INITIAL:
this.#resetCommonUI();
//TODO
this.#showSuggestionButton(true);
this.#showDefaultTabGroupActions(true);
this.#showSuggestionMessage(false);
this.#setSelectToggleState("deselect");
this.#showSuggestionsDisclaimer(true);
this.#setSuggestionsButtonCreateModeState(true);
this.#showSuggestionsSeparator(true);
break;
// CREATE AI INITIAL SUGGESTIONS DISABLED
case MozTabbrowserTabGroupMenu.State
.CREATE_AI_INITIAL_SUGGESTIONS_DISABLED:
this.#resetCommonUI();
//TODO
this.#showSuggestionButton(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionMessage(true);
this.#showDefaultTabGroupActions(true);
this.#showSuggestionsSeparator(true);
break;
// CREATE AI WITH SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSmartSuggestionsContainer(true);
this.#showSuggestionButton(false);
this.#showSuggestionsSeparator(true);
this.$showDefaultTabGroupActions(false);
break;
// CREATE AI WITH NO SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.CREATE_AI_WITH_NO_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSuggestionMessage(true);
this.#showDefaultTabGroupActions(true);
this.#showSuggestionButton(false);
this.#showSuggestionsSeparator(true);
break;
// EDIT STANDARD INITIAL
case MozTabbrowserTabGroupMenu.State.EDIT_STANDARD_INITIAL:
this.#resetCommonUI();
//TODO
this.#showSuggestionButton(false);
this.#showSuggestionMessage(false);
this.#showDefaultTabGroupActions(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionsSeparator(false);
break;
// EDIT AI INITIAL
case MozTabbrowserTabGroupMenu.State.EDIT_AI_INITIAL:
this.#resetCommonUI();
//TODO
this.#showSuggestionMessage(false);
this.#setSelectToggleState("deselect");
this.#showSuggestionButton(true);
this.#showDefaultTabGroupActions(false);
this.#showSuggestionsDisclaimer(false);
this.#setSuggestionsButtonCreateModeState(false);
this.#showSuggestionsSeparator(true);
break;
// EDIT AI INITIAL SUGGESTIONS DISABLED
case MozTabbrowserTabGroupMenu.State
.EDIT_AI_INITIAL_SUGGESTIONS_DISABLED:
this.#resetCommonUI();
//TODO
this.#showSuggestionMessage(true);
this.#showSuggestionButton(false);
this.#showDefaultTabGroupActions(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionsSeparator(true);
break;
// EDIT AI WITH SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSmartSuggestionsContainer(true);
this.#setEditModeSuggestionState(true);
this.#showSuggestionsSeparator(false);
break;
// EDIT AI WITH NO SUGGESTIONS
case MozTabbrowserTabGroupMenu.State.EDIT_AI_WITH_NO_SUGGESTIONS:
//TODO
this.#setLoadingState(false);
this.#showSuggestionMessage(true);
this.#showSuggestionsSeparator(true);
break;
// LOADING
case MozTabbrowserTabGroupMenu.State.LOADING:
//TODO
this.#showDefaultTabGroupActions(false);
this.#showSuggestionButton(false);
this.#showSuggestionsDisclaimer(false);
this.#showSuggestionMessage(false);
this.#setLoadingState(true);
this.#showSuggestionsSeparator(true);
this.#showDefaultTabGroupActions(false);
break;
// ERROR

View File

@@ -0,0 +1,28 @@
# 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/.
tab-group-editor-title-suggest = Suggested tabs
tab-group-editor-smart-suggest-button-edit=
.label = Suggest more tabs for group
# Button appearing during creation of new tab group.
# Clicking will suggest tabs to group together in the tab group.
tab-group-editor-smart-suggest-button-create=
.label = Suggest tabs to group
tab-group-editor-suggestions-header = Suggested Tabs
tab-group-suggestions-loading-header = Suggested Tabs
tab-group-editor-deselect-suggestions =
.label = Deselect all
tab-group-editor-select-suggestions =
.label = Select all
tab-group-editor-no-tabs-found =
.label = As you open similar tabs, { -brand-short-name } will suggest them for this group.
tab-group-suggestions-disclaimer = { -brand-short-name } uses AI to <a data-l10n-name="support">suggest tabs and group names.</a> Some suggestions may be inaccurate.

View File

@@ -17,6 +17,7 @@
preview/credentialChooser.ftl (../../toolkit/components/credentialmanagement/credentialChooser.ftl)
browser (%browser/**/*.ftl)
preview/backupSettings.ftl (../locales-preview/backupSettings.ftl)
preview/smartTabGroups.ftl (../locales-preview/smartTabGroups.ftl)
preview/tabUnload.ftl (../locales-preview/tabUnload.ftl)
@AB_CD@.jar:

View File

@@ -6,6 +6,8 @@
--tabstrip-inner-border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
--tabstrip-min-height: calc(var(--tab-min-height) + 2 * var(--tab-block-margin));
--tab-min-height: 36px;
--tab-group-suggestions-loading-animation-color-1: color-mix(in srgb, currentColor 5%, transparent);
--tab-group-suggestions-loading-animation-color-2: color-mix(in srgb, currentColor 35%, transparent);
&[uidensity=compact] {
--tab-min-height: 29px;
}
@@ -1690,3 +1692,110 @@ toolbar:not(#TabsToolbar) #firefox-view-button {
fill: transparent;
stroke: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
}
.tab-group-suggestion-label {
--text-color-disabled: var(--panel-color);
--button-opacity-disabled: 1;
}
#tab-group-suggestions-heading,
#tab-group-main {
flex-direction: column;
}
#tab-group-default-actions,
#tab-group-suggestions-load-actions,
#tab-group-suggestion-button,
#tab-group-suggestions-message {
display: none;
}
#tab-group-suggestions-heading:not([hidden]),
#tab-group-main:not([hidden]),
#tab-group-suggestions-separator:not([hidden]),
#tab-group-suggestions-load-actions:not([hidden]),
#tab-group-suggestions-loading:not([hidden]),
#tab-group-default-actions:not([hidden]),
#tab-group-suggestion-button:not([hidden]),
#tab-group-suggestions-message:not([hidden]) {
display: flex;
}
#tab-group-suggestions-container:not([hidden]) {
display: block;
}
#tab-group-suggestions-disclaimer > a {
display: inline;
color: inherit;
}
#tab-group-suggestions-disclaimer:not([hidden]) {
display: initial;
}
#tab-group-select-toggle {
position: relative;
margin-top: 0.5em;
}
#tab-group-suggestion-button {
color: var(--color-accent-primary);
--button-font-weight: var(--font-weight-normal);
}
#tab-group-suggestions-loading {
gap: 4px;
flex-direction: column;
margin: 0 8px 8px;
}
#tab-group-suggestions-message {
font-size: 0.85em;
--button-font-weight: var(--font-weight-normal);
}
.tab-group-suggestions-loading-header,
#tab-group-suggestions-header {
margin: 8px 0;
}
@keyframes tab-group-loading-block-animation {
0% {
background-position: 200% 0;
}
50% {
background-position: 0 0;
}
100% {
background-position: -200% 0;
}
}
.tab-group-suggestions-loading-block:nth-of-type(2) {
animation-delay: 0.1s;
}
.tab-group-suggestions-loading-block:nth-of-type(3) {
animation-delay: 0.2s;
}
.tab-group-suggestions-loading-block:nth-of-type(4) {
animation-delay: 0.3s;
}
.tab-group-suggestions-loading-block {
animation: tab-group-loading-block-animation 3s infinite;
background: linear-gradient(100deg,
color-mix(in srgb, var(--tab-group-suggestions-loading-animation-color-2), transparent 60%) 30%,
var(--tab-group-suggestions-loading-animation-color-1) 50%,
color-mix(in srgb, var(--tab-group-suggestions-loading-animation-color-2), transparent 60%) 70%);
background-size: 200% 100%;
border-radius: var(--border-radius-small);
height: 1.5em;
margin: 0;
margin-bottom: 0.5em;
padding: 0;
white-space: nowrap;
width: 100%;
}