Bug 1322738 - Implement compact about:newtab tiles styling. r=gijs
authorDão Gottwald <dao@mozilla.com>
Wed, 04 Jan 2017 22:39:52 +0100
changeset 375269 c8883a87c6dc7c8d355fc93c9ee08bb75cfbf7db
parent 375268 f897399fb28a18b34f5200677e2d585e5d4342a2
child 375270 f13abb8ba9f366c9f32a3146245adf642528becd
child 375358 73dae2d9869edc721b053629d766d66074d1ce68
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs1322738
milestone53.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 1322738 - Implement compact about:newtab tiles styling. r=gijs
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
@@ -1151,16 +1151,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,