Skip to content

Commit

Permalink
Content and styling improvements (#881)
Browse files Browse the repository at this point in the history
* change 'ALL' to 'All technologies'

* prototype categories and description

* remove console.logs and unused code

* prototype custom colors in dark mode

* prototype different timeseries colors in dark mode

* format numbers according to locale

* increase color contrast in dark mode

* move beta header down

* update placeholder text on landing and in categories

* have fallback when categories and description are empty

* only fetch tech info on drilldown

* Turn off target-size audit

* fix bug: landing page color theme

* fix color contrast in dark mode

* Update src/js/techreport/index.js

Co-authored-by: Rick Viscomi <[email protected]>

* fix z-index and replace base url with constant

* save constants

---------

Co-authored-by: Barry Pollard <[email protected]>
Co-authored-by: Rick Viscomi <[email protected]>
3 people authored Aug 9, 2024
1 parent fbfef3a commit df56a3d
Showing 20 changed files with 203 additions and 62 deletions.
1 change: 1 addition & 0 deletions .github/lighthouse/lighthouse-config-dev.json
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
"service-worker": "off",
"speed-index": "off",
"splash-screen": "off",
"target-size": "off",
"themed-omnibox": "off",
"third-party-facades": "off",
"total-byte-weight": "off",
1 change: 1 addition & 0 deletions .github/lighthouse/lighthouse-config-prod.json
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
"service-worker": "off",
"speed-index": "off",
"splash-screen": "off",
"target-size": "off",
"themed-omnibox": "off",
"third-party-facades": "off",
"total-byte-weight": "off",
55 changes: 47 additions & 8 deletions config/techreport.json
Original file line number Diff line number Diff line change
@@ -47,7 +47,24 @@
},
"config": {
"default": {
"app": ["WordPress", "Squarespace", "Drupal"]
"app": ["WordPress", "Squarespace", "Drupal"],
"series": {
"breakdown": "client",
"breakdown_values": [
{
"name": "desktop",
"color": "#669E8E",
"color_dark": "#fff000",
"suffix": "%"
},
{
"name": "mobile",
"color": "#BD6EBE",
"color_dark": "#ff00f0",
"suffix": "%"
}
]
}
},
"popular_tech": {
"id": "popular_tech",
@@ -76,11 +93,13 @@
{
"name": "desktop",
"color": "#669E8E",
"color_dark": "#fff000",
"suffix": "%"
},
{
"name": "mobile",
"color": "#BD6EBE",
"color_dark": "#ff00f0",
"suffix": "%"
}
]
@@ -158,11 +177,13 @@
"values": [
{
"name": "desktop",
"color": "#669E8E"
"color": "#669E8E",
"color_dark": "#fff000"
},
{
"name": "mobile",
"color": "#BD6EBE"
"color": "#BD6EBE",
"color_dark": "#ff00f0"
}
],
"defaults": [
@@ -339,11 +360,13 @@
{
"name": "desktop",
"color": "#669E8E",
"color_dark": "#fff000",
"suffix": "%"
},
{
"name": "mobile",
"color": "#BD6EBE",
"color_dark": "#ff00f0",
"suffix": "%"
}
],
@@ -477,11 +500,13 @@
"values": [
{
"name": "desktop",
"color": "#669E8E"
"color": "#669E8E",
"color_dark": "#fff000"
},
{
"name": "mobile",
"color": "#BD6EBE"
"color": "#BD6EBE",
"color_dark": "#ff00f0"
}
],
"defaults": [
@@ -607,12 +632,14 @@
{
"name": "desktop",
"color": "#669E8E",
"suffix": " bytes"
"suffix": " bytes",
"color_dark": "#fff000"
},
{
"name": "mobile",
"color": "#BD6EBE",
"suffix": " bytes"
"suffix": " bytes",
"color_dark": "#ff00f0"
}
],
"defaults": [
@@ -669,8 +696,20 @@
"#8E3496",
"#CB377C"
],
"app_dark": [
"#5980EB",
"#D55316",
"#A8A9CA",
"#68A16D",
"#B979A7",
"#AC8D1C",
"#947786",
"#449DB1",
"#C861D2",
"#E24070"
],
"overrides": {
"WordPress": "#ff0000"
"WordPress": "#fff000"
}
},
"default": {
5 changes: 4 additions & 1 deletion src/js/components/drilldownHeader.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DataUtils } from "../techreport/utils/data";

function setTitle(title) {
const mainTitle = document.querySelector('h2 span.main-title');
mainTitle.textContent = title;
@@ -33,7 +35,8 @@ function update(data, filters) {
const app = filters.app[0];

if(app) {
setTitle(app);
const formattedApp = DataUtils.formatAppName(app);
setTitle(formattedApp);
}

if(data[app]) {
2 changes: 1 addition & 1 deletion src/js/components/filters.js
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ class Filters {
const optionTmpl = document.getElementById('filter-option').content.cloneNode(true);
const option = optionTmpl.querySelector('option');
const formattedTech = technology.technology;
option.textContent = technology.technology;
option.textContent = DataUtils.formatAppName(technology.technology);
option.value = formattedTech;
if(formattedTech === techSelector.getAttribute('data-selected')) {
option.selected = true;
67 changes: 52 additions & 15 deletions src/js/techreport/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Filters from '../components/filters';
import { Constants } from './utils/constants';
const { DrilldownHeader } = require("../components/drilldownHeader");
const { DataUtils } = require("./utils/data");
const { UIUtils } = require("./utils/ui");
@@ -25,17 +26,21 @@ class TechReport {
this.initializePage();
this.getAllMetricData();
this.bindSettingsListeners();
this.initializeAccessibility();
}

// Initialize the sections for the different pages
initializePage() {
this.updateStyling();

switch(this.pageId) {
case 'landing':
this.initializeLanding();
break;

case 'drilldown':
this.initializeReport();
this.getTechInfo();
break;

case 'comparison':
@@ -44,18 +49,14 @@ class TechReport {
}
}

// TODO
initializeLanding() {
}

// TODO
initializeReport() {
// TODO: Move to function
// Load accessibility/themeing info
initializeAccessibility() {
// Show indicators?
const showIndicators = localStorage.getItem('showIndicators');
document.querySelector('main').dataset.showIndicators = showIndicators;
document.querySelector('#indicators-check').checked = showIndicators === 'true';

// TODO: Move to function
// Dark or light mode?
const theme = localStorage.getItem('haTheme');
document.querySelector('html').dataset.theme = theme;
const btn = document.querySelector('.theme-switcher');
@@ -64,7 +65,13 @@ class TechReport {
} else if(theme === 'light') {
btn.innerHTML = '🌚 Switch to dark theme';
}
}

initializeLanding() {
}

// TODO
initializeReport() {
const sections = document.querySelectorAll('[data-type="section"]');
// TODO: add general config too
sections.forEach(section => {
@@ -79,7 +86,6 @@ class TechReport {
});

this.bindClientListener();
this.updateStyling();
}

// Watch for changes in the client dropdown
@@ -174,8 +180,6 @@ class TechReport {
},
];

const base = 'https://prod-gw-2vzgiib6.ue.gateway.dev/v1';

const technology = technologies.join('%2C')
.replaceAll(" ", "%20");

@@ -186,18 +190,21 @@ class TechReport {
technologies.forEach(tech => allResults[tech] = []);

Promise.all(apis.map(api => {
const url = `${base}/${api.endpoint}?technology=${technology}&geo=${geo}&rank=${rank}`;
const url = `${Constants.apiBase}/${api.endpoint}?technology=${technology}&geo=${geo}&rank=${rank}`;

return fetch(url)
.then(result => result.json())
.then(result => {
// Loop through all the rows of the API result
result.forEach(row => {
const parsedRow = {
...row,
}

// Parse the data and add it to the results
if(api.parse) {
parsedRow[api.metric] = api.parse(parsedRow[api.metric], parsedRow?.date);
const metric = parsedRow[api.metric] || parsedRow;
parsedRow[api.metric] = api.parse(metric, parsedRow?.date);
}

const resIndex = allResults[row.technology].findIndex(res => res.date === row.date);
@@ -217,6 +224,37 @@ class TechReport {
});
}

// Get the information about the selected technology
getTechInfo() {
const technologies = this.filters.app;
const technology = technologies.join('%2C')
.replaceAll(" ", "%20");

const url = `${Constants.apiBase}/technologies?technology=${technology}`;

fetch(url)
.then(result => result.json())
.then(result => {
const techInfo = result[0];

const categoryListEl = document.getElementsByClassName('category-list')[0];
categoryListEl.innerHTML = '';

const categories = techInfo && techInfo.category ? techInfo.category.split(', ') : [];
categories.forEach(category => {
const categoryItemEl = document.createElement('li');
categoryItemEl.className = 'cell';
categoryItemEl.textContent = category;
categoryListEl.append(categoryItemEl);
});

const descriptionEl = document.createElement('p');
descriptionEl.className = 'tech-description';
descriptionEl.textContent = techInfo?.description;
categoryListEl.after(descriptionEl);
});
}

// Update components and sections that are relevant to the current page
updateComponents(data) {
switch(this.pageId) {
@@ -239,12 +277,11 @@ class TechReport {
// Fetch the data for the filter dropdowns
getFilterInfo() {
const filterData = {};
const base = 'https://prod-gw-2vzgiib6.ue.gateway.dev/v1';

const filterApis = ['categories', 'technologies', 'ranks', 'geos'];

Promise.all(filterApis.map(api => {
const url = `${base}/${api}`;
const url = `${Constants.apiBase}/${api}`;

return fetch(url)
.then(result => result.json())
5 changes: 4 additions & 1 deletion src/js/techreport/tableLinked.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DataUtils } from "./utils/data";

class TableLinked {
constructor(id, config, filters, data) {
this.id = id;
@@ -40,7 +42,8 @@ class TableLinked {
cell = document.createElement('th');
const link = document.createElement('a');
link.setAttribute('href', `?tech=${app}`);
link.innerHTML = app;
const formattedApp = DataUtils.formatAppName(app);
link.textContent = formattedApp;
cell.append(link);
} else if(column.key === 'client') {
cell = document.createElement('td');
27 changes: 20 additions & 7 deletions src/js/techreport/timeseries.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Table } from "./table";
import { DataUtils } from "./utils/data";
import { UIUtils } from "./utils/ui";
class Timeseries {
// Create the component
@@ -136,7 +137,11 @@ class Timeseries {
/* Create a wrapper */
const itemWrapper = document.createElement('div');
itemWrapper.classList.add('breakdown-item');
itemWrapper.style.setProperty('--breakdown-color', breakdown.color);

/* Set the breakdown color depending on chosen theme */
const theme = document.querySelector('html').dataset.theme;
const themeColor = theme === 'dark' ? breakdown.color_dark : breakdown.color;
itemWrapper.style.setProperty('--breakdown-color', themeColor);

/* Add a text label to the wrapper */
const breakdownLabel = document.createElement('p');
@@ -153,7 +158,7 @@ class Timeseries {
} else {
/* Add the value to the wrapper */
const valueLabel = document.createElement('p');
valueLabel.textContent = `${latestValue}${breakdown.suffix || ''}`;
valueLabel.textContent = `${latestValue.toLocaleString()}${breakdown.suffix || ''}`;
valueLabel.classList.add('breakdown-value');
itemWrapper.appendChild(valueLabel);
}
@@ -193,8 +198,8 @@ class Timeseries {
const latestEndpoint = latest[endpoint];
const latestSubcategory = latestEndpoint?.find(row => row.name === subcategory);
const latestClient = latestSubcategory?.[client];
const latestValue = latestClient?.[metric];
const summaryValue = latestClient?.[summary];
const latestValue = latestClient?.[metric]?.toLocaleString();
const summaryValue = latestClient?.[summary]?.toLocaleString();

/* Select the container to which we'll add elements. */
const card = container.querySelector(`[data-app="${app}"]`);
@@ -203,7 +208,8 @@ class Timeseries {
const value = card.getElementsByClassName('breakdown-value')[0];

/* Update text */
label.textContent = latest.technology;
const formattedApp = DataUtils.formatAppName(latest.technology);
label.textContent = formattedApp;
if(latestValue) {
if(summary) {
value.textContent = `${summaryValue}`;
@@ -343,7 +349,7 @@ class Timeseries {
document.getElementsByTagName('main')[0].append(pointSvg);

pointSeries.innerHTML = point.series.name;
pointItem.innerHTML = `${pointSvg.outerHTML} ${pointSeries.outerHTML}: ${point.y}`;
pointItem.innerHTML = `${pointSvg.outerHTML} ${pointSeries.outerHTML}: ${point.y.toLocaleString()}`;

pointList.appendChild(pointItem);
});
@@ -434,6 +440,9 @@ class Timeseries {

const category = this.getCategory(config);

// Get color scheme
const theme = document.querySelector('html').dataset.theme;

// Breakdown data by categories defined in config
config?.series?.values?.forEach((value, index) => {
// Filter by selected client & sort
@@ -454,14 +463,18 @@ class Timeseries {

const sortedData = formattedData.sort((a, b) => new Date(a.x) - new Date(b.x));

// Pick color from settings depending on theme
const colors = this.defaults(config)?.chart?.colors;
const colorDark = value.color_dark;
const colorLight = value.color;
const seriesColor = theme === "dark" ? colorDark : colorLight;

// Push the configurations and formatted data to the series array
series.push(
{
name: value.name,
data: sortedData,
color: value.color || colors[index],
color: seriesColor || colors?.[index],
lineWidth: 2,
}
)
5 changes: 5 additions & 0 deletions src/js/techreport/utils/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const apiBase = 'https://prod-gw-2vzgiib6.ue.gateway.dev/v1';

export const Constants = {
apiBase,
};
5 changes: 5 additions & 0 deletions src/js/techreport/utils/data.js
Original file line number Diff line number Diff line change
@@ -60,6 +60,10 @@ const formatBytes = (value) => {
return value > 1048576 ? `${Math.round(value / 1048576)} MB` : value > 1024 ? `${Math.round(value / 1024)} KB` : `${submetric.desktop.median_bytes} bytes`;
};

const formatAppName = (app) => {
return app === 'ALL' ? 'All technologies' : app;
}

const parsePageWeightData = (metric, date) => {
return metric.map(submetric => {
return {
@@ -103,4 +107,5 @@ export const DataUtils = {
parsePageWeightData,
filterDuplicates,
getLighthouseScoreCategories,
formatAppName,
};
6 changes: 5 additions & 1 deletion src/js/techreport/utils/ui.js
Original file line number Diff line number Diff line change
@@ -5,14 +5,18 @@ const getAppColor = (tech, technologies, colors) => {
const sortedTechs = [...technologies].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
const techIndex = sortedTechs.indexOf(tech);

// Get color scheme
const theme = document.querySelector('html').dataset.theme;

// Return custom colors if configured
if(colors.overrides && colors.overrides[tech]) {
return colors.overrides[tech];
}

// Otherwise reutrn based on alphabetic position
if(techIndex < colors.app.length) {
return colors.app[techIndex];
const appColors = theme === "dark" ? colors.app_dark : colors.app;
return appColors[techIndex];
}
}

46 changes: 35 additions & 11 deletions static/css/techreport/techreport.css
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
--color-page-border: var(--color-teal-medium);
--color-tooltip-background: var(--color-card-background);
--color-tooltip-border: var(--color-card-border);
--color-nav: #667a7d;

/* Font sizes */
--font-size-medium: 1.75rem;
@@ -39,6 +40,8 @@
--card-shadow: 0 2px 7px 0px rgba(143, 149, 150, 0.05);
--card-radius: 0.25rem;
--table-row-hover: var(--color-blue-100);
--color-panel-text: #203b40;
--color-panel-background: #bfe1e7;

/* Graph colors */
--graph-color-primary: var(--color-teal-dark);
@@ -66,6 +69,9 @@
--color-bg-gradient: #111;
--color-page-border: #000;
--color-tooltip-border: var(--color-page-background);
--color-panel-text: #bfe1e7;
--color-panel-background: #203b40;
--color-nav: #bfe1e7;

/* Graph colors */
--graph-color-labels: #a6bbbe;
@@ -86,6 +92,15 @@ main :is(a, p a) {
color: var(--color-link);
}

main :is(a, p a):is(:hover, :focus) {
color: var(--color-text);
text-decoration-thickness: 2px;
}

nav {
color: var(--color-nav);
}

/* CTA */
.cta-link {
background-color: var(--color-teal-dark);
@@ -299,6 +314,10 @@ main :is(a, p a) {
outline-offset: 2px;
}

.dropdown-content {
z-index: 2;
}

.select-label::before {
content: "";
display: block;
@@ -330,11 +349,11 @@ main :is(a, p a) {
}

.select-label:has(select:is(:focus-visible, :hover))::after {
border-color: #f2f9ff;
border-color: var(--color-page-background);
}

.select-label:has(select:focus-visible) {
background-color: #f2f9ff;
background-color: var(--color-page-background);
}

.select-label:has(select:focus-visible) label {
@@ -370,7 +389,7 @@ main :is(a, p a) {
}

.tech-selector-group:has(.remove-tech:is(:focus, :hover)) {
background-color: #f2f9ff;
background-color: var(--color-page-background);
}

.tech-selector-group {
@@ -391,7 +410,7 @@ main :is(a, p a) {
position: absolute;
right: 0;
border-radius: 0 4px 4px 0;
z-index: 0;
z-index: 2;
}

.tech-input-wrapper::after {
@@ -407,7 +426,7 @@ main :is(a, p a) {
border-left: 1.5px solid var(--color-text-darker);
border-radius: 1px;
transform: rotate(-45deg);
z-index: 0;
z-index: 3;
}

.tech-input-wrapper select {
@@ -421,11 +440,11 @@ main :is(a, p a) {
}

.tech-input-wrapper:has(select:is(:focus-visible, :hover))::after {
border-color: #f2f9ff;
border-color: var(--color-page-background);
}

.tech-input-wrapper:has(select:focus-visible) {
background-color: #f2f9ff;
background-color: var(--color-page-background);
color: var(--color-text);
}

@@ -436,6 +455,7 @@ main :is(a, p a) {
[data-theme="dark"] select option,
[data-theme="dark"] .tech-input-wrapper:has(select:focus-visible) select {
color: var(--color-page-background) !important;
background-color: var(--color-text-darker) !important;
}

.tech-selector-group .content {
@@ -653,11 +673,11 @@ select {
}

.subcategory-selector-wrapper:has(select:is(:focus-visible, :hover))::after {
border-color: #f2f9ff;
border-color: var(--color-page-background);
}

.subcategory-selector-wrapper:has(select:focus-visible) {
background-color: #f2f9ff;
background-color: var(--color-page-background);
}

.subcategory-selector-wrapper:has(select:focus-visible) label {
@@ -686,8 +706,8 @@ select {

/* Info message */
.info-panel {
background: #bfe1e7;
color: #203b40;
background: var(--color-panel-background);
color: var(--color-panel-text);
font-weight: 400;
padding: 0.5rem;
}
@@ -1143,6 +1163,10 @@ path.highcharts-tick {
stroke-width: 1px;
}

.tooltip-wrapper {
color: var(--color-text);
}

.tooltip-wrapper ul {
margin-top: 0.5rem;
}
2 changes: 1 addition & 1 deletion templates/techreport/comparison.html
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ <h1>
</div>
</div>

{% set filter_tech_title = technologies_str or tech_report_page.filters.app[0] or 'ALL' %}
{% set filter_tech_title = technologies_str or tech_report_page.filters.app[0] or 'All Technologies' %}
{% include "techreport/components/filter_info_header.html" %}

<div id="report-content" class="report-content">
2 changes: 1 addition & 1 deletion templates/techreport/components/filter_info_header.html
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
<div class="result-info">
<p>
<a href="#tech-1">
{{ filter_tech_title }}
{{ filter_tech_title.replace('ALL', 'All technologies') }}
</a>
</p>
<div>
7 changes: 6 additions & 1 deletion templates/techreport/components/table.html
Original file line number Diff line number Diff line change
@@ -23,7 +23,12 @@
data-metric="{{column.metric}}"
class="{{ column.className }}"
>
{{ app }}
{% if app == 'ALL' %}
All technologies
{% else %}
{{ app }}
{% endif %}

{% if column.hiddenSuffix %}
<span aria-hidden="true">
{{ column.hiddenSuffix }}
7 changes: 2 additions & 5 deletions templates/techreport/drilldown.html
Original file line number Diff line number Diff line change
@@ -9,16 +9,13 @@ <h1>
<span class="subtitle">Tech Report</span>
<span class="">Drilldown</span>
</h1>
<!-- <ul class="category-list categories">
<li class="cell">Placeholder</li>
</ul> -->
</div>
<div class="filters">
{% include "techreport/templates/filters.html" %}
</div>
</div>

{% set filter_tech_title = tech_report_page.filters.app[0] or 'ALL' %}
{% set filter_tech_title = tech_report_page.filters.app[0] or 'All technologies' %}
{% include "techreport/components/filter_info_header.html" %}

<div id="report-content" class="report-content">
@@ -28,7 +25,7 @@ <h2>
<span class="main-title">ALL</span>
</h2>
<ul class="category-list categories">
<li class="cell">Placeholder</li>
<li class="cell">Uncategorized</li>
</ul>
</div>

2 changes: 1 addition & 1 deletion templates/techreport/landing.html
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ <h1>
<span class="title">Tech Report</span>
</h1>
<p>
Placeholder text: A short description about what it is that we display in the Core Web Vitals report, and how it can be used. There should probably be links here to the individual technology pages and a few interesting comparison pages, as well as to the methodology page and the discussions etc like the reports have today.
Track and compare web technology performance and adoption. Real-world Core Web Vitals performance data is provided by the Chrome UX Report at the origin level, and technologies are identified by HTTP Archive on the home page and one interior page.
</p>
</div>
</div>
14 changes: 7 additions & 7 deletions templates/techreport/techreport.html
Original file line number Diff line number Diff line change
@@ -11,13 +11,6 @@
{% endblock %}

{% block report_navigation %}
<div class="info-panel">
<div class="block-l">
<p class="info-label">Beta version</p>
<p>This dashboard is still under development.</p>
</div>
</div>

<nav class="report-navigation">
{% set filters = "" %}
{% if tech_report_page.filters %}
@@ -56,6 +49,13 @@
</li>
</ul>
</nav>

<div class="info-panel">
<div class="block-l">
<p class="info-label">Beta version</p>
<p>This dashboard is still under development.</p>
</div>
</div>
{% endblock %}

{% block main %}
4 changes: 4 additions & 0 deletions templates/techreport/templates/filters.html
Original file line number Diff line number Diff line change
@@ -11,6 +11,10 @@
{% for technology in technologies %}
{% set key = loop.index %}
{% set technology = technology %}
{% set technologyName = technology %}
{% if technology == "ALL" %}
{% set technologyName = "All technologies" %}
{% endif %}
{% set name = "tech-" + key|string %}
{% include "techreport/templates/selector_tech.html" %}
{% endfor %}
2 changes: 1 addition & 1 deletion templates/techreport/templates/selector_tech.html
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
<div class="tech-input-wrapper">
<select name="tech" class="tech" data-selected="{{ technology }}" id="{{ name }}">
<option value="{{ technology }}" selected="true">
{{ technology }}
{{ technologyName }}
</option>
</select>
</div>

0 comments on commit df56a3d

Please sign in to comment.