Bug 1322738 - Implement compact about:newtab tiles styling. r=gijs a=lizzard
authorDão Gottwald <dao@mozilla.com>
Wed, 04 Jan 2017 22:39:52 +0100
changeset 353376 6329a43064daac4f8bef53202ae3ff57e173c9d7
parent 353375 01a5cd136989665e51c9a21542f94af20605e48d
child 353377 bac566c43bc43f92809aa09590aa37553803da1c
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs, lizzard
bugs1322738
milestone52.0a2
Bug 1322738 - Implement compact about:newtab tiles styling. r=gijs a=lizzard
browser/app/profile/firefox.js
browser/base/content/newtab/grid.js
browser/base/content/newtab/newTab.css
browser/base/content/newtab/page.js
browser/base/content/test/newtab/browser_newtab_bug991210.js
browser/themes/shared/newtab/newTab.inc.css
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1149,16 +1149,19 @@ pref("browser.newtab.preload", true);
 pref("browser.newtabpage.introShown", false);
 
 // Toggles the content of 'about:newtab'. Shows the grid when enabled.
 pref("browser.newtabpage.enabled", true);
 
 // Toggles the enhanced content of 'about:newtab'. Shows sponsored tiles.
 sticky_pref("browser.newtabpage.enhanced", true);
 
+// enables Activity Stream inspired layout
+pref("browser.newtabpage.compact", false);
+
 // number of rows of newtab grid
 pref("browser.newtabpage.rows", 3);
 
 // number of columns of newtab grid
 pref("browser.newtabpage.columns", 5);
 
 // directory tiles download URL
 pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
--- a/browser/base/content/newtab/grid.js
+++ b/browser/base/content/newtab/grid.js
@@ -204,50 +204,52 @@ var gGrid = {
     // let's bail out to avoid caching zero heights and widths.
     // We'll be called again when DOMContentLoaded fires.
     // Same goes for the grid if that's not ready yet.
     if (!this.isDocumentLoaded || !this._ready) {
       return;
     }
 
     // Save the cell's computed height/width including margin and border
-    if (this._cellMargin === undefined) {
+    if (this._cellHeight === undefined) {
       let refCell = document.querySelector(".newtab-cell");
-      this._cellMargin = parseFloat(getComputedStyle(refCell).marginTop);
-      this._cellHeight = refCell.offsetHeight + this._cellMargin +
-        parseFloat(getComputedStyle(refCell).marginBottom);
-      this._cellWidth = refCell.offsetWidth + this._cellMargin;
+      let style = getComputedStyle(refCell);
+      this._cellHeight = refCell.offsetHeight +
+        parseFloat(style.marginTop) + parseFloat(style.marginBottom);
+      this._cellWidth = refCell.offsetWidth +
+        parseFloat(style.marginLeft) + parseFloat(style.marginRight);
     }
 
     let searchContainer = document.querySelector("#newtab-search-container");
     // Save search-container margin height
-    if (this._searchContainerMargin  === undefined) {
-      this._searchContainerMargin = parseFloat(getComputedStyle(searchContainer).marginBottom) +
-                                    parseFloat(getComputedStyle(searchContainer).marginTop);
+    if (this._searchContainerMargin === undefined) {
+      let style = getComputedStyle(searchContainer);
+      this._searchContainerMargin = parseFloat(style.marginBottom) +
+                                    parseFloat(style.marginTop);
     }
 
     // Find the number of rows we can place into view port
-    let availHeight = document.documentElement.clientHeight - this._cellMargin -
+    let availHeight = document.documentElement.clientHeight -
                       searchContainer.offsetHeight - this._searchContainerMargin;
     let visibleRows = Math.floor(availHeight / this._cellHeight);
 
     // Find the number of columns that fit into view port
     let maxGridWidth = gGridPrefs.gridColumns * this._cellWidth + GRID_WIDTH_EXTRA;
     // available width is current grid width, but no greater than maxGridWidth
     let availWidth = Math.min(document.querySelector("#newtab-grid").clientWidth,
                               maxGridWidth);
     // finally get the number of columns we can fit into view port
-    let gridColumns =  Math.floor(availWidth / this._cellWidth);
+    let gridColumns = Math.floor(availWidth / this._cellWidth);
     // walk sites backwords until a pinned or history tile is found or visibleRows reached
     let tileIndex = Math.min(gGridPrefs.gridRows * gridColumns, this.sites.length) - 1;
     while (tileIndex >= visibleRows * gridColumns) {
       if (this._isHistoricalTile(tileIndex)) {
         break;
       }
-      tileIndex --;
+      tileIndex--;
     }
 
     // Compute the actual number of grid rows we will display (potentially
     // with a scroll bar). tileIndex now points to a historical tile with
     // heighest index or to the last index of the visible row, if none found
     // Dividing tileIndex by number of tiles in a column gives the rows
     let gridRows = Math.floor(tileIndex / gridColumns) + 1;
 
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -131,16 +131,22 @@ input[type=button] {
 /* CELLS */
 .newtab-cell {
   display: -moz-box;
   height: 210px;
   margin: 20px 10px 35px;
   width: 290px;
 }
 
+body.compact .newtab-cell {
+  width: 110px;
+  height: 110px;
+  margin: 12px;
+}
+
 /* SITES */
 .newtab-site {
   position: relative;
   -moz-box-flex: 1;
   transition: 100ms ease-out;
   transition-property: top, left, opacity;
 }
 
@@ -174,20 +180,17 @@ input[type=button] {
   text-align: center;
 }
 
 .newtab-sponsored,
 .newtab-title {
   bottom: 0;
   white-space: nowrap;
   text-overflow: ellipsis;
-  font-size: 13px;
-  line-height: 30px;
   vertical-align: middle;
-  background-color: #F2F2F2;
 }
 
 .newtab-suggested {
   border: 1px solid transparent;
   border-radius: 2px;
   font-size: 12px;
   height: 17px;
   line-height: 17px;
@@ -203,18 +206,16 @@ input[type=button] {
 
 .newtab-suggested-bounds {
   max-height: 34px; /* 34 / 17 = 2 lines maximum */
 }
 
 .newtab-title {
   left: 0;
   padding: 0 4px;
-  border: 1px solid #FFFFFF;
-  border-radius: 0px 0px 8px 8px;
 }
 
 .newtab-sponsored {
   background-color: #FFFFFF;
   border: 1px solid #E2E2E2;
   border-radius: 3px;
   color: #4A4A4A;
   cursor: pointer;
@@ -282,17 +283,16 @@ input[type=button] {
   pointer-events: none;
   position: static;
   width: 18px;
 }
 
 /* CONTROLS */
 .newtab-control {
   position: absolute;
-  top: 4px;
   opacity: 0;
   transition: opacity 100ms ease-out;
 }
 
 .newtab-control:-moz-focusring,
 .newtab-cell:not([ignorehover]) > .newtab-site:hover > .newtab-control {
   opacity: 1;
 }
@@ -302,26 +302,16 @@ input[type=button] {
 }
 
 @media (-moz-touch-enabled) {
   .newtab-control {
     opacity: 1;
   }
 }
 
-.newtab-control-pin:dir(ltr),
-.newtab-control-block:dir(rtl) {
-  left: 4px;
-}
-
-.newtab-control-block:dir(ltr),
-.newtab-control-pin:dir(rtl) {
-  right: 4px;
-}
-
 /* DRAG & DROP */
 
 /*
  * This is just a temporary drag element used for dataTransfer.setDragImage()
  * so that we can use custom drag images and elements. It needs an opacity of
  * 0.01 so that the core code detects that it's in fact a visible element.
  */
 .newtab-drag {
@@ -334,16 +324,21 @@ input[type=button] {
 /* SEARCH */
 #newtab-search-container {
   display: -moz-box;
   position: relative;
   -moz-box-pack: center;
   margin: 40px 0 15px;
 }
 
+body.compact #newtab-search-container {
+  margin-top: 0;
+  margin-bottom: 80px;
+}
+
 #newtab-search-container[page-disabled] {
   opacity: 0;
   pointer-events: none;
 }
 
 #newtab-search-form {
   display: -moz-box;
   position: relative;
--- a/browser/base/content/newtab/page.js
+++ b/browser/base/content/newtab/page.js
@@ -114,23 +114,27 @@ var gPage = {
 
     this._initialized = true;
 
     // Set submit button label for when CSS background are disabled (e.g.
     // high contrast mode).
     document.getElementById("newtab-search-submit").value =
       document.body.getAttribute("dir") == "ltr" ? "\u25B6" : "\u25C0";
 
+    if (Services.prefs.getBoolPref("browser.newtabpage.compact")) {
+      document.body.classList.add("compact");
+    }
+
     // Initialize search.
     gSearch.init();
 
     if (document.hidden) {
       addEventListener("visibilitychange", this);
     } else {
-      setTimeout(_ => this.onPageFirstVisible());
+      setTimeout(() => this.onPageFirstVisible());
     }
 
     // Initialize and render the grid.
     gGrid.init();
 
     // Initialize the drop target shim.
     gDropTargetShim.init();
 
--- a/browser/base/content/test/newtab/browser_newtab_bug991210.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug991210.js
@@ -15,18 +15,17 @@ add_task(function* () {
   NewTabUtils.links.addProvider(afterLoadProvider);
 
   // wait until about:newtab loads before calling provider callback
   yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab");
 
   afterLoadProvider.callback([]);
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
-    let {_cellMargin, _cellHeight, _cellWidth, node} = content.gGrid;
-    Assert.notEqual(_cellMargin, null, "grid has a computed cell margin");
+    let {_cellHeight, _cellWidth, node} = content.gGrid;
     Assert.notEqual(_cellHeight, null, "grid has a computed cell height");
     Assert.notEqual(_cellWidth, null, "grid has a computed cell width");
     let {height, maxHeight, maxWidth} = node.style;
     Assert.notEqual(height, "", "grid has a computed grid height");
     Assert.notEqual(maxHeight, "", "grid has a computed grid max-height");
     Assert.notEqual(maxWidth, "", "grid has a computed grid max-width");
   });
 
--- a/browser/themes/shared/newtab/newTab.inc.css
+++ b/browser/themes/shared/newtab/newTab.inc.css
@@ -96,99 +96,150 @@
   background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 64, 32, 32);
   background-color: #FFFFFF;
   border: solid 1px #CCCCCC;
   border-radius: 2px;
 }
 
 /* CELLS */
 .newtab-cell {
+  --cell-corner-radius: 8px;
   background-color: rgba(255,255,255,.2);
-  border-radius: 8px;
+  border-radius: var(--cell-corner-radius);
+}
+
+body.compact .newtab-cell {
+  --cell-corner-radius: 2px;
 }
 
 .newtab-cell:empty {
   outline: 2px dashed #c1c1c1;
-  -moz-outline-radius: 8px;
+  outline-offset: -2px;
+  -moz-outline-radius: var(--cell-corner-radius);
 }
 
 /* SITES */
-.newtab-site {
-  border-radius: inherit;
+body:not(.compact) .newtab-site {
+  border-radius: var(--cell-corner-radius);
   box-shadow: 0 1px 3px #c1c1c1;
   text-decoration: none;
   transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.newtab-cell:not([ignorehover]) .newtab-control:hover ~ .newtab-link,
-.newtab-cell:not([ignorehover]) .newtab-link:hover,
-.newtab-site[dragged] {
+body:not(.compact) .newtab-cell:not([ignorehover]) .newtab-control:hover ~ .newtab-link,
+body:not(.compact) .newtab-cell:not([ignorehover]) .newtab-link:hover,
+body:not(.compact) .newtab-site[dragged] {
   border: 2px solid white;
   box-shadow: 0 0 6px 1px #add6ff;
   margin: -2px;
 }
 
 .newtab-site[dragged] {
   transition-property: box-shadow, background-color;
   background-color: rgb(242,242,242);
 }
 
 /* LINKS */
 .newtab-link {
-  border-radius: 10px;
+  border-radius: var(--cell-corner-radius);
   overflow: hidden;
 }
 
 /***
  * If you change the sizes here, change them in newTab.css
  * and the preference values:
  * toolkit.pageThumbs.minWidth
  * toolkit.pageThumbs.minHeight
  */
 /* THUMBNAILS */
 .newtab-thumbnail {
   background-origin: padding-box;
   background-clip: padding-box;
   background-repeat: no-repeat;
   background-size: cover;
-  border-radius: 8px 8px 0px 0px;
   height: 180px;
   transition: opacity 100ms ease-out;
 }
 
+body.compact .newtab-thumbnail {
+  height: 100%;
+  border-radius: calc(var(--cell-corner-radius) + 1px);
+  outline: 1px solid hsla(0,0%,0%,.1);
+  -moz-outline-radius: var(--cell-corner-radius);
+  outline-offset: -1px;
+}
+
 .newtab-cell:not([ignorehover]) .newtab-site:hover .newtab-thumbnail.enhanced-content {
   opacity: 0;
 }
 
 .newtab-site[type=affiliate] .newtab-thumbnail,
 .newtab-site[type=enhanced] .newtab-thumbnail,
 .newtab-site[type=organic] .newtab-thumbnail,
 .newtab-site[type=sponsored] .newtab-thumbnail {
   background-position: center center;
+}
+
+.newtab-site[type=affiliate] .newtab-thumbnail,
+body:not(.compact) .newtab-site[type=enhanced] .newtab-thumbnail,
+body:not(.compact) .newtab-site[type=organic] .newtab-thumbnail,
+body:not(.compact) .newtab-site[type=sponsored] .newtab-thumbnail {
   background-size: auto;
 }
 
 /* TITLES */
-.newtab-sponsored,
+
+.newtab-title {
+  background-color: #F2F2F2;
+  font-size: 13px;
+  line-height: 30px;
+  border: 1px solid #fff;
+  border-radius: 0 0 var(--cell-corner-radius) var(--cell-corner-radius);
+}
+
+body.compact .newtab-title {
+  background-color: hsla(0,0%,100%,.8);
+  font-size: 12px;
+  line-height: 21px;
+}
+
 .newtab-title,
-.newtab-suggested  {
+.newtab-suggested {
   color: #5c5c5c;
 }
 
+body.compact .newtab-title,
+body.compact .newtab-suggested {
+  color: black;
+}
+
+body.compact .newtab-title {
+  border: 1px solid hsla(0,0%,80%,.8);
+  border-top-color: hsla(0,0%,0%,.1);
+  background-clip: padding-box;
+}
+
 .newtab-suggested[active] {
   background-color: rgba(51, 51, 51, 0.95);
   border: 0;
   color: white;
 }
 
-.newtab-site:hover .newtab-title {
+body:not(.compact) .newtab-site:hover .newtab-title {
   color: white;
   background-color: #333;
-  border: 1px solid #333;
-  border-top: 1px solid white;
+  border-color: #333;
+  border-top-color: white;
+}
+
+body.compact .newtab-site:hover .newtab-title {
+  color: white;
+  background-color: hsla(0,0%,20%,.8);
+  border-color: hsla(0,0%,0%,.8);
+  border-top-color: white;
 }
 
 .newtab-site[pinned] .newtab-title {
   padding-inline-start: 24px;
 }
 
 .newtab-site[pinned] .newtab-title::before {
   background-image: -moz-image-rect(url("chrome://browser/skin/newtab/controls.svg"), 7, 278, 28, 266);
@@ -209,16 +260,41 @@
 
 /* CONTROLS */
 .newtab-control {
   background-color: transparent;
   background-size: 24px;
   border: none;
   height: 24px;
   width: 24px;
+  top: 4px;
+}
+
+.newtab-control-pin:dir(ltr),
+.newtab-control-block:dir(rtl) {
+  left: 4px;
+}
+
+.newtab-control-block:dir(ltr),
+.newtab-control-pin:dir(rtl) {
+  right: 4px;
+}
+
+body.compact .newtab-control {
+  top: -8px;
+}
+
+body.compact .newtab-control-pin:dir(ltr),
+body.compact .newtab-control-block:dir(rtl) {
+  left: -8px;
+}
+
+body.compact .newtab-control-block:dir(ltr),
+body.compact .newtab-control-pin:dir(rtl) {
+  right: -8px;
 }
 
 .newtab-control-pin,
 .newtab-site[pinned] .newtab-control-pin:hover:active {
   background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 96, 32, 64);
 }
 
 .newtab-control-pin:hover,