Bug 1355324 - Create a popup to switch between sidebars from the sidebar header;r=Gijs draft
authorBrian Grinstead <bgrinstead@mozilla.com>
Tue, 16 May 2017 10:31:00 -0700
changeset 578827 ae9d07e61e997c60b9633126296f20b9c3bed7f4
parent 578818 b8e9b674033bcd1f3a4c59b9d0ee7619c1a17cc5
child 628854 326e187b96ca545d1fcf36c6666ea1cc42247956
push id59082
push userbgrinstead@mozilla.com
push dateTue, 16 May 2017 17:31:25 +0000
reviewersGijs
bugs1355324
milestone55.0a1
Bug 1355324 - Create a popup to switch between sidebars from the sidebar header;r=Gijs MozReview-Commit-ID: HBwIfmtKybi
addon-sdk/source/test/test-ui-sidebar.js
browser/base/content/browser-sidebar.js
browser/base/content/browser.xul
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_bug409481.js
browser/base/content/test/sidebar/.eslintrc.js
browser/base/content/test/sidebar/browser.ini
browser/base/content/test/sidebar/browser_bug409481.js
browser/base/content/test/sidebar/browser_sidebar_switcher.js
browser/base/moz.build
browser/components/places/tests/browser/browser_sidebarpanels_click.js
browser/themes/linux/browser.css
browser/themes/osx/browser.css
browser/themes/shared/customizableui/panelUI.inc.css
browser/themes/shared/jar.inc.mn
browser/themes/shared/sidebar.inc.css
browser/themes/shared/sidebar/arrow-dropdown.svg
browser/themes/shared/sidebar/bookmark-filled.svg
browser/themes/shared/sidebar/close.svg
browser/themes/shared/sidebar/history.svg
browser/themes/shared/sidebar/sync.svg
browser/themes/windows/browser-aero.css
browser/themes/windows/browser.css
--- a/addon-sdk/source/test/test-ui-sidebar.js
+++ b/addon-sdk/source/test/test-ui-sidebar.js
@@ -1239,17 +1239,17 @@ exports.testShowToOpenXToClose = functio
   assert.ok(!isChecked(menuitem), 'menuitem is not checked');
 
   sidebar.show();
 
   yield shown.promise;
 
   assert.ok(isChecked(menuitem), 'menuitem is checked');
 
-  let closeButton = window.document.querySelector('#sidebar-header > toolbarbutton.close-icon');
+  let closeButton = window.document.querySelector('#sidebar-close');
   simulateCommand(closeButton);
 
   yield hidden.promise;
 
   assert.ok(!isChecked(menuitem), 'menuitem is not checked');
 
   sidebar.destroy();
 }
--- a/browser/base/content/browser-sidebar.js
+++ b/browser/base/content/browser-sidebar.js
@@ -26,30 +26,79 @@ var SidebarUI = {
   _title: null,
   _splitter: null,
 
   init() {
     this._box = document.getElementById("sidebar-box");
     this.browser = document.getElementById("sidebar");
     this._title = document.getElementById("sidebar-title");
     this._splitter = document.getElementById("sidebar-splitter");
+    this._icon = document.getElementById("sidebar-icon");
+    this._switcherPanel = document.getElementById("sidebarMenu-popup");
+    this._switcherTarget = document.getElementById("sidebar-switcher-target");
+    this._switcherArrow = document.getElementById("sidebar-switcher-arrow");
+
+    this._switcherTarget.addEventListener("command", () => {
+      this.toggleSwitcherPanel();
+    });
   },
 
   uninit() {
     let enumerator = Services.wm.getEnumerator(null);
     enumerator.getNext();
     if (!enumerator.hasMoreElements()) {
       document.persist("sidebar-box", "sidebarcommand");
       document.persist("sidebar-box", "width");
       document.persist("sidebar-box", "src");
       document.persist("sidebar-title", "value");
     }
   },
 
   /**
+   * Opens the switcher panel if it's closed, or closes it if it's open.
+   */
+  toggleSwitcherPanel() {
+    if (this._switcherPanel.state == "open" || this._switcherPanel.state == "showing") {
+      this.hideSwitcherPanel();
+    } else {
+      this.showSwitcherPanel();
+    }
+  },
+
+  hideSwitcherPanel() {
+    this._switcherPanel.hidePopup();
+  },
+
+  showSwitcherPanel() {
+    this._ensureShortcutsShown();
+    this._switcherPanel.addEventListener("popuphiding", () => {
+      this._switcherTarget.classList.remove("active");
+    }, {once: true});
+    this._switcherPanel.hidden = false;
+    this._switcherPanel.openPopup(this._icon);
+    this._switcherTarget.classList.add("active");
+  },
+
+  _addedShortcuts: false,
+  _ensureShortcutsShown() {
+    if (this._addedShortcuts) {
+      return;
+    }
+    this._addedShortcuts = true;
+    for (let button of this._switcherPanel.querySelectorAll("toolbarbutton[key]")) {
+      let keyId = button.getAttribute("key");
+      let key = document.getElementById(keyId);
+      if (!key) {
+        continue;
+      }
+      button.setAttribute("shortcut", ShortcutUtils.prettifyShortcut(key));
+    }
+  },
+
+  /**
    * Try and adopt the status of the sidebar from another window.
    * @param {Window} sourceWindow - Window to use as a source for sidebar status.
    * @return true if we adopted the state, or false if the caller should
    * initialize the state itself.
    */
   adoptFromWindow(sourceWindow) {
     // If the opener had a sidebar, open the same sidebar in our window.
     // The opener can be the hidden window too, if we're coming from the state
@@ -217,16 +266,18 @@ var SidebarUI = {
         } else {
           sidebarBroadcaster.setAttribute("checked", "true");
         }
       }
 
       this._box.hidden = false;
       this._splitter.hidden = false;
 
+      this.hideSwitcherPanel();
+
       this._box.setAttribute("sidebarcommand", sidebarBroadcaster.id);
       this.lastOpenedId = sidebarBroadcaster.id;
 
       let title = sidebarBroadcaster.getAttribute("sidebartitle");
       if (!title) {
         title = sidebarBroadcaster.getAttribute("label");
       }
       this._title.value = title;
@@ -271,16 +322,18 @@ var SidebarUI = {
   /**
    * Hide the sidebar.
    */
   hide() {
     if (!this.isOpen) {
       return;
     }
 
+    this.hideSwitcherPanel();
+
     let commandID = this._box.getAttribute("sidebarcommand");
     let sidebarBroadcaster = document.getElementById(commandID);
 
     if (sidebarBroadcaster.getAttribute("checked") != "true") {
       return;
     }
 
     // Replace the document currently displayed in the sidebar with about:blank
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -284,16 +284,51 @@
         <arrowscrollbox id="social-share-provider-buttons" orient="horizontal" flex="1" pack="end">
           <toolbarbutton id="add-share-provider" class="share-provider-button" type="radio"
                          group="share-providers" tooltiptext="&findShareServices.label;"
                          oncommand="SocialShare.showDirectory()"/>
         </arrowscrollbox>
       </hbox>
       <hbox id="share-container" flex="1"/>
     </panel>
+    <panel id="sidebarMenu-popup"
+           class="cui-widget-panel"
+           role="group"
+           type="arrow"
+           hidden="true"
+           flip="slide"
+           orient="vertical"
+           position="bottomcenter topleft">
+      <toolbarbutton id="sidebar-switcher-bookmarks"
+                     class="subviewbutton subviewbutton-iconic"
+                     key="viewBookmarksSidebarKb"
+                     observes="viewBookmarksSidebar"
+                     oncommand="SidebarUI.show('viewBookmarksSidebar');">
+         <observes element="viewBookmarksSidebar" attribute="checked"/>
+       </toolbarbutton>
+      <toolbarbutton id="sidebar-switcher-history"
+                     label="&historyButton.label;"
+                     class="subviewbutton subviewbutton-iconic"
+                     key="key_gotoHistory"
+                     observes="viewHistorySidebar"
+                     oncommand="SidebarUI.show('viewHistorySidebar');">
+         <observes element="viewHistorySidebar" attribute="checked"/>
+       </toolbarbutton>
+      <toolbarbutton id="sidebar-switcher-tabs"
+                     label="&syncedTabs.sidebar.label;"
+                     class="subviewbutton subviewbutton-iconic"
+                     observes="viewTabsSidebar"
+                     oncommand="SidebarUI.show('viewTabsSidebar');">
+         <observes element="viewTabsSidebar" attribute="checked"/>
+       </toolbarbutton>
+      <toolbarseparator/>
+      <toolbarbutton label="&sidebarCloseButton.tooltip;"
+                     class="subviewbutton"
+                     oncommand="SidebarUI.hide()"/>
+    </panel>
 
     <menupopup id="toolbar-context-menu"
                onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
       <menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
                 accesskey="&customizeMenu.moveToPanel.accesskey;"
                 label="&customizeMenu.moveToPanel.label;"
                 contexttype="toolbaritem"
                 class="customize-context-moveToPanel"/>
@@ -1110,19 +1145,24 @@
 
   <hbox id="fullscr-toggler" hidden="true"/>
 
   <deck id="content-deck" flex="1">
     <hbox flex="1" id="browser">
       <vbox id="browser-border-start" hidden="true" layer="true"/>
       <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
         <sidebarheader id="sidebar-header" align="center">
-          <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
+          <toolbarbutton id="sidebar-switcher-target" flex="1" class="tabbable">
+            <image id="sidebar-icon" consumeanchor="sidebar-switcher-target"/>
+            <label id="sidebar-title" persist="value" crop="end" control="sidebar"/>
+            <image id="sidebar-switcher-arrow"/>
+            <spacer flex="1"/>
+          </toolbarbutton>
           <image id="sidebar-throbber"/>
-          <toolbarbutton class="close-icon tabbable" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="SidebarUI.hide();"/>
+          <toolbarbutton id="sidebar-close" class="tabbable" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="SidebarUI.hide();"/>
         </sidebarheader>
         <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true" disablefullscreen="true"
                   style="min-width: 14em; width: 18em; max-width: 36em;" tooltip="aHTMLTooltip"/>
       </vbox>
 
       <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
       <vbox id="appcontent" flex="1">
         <notificationbox id="high-priority-global-notificationbox" notificationside="top"/>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -135,18 +135,16 @@ skip-if = true # browser_bug321000.js is
 [browser_bug380960.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug386835.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug406216.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug408415.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_bug409481.js]
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug409624.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug413915.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug416661.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug417483.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/sidebar/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test"
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/sidebar/browser.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+
+[browser_bug409481.js]
+[browser_sidebar_switcher.js]
rename from browser/base/content/test/general/browser_bug409481.js
rename to browser/base/content/test/sidebar/browser_bug409481.js
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/sidebar/browser_sidebar_switcher.js
@@ -0,0 +1,42 @@
+
+function showSwitcherPanelPromise() {
+  return new Promise(resolve => {
+    SidebarUI._switcherPanel.addEventListener("popupshown", () => {
+      resolve();
+    }, {once: true});
+    SidebarUI.showSwitcherPanel();
+  });
+}
+
+function clickSwitcherButton(querySelector) {
+  let sidebarPopup = document.querySelector("#sidebarMenu-popup");
+  let switcherPromise = Promise.all([
+    BrowserTestUtils.waitForEvent(window, "SidebarFocused"),
+    BrowserTestUtils.waitForEvent(sidebarPopup, "popuphidden"),
+  ]);
+  document.querySelector(querySelector).click();
+  return switcherPromise;
+}
+
+add_task(function* () {
+  // If a sidebar is already open, close it.
+  if (!document.getElementById("sidebar-box").hidden) {
+    ok(false, "Unexpected sidebar found - a previous test failed to cleanup correctly");
+    SidebarUI.hide();
+  }
+
+  let sidebar = document.querySelector("#sidebar-box");
+  yield SidebarUI.show("viewBookmarksSidebar");
+
+  yield showSwitcherPanelPromise();
+  yield clickSwitcherButton("#sidebar-switcher-history");
+  is(sidebar.getAttribute("sidebarcommand"), "viewHistorySidebar", "History sidebar loaded");
+
+  yield showSwitcherPanelPromise();
+  yield clickSwitcherButton("#sidebar-switcher-tabs");
+  is(sidebar.getAttribute("sidebarcommand"), "viewTabsSidebar", "Tabs sidebar loaded");
+
+  yield showSwitcherPanelPromise();
+  yield clickSwitcherButton("#sidebar-switcher-bookmarks");
+  is(sidebar.getAttribute("sidebarcommand"), "viewBookmarksSidebar", "Bookmarks sidebar loaded");
+});
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -22,16 +22,17 @@ BROWSER_CHROME_MANIFESTS += [
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/pageinfo/browser.ini',
     'content/test/permissions/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/popups/browser.ini',
     'content/test/referrer/browser.ini',
+    'content/test/sidebar/browser.ini',
     'content/test/siteIdentity/browser.ini',
     'content/test/social/browser.ini',
     'content/test/static/browser.ini',
     'content/test/sync/browser.ini',
     'content/test/tabcrashed/browser.ini',
     'content/test/tabPrompts/browser.ini',
     'content/test/tabs/browser.ini',
     'content/test/urlbar/browser.ini',
--- a/browser/components/places/tests/browser/browser_sidebarpanels_click.js
+++ b/browser/components/places/tests/browser/browser_sidebarpanels_click.js
@@ -12,17 +12,17 @@ function test() {
   const BOOKMARKS_SIDEBAR_ID = "viewBookmarksSidebar";
   const BOOKMARKS_SIDEBAR_TREE_ID = "bookmarks-view";
   const HISTORY_SIDEBAR_ID = "viewHistorySidebar";
   const HISTORY_SIDEBAR_TREE_ID = "historyTree";
   const TEST_URL = "http://mochi.test:8888/browser/browser/components/places/tests/browser/sidebarpanels_click_test_page.html";
 
   // If a sidebar is already open, close it.
   if (!document.getElementById("sidebar-box").hidden) {
-    info("Unexpected sidebar found - a previous test failed to cleanup correctly");
+    ok(false, "Unexpected sidebar found - a previous test failed to cleanup correctly");
     SidebarUI.hide();
   }
 
   let sidebar = document.getElementById("sidebar");
   let tests = [];
   let currentTest;
 
   tests.push({
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -929,24 +929,23 @@ html|span.ac-emphasize-text-url {
 }
 
 /* Implements editBookmarkPanel resizing on folderTree un-collapse. */
 #editBMPanel_folderTree {
   min-width: 27em;
 }
 
 /* Content area */
+
+%include ../shared/sidebar.inc.css
+
 #sidebar {
   background-color: Window;
 }
 
-#sidebar-header > .close-icon:not(:hover):-moz-lwtheme-brighttext {
-  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
-}
-
 .browserContainer > findbar {
   background-color: -moz-dialog;
   color: -moz-DialogText;
   text-shadow: none;
 }
 
 /* Tabstrip */
 
@@ -1075,22 +1074,16 @@ html|span.ac-emphasize-text-url {
 .alltabs-item[selected="true"] {
   font-weight: bold;
 }
 
 .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://global/skin/icons/loading.png");
 }
 
-/* Sidebar */
-#sidebar-throbber[loading="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading.png");
-  margin-inline-end: 4px;
-}
-
 toolbarbutton.chevron {
   list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important;
 }
 
 toolbar[brighttext] toolbarbutton.chevron {
   list-style-image: url("chrome://global/skin/toolbar/chevron-inverted.png") !important;
 }
 
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1358,88 +1358,25 @@ html|span.ac-emphasize-text-url {
 #historySwipeAnimationNextPage {
   box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
 }
 
 #historySwipeAnimationContainer {
   background: url("chrome://browser/skin/subtle-pattern.png") #B3B9C1;
 }
 
+
 /* ----- SIDEBAR ELEMENTS ----- */
 
+%include ../shared/sidebar.inc.css
+
 #sidebar-box {
   -moz-appearance: -moz-mac-source-list;
-  box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2);
 }
 
-sidebarheader {
-  padding: 2px 2px 0;
-  text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
-}
-
-.sidebar-splitter {
-  border-inline-start: none;
-  border-inline-end: 1px solid #b4b4b4;
-  min-width: 1px;
-  width: 3px;
-  background-image: none !important;
-  background-color: transparent;
-  margin-inline-start: -3px;
-  position: relative;
-}
-
-#appcontent ~ .sidebar-splitter {
-  border-inline-start: 1px solid #ccc;
-  border-inline-end: none;
-  margin-inline-start: 0;
-  margin-inline-end: -3px;
-}
-
-.sidebar-title,
-#sidebar-title {
-  color: #596c80;
-  font-weight: bold;
-}
-
-.sidebar-title:-moz-window-inactive,
-#sidebar-title:-moz-window-inactive {
-  color: #868b92;
-}
-
-.sidebar-throbber[loading="true"],
-#sidebar-throbber[loading="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading.png");
-}
-
-@media (min-resolution: 2dppx) {
-  .sidebar-throbber[loading="true"],
-  #sidebar-throbber[loading="true"] {
-    list-style-image: url("chrome://global/skin/icons/loading@2x.png");
-    width: 16px;
-  }
-}
-
-@media (-moz-mac-yosemite-theme) {
-  #sidebar-box {
-    box-shadow: none;
-  }
-
-  sidebarheader {
-    text-shadow: none;
-    font-weight: 500;
-  }
-
-  .sidebar-title,
-  #sidebar-title {
-    color: #636363;
-    font-weight: 500;
-  }
-}
-
-
 /* ----- CONTENT ----- */
 
 .browserContainer > findbar {
   background: @scopeBarBackground@;
   border-top: @scopeBarSeparatorBorder@;
   color: -moz-DialogText;
   text-shadow: none;
 }
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1108,35 +1108,35 @@ panelview:not([mainView]) .subviewbutton
 
 .subviewbutton:not(.panel-subview-footer) > .toolbarbutton-text,
 /* Bookmark items need a more specific selector. */
 .PanelUI-subView .subviewbutton:not(.panel-subview-footer) > .menu-text,
 .PanelUI-subView .subviewbutton:not(.panel-subview-footer) > .menu-iconic-text {
   font: menu;
 }
 
-.PanelUI-subView .subviewbutton[shortcut]::after {
+.subviewbutton[shortcut]::after {
   content: attr(shortcut);
   float: right;
   color: GrayText;
 }
 
 .PanelUI-subView .subviewbutton-nav::after {
   -moz-context-properties: fill;
   content: url(chrome://browser/skin/menu-icons/back-small.svg);
   fill: GrayText;
   float: right;
 }
 
 .PanelUI-subView .subviewbutton-nav:-moz-locale-dir(ltr)::after {
   transform: scaleX(-1);
 }
 
-.PanelUI-subView.cui-widget-panelview .subviewbutton[shortcut]::after,
-photonpanelmultiview .PanelUI-subView .subviewbutton[shortcut]::after,
+.subviewbutton[shortcut]::after,
+.subviewbutton[shortcut]::after,
 .PanelUI-subView .subviewbutton-nav::after {
   margin-inline-start: 10px;
 }
 
 /* This is a <label> but it should fit in with the menu font- and colorwise. */
 #PanelUI-characterEncodingView-autodetect-label {
   font: menu;
   color: inherit;
@@ -1273,17 +1273,18 @@ menuitem.panel-subview-footer@menuStateA
 /* Disabled (empty) item is always alone and never has an icon, so fix its left padding */
 #BMB_bookmarksPopup menupopup[emptyplacesresult] .bookmark-item.subviewbutton {
   padding-left: 6px;
 }
 
 #widget-overflow-scroller > toolbarseparator,
 .PanelUI-subView menuseparator,
 .PanelUI-subView toolbarseparator,
-.cui-widget-panelview menuseparator {
+.cui-widget-panelview menuseparator,
+.cui-widget-panel toolbarseparator {
   -moz-appearance: none;
   min-height: 0;
   border-top: 1px solid var(--panel-separator-color);
   border-bottom: none;
   margin: 6px 0;
   padding: 0;
 }
 
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -42,16 +42,21 @@
   skin/classic/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
   skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
   skin/classic/browser/customizableui/panelarrow-customizeTip.png  (../shared/customizableui/panelarrow-customizeTip.png)
   skin/classic/browser/customizableui/panelarrow-customizeTip@2x.png  (../shared/customizableui/panelarrow-customizeTip@2x.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png  (../shared/customizableui/subView-arrow-back-inverted@2x.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png  (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl@2x.png  (../shared/customizableui/subView-arrow-back-inverted-rtl@2x.png)
+  skin/classic/browser/sidebar/arrow-dropdown.svg           (../shared/sidebar/arrow-dropdown.svg)
+  skin/classic/browser/sidebar/bookmark-filled.svg          (../shared/sidebar/bookmark-filled.svg)
+  skin/classic/browser/sidebar/close.svg                    (../shared/sidebar/close.svg)
+  skin/classic/browser/sidebar/history.svg                  (../shared/sidebar/history.svg)
+  skin/classic/browser/sidebar/sync.svg                     (../shared/sidebar/sync.svg)
   skin/classic/browser/customizableui/whimsy.png               (../shared/customizableui/whimsy.png)
   skin/classic/browser/customizableui/whimsy@2x.png            (../shared/customizableui/whimsy@2x.png)
   skin/classic/browser/downloads/contentAreaDownloadsView.css  (../shared/downloads/contentAreaDownloadsView.css)
   skin/classic/browser/downloads/download-blocked.svg          (../shared/downloads/download-blocked.svg)
   skin/classic/browser/downloads/download-summary.svg          (../shared/downloads/download-summary.svg)
   skin/classic/browser/drm-icon.svg                            (../shared/drm-icon.svg)
   skin/classic/browser/fullscreen/insecure.svg                 (../shared/fullscreen/insecure.svg)
   skin/classic/browser/fullscreen/secure.svg                   (../shared/fullscreen/secure.svg)
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/sidebar.inc.css
@@ -0,0 +1,125 @@
+%if 0
+/* 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/. */
+%endif
+
+#sidebar-box {
+  --icon-fill: rgba(12, 12, 13, 0.8);
+  --header-background-color: #F2F2F2;
+  --header-background-color-hover: rgba(204, 204, 204, 0.6);
+  --title-font-size: 13px;
+}
+
+.sidebar-header,
+#sidebar-header {
+  padding: 4px;
+  background-color: var(--header-background-color);
+  text-shadow: none;
+}
+
+.sidebar-splitter {
+  -moz-appearance: none;
+  border: 0 solid #ccc;
+  border-inline-end-width: 1px;
+  min-width: 1px;
+  width: 3px;
+  background-image: none !important;
+  background-color: transparent;
+  margin-inline-start: -3px;
+  position: relative;
+}
+
+#appcontent ~ .sidebar-splitter {
+  border-inline-end-width: 0;
+  border-inline-start-width: 1px;
+  margin-inline-start: 0;
+  margin-inline-end: -3px;
+}
+
+#sidebar-throbber[loading="true"] {
+  list-style-image: url("chrome://global/skin/icons/loading.png");
+}
+
+@media (min-resolution: 2dppx) {
+  .sidebar-throbber[loading="true"],
+  #sidebar-throbber[loading="true"] {
+    list-style-image: url("chrome://global/skin/icons/loading@2x.png");
+    width: 16px;
+  }
+}
+
+.sidebar-title,
+#sidebar-title {
+  margin: 0;
+  padding: 0;
+  padding-inline-start: 8px;
+  padding-inline-end: 4px;
+  color: -moz-DialogText;
+  font-size: var(--title-font-size);
+}
+
+#sidebar-switcher-arrow {
+  -moz-context-properties: fill;
+  fill: var(--icon-fill);
+  list-style-image: url(chrome://browser/skin/sidebar/arrow-dropdown.svg);
+  width: 12px;
+  height: 12px;
+}
+
+#sidebar-close {
+  -moz-appearance: none;
+  -moz-context-properties: fill;
+  fill: var(--icon-fill);
+  list-style-image: url(chrome://browser/skin/sidebar/close.svg);
+  margin: 0;
+  padding: 4px;
+}
+
+#sidebar-switcher-target {
+  -moz-appearance: none;
+  padding: 4px;
+  margin-inline-end: 4px;
+}
+
+#sidebar-box #sidebar-switcher-target:hover,
+#sidebar-switcher-target.active,
+#sidebar-close:hover {
+  background: var(--header-background-color-hover);
+}
+
+#sidebarMenu-popup .subviewbutton {
+  min-width: 190px;
+}
+
+%ifndef XP_MACOSX
+/* Allow room for the checkbox drawn as a background image at the start of the toolbarbutton */
+#sidebarMenu-popup .subviewbutton-iconic > .toolbarbutton-icon {
+  padding-inline-start: 16px;
+}
+#sidebarMenu-popup .subviewbutton-iconic > .toolbarbutton-text {
+  padding-inline-start: 0;
+}
+%endif
+
+/* Use bookmarks star as default icon for the sidebar box (including when opening a web page) */
+#sidebar-switcher-bookmarks > .toolbarbutton-icon,
+#sidebar-box #sidebar-icon {
+  -moz-context-properties: fill;
+  fill: var(--icon-fill);
+  list-style-image: url(chrome://browser/skin/sidebar/bookmark-filled.svg);
+}
+
+#sidebar-switcher-history > .toolbarbutton-icon,
+#sidebar-box[sidebarcommand="viewHistorySidebar"] #sidebar-icon {
+  -moz-context-properties: fill;
+  fill: var(--icon-fill);
+  list-style-image: url(chrome://browser/skin/sidebar/history.svg);
+}
+
+#sidebar-switcher-tabs > .toolbarbutton-icon,
+#sidebar-box[sidebarcommand="viewTabsSidebar"] #sidebar-icon {
+  -moz-context-properties: fill;
+  fill: var(--icon-fill);
+  list-style-image: url(chrome://browser/skin/sidebar/sync.svg);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/sidebar/arrow-dropdown.svg
@@ -0,0 +1,6 @@
+<!-- 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">
+  <path fill="context-fill" d="M8 12a1 1 0 0 1-.707-.293l-5-5a1 1 0 0 1 1.414-1.414L8 9.586l4.293-4.293a1 1 0 0 1 1.414 1.414l-5 5A1 1 0 0 1 8 12z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/sidebar/bookmark-filled.svg
@@ -0,0 +1,6 @@
+<!-- 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">
+  <path fill="context-fill" d="M15.845 6.064A1.1 1.1 0 0 0 15 5.331L10.911 4.6 8.985.735a1.1 1.1 0 0 0-1.969 0L5.089 4.6l-4.081.729a1.1 1.1 0 0 0-.615 1.834L3.32 10.31l-.609 4.36a1.1 1.1 0 0 0 1.6 1.127L8 13.873l3.69 1.927a1.1 1.1 0 0 0 1.6-1.127l-.61-4.363 2.926-3.146a1.1 1.1 0 0 0 .239-1.1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/sidebar/close.svg
@@ -0,0 +1,6 @@
+<!-- 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">
+  <path fill="context-fill" d="M9.061,8l3.47-3.47A.75.75,0,0,0,11.47,3.47L8,6.939,4.53,3.47A.75.75,0,0,0,3.47,4.53L6.939,8,3.47,11.47A.75.75,0,1,0,4.53,12.53L8,9.061l3.47,3.47A.75.75,0,0,0,12.53,11.47Z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/sidebar/history.svg
@@ -0,0 +1,6 @@
+<!-- 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">
+  <path fill="context-fill" d="M8 0a8 8 0 1 0 8 8 8.009 8.009 0 0 0-8-8zm0 14a6 6 0 1 1 6-6 6.007 6.007 0 0 1-6 6zm3.5-6H8V4.5a.5.5 0 0 0-1 0v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 0-1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/sidebar/sync.svg
@@ -0,0 +1,6 @@
+<!-- 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">
+  <path fill="context-fill" d="M14 1a1 1 0 0 0-1 1v1.146A6.948 6.948 0 0 0 1.227 6.307a1 1 0 1 0 1.94.484A4.983 4.983 0 0 1 8 3a4.919 4.919 0 0 1 3.967 2H10a1 1 0 0 0 0 2h4a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm.046 7.481a1 1 0 0 0-1.213.728A4.983 4.983 0 0 1 8 13a4.919 4.919 0 0 1-3.967-2H6a1 1 0 0 0 0-2H2a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-1.146a6.948 6.948 0 0 0 11.773-3.161 1 1 0 0 0-.727-1.212z"/>
+</svg>
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -11,57 +11,24 @@
   }
 }
 
 @media (-moz-windows-default-theme) {
   .sidebar-header,
   #sidebar-header {
     -moz-appearance: none;
     border-bottom: none;
-    text-shadow: none;
-  }
-
-  .sidebar-title,
-  #sidebar-title {
-    font-weight: bold;
-  }
-
-  .sidebar-splitter {
-    border: 0;
-    border-inline-end: 1px solid ThreeDLightShadow;
-    min-width: 0;
-    width: 3px;
-    background-color: transparent;
-    margin-inline-start: -3px;
-    position: relative;
-  }
-
-  #appcontent ~ .sidebar-splitter {
-    border-inline-start: 1px solid ThreeDLightShadow;
-    border-inline-end: none;
-    margin-inline-start: 0;
-    margin-inline-end: -3px;
   }
 
   .menu-accel,
   .menu-iconic-accel {
     color: graytext;
   }
 
   @media (-moz-os-version: windows-win7) {
-    .sidebar-header:not(:-moz-lwtheme),
-    #sidebar-header:not(:-moz-lwtheme) {
-      background-color: #EEF3FA;
-    }
-
-    .sidebar-splitter,
-    #appcontent ~ .sidebar-splitter {
-      border-color: #A9B7C9;
-    }
-
     #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(:-moz-lwtheme),
     #browser-bottombox:not(:-moz-lwtheme),
     .browserContainer > findbar {
       background-color: @customToolbarColor@;
     }
 
     .tab-background-middle[selected=true]:not(:-moz-lwtheme) {
       background-color: @customToolbarColor@;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1382,50 +1382,22 @@ treechildren.searchbar-treebody::-moz-tr
 
 /* Implements editBookmarkPanel resizing on folderTree un-collapse. */
 #editBMPanel_folderTree {
   min-width: 27em;
 }
 
 /* ::::: content area ::::: */
 
+%include ../shared/sidebar.inc.css
+
 #sidebar {
   background-color: Window;
 }
 
-#sidebar-title {
-  padding-inline-start: 0px;
-}
-
-#sidebar-header > .close-icon {
-  -moz-appearance: none;
-  padding: 2px;
-  margin: 0;
-  border: none;
-}
-
-@media not all and (min-resolution: 1.1dppx) {
-  #sidebar-header > .close-icon:-moz-lwtheme-brighttext {
-    list-style-image: url("chrome://global/skin/icons/close-inverted.png");
-  }
-}
-
-@media (min-resolution: 1.1dppx) {
-  #sidebar-header > .close-icon:-moz-lwtheme-brighttext {
-    list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
-  }
-}
-
-@media (-moz-os-version: windows-win7) {
-  #sidebar-header > .close-icon {
-    padding-top: 4px;
-    padding-bottom: 4px;
-  }
-}
-
 .browserContainer > findbar {
   background-color: -moz-dialog;
   color: -moz-DialogText;
   text-shadow: none;
 }
 
 /* Tabstrip */
 
@@ -1589,28 +1561,16 @@ toolbarbutton.chevron > .toolbarbutton-t
 toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 toolbarbutton.chevron > .toolbarbutton-icon {
   margin: 0;
 }
 
-#sidebar-throbber[loading="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading.png");
-  margin-inline-end: 4px;
-}
-
-@media (min-resolution: 1.1dppx) {
-  #sidebar-throbber[loading="true"] {
-    list-style-image: url("chrome://global/skin/icons/loading@2x.png");
-    width: 16px;
-  }
-}
-
 /* Bookmarks toolbar */
 #PlacesToolbarDropIndicator {
   list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
 }
 
 toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   -moz-appearance: none;
   background: Highlight !important;