Bug 1505130 - Update styling of USB scanning status in sidebar, r=jdescottes,ladybenko
authorOla Gasidlo <ogasidlo@mozilla.com>
Fri, 01 Mar 2019 13:31:00 +0000
changeset 519857 c1d95be237463b87764315db98860fa7887625a0
parent 519856 ccd70bb02d61d1b627815f921caaebe1ce999e4f
child 519858 4cb69524998c9c6fcf1cad71e97bfac91a6a712f
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes, ladybenko
bugs1505130
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1505130 - Update styling of USB scanning status in sidebar, r=jdescottes,ladybenko Added message-info component to sidebar (including styling + icon) Differential Revision: https://phabricator.services.mozilla.com/D16971
devtools/client/aboutdebugging-new/src/base.css
devtools/client/aboutdebugging-new/src/components/RuntimePage.js
devtools/client/aboutdebugging-new/src/components/shared/Message.css
devtools/client/aboutdebugging-new/src/components/shared/Message.js
devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css
devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
devtools/client/aboutdebugging-new/src/components/sidebar/SidebarItem.css
devtools/client/aboutdebugging-new/src/constants.js
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_addons_manifest_url.js
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_addons_temporary_install_error.js
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_connect_toggle_usb_devices.js
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_status.js
devtools/client/aboutdebugging-new/test/browser/helper-real-usb.js
devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
devtools/client/jar.mn
devtools/client/themes/images/aboutdebugging-information.svg
--- a/devtools/client/aboutdebugging-new/src/base.css
+++ b/devtools/client/aboutdebugging-new/src/base.css
@@ -28,19 +28,19 @@
 
   /* Colors from Photon */
   --success-50: #30e60b;
   --warning-50: #ffe900;
   --warning-90: #3e2800;
   --error-50: #ff0039;
   --error-60: #d70022;
   --highlight-50: #0a84ff;
-  --grey-20: #ededf0;
+  --grey-20: #ededf0; /* for ui, no special semantic */
   --grey-30: #d7d7db; /* for ui, no special semantic */
-  --grey-90: #0c0c0d;
+  --grey-90: #0c0c0d; /* for ui, no special semantic */
   --grey-90-a10: rgba(12, 12, 13, 0.1);
   --grey-90-a20: rgba(12, 12, 13, 0.2);
   --grey-90-a30: rgba(12, 12, 13, 0.3);
   --grey-90-a60: rgba(12, 12, 13, 0.6);
   --grey-90-a80: rgba(12, 12, 13, 0.8);
   --white-100: #fff; /* for ui, no special semantic */
 
   /* Typography from Photon */
@@ -61,16 +61,17 @@
   --page-width: 664px;
   --base-unit: 4px;
 
   /* Global styles */
   --base-font-style: message-box;
   --base-font-size: var(--body-10-font-size);
   --base-font-weight: var(--body-10-font-weight);
   --base-line-height: 1.8;
+  --message-font-size: 13px; /* Body 10 in Photon - https://design.firefox.com/photon/visuals/typography.html */
   --button-font-size: var(--base-font-size);
   --micro-font-size: 11px;
 
   --monospace-font-family: monospace;
 
   /*
    * Variables particular to about:debugging
    */
--- a/devtools/client/aboutdebugging-new/src/components/RuntimePage.js
+++ b/devtools/client/aboutdebugging-new/src/components/RuntimePage.js
@@ -126,22 +126,27 @@ class RuntimePage extends PureComponent 
       );
     });
 
     return Message(
       {
         level: MESSAGE_LEVEL.ERROR,
       },
       dom.div(
-        {},
+        {
+          className: "js-tmp-extension-install-error",
+        },
         Localized(
           {
             id: "about-debugging-tmp-extension-install-error",
           },
-          dom.span({}, "There was an error during the temporary add-on installation")
+          dom.span(
+            { },
+            "There was an error during the temporary add-on installation"
+          )
         ),
         errors
       )
     );
   }
 
   render() {
     const {
--- a/devtools/client/aboutdebugging-new/src/components/shared/Message.css
+++ b/devtools/client/aboutdebugging-new/src/components/shared/Message.css
@@ -2,22 +2,26 @@
  * 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/. */
 
 .message--level-error {
   --message-color: var(--white-100);
   --message-background-color: var(--error-60);
 }
 
+.message--level-info {
+  --message-color: var(--grey-90);
+  --message-background-color: var(--grey-20);
+}
+
 .message--level-warning {
   --message-color: var(--warning-90);
   --message-background-color: var(--warning-50);
 }
 
-
 /*
  * Layout of the message
  *
  *  +--------+-----------------+
  *  | Icon   | Message content |
  *  |        | (several lines) |
  *  |        | (     ...     ) |
  *  +--------+-----------------+
@@ -27,15 +31,19 @@
   border-radius: var(--base-unit);
   color: var(--message-color);
   display: grid;
   fill: var(--message-color);
   grid-column-gap: var(--base-unit);
   grid-template-columns: calc(var(--base-unit) * 6) 1fr;
   margin: calc(var(--base-unit) * 2) 0;
   padding: var(--base-unit);
-
   -moz-context-properties: fill;
 }
 
 .message__icon {
   margin: var(--base-unit);
 }
+
+.message__body {
+  font-size: var(--message-font-size);
+  font-weight: 400;
+}
--- a/devtools/client/aboutdebugging-new/src/components/shared/Message.js
+++ b/devtools/client/aboutdebugging-new/src/components/shared/Message.js
@@ -8,16 +8,17 @@ const { PureComponent } = require("devto
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const { MESSAGE_LEVEL } = require("../../constants");
 
 const ICONS = {
   // Reuse the warning icon for errors. Waiting for the proper icon in Bug 1520191.
   [MESSAGE_LEVEL.ERROR]: "chrome://global/skin/icons/warning.svg",
+  [MESSAGE_LEVEL.INFO]: "chrome://devtools/skin/images/aboutdebugging-information.svg",
   [MESSAGE_LEVEL.WARNING]: "chrome://global/skin/icons/warning.svg",
 };
 
 /**
  * This component is designed to display a photon-style message bar. The component is
  * responsible for displaying the message container with the appropriate icon. The content
  * of the message should be passed as the children of this component.
  */
@@ -25,27 +26,32 @@ class Message extends PureComponent {
   static get propTypes() {
     return {
       children: PropTypes.node.isRequired,
       level: PropTypes.oneOf(Object.values(MESSAGE_LEVEL)).isRequired,
     };
   }
 
   render() {
-    const { level } = this.props;
+    const { level, children } = this.props;
     const iconSrc = ICONS[level];
 
     return dom.aside(
       {
         className: `message message--level-${level} js-message`,
       },
       dom.img(
         {
           className: "message__icon",
           src: iconSrc,
         }
       ),
-      this.props.children
+      dom.div(
+        {
+          className: "message__body",
+        },
+        children
+      ),
     );
   }
 }
 
 module.exports = Message;
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css
@@ -1,15 +1,15 @@
 /* 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/. */
 
-.sidebar__devices__message {
+.sidebar__label {
   color: var(--grey-40);
-  display: inline-block;
+  display: block;
   padding: 12px 0;
   text-align: center;
-  width: 100%;
+  font-size: var(--message-font-size);
 }
 
 .sidebar__refresh-usb {
   text-align: center;
 }
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
@@ -6,20 +6,21 @@
 
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
 const Localized = createFactory(FluentReact.Localized);
 
-const { PAGE_TYPES, RUNTIMES } = require("../../constants");
+const { MESSAGE_LEVEL, PAGE_TYPES, RUNTIMES } = require("../../constants");
 const Types = require("../../types/index");
 loader.lazyRequireGetter(this, "ADB_ADDON_STATES", "devtools/shared/adb/adb-addon", true);
 
+const Message = createFactory(require("../shared/Message"));
 const SidebarItem = createFactory(require("./SidebarItem"));
 const SidebarFixedItem = createFactory(require("./SidebarFixedItem"));
 const SidebarRuntimeItem = createFactory(require("./SidebarRuntimeItem"));
 const RefreshDevicesButton = createFactory(require("./RefreshDevicesButton"));
 const FIREFOX_ICON = "chrome://devtools/skin/images/aboutdebugging-firefox-logo.svg";
 const CONNECT_ICON = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
 const GLOBE_ICON = "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
 const USB_ICON = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
@@ -37,40 +38,46 @@ class Sidebar extends PureComponent {
       usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
     };
   }
 
   renderAdbAddonStatus() {
     const isAddonInstalled = this.props.adbAddonStatus === ADB_ADDON_STATES.INSTALLED;
     const localizationId = isAddonInstalled ? "about-debugging-sidebar-usb-enabled" :
                                               "about-debugging-sidebar-usb-disabled";
-    return Localized(
+    return Message(
       {
-        id: localizationId,
-      }, dom.aside(
-        {
-          className: "sidebar__devices__message js-sidebar-usb-status",
-        },
-        localizationId
+          level: MESSAGE_LEVEL.INFO,
+      },
+        Localized(
+          {
+            id: localizationId,
+          },
+          dom.div(
+            {
+              className: "js-sidebar-usb-status",
+            },
+            localizationId
+          )
       )
     );
   }
 
   renderDevicesEmpty() {
     return SidebarItem(
       {
         isSelected: false,
       },
       Localized(
         {
           id: "about-debugging-sidebar-no-devices",
         },
         dom.aside(
           {
-            className: "sidebar__devices__message js-sidebar-no-devices",
+            className: "sidebar__label js-sidebar-no-devices",
           },
           "No devices discovered"
         )
       )
     );
   }
 
   renderDevices() {
@@ -144,18 +151,18 @@ class Sidebar extends PureComponent {
               selectedRuntimeId === RUNTIMES.THIS_FIREFOX,
             key: RUNTIMES.THIS_FIREFOX,
             name: "This Firefox",
             to: `/runtime/${RUNTIMES.THIS_FIREFOX}`,
           })
         ),
         SidebarItem(
           {
+            className: "sidebar-item--overflow",
             isSelected: false,
-            key: "separator-0",
           },
           dom.hr({ className: "separator" }),
           this.renderAdbAddonStatus(),
         ),
         this.renderDevices(),
         SidebarItem(
           {
             className: "sidebar-item--breathe sidebar__refresh-usb",
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarItem.css
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarItem.css
@@ -13,16 +13,21 @@
   border-radius: 2px;
   height: var(--category-height);
   padding-inline-end: var(--category-padding);
   padding-inline-start: var(--category-padding);
   transition: background-color var(--category-transition-duration);
   -moz-user-select: none;
 }
 
+.sidebar-item--overflow {
+  min-height: var(--category-height);
+  height: auto;
+}
+
 .sidebar-item__link {
   display: block;
   height: 100%;
 }
 
 .sidebar-item__link,
 .sidebar-item__link:hover {
   color: inherit; /* do not apply usual link colors, but grab this element parent's */
--- a/devtools/client/aboutdebugging-new/src/constants.js
+++ b/devtools/client/aboutdebugging-new/src/constants.js
@@ -75,16 +75,17 @@ const DEBUG_TARGET_PANE = {
   SERVICE_WORKER: "serviceWorker",
   SHARED_WORKER: "sharedWorker",
   TAB: "tab",
   TEMPORARY_EXTENSION: "temporaryExtension",
 };
 
 const MESSAGE_LEVEL = {
   ERROR: "error",
+  INFO: "info",
   WARNING: "warning",
 };
 
 const PAGE_TYPES = {
   RUNTIME: "runtime",
   CONNECT: "connect",
 };
 
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_addons_manifest_url.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_addons_manifest_url.js
@@ -18,17 +18,17 @@ add_task(async function() {
   await checkAdbNotRunning();
 
   const { document, tab, window } = await openAboutDebugging();
   await selectThisFirefoxPage(document, window.AboutDebugging.store);
   const usbStatusElement = document.querySelector(".js-sidebar-usb-status");
 
   info("Install ADB");
   adbAddon.install("internal");
-  await waitUntil(() => usbStatusElement.textContent.includes("USB devices enabled"));
+  await waitUntil(() => usbStatusElement.textContent.includes("USB enabled"));
   await waitForAdbStart();
 
   info("Wait until the debug target for ADB appears");
   await waitUntil(() => findDebugTargetByText(ABD_ADDON_NAME, document));
   const adbExtensionItem = findDebugTargetByText(ABD_ADDON_NAME, document);
 
   const manifestUrlElement = adbExtensionItem.querySelector(".js-manifest-url");
   ok(manifestUrlElement, "A link to the manifest is displayed");
@@ -48,14 +48,14 @@ add_task(async function() {
   ok(manifestObject, "The displayed content is a valid JSON object");
   is(manifestObject.name, ABD_ADDON_NAME, "Manifest tab shows the expected content");
 
   info("Close the manifest.json tab");
   await removeTab(target);
 
   info("Uninstall the adb extension and wait for the message to udpate");
   adbAddon.uninstall();
-  await waitUntil(() => usbStatusElement.textContent.includes("USB devices disabled"));
+  await waitUntil(() => usbStatusElement.textContent.includes("USB disabled"));
   await waitForAdbStop();
 
   await waitForRequestsToSettle(window.AboutDebugging.store);
   await removeTab(tab);
 });
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_addons_temporary_install_error.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_addons_temporary_install_error.js
@@ -26,17 +26,17 @@ add_task(async function testInvalidJsonE
   const installError = await installBadExtension(INVALID_JSON_EXTENSION_PATH, document);
   ok(installError.textContent.includes("JSON.parse: unexpected keyword"),
     "The expected installation error is displayed: " + installError.textContent);
 
   info("Install a valid extension to make the message disappear");
   await installTemporaryExtension(EXTENSION_PATH, EXTENSION_NAME, document);
 
   info("Wait until the error message disappears");
-  await waitUntil(() => !document.querySelector(".js-message"));
+  await waitUntil(() => !document.querySelector(".js-tmp-extension-install-error"));
 
   info("Wait for the temporary addon to be displayed as a debug target");
   await waitUntil(() => findDebugTargetByText(EXTENSION_NAME, document));
 
   await removeTemporaryExtension(EXTENSION_NAME, document);
 
   await removeTab(tab);
 });
@@ -60,11 +60,11 @@ add_task(async function testInvalidPrope
 
 async function installBadExtension(path, document) {
   info("Install a bad extension at path: " + path);
   // Do not use installTemporaryAddon here since the install will fail.
   prepareMockFilePicker(path);
   document.querySelector(".js-temporary-extension-install-button").click();
 
   info("Wait until the install error message appears");
-  await waitUntil(() => document.querySelector(".js-message"));
-  return document.querySelector(".js-message");
+  await waitUntil(() => document.querySelector(".js-tmp-extension-install-error"));
+  return document.querySelector(".js-tmp-extension-install-error");
 }
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_connect_toggle_usb_devices.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_connect_toggle_usb_devices.js
@@ -41,17 +41,17 @@ add_task(async function() {
     "The message about enabling USB devices is no longer rendered");
 
   info("Check that the addon was installed with the proper source");
   const adbExtensionId = Services.prefs.getCharPref("devtools.remote.adb.extensionID");
   const addon = await AddonManager.getAddonByID(adbExtensionId);
   Assert.deepEqual(addon.installTelemetryInfo, { source: "about:debugging" },
     "Got the expected addon.installTelemetryInfo");
 
-  // Right now we are resuming as soon as "USB devices enabled" is displayed, but ADB
+  // Right now we are resuming as soon as "USB enabled" is displayed, but ADB
   // might still be starting up. If we move to uninstall directly, the ADB startup will
   // fail and we will have an unhandled promise rejection.
   // See Bug 1498469.
   await waitForAdbStart();
 
   info("Click on the toggle button");
   usbToggleButton.click();
 
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_status.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_status.js
@@ -16,28 +16,28 @@ add_task(async function() {
   await pushPref("devtools.remote.adb.extensionURL",
                  CHROME_URL_ROOT + "resources/test-adb-extension/adb-extension-#OS#.xpi");
   await checkAdbNotRunning();
 
   const { document, tab } = await openAboutDebugging();
 
   const usbStatusElement = document.querySelector(".js-sidebar-usb-status");
   ok(usbStatusElement, "Sidebar shows the USB status element");
-  ok(usbStatusElement.textContent.includes("USB devices disabled"),
+  ok(usbStatusElement.textContent.includes("USB disabled"),
     "USB status element has the expected content");
 
   info("Install the adb extension and wait for the message to udpate");
   // Use "internal" as the install source to avoid triggering telemetry.
   adbAddon.install("internal");
-  await waitUntil(() => usbStatusElement.textContent.includes("USB devices enabled"));
-  // Right now we are resuming as soon as "USB devices enabled" is displayed, but ADB
+  await waitUntil(() => usbStatusElement.textContent.includes("USB enabled"));
+  // Right now we are resuming as soon as "USB enabled" is displayed, but ADB
   // might still be starting up. If we move to uninstall directly, the ADB startup will
   // fail and we will have an unhandled promise rejection.
   // See Bug 1498469.
   await waitForAdbStart();
 
   info("Uninstall the adb extension and wait for the message to udpate");
   adbAddon.uninstall();
-  await waitUntil(() => usbStatusElement.textContent.includes("USB devices disabled"));
+  await waitUntil(() => usbStatusElement.textContent.includes("USB disabled"));
   await waitForAdbStop();
 
   await removeTab(tab);
 });
--- a/devtools/client/aboutdebugging-new/test/browser/helper-real-usb.js
+++ b/devtools/client/aboutdebugging-new/test/browser/helper-real-usb.js
@@ -33,17 +33,17 @@ async function openAboutDebuggingWithADB
 
   await pushPref("devtools.remote.adb.extensionURL",
                  CHROME_URL_ROOT + "resources/test-adb-extension/adb-extension-#OS#.xpi");
   await checkAdbNotRunning();
 
   const { adbAddon } = require("devtools/shared/adb/adb-addon");
   adbAddon.install("internal");
   const usbStatusElement = document.querySelector(".js-sidebar-usb-status");
-  await waitUntil(() => usbStatusElement.textContent.includes("USB devices enabled"));
+  await waitUntil(() => usbStatusElement.textContent.includes("USB enabled"));
   await waitForAdbStart();
 
   return { document, tab, window };
 }
 /* exported openAboutDebuggingWithADB */
 
 function _getExpectedRuntimesPath() {
   const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
--- a/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
+++ b/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
@@ -16,21 +16,21 @@ about-debugging-this-firefox-runtime-nam
 about-debugging-sidebar-this-firefox =
   .name = { about-debugging-this-firefox-runtime-name }
 
 # Sidebar heading for connecting to some remote source
 about-debugging-sidebar-connect =
   .name = Connect
 
 # Text displayed in the about:debugging sidebar when USB devices discovery is enabled.
-about-debugging-sidebar-usb-enabled = USB devices enabled
+about-debugging-sidebar-usb-enabled = USB enabled
 
 # Text displayed in the about:debugging sidebar when USB devices discovery is disabled
 # (for instance because the mandatory ADB extension is not installed).
-about-debugging-sidebar-usb-disabled = USB devices disabled
+about-debugging-sidebar-usb-disabled = USB disabled
 
 # Connection status (connected) for runtime items in the sidebar
 aboutdebugging-sidebar-runtime-connection-status-connected = Connected
 # Connection status (disconnected) for runtime items in the sidebar
 aboutdebugging-sidebar-runtime-connection-status-disconnected = Disconnected
 
 # Text displayed in the about:debugging sidebar when no device was found.
 about-debugging-sidebar-no-devices = No devices discovered
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -91,16 +91,17 @@ devtools.jar:
     skin/images/filter-swatch.svg (themes/images/filter-swatch.svg)
     skin/images/aboutdebugging-connect-icon.svg (themes/images/aboutdebugging-connect-icon.svg)
     skin/images/aboutdebugging-firefox-aurora.svg (themes/images/aboutdebugging-firefox-aurora.svg)
     skin/images/aboutdebugging-firefox-beta.svg (themes/images/aboutdebugging-firefox-beta.svg)
     skin/images/aboutdebugging-firefox-logo.svg (themes/images/aboutdebugging-firefox-logo.svg)
     skin/images/aboutdebugging-firefox-nightly.svg (themes/images/aboutdebugging-firefox-nightly.svg)
     skin/images/aboutdebugging-firefox-release.svg (themes/images/aboutdebugging-firefox-release.svg)
     skin/images/aboutdebugging-globe-icon.svg (themes/images/aboutdebugging-globe-icon.svg)
+    skin/images/aboutdebugging-information.svg (themes/images/aboutdebugging-information.svg)
     skin/images/aboutdebugging-usb-icon.svg (themes/images/aboutdebugging-usb-icon.svg)
     skin/images/fox-smiling.svg (themes/images/fox-smiling.svg)
     skin/images/grid.svg (themes/images/grid.svg)
     skin/images/angle-swatch.svg (themes/images/angle-swatch.svg)
     skin/images/flexbox-swatch.svg (themes/images/flexbox-swatch.svg)
     skin/images/pseudo-class.svg (themes/images/pseudo-class.svg)
     skin/images/copy.svg (themes/images/copy.svg)
     skin/images/animation-fast-track.svg (themes/images/animation-fast-track.svg)
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/aboutdebugging-information.svg
@@ -0,0 +1,8 @@
+<!-- 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 xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+	<path d="M8 16a8 8 0 1 1 8-8 8.009 8.009 0 0 1-8 8zM8 2a6 6 0 1 0 6 6 6.006 6.006 0 0 0-6-6z"/>
+	<path d="M8 7a1 1 0 0 0-1 1v3a1 1 0 0 0 2 0V8a1 1 0 0 0-1-1z"/>
+	<circle cx="8" cy="5" r="1.188"/>
+</svg>