Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 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
48 changes: 10 additions & 38 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());

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,29 @@ 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 =
const makeScoreGauges = () =>
Copy link
Contributor

Choose a reason for hiding this comment

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

definitely overkill to avoid coming up with different variable names :P

what about scoreGauges and stickyScoreGauges :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ideally I'd like no variables for them at all.

scoreHeader.append(
	...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));

?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally I'd like no variables for them at all.

I don't really see what that gains you over a named variable, but sure, that works too :)

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(...makeScoreGauges());
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(...makeScoreGauges());
reportFragment.appendChild(stickyHeader);
}

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

return reportFragment;
}
Expand Down
85 changes: 62 additions & 23 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,33 +80,36 @@ 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);

// 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I had a dream that the comments were co-located on the lines below because I could've sworn that was the case 😆

// also, it saves the AuditsPanel HTML, which is funky.
if (this._dom.isDevTools()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

what about just display:none on the export button? Then this stuff won't have to be special-cased

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

this._dom.find('.lh-export__button', this._document).remove();
} else {
this._setupMediaQueryListeners();
this._setupExportButton();
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());
this._setupThirdPartyFilter();

let turnOffTheLights = false;
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
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 +119,35 @@ 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);

/** @type {Document | HTMLElement} */
let elToAddScrollListener = this._document;
Copy link
Contributor

Choose a reason for hiding this comment

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

this doesn't need to be fixed now, but we shouldn't have to hardcode the different possible scroll containers the report is in. Either it should be something obvious, something we can query, or something we shouldn't be messing with in the first place because who knows how the caller is using the report.

This was the reason we originally had the separate devtools-ui-features.js or whatever (and viewer has viewer-ui-features.js), because report-ui-features.js is written very specifically for report-template.html. We got rid of the file because devtools didn't need it at the time, but now that it does, maybe it's worth splitting ui features down a different axis. That way if PSI, web.dev, etc etc start needing things in here we won't have to add a case for each of their scroll containers too :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

maybe find the nearest ancestor with scroll overflow?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

did that. works well.

Copy link
Contributor

@brendankenny brendankenny May 29, 2019

Choose a reason for hiding this comment

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

did that. works well

I was thinking more like IntersectionObserver or refactoring but that works for now too. Hopefully stack overflow did their due diligence there :P

if (this._dom.isDevTools()) {
elToAddScrollListener = this._dom.find('.audits2-results-container', this._document);
}
elToAddScrollListener.addEventListener('scroll', this._updateStickyHeaderOnScroll);

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;
}

_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 +208,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.
// 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 +574,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
// 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 +602,13 @@ 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';
// This is normally 0 - but in DevTools, it's not, since the entire report could be docked.
const origin = this.stickyHeaderEl.getBoundingClientRect().left;
const offset = gaugeToHighlight.getBoundingClientRect().left - origin;

// Mutate at end to avoid layout thrashing.
this.stickyHeaderEl.classList.toggle('lh-sticky-header--visible', showStickyHeader);
this.highlightEl.style.left = offset;
this.highlightEl.style.left = offset + 'px';
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If you look closely, the highlighter starts off on the far left before quickly rendering to the first gauge. I think this is b/c of the display: none changes. I thought doing this.highlightEl.style.left = ... first would fix it, but it does not.

}
}

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
15 changes: 10 additions & 5 deletions lighthouse-core/report/html/templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,25 +171,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;
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
Contributor

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 Down Expand Up @@ -219,7 +224,7 @@
<template id="tmpl-lh-topbar">
<style>
.lh-topbar {
position: fixed;
position: sticky;
top: 0;
left: 0;
right: 0;
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