Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

devtools: enable sticky header, top bar, and report ui features #9023

Merged
merged 42 commits into from
May 30, 2019
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
41aa187
report(redesign): update styles for devtools
connorjclark May 22, 2019
000f841
sc
connorjclark May 22, 2019
c0bf21d
report ui features in devtools. add sticky header and topbar
connorjclark May 25, 2019
1e040cc
fix scroll
connorjclark May 25, 2019
a6e722e
remove alt devtools header
connorjclark May 25, 2019
7129ae1
fix highlighter in dt
connorjclark May 25, 2019
ca0afd1
comments
connorjclark May 25, 2019
4a6a796
margin for container
connorjclark May 25, 2019
fe61b86
better comment
connorjclark May 28, 2019
720dbb4
fix type
connorjclark May 28, 2019
0153c0e
fix header check test
connorjclark May 28, 2019
009c7d2
comment
connorjclark May 28, 2019
0ee54c8
report: increase UI density for devtools (#9070)
paulirish May 28, 2019
cc763f8
maybe remove lh container top page margin
connorjclark May 28, 2019
7ace084
remove most of top of page shiiiit
connorjclark May 28, 2019
6650b66
nearly there
connorjclark May 28, 2019
8063f18
display none sticky header
connorjclark May 28, 2019
63c9638
disable anim
connorjclark May 28, 2019
739b20a
Merge remote-tracking branch 'origin/master' into rd-devtools
connorjclark May 28, 2019
4b86fb4
restructure render fn
connorjclark May 28, 2019
bdbf379
toggle dark class on lh-vars el
connorjclark May 28, 2019
181a5ed
comment
connorjclark May 28, 2019
2031b5e
Merge remote-tracking branch 'origin/master' into rd-devtools
connorjclark May 29, 2019
b2016ea
comment
connorjclark May 29, 2019
f16f78f
display none export
connorjclark May 29, 2019
e3a4ba0
remove extra margin
connorjclark May 29, 2019
19215e9
find first scrollable ancestor
connorjclark May 29, 2019
6059968
comment
connorjclark May 29, 2019
9dd16c1
nit/tuck
connorjclark May 29, 2019
82bb8e6
header gauges
connorjclark May 29, 2019
aec1ac3
highlight fix
connorjclark May 29, 2019
0c1b09e
pr changes
connorjclark May 29, 2019
656e941
work around resize event for dt
connorjclark May 30, 2019
8ded84e
types
connorjclark May 30, 2019
6dabf64
bump
connorjclark May 30, 2019
df79fcb
limit resize observer to devtools
connorjclark May 30, 2019
427baf5
create highlight div in report ui feats
connorjclark May 30, 2019
d383120
comment
connorjclark May 30, 2019
b6879b1
pr
connorjclark May 30, 2019
26f2864
lint
connorjclark May 30, 2019
018a64b
fix config for viewer tsconfig
connorjclark May 30, 2019
2f3da14
Merge remote-tracking branch 'origin/master' into rd-devtools
connorjclark May 30, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 16 additions & 40 deletions lighthouse-core/report/html/renderer/report-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,6 @@ class ReportRenderer {
return el;
}

/**
* @return {Element}
*/
_renderReportShortHeader() {
const shortHeaderContainer = this._dom.createElement('div', 'lh-header-container');
const wrapper = this._dom.cloneTemplate('#tmpl-lh-scores-wrapper', this._templateContext);
shortHeaderContainer.appendChild(wrapper);
return shortHeaderContainer;
}


/**
* @param {LH.ReportResult} report
* @return {DocumentFragment}
Expand Down Expand Up @@ -195,16 +184,8 @@ class ReportRenderer {
* @return {DocumentFragment}
*/
_renderReport(report) {
let header;
const headerContainer = this._dom.createElement('div');
if (this._dom.isDevTools()) {
headerContainer.classList.add('lh-header-plain');
header = this._renderReportShortHeader();
} else {
headerContainer.classList.add('lh-header-sticky');
header = this._renderReportHeader();
}
headerContainer.appendChild(header);
headerContainer.appendChild(this._renderReportHeader());
brendankenny marked this conversation as resolved.
Show resolved Hide resolved

const container = this._dom.createElement('div', 'lh-container');
const reportSection = container.appendChild(this._dom.createElement('div', 'lh-report'));
Expand Down Expand Up @@ -242,38 +223,33 @@ class ReportRenderer {
wrapper.appendChild(renderer.render(category, report.categoryGroups));
}

const reportFragment = this._dom.createFragment();
const topbarDocumentFragment = this._renderReportTopbar(report);
reportFragment.appendChild(topbarDocumentFragment);

if (scoreHeader) {
const scoreGauges =
this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers);
scoreHeader.append(...scoreGauges);
const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext);
const scoresContainer = this._dom.find('.lh-scores-container', headerContainer);
scoreHeader.append(
...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));
scoresContainer.appendChild(scoreHeader);
scoresContainer.appendChild(scoreScale);
}

reportSection.appendChild(this._renderReportFooter(report));

const reportFragment = this._dom.createFragment();

if (!this._dom.isDevTools()) {
const topbarDocumentFragment = this._renderReportTopbar(report);
reportFragment.appendChild(topbarDocumentFragment);
}

if (scoreHeader && !this._dom.isDevTools()) {
const stickyHeader = this._dom.createElement('div', 'lh-sticky-header');
this._dom.createChildOf(stickyHeader, 'div', 'lh-highlighter');

const scoreGauges =
this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers);
stickyHeader.append(...scoreGauges);

stickyHeader.append(
...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));
// The highlighter is placed in the first gauge to avoid an layout issue where the first
// paint comes before the highlighter's calculated position is applied. This causes
// the initial positioning to be rendered for a split second. As a workaround, the
// highlighter is placed in the first score gauge so that the initial position is correct.
brendankenny marked this conversation as resolved.
Show resolved Hide resolved
const firstGauge = this._dom.find('.lh-gauge__wrapper', stickyHeader);
this._dom.createChildOf(firstGauge, 'div', 'lh-highlighter');
reportFragment.appendChild(stickyHeader);
}

reportFragment.appendChild(headerContainer);
reportFragment.appendChild(container);
reportSection.appendChild(this._renderReportFooter(report));

return reportFragment;
}
Expand Down
90 changes: 73 additions & 17 deletions lighthouse-core/report/html/renderer/report-ui-features.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class ReportUIFeatures {
this._dom = dom;
/** @type {Document} */
this._document = this._dom.document();
/** @type {ParentNode} */
this._templateContext = this._dom.document();
/** @type {boolean} */
this._copyAttempt = false;
/** @type {HTMLElement} */
Expand Down Expand Up @@ -78,16 +80,16 @@ class ReportUIFeatures {
* @param {LH.Result} report
*/
initFeatures(report) {
if (this._dom.isDevTools()) return;

this.json = report;

this._setupMediaQueryListeners();
this._setupExportButton();
this._setupThirdPartyFilter();
this._setUpCollapseDetailsAfterPrinting();
this._resetUIState();
this._document.addEventListener('keyup', this.onKeyUp);
this._document.addEventListener('copy', this.onCopy);

const topbarLogo = this._dom.find('.lh-topbar__logo', this._document);
topbarLogo.addEventListener('click', () => this._toggleDarkTheme());

Expand All @@ -96,15 +98,10 @@ class ReportUIFeatures {
turnOffTheLights = true;
}

// Fireworks.
const scoresAll100 = Object.values(report.categories).every(cat => cat.score === 1);
if (!this._dom.isDevTools() && scoresAll100) {
const scoresAll100 = Object.values(this.json.categories).every(cat => cat.score === 1);
if (scoresAll100) {
turnOffTheLights = true;
const scoresContainer = this._dom.find('.lh-scores-container', this._document);
scoresContainer.classList.add('score100');
scoresContainer.addEventListener('click', _ => {
scoresContainer.classList.toggle('fireworks-paused');
});
this._enableFireworks();
}

if (turnOffTheLights) {
Expand All @@ -114,11 +111,61 @@ class ReportUIFeatures {
// There is only a sticky header when at least 2 categories are present.
if (Object.keys(this.json.categories).length >= 2) {
this._setupStickyHeaderElements();
this._document.addEventListener('scroll', this._updateStickyHeaderOnScroll);
window.addEventListener('resize', this._updateStickyHeaderOnScroll);
const containerEl = this._dom.find('.lh-container', this._document);
const elToAddScrollListener = this._getScrollParent(containerEl);
elToAddScrollListener.addEventListener('scroll', this._updateStickyHeaderOnScroll);
// We can't rely on listening to the window resize event for DevTools, so we first
// attempt the new ResizeObserver web platform feature. It has poor cross browser
// support, so we should check that it's supported. However, there are some performance
// issues with using window.ResizeObserver - it updates much more often than the 'resize'
Copy link
Collaborator Author

@connorjclark connorjclark May 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using the ResizeObserver in the deploy report (It's disabled outside devtools but if you revert that bit), and add some logging to the callback:

// Show sticky header when the score scale begins to go underneath the topbar.
const topbarBottom = this.topbarEl.getBoundingClientRect().bottom;
const scoreScaleTop = this.scoreScaleEl.getBoundingClientRect().top;
const showStickyHeader = topbarBottom >= scoreScaleTop;
// add this line
console.log(topbarBottom, scoreScaleTop, showStickyHeader);

image

You see that the position of our topbar is jumping all over the place!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we should just disable it outside DevTools for now, luckily it works there perfectly.

// event fires, and the experience is choppy in LH. For now, limit use to just DevTools,
// which doesn't seem affected for some reason.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since in theory ResizeObserver is more efficient and the future path to monitoring resizes, what about
// Use ResizeObserver where available. TODO: there is an issue with incorrect position numbers and, as a result, performance issues due to layout thrashing. See https://github.com/GoogleChrome/lighthouse/pull/9023/files#r288822287 for details.

Copy link
Collaborator Author

@connorjclark connorjclark May 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you also suggesting removing the devtools check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you also suggesting removing the devtools check?

whoops, no, good point. I like your version

if (this._dom.isDevTools()) {
const resizeObserver = new window.ResizeObserver(this._updateStickyHeaderOnScroll);
resizeObserver.observe(containerEl);
} else {
window.addEventListener('resize', this._updateStickyHeaderOnScroll);
}
}
}

/**
* Define a custom element for <templates> to be extracted from. For example:
* this.setTemplateContext(new DOMParser().parseFromString(htmlStr, 'text/html'))
* @param {ParentNode} context
*/
setTemplateContext(context) {
this._templateContext = context;
}

/**
* Finds the first scrollable ancestor of `element`. Falls back to the document.
* @param {HTMLElement} element
* @return {Node}
*/
_getScrollParent(element) {
const {overflowY} = window.getComputedStyle(element);
const isScrollable = overflowY !== 'visible' && overflowY !== 'hidden';

if (isScrollable && element.scrollHeight >= element.clientHeight) {
brendankenny marked this conversation as resolved.
Show resolved Hide resolved
return element;
}

if (element.parentElement) {
return this._getScrollParent(element.parentElement);
}

return document;
}
brendankenny marked this conversation as resolved.
Show resolved Hide resolved

_enableFireworks() {
const scoresContainer = this._dom.find('.lh-scores-container', this._document);
scoresContainer.classList.add('score100');
scoresContainer.addEventListener('click', _ => {
scoresContainer.classList.toggle('fireworks-paused');
});
}

/**
* Fires a custom DOM event on target.
* @param {string} name Name of the event.
Expand Down Expand Up @@ -179,13 +226,13 @@ class ReportUIFeatures {
if (thirdPartyRows.size === urlItems.length || !thirdPartyRows.size) return;

// create input box
const filterTemplate = this._dom.cloneTemplate('#tmpl-lh-3p-filter', this._document);
const filterTemplate = this._dom.cloneTemplate('#tmpl-lh-3p-filter', this._templateContext);
const filterInput = this._dom.find('input', filterTemplate);
const id = `lh-3p-filter-label--${index}`;

filterInput.id = id;
filterInput.addEventListener('change', e => {
// Remove rows from the dom and keep track of them to readd on uncheck.
// Remove rows from the dom and keep track of them to re-add on uncheck.
brendankenny marked this conversation as resolved.
Show resolved Hide resolved
// Why removing instead of hiding? To keep nth-child(even) background-colors working.
if (e.target instanceof HTMLInputElement && !e.target.checked) {
for (const row of thirdPartyRows.values()) {
Expand Down Expand Up @@ -545,7 +592,15 @@ class ReportUIFeatures {
* @param {boolean} [force]
*/
_toggleDarkTheme(force) {
this._document.body.classList.toggle('dark', force);
const el = this._dom.find('.lh-vars', this._document);
// This seems unnecessary, but in DevTools, passing "undefined" as the second
brendankenny marked this conversation as resolved.
Show resolved Hide resolved
// parameter acts like passing "false".
// https://github.com/ChromeDevTools/devtools-frontend/blob/dd6a6d4153647c2a4203c327c595692c5e0a4256/front_end/dom_extension/DOMExtension.js#L809-L819
if (typeof force === 'undefined') {
el.classList.toggle('dark');
} else {
el.classList.toggle('dark', force);
}
}

_updateStickyHeaderOnScroll() {
Expand All @@ -565,11 +620,12 @@ class ReportUIFeatures {
// Category order matches gauge order in sticky header.
const gaugeWrapperEls = this.stickyHeaderEl.querySelectorAll('.lh-gauge__wrapper');
const gaugeToHighlight = gaugeWrapperEls[highlightIndex];
const offset = gaugeToHighlight.getBoundingClientRect().left + 'px';
const origin = gaugeWrapperEls[0].getBoundingClientRect().left;
const offset = gaugeToHighlight.getBoundingClientRect().left - origin;

// Mutate at end to avoid layout thrashing.
this.highlightEl.style.transform = `translate(${offset}px)`;
this.stickyHeaderEl.classList.toggle('lh-sticky-header--visible', showStickyHeader);
this.highlightEl.style.left = offset;
}
}

Expand Down
37 changes: 21 additions & 16 deletions lighthouse-core/report/html/report-styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,24 @@
--audit-indent: 16px;
--expandable-indent: 16px;

--gauge-circle-size-big: 72px;
--gauge-circle-size: 64px;

--audits-margin-bottom: 20px;
--env-name-min-width: 120px;
--header-padding: 16px 0 16px 0;
--plugin-icon-size: 75%;
--pwa-icon-margin: 0 7px 0 -3px;
--score-container-width: 92px;
--score-number-font-size-big: 34px;
--score-number-font-size: 26px;
--score-shape-margin-left: 2px;
--score-shape-size: 10px;
--score-title-font-size-big: 22px;
--score-title-font-size: 14px;
--score-title-line-height-big: 26px;
--score-title-line-height: 20px;

--lh-audit-vpadding: 4px;
--lh-audit-hgap: 12px;
--lh-audit-group-vpadding: 12px;
Expand Down Expand Up @@ -555,6 +573,9 @@
.lh-column:first-of-type {
margin-right: 0px;
}
.lh-column:first-of-type .lh-metric:last-of-type {
border-bottom: 0;
}
}


Expand Down Expand Up @@ -952,22 +973,6 @@
}

/* Report */

.lh-header-sticky {
/** TODO: Redesigned report has a small sticky header.
For now, disable the current sticky behavior. */
/* position: -webkit-sticky;
position: sticky; */
top: 0;
width: 100%;
min-width: var(--report-min-width);
z-index: 2;
will-change: transform;
}
.lh-header-plain {
margin-top: var(--section-padding);
}

.lh-list > div:not(:last-child) {
padding-bottom: 20px;
}
Expand Down
32 changes: 24 additions & 8 deletions lighthouse-core/report/html/templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@
.lh-scores-container {
display: flex;
flex-direction: column;
margin-top: var(--topbar-height);
padding: var(--header-padding);
position: relative;
width: 100%;
Expand All @@ -171,25 +170,30 @@
--plugin-icon-size: 75%;
--score-container-width: 60px;
--score-number-font-size: 13px;
position: fixed;
position: sticky;
left: 0;
right: 0;
top: var(--topbar-height);
font-weight: 700;
display: flex;
display: none;
brendankenny marked this conversation as resolved.
Show resolved Hide resolved
justify-content: center;
background-color: var(--color-sticky-header-bg);
border-bottom: 1px solid var(--color-black-200);
padding-top: var(--score-container-padding);
padding-bottom: 4px;
z-index: 1;
pointer-events: none;
opacity: 0;
}

.lh-sticky-header--visible {
display: flex;
pointer-events: auto;
opacity: 1;
}

/* Disable the gauge arc animation for the sticky header, so toggling display: none
does not play the animation. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

evidence number 25 that these different uses of the score gauges should share less than they do :)

.lh-sticky-header .lh-gauge-arc {
animation: none;
}

.lh-sticky-header .lh-gauge__label {
Expand All @@ -201,8 +205,11 @@
height: 1px;
background: var(--color-highlighter-bg);
position: absolute;
bottom: -1px;
left: 0;
bottom: -5px;
}

.lh-gauge__wrapper:first-of-type {
contain: none;
}
</style>
<div class="lh-scores-wrapper">
Expand All @@ -219,7 +226,7 @@
<template id="tmpl-lh-topbar">
<style>
.lh-topbar {
position: fixed;
position: sticky;
top: 0;
left: 0;
right: 0;
Expand Down Expand Up @@ -256,6 +263,15 @@
cursor: pointer;
margin-right: 5px;
}
/*
Some features in the top right drop down menu don't work in the DevTools
client. They could with some tweaks, but currently they don't. For example:
Saving as HTML/JSON - does not bring up a file dialog, as one would expect in DevTools.
also, it saves the AuditsPanel HTML, which is funky.
*/
.lh-devtools .lh-export__button {
display: none;
}
.lh-export__button svg {
fill: var(--lh-export-icon-color);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('ReportRenderer', () => {
it('should render a report', () => {
const container = renderer._dom._document.body;
const output = renderer.renderReport(sampleResults, container);
assert.ok(output.querySelector('.lh-header-sticky'), 'has a header');
assert.ok(output.querySelector('.lh-header-container'), 'has a header');
assert.ok(output.querySelector('.lh-report'), 'has report body');
// 3 sets of gauges - one in sticky header, one in scores header, and one in each section.
assert.equal(output.querySelectorAll('.lh-gauge__wrapper, .lh-gauge--pwa__wrapper').length,
Expand Down
Loading