commit c667111b6d44f55a32c66da97174d17eed8e38be
parent 90469d9da14828335fdf050657b5ab0742a220cf
Author: Anna Kulyk <akulyk@mozilla.com>
Date: Wed, 3 Dec 2025 23:45:14 +0000
Bug 1971841 - Part 2: Create sync-engines-list custom component r=hjones,fluent-reviewers,desktop-theme-reviewers,bolsson
Differential Revision: https://phabricator.services.mozilla.com/D272470
Diffstat:
8 files changed, 230 insertions(+), 0 deletions(-)
diff --git a/browser/components/preferences/jar.mn b/browser/components/preferences/jar.mn
@@ -40,3 +40,5 @@ browser.jar:
content/browser/preferences/widgets/security-privacy-card.mjs (widgets/security-privacy/security-privacy-card/security-privacy-card.mjs)
content/browser/preferences/widgets/security-privacy-card.css (widgets/security-privacy/security-privacy-card/security-privacy-card.css)
content/browser/preferences/widgets/sync-device-name.mjs (widgets/sync-device-name/sync-device-name.mjs)
+ content/browser/preferences/widgets/sync-engines-list.mjs (widgets/sync-engine-list/sync-engines-list.mjs)
+ content/browser/preferences/widgets/sync-engines-list.css (widgets/sync-engine-list/sync-engines-list.css)
diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml
@@ -100,6 +100,7 @@
<script type="module" src="chrome://browser/content/preferences/widgets/security-privacy-card.mjs"></script>
<script type="module" src="chrome://global/content/elements/moz-input-color.mjs"></script>
<script type="module" src="chrome://browser/content/preferences/widgets/sync-device-name.mjs"></script>
+ <script type="module" src="chrome://browser/content/preferences/widgets/sync-engines-list.mjs"></script>
</head>
<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
diff --git a/browser/components/preferences/widgets/sync-engine-list/sync-engines-list.css b/browser/components/preferences/widgets/sync-engine-list/sync-engines-list.css
@@ -0,0 +1,35 @@
+/* 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/. */
+
+#heading {
+ font-weight: var(--heading-font-weight);
+}
+
+.engines-list-wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-medium);
+}
+
+.engines-list-container {
+ display: grid;
+ grid-template-rows: auto;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: var(--space-large) var(--space-medium);
+}
+
+.sync-engine {
+ display: flex;
+ align-items: center;
+ gap: var(--space-small);
+
+ img {
+ width: var(--icon-size);
+ height: var(--icon-size);
+ pointer-events: none;
+ -moz-context-properties: fill, stroke;
+ fill: var(--icon-color);
+ stroke: var(--icon-color);
+ }
+}
diff --git a/browser/components/preferences/widgets/sync-engine-list/sync-engines-list.mjs b/browser/components/preferences/widgets/sync-engine-list/sync-engines-list.mjs
@@ -0,0 +1,123 @@
+/* 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/. */
+
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+import { html } from "chrome://global/content/vendor/lit.all.mjs";
+
+window.MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl");
+
+/**
+ * @typedef {object} EngineInfo
+ * @property {string} iconSrc - The icon URL for the engine.
+ * @property {string} l10nId - The localization ID for the engine.
+ */
+
+/**
+ * @type {Record<string, EngineInfo>}
+ */
+const engineTypeToMetadata = {
+ bookmarks: {
+ iconSrc: "chrome://browser/skin/bookmark-hollow.svg",
+ l10nId: "sync-currently-syncing-bookmarks",
+ },
+ history: {
+ iconSrc: "chrome://browser/skin/history.svg",
+ l10nId: "sync-currently-syncing-history",
+ },
+ tabs: {
+ iconSrc: "chrome://browser/skin/tabs.svg",
+ l10nId: "sync-currently-syncing-tabs",
+ },
+ passwords: {
+ iconSrc: "chrome://browser/skin/login.svg",
+ l10nId: "sync-currently-syncing-passwords",
+ },
+ addresses: {
+ iconSrc: "chrome://browser/skin/notification-icons/geo.svg",
+ l10nId: "sync-currently-syncing-addresses",
+ },
+ payments: {
+ iconSrc: "chrome://browser/skin/payment-methods-16.svg",
+ l10nId: "sync-currently-syncing-payment-methods",
+ },
+ addons: {
+ iconSrc: "chrome://mozapps/skin/extensions/extension.svg",
+ l10nId: "sync-currently-syncing-addons",
+ },
+ settings: {
+ iconSrc: "chrome://global/skin/icons/settings.svg",
+ l10nId: "sync-currently-syncing-settings",
+ },
+};
+
+/**
+ * A custom element that displays synced engines in Sync settings section.
+ *
+ * @tagname sync-engines-list
+ * @property {string[]} engines - Array of engine types to display.
+ * Options: bookmarks, history, tabs, passwords, addresses, payments, addons, settings.
+ */
+class SyncEnginesList extends MozLitElement {
+ static properties = {
+ engines: { type: Array },
+ };
+
+ constructor() {
+ super();
+
+ /** @type {string[]} */
+ this.engines = [];
+ }
+
+ /**
+ * @param {string} type
+ */
+ engineTemplate(type) {
+ let metadata = engineTypeToMetadata[type];
+ if (!metadata) {
+ return null;
+ }
+
+ return html`
+ <div class="sync-engine">
+ <img src=${metadata.iconSrc} role="presentation" />
+ <label data-l10n-id=${metadata.l10nId}></label>
+ </div>
+ `;
+ }
+
+ syncedEnginesTemplate() {
+ return html`<moz-box-item>
+ <div class="engines-list-wrapper">
+ <span
+ id="heading"
+ data-l10n-id="sync-syncing-across-devices-heading-2"
+ ></span>
+ <div class="engines-list-container">
+ ${this.engines.map(type => this.engineTemplate(type))}
+ </div>
+ </div>
+ </moz-box-item>`;
+ }
+
+ emptyStateTemplate() {
+ return html`<placeholder-message
+ data-l10n-id="sync-syncing-across-devices-empty-state"
+ imageSrc="chrome://global/skin/illustrations/security-error.svg"
+ ></placeholder-message>`;
+ }
+
+ render() {
+ return html`
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/preferences/widgets/sync-engines-list.css"
+ />
+ ${this.engines.length
+ ? this.syncedEnginesTemplate()
+ : this.emptyStateTemplate()}
+ `;
+ }
+}
+customElements.define("sync-engines-list", SyncEnginesList);
diff --git a/browser/components/preferences/widgets/sync-engine-list/sync-engines-list.stories.mjs b/browser/components/preferences/widgets/sync-engine-list/sync-engines-list.stories.mjs
@@ -0,0 +1,57 @@
+/* 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/. */
+
+import { html } from "chrome://global/content/vendor/lit.all.mjs";
+import "chrome://browser/content/preferences/widgets/sync-engines-list.mjs";
+import "chrome://browser/content/preferences/widgets/placeholder-message.mjs";
+
+export default {
+ title: "Domain-specific UI Widgets/Settings/Sync Engines List",
+ component: "sync-engines-list",
+ parameters: {
+ status: "in-development",
+ },
+ argTypes: {
+ engines: {
+ control: "check",
+ options: [
+ "bookmarks",
+ "history",
+ "tabs",
+ "passwords",
+ "settings",
+ "addresses",
+ "payments",
+ "addons",
+ ],
+ },
+ },
+};
+
+window.MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl");
+
+const Template = ({ engines = [] }) => html`
+ <div style="max-width: 520px">
+ <sync-engines-list .engines=${engines}></sync-engines-list>
+ </div>
+`;
+
+export const Default = Template.bind({});
+Default.args = {
+ // Note: "addons" icon currently doesn’t render in Storybook.
+ engines: [
+ "bookmarks",
+ "history",
+ "tabs",
+ "passwords",
+ "settings",
+ "addresses",
+ "payments",
+ ],
+};
+
+export const EmptyState = Template.bind({});
+EmptyState.args = {
+ engines: [],
+};
diff --git a/browser/locales/en-US/browser/preferences/preferences.ftl b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -1047,6 +1047,12 @@ prefs-syncing-button =
sync-syncing-across-devices-heading = You are syncing these items across all your connected devices:
+sync-syncing-across-devices-heading-2 = Data synced across devices
+
+sync-syncing-across-devices-empty-state =
+ .label = You aren’t syncing anything… yet.
+ .description = Start syncing to get all of your data on all your devices.
+
sync-currently-syncing-bookmarks = Bookmarks
sync-currently-syncing-history = History
sync-currently-syncing-tabs = Open tabs
diff --git a/browser/themes/shared/icons/payment-methods-16.svg b/browser/themes/shared/icons/payment-methods-16.svg
@@ -0,0 +1,4 @@
+<!-- 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/. -->
+ <svg width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg"><path d="M7 11H3V9.5h4V11z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14 2a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h12zM1.5 12a.5.5 0 0 0 .5.5h12a.5.5 0 0 0 .5-.5V7h-13v5zM2 3.5a.5.5 0 0 0-.5.5v1.5h13V4a.5.5 0 0 0-.5-.5H2z"/></svg>
+\ No newline at end of file
diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
@@ -218,6 +218,7 @@
skin/classic/browser/new-tab.svg (../shared/icons/new-tab.svg)
skin/classic/browser/notification-fill-12.svg (../shared/icons/notification-fill-12.svg)
skin/classic/browser/open.svg (../shared/icons/open.svg)
+ skin/classic/browser/payment-methods-16.svg (../shared/icons/payment-methods-16.svg)
skin/classic/browser/pin-12.svg (../shared/icons/pin-12.svg)
skin/classic/browser/pin.svg (../shared/icons/pin.svg)
skin/classic/browser/privateBrowsing.svg (../shared/icons/privateBrowsing.svg)