Bug 1467572 - Part 5: Implement the new style for the global toolbar. r=rcaliman
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 15 Aug 2018 17:27:34 -0400
changeset 431852 dae96e14900fcca69d0215602b1b30b29ace0233
parent 431851 3427989ad89ec6484698eda2a13682cbd1f1a813
child 431853 9f1db12b0ab98e66e49a0816a353ce99e7acdaa9
push id34451
push userebalazs@mozilla.com
push dateThu, 16 Aug 2018 09:25:15 +0000
treeherdermozilla-central@161817e6d127 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrcaliman
bugs1467572
milestone63.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 1467572 - Part 5: Implement the new style for the global toolbar. r=rcaliman
devtools/client/responsive.html/components/App.js
devtools/client/responsive.html/components/DevicePixelRatioSelector.js
devtools/client/responsive.html/components/DeviceSelector.js
devtools/client/responsive.html/components/GlobalToolbar.js
devtools/client/responsive.html/components/ReloadConditions.js
devtools/client/responsive.html/components/Toolbar.js
devtools/client/responsive.html/components/Viewports.js
devtools/client/responsive.html/components/moz.build
devtools/client/responsive.html/index.css
devtools/client/responsive.html/index.js
devtools/client/responsive.html/test/browser/browser_network_throttling.js
devtools/client/responsive.html/test/browser/head.js
devtools/client/shared/components/throttling/NetworkThrottlingSelector.js
--- a/devtools/client/responsive.html/components/App.js
+++ b/devtools/client/responsive.html/components/App.js
@@ -26,17 +26,17 @@ const {
   changeDevice,
   changePixelRatio,
   removeDeviceAssociation,
   resizeViewport,
   rotateViewport,
 } = require("../actions/viewports");
 
 const DeviceModal = createFactory(require("./DeviceModal"));
-const GlobalToolbar = createFactory(require("./GlobalToolbar"));
+const Toolbar = createFactory(require("./Toolbar"));
 const Viewports = createFactory(require("./Viewports"));
 
 const Types = require("../types");
 
 class App extends Component {
   static get propTypes() {
     return {
       devices: PropTypes.shape(Types.devices).isRequired,
@@ -211,17 +211,17 @@ class App extends Component {
     if (devices.modalOpenedFromViewport !== null) {
       deviceAdderViewportTemplate = viewports[devices.modalOpenedFromViewport];
     }
 
     return dom.div(
       {
         id: "app",
       },
-      GlobalToolbar({
+      Toolbar({
         devices,
         displayPixelRatio,
         networkThrottling,
         reloadConditions,
         screenshot,
         selectedDevice,
         selectedPixelRatio,
         touchSimulation,
--- a/devtools/client/responsive.html/components/DevicePixelRatioSelector.js
+++ b/devtools/client/responsive.html/components/DevicePixelRatioSelector.js
@@ -114,17 +114,17 @@ class DevicePixelRatioSelector extends P
     let listContent = PIXEL_RATIO_PRESET.map(createVisibleOption);
 
     if (state == Types.loadableState.LOADED) {
       listContent = listContent.concat(hiddenOptions.map(createHiddenOption));
     }
 
     return dom.select(
       {
-        id: "global-device-pixel-ratio-selector",
+        id: "device-pixel-ratio-selector",
         value: selectedPixelRatio.value || displayPixelRatio,
         disabled: isDisabled,
         onChange: this.onSelectChange,
         onFocus: this.onFocusChange,
         onBlur: this.onFocusChange,
         className: selectorClass,
         title: title
       },
--- a/devtools/client/responsive.html/components/DeviceSelector.js
+++ b/devtools/client/responsive.html/components/DeviceSelector.js
@@ -67,17 +67,17 @@ class DeviceSelector extends PureCompone
         }
       }
     }
 
     options.sort(function(a, b) {
       return a.name.localeCompare(b.name);
     });
 
-    let selectClass = "viewport-device-selector toolbar-dropdown";
+    let selectClass = "toolbar-dropdown";
     if (selectedDevice) {
       selectClass += " selected";
     }
 
     const state = devices.listState;
     let listContent;
 
     if (state == Types.loadableState.LOADED) {
@@ -112,16 +112,17 @@ class DeviceSelector extends PureCompone
         value: "",
         title: "",
         disabled: true,
       }, getStr("responsive.deviceListError"))];
     }
 
     return dom.select(
       {
+        id: "device-selector",
         className: selectClass,
         value: selectedDevice,
         title: selectedDevice,
         onChange: this.onSelectChange,
         disabled: (state !== Types.loadableState.LOADED),
       },
       ...listContent
     );
--- a/devtools/client/responsive.html/components/ReloadConditions.js
+++ b/devtools/client/responsive.html/components/ReloadConditions.js
@@ -21,17 +21,17 @@ class ReloadConditions extends PureCompo
 
   render() {
     const {
       reloadConditions,
       onChangeReloadCondition,
     } = this.props;
 
     return ToggleMenu({
-      id: "global-reload-conditions-menu",
+      id: "reload-conditions-menu",
       items: [
         {
           id: "touchSimulation",
           label: getStr("responsive.reloadConditions.touchSimulation"),
           checked: reloadConditions.touchSimulation,
         },
         {
           id: "userAgent",
rename from devtools/client/responsive.html/components/GlobalToolbar.js
rename to devtools/client/responsive.html/components/Toolbar.js
--- a/devtools/client/responsive.html/components/GlobalToolbar.js
+++ b/devtools/client/responsive.html/components/Toolbar.js
@@ -10,17 +10,17 @@ const dom = require("devtools/client/sha
 
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 const DevicePixelRatioSelector = createFactory(require("./DevicePixelRatioSelector"));
 const DeviceSelector = createFactory(require("./DeviceSelector"));
 const NetworkThrottlingSelector = createFactory(require("devtools/client/shared/components/throttling/NetworkThrottlingSelector"));
 const ReloadConditions = createFactory(require("./ReloadConditions"));
 
-class GlobalToolbar extends PureComponent {
+class Toolbar extends PureComponent {
   static get propTypes() {
     return {
       devices: PropTypes.shape(Types.devices).isRequired,
       displayPixelRatio: Types.pixelRatio.value.isRequired,
       networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
       reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
       screenshot: PropTypes.shape(Types.screenshot).isRequired,
       selectedDevice: PropTypes.string.isRequired,
@@ -60,60 +60,63 @@ class GlobalToolbar extends PureComponen
     } = this.props;
 
     let touchButtonClass = "toolbar-button devtools-button";
     if (touchSimulation.enabled) {
       touchButtonClass += " checked";
     }
 
     return dom.header(
-      {
-        id: "global-toolbar",
-        className: "container",
-      },
+      { id: "toolbar" },
       DeviceSelector({
         devices,
         selectedDevice,
         viewportId: 0,
         onChangeDevice,
         onResizeViewport,
         onUpdateDeviceModal,
       }),
-      NetworkThrottlingSelector({
-        networkThrottling,
-        onChangeNetworkThrottling,
-      }),
-      DevicePixelRatioSelector({
-        devices,
-        displayPixelRatio,
-        selectedDevice,
-        selectedPixelRatio,
-        onChangePixelRatio,
-      }),
-      ReloadConditions({
-        reloadConditions,
-        onChangeReloadCondition,
-      }),
-      dom.button({
-        id: "global-touch-simulation-button",
-        className: touchButtonClass,
-        title: (touchSimulation.enabled ?
-          getStr("responsive.disableTouch") : getStr("responsive.enableTouch")),
-        onClick: () => onChangeTouchSimulation(!touchSimulation.enabled),
-      }),
-      dom.button({
-        id: "global-screenshot-button",
-        className: "toolbar-button devtools-button",
-        title: getStr("responsive.screenshot"),
-        onClick: onScreenshot,
-        disabled: screenshot.isCapturing,
-      }),
-      dom.button({
-        id: "global-exit-button",
-        className: "toolbar-button devtools-button",
-        title: getStr("responsive.exit"),
-        onClick: onExit,
-      })
+      dom.div(
+        { id: "toolbar-center-controls" },
+        DevicePixelRatioSelector({
+          devices,
+          displayPixelRatio,
+          selectedDevice,
+          selectedPixelRatio,
+          onChangePixelRatio,
+        }),
+        NetworkThrottlingSelector({
+          networkThrottling,
+          onChangeNetworkThrottling,
+        }),
+        dom.button({
+          id: "touch-simulation-button",
+          className: touchButtonClass,
+          title: (touchSimulation.enabled ?
+            getStr("responsive.disableTouch") : getStr("responsive.enableTouch")),
+          onClick: () => onChangeTouchSimulation(!touchSimulation.enabled),
+        })
+      ),
+      dom.div(
+        { id: "toolbar-end-controls" },
+        dom.button({
+          id: "screenshot-button",
+          className: "toolbar-button devtools-button",
+          title: getStr("responsive.screenshot"),
+          onClick: onScreenshot,
+          disabled: screenshot.isCapturing,
+        }),
+        ReloadConditions({
+          reloadConditions,
+          onChangeReloadCondition,
+        }),
+        dom.button({
+          id: "exit-button",
+          className: "toolbar-button devtools-button",
+          title: getStr("responsive.exit"),
+          onClick: onExit,
+        })
+      )
     );
   }
 }
 
-module.exports = GlobalToolbar;
+module.exports = Toolbar;
--- a/devtools/client/responsive.html/components/Viewports.js
+++ b/devtools/client/responsive.html/components/Viewports.js
@@ -28,29 +28,49 @@ class Viewports extends Component {
       screenshot,
       viewports,
       onBrowserMounted,
       onContentResize,
       onRemoveDeviceAssociation,
       onResizeViewport,
     } = this.props;
 
-    return dom.div(
-      {
-        id: "viewports",
-      },
-      viewports.map((viewport, i) => {
-        return ResizableViewport({
-          key: viewport.id,
-          screenshot,
-          swapAfterMount: i == 0,
-          viewport,
-          onBrowserMounted,
-          onContentResize,
-          onRemoveDeviceAssociation,
-          onResizeViewport,
-        });
-      })
+    const viewportSize = window.getViewportSize();
+    // The viewport may not have been created yet. Default to justify-content: center
+    // for the container.
+    let justifyContent = "center";
+
+    // If the RDM viewport is bigger than the window's inner width, set the container's
+    // justify-content to start so that the left-most viewport is visible when there's
+    // horizontal overflow. That is when the horizontal space become smaller than the
+    // viewports and a scrollbar appears, then the first viewport will still be visible.
+    if (viewportSize && viewportSize.width > window.innerWidth) {
+      justifyContent = "start";
+    }
+
+    return (
+      dom.div(
+        {
+          id: "viewports-container",
+          style: {
+            justifyContent,
+          },
+        },
+        dom.div({ id: "viewports" },
+          viewports.map((viewport, i) => {
+            return ResizableViewport({
+              key: viewport.id,
+              screenshot,
+              swapAfterMount: i == 0,
+              viewport,
+              onBrowserMounted,
+              onContentResize,
+              onRemoveDeviceAssociation,
+              onResizeViewport,
+            });
+          })
+        )
+      )
     );
   }
 }
 
 module.exports = Viewports;
--- a/devtools/client/responsive.html/components/moz.build
+++ b/devtools/client/responsive.html/components/moz.build
@@ -6,15 +6,15 @@
 
 DevToolsModules(
     'App.js',
     'Browser.js',
     'DeviceAdder.js',
     'DeviceModal.js',
     'DevicePixelRatioSelector.js',
     'DeviceSelector.js',
-    'GlobalToolbar.js',
     'ReloadConditions.js',
     'ResizableViewport.js',
     'ToggleMenu.js',
+    'Toolbar.js',
     'ViewportDimension.js',
     'Viewports.js',
 )
--- a/devtools/client/responsive.html/index.css
+++ b/devtools/client/responsive.html/index.css
@@ -26,34 +26,30 @@
 * {
   box-sizing: border-box;
 }
 
 :root,
 input,
 select,
 button {
-  font-size: 11px;
+  font-size: 12px;
 }
 
 html,
 body,
 #root {
   height: 100%;
-  margin: 0;
+  overflow: hidden;
 }
 
 #app {
-  /* Center the viewports container */
   display: flex;
-  align-items: center;
   flex-direction: column;
-  padding-top: 15px;
-  padding-bottom: 1%;
-  position: relative;
+  width: 100%;
   height: 100%;
 }
 
 /**
  * Common styles for shared components
  */
 
 .container {
@@ -139,17 +135,17 @@ select > option.divider {
   position: relative;
 }
 
 .devtools-toggle-menu .devtools-menu {
   display: none;
   flex-direction: column;
   align-items: start;
   position: absolute;
-  left: 0;
+  right: 0;
   top: 100%;
   z-index: 1;
   padding: 5px;
   border-radius: 2px;
   background-color: var(--theme-toolbar-background);
   box-shadow: var(--rdm-box-shadow);
 }
 
@@ -160,128 +156,145 @@ select > option.divider {
 .devtools-toggle-menu .devtools-menu-item {
   display: flex;
   align-items: center;
 }
 
 /**
  * Common background for dropdowns like select and toggle menu
  */
+
 .toolbar-dropdown,
 .toolbar-dropdown.devtools-button,
 .toolbar-dropdown.devtools-button:hover:not(:empty):not(:disabled):not(.checked) {
   background-color: var(--theme-toolbar-background);
   background-image: var(--select-arrow-image);
   background-position: 100% 50%;
   background-repeat: no-repeat;
   background-size: 7px;
   -moz-context-properties: fill;
   fill: currentColor;
 }
 
+.toolbar-dropdown {
+  background-position-x: right 5px;
+  border-right: 1px solid var(--theme-splitter-color);
+  padding-right: 15px;
+}
+
 /**
- * Global Toolbar
+ * Toolbar
  */
 
-#global-toolbar {
-  color: var(--theme-body-color-alt);
-  border-radius: 2px;
-  box-shadow: var(--rdm-box-shadow);
-  margin: 0 0 15px 0;
-  padding: 4px 5px;
-  display: inline-flex;
-  align-items: center;
+#toolbar {
+  background-color: var(--theme-toolbar-background);
+  border-bottom: 1px solid var(--theme-splitter-color);
+  display: grid;
+  grid-template-columns: min-content auto min-content;
+  width: 100%;
+  min-height: 29px;
   -moz-user-select: none;
 }
 
-#global-toolbar > .toolbar-button:first-of-type {
+#toolbar > .toolbar-button:first-of-type {
   margin-inline-start: 8px;
 }
 
-#global-toolbar > .toolbar-button::before {
+#toolbar > .toolbar-button::before {
   width: 12px;
   height: 12px;
   background-size: cover;
 }
 
-#global-toolbar .toolbar-dropdown {
-  background-position-x: right 5px;
-  border-right: 1px solid var(--theme-splitter-color);
-  padding-right: 15px;
-  /* padding-left: 0; */
+#device-selector {
+  border-right: none;
 }
 
-#global-touch-simulation-button::before {
+#toolbar-center-controls,
+#toolbar-end-controls {
+  display: flex;
+  align-items: center;
+}
+
+#toolbar-center-controls {
+  justify-self: center;
+}
+
+#touch-simulation-button::before {
   background-image: url("./images/touch-events.svg");
 }
 
-#global-screenshot-button::before {
+#screenshot-button::before {
   background-image: url("./images/screenshot.svg");
 }
 
-#global-exit-button::before {
+#exit-button::before {
   background-image: url("chrome://devtools/skin/images/close.svg");
 }
 
-#global-screenshot-button:disabled {
+#screenshot-button:disabled {
   filter: var(--theme-icon-checked-filter);
   opacity: 1 !important;
 }
 
-#global-network-throttling-selector {
+#network-throttling-selector {
   height: 15px;
   padding-left: 0;
   width: 103px;
 }
 
-#global-device-pixel-ratio-selector {
+#device-pixel-ratio-selector {
   -moz-user-select: none;
   color: var(--viewport-color);
   height: 15px;
   /* `max-width` is here to keep the UI compact if the device pixel ratio changes to a
      repeating decimal value.  This can happen if you zoom the UI (Cmd + Plus / Minus on
      macOS for example). */
   max-width: 8em;
 }
 
-#global-device-pixel-ratio-selector.focused,
-#global-device-pixel-ratio-selector:not(.disabled):hover {
+#device-pixel-ratio-selector.focused,
+#device-pixel-ratio-selector:not(.disabled):hover {
   color: var(--viewport-hover-color);
 }
 
-#global-device-pixel-ratio-selector:focus {
+#device-pixel-ratio-selector:focus {
   color: var(--viewport-active-color);
 }
 
-#global-device-pixel-ratio-selector.selected {
+#device-pixel-ratio-selector.selected {
   color: var(--viewport-active-color);
 }
 
-#global-device-pixel-ratio-selector > option {
+#device-pixel-ratio-selector > option {
   padding: 5px;
 }
 
 .viewport-rotate-button {
   position: absolute;
   right: 0;
 }
 
 .viewport-rotate-button::before {
   background-image: url("./images/rotate-viewport.svg");
 }
 
+#viewports-container {
+  display: flex;
+  justify-content: center;
+  overflow: auto;
+  height: 100%;
+  width: 100%;
+}
+
 #viewports {
-  /* Make sure left-most viewport is visible when there's horizontal overflow.
-     That is, when the horizontal space become smaller than the viewports and a
-     scrollbar appears, then the first viewport will still be visible */
-  position: sticky;
-  left: 0;
   /* Individual viewports are inline elements, make sure they stay on a single
      line */
   white-space: nowrap;
+  padding-top: 30px;
 }
 
 /**
  * Viewport Container
  */
 
 .viewport {
   display: inline-block;
--- a/devtools/client/responsive.html/index.js
+++ b/devtools/client/responsive.html/index.js
@@ -132,17 +132,22 @@ window.addInitialViewport = ({ uri, user
     console.error(e);
   }
 };
 
 /**
  * Called by manager.js when tests want to check the viewport size.
  */
 window.getViewportSize = () => {
-  const { width, height } = bootstrap.store.getState().viewports[0];
+  const { viewports } = bootstrap.store.getState();
+  if (!viewports.length) {
+    return null;
+  }
+
+  const { width, height } = viewports[0];
   return { width, height };
 };
 
 /**
  * Called by manager.js to set viewport size from tests, GCLI, etc.
  */
 window.setViewportSize = ({ width, height }) => {
   try {
--- a/devtools/client/responsive.html/test/browser/browser_network_throttling.js
+++ b/devtools/client/responsive.html/test/browser/browser_network_throttling.js
@@ -26,17 +26,17 @@ addRDMTask(TEST_URL, async function({ ui
 
   // Test switching back to no throttling
   await selectNetworkThrottling(ui, "No throttling");
   testNetworkThrottlingSelectorLabel(ui, "No throttling");
   await testNetworkThrottlingState(ui, null);
 });
 
 function testNetworkThrottlingSelectorLabel(ui, expected) {
-  const selector = "#global-network-throttling-selector";
+  const selector = "#network-throttling-selector";
   const select = ui.toolWindow.document.querySelector(selector);
   is(select.selectedOptions[0].textContent, expected,
     `Select label should be changed to ${expected}`);
 }
 
 var testNetworkThrottlingState = async function(ui, expected) {
   const state = await ui.emulationFront.getNetworkThrottling();
   Assert.deepEqual(state, expected, "Network throttling state should be " +
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -268,17 +268,17 @@ const selectDevice = (ui, value) => Prom
   changeSelectValue(ui, ".viewport-device-selector", value)
 ]);
 
 const selectDevicePixelRatio = (ui, value) =>
   changeSelectValue(ui, "#global-device-pixel-ratio-selector", value);
 
 const selectNetworkThrottling = (ui, value) => Promise.all([
   once(ui, "network-throttling-changed"),
-  changeSelectValue(ui, "#global-network-throttling-selector", value)
+  changeSelectValue(ui, "#network-throttling-selector", value)
 ]);
 
 function getSessionHistory(browser) {
   return ContentTask.spawn(browser, {}, async function() {
     /* eslint-disable no-undef */
     const { SessionHistory } =
       ChromeUtils.import("resource://gre/modules/sessionstore/SessionHistory.jsm", {});
     return SessionHistory.collect(docShell);
--- a/devtools/client/shared/components/throttling/NetworkThrottlingSelector.js
+++ b/devtools/client/shared/components/throttling/NetworkThrottlingSelector.js
@@ -94,17 +94,17 @@ class NetworkThrottlingSelector extends 
           },
           profile.id
         );
       }),
     ];
 
     return dom.select(
       {
-        id: "global-network-throttling-selector",
+        id: "network-throttling-selector",
         className: selectClass,
         value: selectedProfile,
         onChange: this.onSelectChange,
       },
       ...listContent
     );
   }
 }