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

report(redesign): add toggle control to show metric descriptions #8661

Merged
merged 23 commits into from
May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,16 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
element.appendChild(this.renderCategoryHeader(category, groups));
}

// Metrics
// Metrics.
const metricAudits = category.auditRefs.filter(audit => audit.group === 'metrics');
const metricAuditsEl = this.renderAuditGroup(groups.metrics);

// Metric descriptions toggle.
const auditGroupHeader = this.dom.find('.lh-audit-group__header', metricAuditsEl);
const toggleTmpl = this.dom.cloneTemplate('#tmpl-lh-metrics-toggle', this.templateContext);
const toggleEl = this.dom.find('.lh-metrics-toggle', toggleTmpl);
auditGroupHeader.appendChild(toggleEl);

const keyMetrics = metricAudits.filter(a => a.weight >= 3);
const otherMetrics = metricAudits.filter(a => a.weight < 3);

Expand Down
26 changes: 26 additions & 0 deletions lighthouse-core/report/html/renderer/report-ui-features.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ class ReportUIFeatures {
this.stickyHeaderEl; // eslint-disable-line no-unused-expressions
/** @type {HTMLElement} */
this.highlightEl; // eslint-disable-line no-unused-expressions
/** @type {HTMLInputElement} */
this.metricDescriptionToggleEl; // eslint-disable-line no-unused-expressions
/** @type {HTMLElement} */
this.metricAuditGroup; // eslint-disable-line no-unused-expressions

this.onMediaQueryChange = this.onMediaQueryChange.bind(this);
this.onCopy = this.onCopy.bind(this);
Expand All @@ -70,6 +74,7 @@ class ReportUIFeatures {
this.expandAllDetails = this.expandAllDetails.bind(this);
this._toggleDarkTheme = this._toggleDarkTheme.bind(this);
this._updateStickyHeaderOnScroll = this._updateStickyHeaderOnScroll.bind(this);
this._toggleMetricDescription = this._toggleMetricDescription.bind(this);
}

/**
Expand All @@ -92,6 +97,7 @@ class ReportUIFeatures {
this._document.addEventListener('copy', this.onCopy);
this._document.addEventListener('scroll', this._updateStickyHeaderOnScroll);
window.addEventListener('resize', this._updateStickyHeaderOnScroll);
this._setupMetricDescriptionToggleElements();
const topbarLogo = this._dom.find('.lh-topbar__logo', this._document);
topbarLogo.addEventListener('click', this._toggleDarkTheme);
}
Expand Down Expand Up @@ -254,6 +260,26 @@ class ReportUIFeatures {
this._copyAttempt = false;
}

_setupMetricDescriptionToggleElements() {
const metricDescriptionToggleEl = this._document.querySelector('.lh-metrics-toggle__input');
// No metrics if performance category wasn't run.
if (!metricDescriptionToggleEl) return;

this.metricDescriptionToggleEl = /** @type {HTMLInputElement} */ (metricDescriptionToggleEl);
this.metricAuditGroup = this._dom.find('.lh-audit-group--metrics', this._document);
this.metricDescriptionToggleEl.addEventListener('input', this._toggleMetricDescription);
this.metricAuditGroup.addEventListener('click', e => {
const el = /** @type {HTMLElement} */ (e.target);
if (el.closest('.lh-metric__title')) this.metricDescriptionToggleEl.click();
});
}

_toggleMetricDescription() {
this.metricDescriptionToggleEl.blur();
const show = this.metricDescriptionToggleEl.checked;
this.metricAuditGroup.classList.toggle('lh-audit-group--metrics__show-descriptions', show);
}

/**
* Copies the report JSON to the clipboard (if supported by the browser).
*/
Expand Down
76 changes: 69 additions & 7 deletions lighthouse-core/report/html/report-styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
--color-black-800: #424242;
--color-black-900: #212121;
--color-black: #000000;
--color-blue: #2962FF;
--color-green-700: #018642;
--color-green: #0CCE6B;
--color-orange-700: #D04900;
Expand All @@ -102,6 +103,7 @@
--env-item-bg: var(--color-black-100);
--env-name-min-width: 220px;
--env-tem-padding: 10px 0px;
--expandable-padding: 0 0 2px calc(var(--score-shape-margin-left) + var(--score-shape-size) + var(--score-shape-margin-right));
--gauge-circle-size-big: 120px;
--gauge-circle-size: 96px;
--header-padding: 20px 0 20px 0;
Expand All @@ -117,7 +119,10 @@
--score-container-width: 160px;
--score-number-font-size-big: 42px;
--score-number-font-size: 34px;
--score-shape-margin: 7px 12px 0 4px;
--score-shape-margin-left: 4px;
--score-shape-margin-right: 12px;
--score-shape-margin-top: 7px;
--score-shape-margin: var(--score-shape-margin-top) var(--score-shape-margin-right) 0 var(--score-shape-margin-left);
--score-shape-size: 12px;
--score-title-font-size-big: 28px;
--score-title-font-size: 20px;
Expand All @@ -141,6 +146,7 @@
--color-highlighter-bg: var(--body-text-color);

--color-hover: #FAFAFA;
--color-metric-toggle-lines: #7F7F7F;

--plugin-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="%23757575"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>');
--plugin-icon-url-dark: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="%23FFFFFF"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>');
Expand Down Expand Up @@ -210,7 +216,8 @@
--score-container-width: 112px;
--score-number-font-size-big: 34px;
--score-number-font-size: 26px;
--score-shape-margin: 5px 12px 0 2px;
--score-shape-margin-left: 2px;
--score-shape-margin-top: 7px;
--score-shape-size: 10px;
--score-title-font-size-big: 22px;
--score-title-font-size: 14px;
Expand Down Expand Up @@ -525,11 +532,14 @@
.lh-metric {
border-bottom: 1px solid var(--report-secondary-border-color);
}
.lh-metric:first-of-type {
border-top: 1px solid var(--report-secondary-border-color);
}

.lh-metric__innerwrap {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
font-weight: 500;
padding: 8px var(--text-indent);
}

Expand All @@ -539,10 +549,7 @@

.lh-metric__title {
flex: 1;
}

.lh-metric__name {
flex: 1;
font-weight: 500;
}

.lh-metrics__disclaimer {
Expand All @@ -553,13 +560,68 @@
}

.lh-metric__description {
display: none;
color: var(--secondary-text-color);
padding: var(--expandable-padding);
}
.lh-audit-group--metrics__show-descriptions .lh-metric__description {
display: block;
}

.lh-metric__value {
white-space: nowrap; /* No wrapping between metric value and the icon */
font-weight: 500;
}

.lh-metrics-toggle {
position: relative;
}
.lh-metrics-toggle__input {
cursor: pointer;
opacity: 0;
position: absolute;
width: 100%;
height: 100%;
}
.lh-metrics-toggle label {
display: flex;
background-color: #eee;
border-radius: 20px;
overflow: hidden;
}
.lh-metrics-toggle__input:focus + label {
outline: -webkit-focus-ring-color auto 3px;
}
.lh-metrics-toggle__icon {
display: flex;
align-items: center;
justify-content: center;
padding: 2px 5px;
width: 50%;
height: 28px;
}
.lh-metrics-toggle__input:not(:checked) + label .lh-metrics-toggle__icon--less,
.lh-metrics-toggle__input:checked + label .lh-metrics-toggle__icon--more {
background-color: var(--color-blue);
--color-metric-toggle-lines: var(--color-white);
}
.lh-metrics-toggle__lines {
fill: var(--color-metric-toggle-lines);
}
.lh-metrics-toggle label .lh-metrics-toggle__icon--less {
Copy link
Member

Choose a reason for hiding this comment

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

the base .lh-metrics-toggle__icon rule could assume the --less case so this rule isnt necessary

regardless you can move width/height into the base lh-metrics-toggle__icon rule

padding-left: 8px;
}
.lh-metrics-toggle label .lh-metrics-toggle__icon--more {
padding-right: 8px;
}

/* Pushes the metric description toggle button to the right. */
.lh-audit-group--metrics .lh-audit-group__header {
display: flex;
}
.lh-audit-group--metrics .lh-audit-group__header span.lh-audit-group__title {
flex: 1;
}

.lh-metric .lh-metric__innerwrap::before {
content: '';
Expand Down
24 changes: 22 additions & 2 deletions lighthouse-core/report/html/templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,33 @@
<span class="lh-audit-group__title"></span>
<span class="lh-audit-group__itemcount"></span>
<!-- .lh-audit-group__description will be added here -->
<!-- .lh-metrics-toggle will be added here -->
</div>
<div class=""></div>
</div>
</summary>
</details>
</template>

<!-- Lighthouse metrics toggle -->
<template id="tmpl-lh-metrics-toggle">
<div class="lh-metrics-toggle">
Copy link
Member

Choose a reason for hiding this comment

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

i'd like to use a <input type=checkbox> here (as the underlying control).

we shouldn't need JS for this guy (except for this.metricAuditGroup.classList.toggle('lh-audit-group--metrics__show-descriptions'))

this guide seems to be solid on implementation.. also including their resources at the bottom. https://webdesign.tutsplus.com/tutorials/how-to-make-custom-accessible-checkboxes-and-radio-buttons--cms-32074

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, hows that?

<input class="lh-metrics-toggle__input" type="checkbox" name="toggle-metric-descriptions">
<label for="toggle-metric-descriptions">
<div class="lh-metrics-toggle__icon lh-metrics-toggle__icon--less" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<path class="lh-metrics-toggle__lines" d="M4 9h16v2H4zm0 4h10v2H4z" />
</svg>
</div>
<div class="lh-metrics-toggle__icon lh-metrics-toggle__icon--more" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path class="lh-metrics-toggle__lines" d="M3 18h12v-2H3v2zM3 6v2h18V6H3zm0 7h18v-2H3v2z" />
</svg>
</div>
</label>
</div>
</template>

<!-- Lighthouse audit -->
<template id="tmpl-lh-audit">
<div class="lh-audit">
Expand All @@ -88,10 +108,10 @@
<!-- Lighthouse perf metric -->
<template id="tmpl-lh-metric">
<div class="lh-metric">
<div class="lh-metric__innerwrap tooltip-boundary">
<div class="lh-metric__innerwrap">
<span class="lh-metric__title"></span>
<div class="lh-metric__value"></div>
<div class="lh-metric__description tooltip"></div>
<div class="lh-metric__description"></div>
</div>
</div>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,23 @@ const TEMPLATE_FILE_REPORT = fs.readFileSync(__dirname +
'/../../../../report/html/report-template.html', 'utf8');

describe('ReportUIFeatures', () => {
let renderer;
let reportUIFeatures;
let sampleResults;
let dom;

/**
* @param {LH.JSON} lhr
*/
function render(lhr) {
Copy link
Member

Choose a reason for hiding this comment

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

render function looks 👍

main issue is that it can be pretty slow, so we want to share rendered reports between tests as much as possible, but that's what you do here, so looks good to me

const detailsRenderer = new DetailsRenderer(dom);
const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
const renderer = new ReportRenderer(dom, categoryRenderer);
const reportUIFeatures = new ReportUIFeatures(dom);
const container = dom.find('main', dom._document);
renderer.renderReport(lhr, container);
reportUIFeatures.initFeatures(lhr);
return container;
}

beforeAll(() => {
global.Util = Util;
global.ReportUIFeatures = ReportUIFeatures;
Expand Down Expand Up @@ -72,11 +84,7 @@ describe('ReportUIFeatures', () => {
};

dom = new DOM(document.window.document);
const detailsRenderer = new DetailsRenderer(dom);
const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
renderer = new ReportRenderer(dom, categoryRenderer);
sampleResults = Util.prepareReportResult(sampleResultsOrig);
reportUIFeatures = new ReportUIFeatures(dom);
});

afterAll(() => {
Expand All @@ -96,16 +104,11 @@ describe('ReportUIFeatures', () => {

describe('initFeatures', () => {
it('should init a report', () => {
// render a report onto the UIFeature dom
const container = reportUIFeatures._dom._document.querySelector('main');
renderer.renderReport(sampleResults, container);

assert.equal(reportUIFeatures.json, undefined);
reportUIFeatures.initFeatures(sampleResults);
assert.ok(reportUIFeatures.json);
Copy link
Member

Choose a reason for hiding this comment

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

testing json was being used as a proxy test for the reportUIFeatures being initialized, otherwise this is just testing the report renderer.

We could definitely do something much better if you want to come up with something to test :) or just restore and we'll think about it another day

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

How about just removing it? Doesn't seem useful now that we have all these other tests checking individual behaviors.

Copy link
Member

Choose a reason for hiding this comment

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

How about just removing it?

seems fine now, yeah

const container = render(sampleResults);
assert.equal(dom.findAll('.lh-category', container).length, 5);
});

describe('thrid-party filtering', () => {
describe('third-party filtering', () => {
let container;

beforeAll(() => {
Expand All @@ -129,9 +132,7 @@ describe('ReportUIFeatures', () => {
];

// render a report onto the UIFeature dom
container = dom.find('main', dom._document);
renderer.renderReport(lhr, container);
reportUIFeatures.initFeatures(lhr);
container = render(lhr);
});

it('filters out third party resources in details tables when checkbox is clicked', () => {
Expand Down Expand Up @@ -161,4 +162,41 @@ describe('ReportUIFeatures', () => {
});
});
});

describe('metric description toggles', () => {
let container;
let metricsAuditGroup;
let toggle;
const metricsClass = 'lh-audit-group--metrics';
const toggleClass = 'lh-metrics-toggle__input';
const showClass = 'lh-audit-group--metrics__show-descriptions';

describe('works if there is a performance category', () => {
beforeAll(() => {
container = render(sampleResults);
metricsAuditGroup = dom.find(`.${metricsClass}`, container);
toggle = dom.find(`.${toggleClass}`, metricsAuditGroup);
});

it('descriptions hidden by default', () => {
assert.ok(!metricsAuditGroup.classList.contains(showClass));
});

it('can toggle description visibility', () => {
assert.ok(!metricsAuditGroup.classList.contains(showClass));
toggle.click();
assert.ok(metricsAuditGroup.classList.contains(showClass));
toggle.click();
assert.ok(!metricsAuditGroup.classList.contains(showClass));
});
});

it('report still works if performance category does not run', () => {
const lhr = JSON.parse(JSON.stringify(sampleResults));
delete lhr.categories.performance;
container = render(lhr);
assert.ok(!container.querySelector(`.${metricsClass}`));
assert.ok(!container.querySelector(`.${toggleClass}`));
});
});
});