lighthouse 8.6.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/dist/report/bundle.esm.js +5994 -0
  2. package/dist/report/flow.js +30 -13
  3. package/dist/report/standalone.js +41 -35
  4. package/flow-report/.eslintrc.cjs +2 -0
  5. package/flow-report/assets/standalone-flow-template.html +3 -2
  6. package/flow-report/assets/styles.css +108 -31
  7. package/flow-report/src/app.tsx +18 -18
  8. package/flow-report/src/common.tsx +28 -15
  9. package/flow-report/src/header.tsx +12 -13
  10. package/flow-report/src/help-dialog.tsx +3 -4
  11. package/flow-report/src/i18n/i18n.tsx +57 -16
  12. package/flow-report/src/i18n/ui-strings.js +50 -0
  13. package/flow-report/src/icons.tsx +36 -8
  14. package/flow-report/src/sidebar/flow.tsx +3 -3
  15. package/flow-report/src/sidebar/sidebar.tsx +35 -14
  16. package/flow-report/src/summary/category.tsx +97 -24
  17. package/flow-report/src/summary/summary.tsx +21 -14
  18. package/flow-report/src/topbar.tsx +9 -5
  19. package/flow-report/src/util.ts +33 -26
  20. package/flow-report/src/wrappers/category-score.tsx +0 -3
  21. package/flow-report/src/wrappers/markdown.tsx +27 -0
  22. package/flow-report/src/wrappers/report-renderer.tsx +10 -3
  23. package/flow-report/src/wrappers/report.tsx +27 -6
  24. package/flow-report/standalone-flow.tsx +4 -3
  25. package/flow-report/test/common-test.tsx +32 -17
  26. package/flow-report/test/flow-report-pptr-test.ts +46 -0
  27. package/flow-report/test/header-test.tsx +6 -6
  28. package/flow-report/test/setup/env-setup.ts +1 -1
  29. package/flow-report/test/sidebar/sidebar-test.tsx +43 -1
  30. package/flow-report/test/summary/category-test.tsx +120 -24
  31. package/flow-report/test/summary/summary-test.tsx +1 -1
  32. package/flow-report/test/topbar-test.tsx +1 -0
  33. package/flow-report/test/util-test.tsx +32 -11
  34. package/flow-report/test/wrappers/category-score-test.tsx +87 -0
  35. package/flow-report/test/wrappers/markdown-test.tsx +29 -0
  36. package/flow-report/tsconfig.json +1 -0
  37. package/jest.config.js +4 -2
  38. package/lighthouse-cli/.eslintrc.cjs +2 -0
  39. package/lighthouse-cli/cli-flags.js +1 -1
  40. package/lighthouse-cli/run.js +1 -1
  41. package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +0 -0
  42. package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +4 -2
  43. package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +1 -1
  44. package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
  45. package/lighthouse-core/audits/accessibility/axe-audit.js +7 -1
  46. package/lighthouse-core/audits/audit.js +1 -1
  47. package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -0
  48. package/lighthouse-core/audits/byte-efficiency/modern-image-formats.js +4 -2
  49. package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +11 -10
  50. package/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js +5 -3
  51. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images-snapshot.js +2 -1
  52. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +2 -1
  53. package/lighthouse-core/audits/deprecations.js +33 -11
  54. package/lighthouse-core/audits/dobetterweb/uses-http2.js +27 -11
  55. package/lighthouse-core/audits/errors-in-console.js +0 -2
  56. package/lighthouse-core/audits/image-aspect-ratio.js +5 -5
  57. package/lighthouse-core/audits/image-size-responsive.js +6 -6
  58. package/lighthouse-core/audits/installable-manifest.js +5 -3
  59. package/lighthouse-core/audits/preload-lcp-image.js +7 -5
  60. package/lighthouse-core/audits/script-treemap-data.js +1 -1
  61. package/lighthouse-core/audits/unsized-images.js +2 -3
  62. package/lighthouse-core/computed/image-records.js +4 -3
  63. package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +3 -4
  64. package/lighthouse-core/computed/metrics/tbt-utils.js +57 -0
  65. package/lighthouse-core/computed/metrics/total-blocking-time.js +3 -53
  66. package/lighthouse-core/computed/resource-summary.js +1 -1
  67. package/lighthouse-core/config/config-helpers.js +21 -10
  68. package/lighthouse-core/config/constants.js +3 -4
  69. package/lighthouse-core/config/default-config.js +61 -71
  70. package/lighthouse-core/fraggle-rock/config/config.js +1 -1
  71. package/lighthouse-core/fraggle-rock/config/default-config.js +4 -5
  72. package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +6 -1
  73. package/lighthouse-core/fraggle-rock/gather/session.js +3 -4
  74. package/lighthouse-core/gather/connections/cri.js +1 -1
  75. package/lighthouse-core/gather/driver/storage.js +0 -1
  76. package/lighthouse-core/gather/driver.js +3 -7
  77. package/lighthouse-core/gather/fetcher.js +4 -7
  78. package/lighthouse-core/gather/gather-runner.js +29 -6
  79. package/lighthouse-core/gather/gatherers/accessibility.js +27 -0
  80. package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -0
  81. package/lighthouse-core/gather/gatherers/image-elements.js +0 -3
  82. package/lighthouse-core/gather/gatherers/inspector-issues.js +5 -0
  83. package/lighthouse-core/lib/asset-saver.js +7 -4
  84. package/lighthouse-core/lib/emulation.js +45 -1
  85. package/lighthouse-core/lib/i18n/i18n.js +19 -8
  86. package/lighthouse-core/lib/lh-env.js +2 -0
  87. package/lighthouse-core/lib/proto-preprocessor.js +14 -2
  88. package/lighthouse-core/lib/tappable-rects.js +8 -15
  89. package/lighthouse-core/lib/url-shim.js +1 -1
  90. package/lighthouse-core/runner.js +1 -1
  91. package/lighthouse-core/util-commonjs.js +65 -46
  92. package/package.json +27 -17
  93. package/readme.md +3 -3
  94. package/report/.eslintrc.cjs +2 -0
  95. package/report/README.md +1 -1
  96. package/report/assets/standalone-template.html +2 -3
  97. package/report/assets/styles.css +360 -254
  98. package/report/assets/templates.html +21 -76
  99. package/report/clients/bundle.js +1 -0
  100. package/report/clients/standalone.js +6 -15
  101. package/report/generator/README.md +1 -1
  102. package/report/renderer/api.js +32 -0
  103. package/report/renderer/category-renderer.js +59 -19
  104. package/report/renderer/components.js +59 -110
  105. package/report/renderer/crc-details-renderer.js +15 -12
  106. package/report/renderer/dom.js +16 -1
  107. package/report/renderer/drop-down-menu.js +2 -2
  108. package/report/renderer/element-screenshot-renderer.js +8 -8
  109. package/report/renderer/features-util.js +1 -1
  110. package/report/renderer/open-tab.js +9 -3
  111. package/report/renderer/performance-category-renderer.js +55 -34
  112. package/report/renderer/pwa-category-renderer.js +0 -10
  113. package/report/renderer/report-renderer.js +91 -44
  114. package/report/renderer/report-ui-features.js +36 -33
  115. package/report/renderer/swap-locale-feature.js +3 -3
  116. package/report/renderer/topbar-features.js +53 -48
  117. package/report/renderer/util.js +66 -46
  118. package/report/test/clients/bundle-test.js +70 -0
  119. package/report/test/renderer/category-renderer-test.js +48 -3
  120. package/report/test/renderer/i18n-test.js +0 -7
  121. package/report/test/renderer/performance-category-renderer-test.js +51 -14
  122. package/report/test/renderer/pwa-category-renderer-test.js +6 -6
  123. package/report/test/renderer/report-renderer-axe-test.js +10 -12
  124. package/report/test/renderer/report-renderer-test.js +23 -22
  125. package/report/test/renderer/report-ui-features-test.js +20 -10
  126. package/report/test/renderer/text-encoding-test.js +1 -1
  127. package/report/test/renderer/util-test.js +35 -31
  128. package/report/test-assets/faux-psi-template.html +3 -11
  129. package/report/test-assets/faux-psi.js +26 -22
  130. package/report/types/html-renderer.d.ts +2 -0
  131. package/report/types/report-renderer.d.ts +23 -0
  132. package/shared/localization/format.js +64 -30
  133. package/shared/localization/locales/ar-XB.json +72 -75
  134. package/shared/localization/locales/ar.json +72 -75
  135. package/shared/localization/locales/bg.json +72 -75
  136. package/shared/localization/locales/ca.json +72 -75
  137. package/shared/localization/locales/cs.json +89 -92
  138. package/shared/localization/locales/da.json +72 -75
  139. package/shared/localization/locales/de.json +89 -92
  140. package/shared/localization/locales/el.json +72 -75
  141. package/shared/localization/locales/en-GB.json +72 -75
  142. package/shared/localization/locales/en-US.json +75 -75
  143. package/shared/localization/locales/en-XA.json +72 -75
  144. package/shared/localization/locales/en-XL.json +75 -75
  145. package/shared/localization/locales/es-419.json +90 -93
  146. package/shared/localization/locales/es.json +90 -93
  147. package/shared/localization/locales/fi.json +72 -75
  148. package/shared/localization/locales/fil.json +72 -75
  149. package/shared/localization/locales/fr.json +89 -92
  150. package/shared/localization/locales/he.json +73 -76
  151. package/shared/localization/locales/hi.json +72 -75
  152. package/shared/localization/locales/hr.json +72 -75
  153. package/shared/localization/locales/hu.json +89 -92
  154. package/shared/localization/locales/id.json +89 -92
  155. package/shared/localization/locales/it.json +89 -92
  156. package/shared/localization/locales/ja.json +89 -92
  157. package/shared/localization/locales/ko.json +89 -92
  158. package/shared/localization/locales/lt.json +89 -92
  159. package/shared/localization/locales/lv.json +95 -98
  160. package/shared/localization/locales/nl.json +89 -92
  161. package/shared/localization/locales/no.json +72 -75
  162. package/shared/localization/locales/pl.json +72 -75
  163. package/shared/localization/locales/pt-PT.json +72 -75
  164. package/shared/localization/locales/pt.json +89 -92
  165. package/shared/localization/locales/ro.json +90 -93
  166. package/shared/localization/locales/ru.json +89 -92
  167. package/shared/localization/locales/sk.json +89 -92
  168. package/shared/localization/locales/sl.json +89 -92
  169. package/shared/localization/locales/sr-Latn.json +89 -92
  170. package/shared/localization/locales/sr.json +89 -92
  171. package/shared/localization/locales/sv.json +72 -75
  172. package/shared/localization/locales/ta.json +89 -92
  173. package/shared/localization/locales/te.json +89 -92
  174. package/shared/localization/locales/th.json +89 -92
  175. package/shared/localization/locales/tr.json +89 -92
  176. package/shared/localization/locales/uk.json +92 -95
  177. package/shared/localization/locales/vi.json +89 -92
  178. package/shared/localization/locales/zh-HK.json +89 -92
  179. package/shared/localization/locales/zh-TW.json +89 -92
  180. package/shared/localization/locales/zh.json +89 -92
  181. package/shared/localization/locales.js +6 -0
  182. package/shared/test/localization/format-test.js +45 -9
  183. package/shared/test/localization/swap-locale-test.js +0 -12
  184. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +19 -11
  185. package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
  186. package/third-party/download-content-shell/download-content-shell.js +2 -2
  187. package/third-party/download-content-shell/utils.js +0 -24
  188. package/tsconfig-all.json +2 -2
  189. package/tsconfig.json +0 -1
  190. package/types/artifacts.d.ts +7 -7
  191. package/types/enquirer.d.ts +3 -1
  192. package/types/lhr/audit-details.d.ts +6 -5
  193. package/types/lhr/flow.d.ts +3 -2
  194. package/types/lhr/lhr.d.ts +1 -1
  195. package/types/node.d.ts +5 -5
  196. package/types/rollup-plugin-postprocess.d.ts +10 -0
  197. package/changelog.md +0 -5490
  198. package/lighthouse-core/audits/dobetterweb/appcache-manifest.js +0 -67
  199. package/lighthouse-core/audits/dobetterweb/external-anchors-use-rel-noopener.js +0 -96
  200. package/lighthouse-core/audits/redirects-http.js +0 -59
  201. package/lighthouse-core/gather/gatherers/dobetterweb/appcache.js +0 -34
  202. package/lighthouse-core/gather/gatherers/http-redirect.js +0 -46
  203. package/lighthouse-core/lib/i18n/locales/en-US.ctc.json +0 -6699
  204. package/lighthouse-core/lib/i18n/locales/en-XL.ctc.json +0 -6672
  205. package/lighthouse-core/scripts/package.json +0 -4
  206. package/report/clients/psi.js +0 -158
  207. package/report/test/clients/psi-test.js +0 -143
  208. package/shared/localization/locales/en-US.ctc.json +0 -6877
  209. package/shared/localization/locales/en-XL.ctc.json +0 -6852
@@ -27,6 +27,8 @@ module.exports = {
27
27
  ],
28
28
  'newlines-between': 'always',
29
29
  }],
30
+ 'import/group-exports': 2,
31
+ 'import/exports-last': 2,
30
32
  '@typescript-eslint/type-annotation-spacing': 2,
31
33
  },
32
34
  overrides: [
@@ -23,11 +23,12 @@ limitations under the License.
23
23
  <title>Lighthouse Flow Report</title>
24
24
  <style>/*%%LIGHTHOUSE_CSS%%*/</style>
25
25
  <style>/*%%LIGHTHOUSE_FLOW_CSS%%*/</style>
26
+ <style>body {margin: 0}</style>
26
27
  </head>
27
- <body class="flow-vars lh-root lh-vars">
28
+ <body>
28
29
  <noscript>Lighthouse report requires JavaScript. Please enable.</noscript>
29
30
 
30
- <main><!-- report populated here --></main>
31
+ <main class="flow-vars lh-root lh-vars"><!-- report populated here --></main>
31
32
 
32
33
  <script>window.__LIGHTHOUSE_FLOW_JSON__ = %%LIGHTHOUSE_FLOW_JSON%%;</script>
33
34
  <script>%%LIGHTHOUSE_FLOW_JAVASCRIPT%%
@@ -7,6 +7,7 @@
7
7
  .flow-vars {
8
8
  --app-font-size: 12px;
9
9
  --base-spacing: 16px;
10
+ --bold-weight: 500;
10
11
  --category-summary-font-size: 18px;
11
12
  --double-base-spacing: calc(var(--base-spacing) * 2);
12
13
  --gather-mode-icon-size: 16px;
@@ -23,11 +24,14 @@
23
24
  --sidebar-selected-bg-color: #DDEEFF;
24
25
  --sidebar-summary-font-size: 14px;
25
26
  --sidebar-title-font-size: 16px;
26
- --sidebar-max-width: 400px;
27
- --summary-flow-step-label-font-size: 16px;
28
- --summary-subtitle-font-size: 16px;
29
- --summary-title-font-size: 32px;
27
+ --sidebar-width: 320px;
28
+ --summary-flow-step-link-font-size: 14px;
29
+ --summary-navigation-header-font-size: 12px;
30
+ --summary-header-margin: 52px;
31
+ --summary-subtitle-font-size: 12px;
32
+ --summary-title-font-size: 20px;
30
33
  --summary-tooltip-box-shadow-color: rgba(0, 0, 0, 0.25);
34
+ --summary-tooltip-line-height: 16px;
31
35
  --topbar-button-font-size: 14px;
32
36
  --topbar-button-size: 45px;
33
37
  --topbar-title-font-size: 14px;
@@ -114,10 +118,18 @@
114
118
 
115
119
  .Topbar__title {
116
120
  font-size: var(--topbar-title-font-size);
117
- font-weight: bold;
121
+ font-weight: var(--bold-weight);
118
122
  margin-right: var(--double-base-spacing);
119
123
  }
120
124
 
125
+ .Topbar__help-label {
126
+ display: flex;
127
+ align-items: center;
128
+ }
129
+ .Topbar__help-label > :first-child {
130
+ margin-right: var(--half-base-spacing);
131
+ }
132
+
121
133
  .Content {
122
134
  grid-area: content;
123
135
  overflow-y: auto;
@@ -148,19 +160,19 @@
148
160
  .Sidebar {
149
161
  grid-area: sidebar;
150
162
  border-right: 1px solid var(--separator-color);
151
- width: min-content;
152
- max-width: var(--sidebar-max-width);
163
+ width: var(--sidebar-width);
153
164
  overflow-x: hidden;
154
165
  overflow-y: auto;
155
166
  }
156
167
  .Sidebar a {
157
- color: var(--color-gray-800);
168
+ color: var(--color-gray-700);
158
169
  text-decoration: none;
159
170
  }
160
171
 
161
172
  .Sidebar--current {
162
173
  background-color: var(--sidebar-selected-bg-color);
163
174
  color: var(--color-blue-A700) !important;
175
+ font-weight: var(--bold-weight);
164
176
  }
165
177
 
166
178
  .SidebarHeader {
@@ -168,7 +180,7 @@
168
180
  }
169
181
  .SidebarHeader__title {
170
182
  font-size: var(--sidebar-title-font-size);
171
- font-weight: bold;
183
+ font-weight: var(--bold-weight);
172
184
  width: max-content;
173
185
  }
174
186
  .SidebarHeader__date {
@@ -180,6 +192,7 @@
180
192
  margin: var(--base-spacing);
181
193
  padding: var(--half-base-spacing);
182
194
  background-color: var(--color-gray-50);
195
+ color: var(--color-gray-700);
183
196
  border-radius: 3px;
184
197
  }
185
198
 
@@ -258,21 +271,23 @@
258
271
  }
259
272
 
260
273
  .SummaryHeader {
261
- margin: calc(var(--base-spacing) * 3) 0px;
262
- width: 100%;
274
+ margin: var(--summary-header-margin) 0px;
263
275
  }
264
276
 
265
277
  .SummaryHeader__title {
266
- margin: var(--base-spacing) 0;
267
278
  font-size: var(--summary-title-font-size);
279
+ font-weight: var(--bold-weight);
280
+ line-height: 28px;
281
+ margin: 0 0 calc(0.25 * var(--base-spacing));
268
282
  }
269
283
 
270
284
  .SummaryHeader__subtitle {
271
285
  font-size: var(--summary-subtitle-font-size);
286
+ line-height: 16px;
272
287
  }
273
288
 
274
289
  .SummarySectionHeader {
275
- margin-top: var(--double-base-spacing);
290
+ margin-top: var(--base-spacing);
276
291
  }
277
292
 
278
293
  .SummarySectionHeader__content {
@@ -281,15 +296,15 @@
281
296
  }
282
297
 
283
298
  .SummaryFlow {
284
- width: 100%;
285
299
  display: grid;
300
+ max-width: var(--report-content-width);
286
301
  grid-auto-rows: min-content;
287
- grid-template-columns: min-content min-content minmax(var(--min-text-width), 4fr) 1fr 1fr 1fr 1fr;
302
+ grid-template-columns: min-content min-content minmax(var(--min-text-width), max-content) 1fr 1fr 1fr 1fr;
288
303
  align-items: center;
289
304
  margin: var(--base-spacing) 0px;
305
+ --gauge-circle-size: 48px;
290
306
  }
291
307
  .SummaryFlow .lh-fraction__content {
292
- padding: 0px;
293
308
  min-width: unset;
294
309
  }
295
310
 
@@ -321,7 +336,7 @@
321
336
  grid-column: 2;
322
337
  }
323
338
  .SummaryFlowStep .FlowStepThumbnail {
324
- margin: var(--base-spacing) var(--half-base-spacing);
339
+ margin: var(--half-base-spacing);
325
340
  }
326
341
 
327
342
  .FlowStepThumbnail {
@@ -329,7 +344,10 @@
329
344
  justify-self: center;
330
345
  object-fit: cover;
331
346
  object-position: top left;
332
- border: 1px solid var(--color-gray);
347
+ border: 1px solid var(--color-gray-700);
348
+ border-radius: 3px;
349
+ padding: 2px;
350
+ box-sizing: content-box !important;
333
351
  }
334
352
 
335
353
  .SummaryFlowStep__label {
@@ -341,11 +359,13 @@
341
359
  }
342
360
 
343
361
  .SummaryFlowStep__mode {
344
- color: var(--color-gray-700);
362
+ color: var(--color-blue-A700);
363
+ font-weight: var(--bold-weight);
345
364
  }
346
365
 
347
366
  .SummaryFlowStep__link {
348
- font-size: var(--summary-flow-step-label-font-size);
367
+ font-size: var(--summary-flow-step-link-font-size);
368
+ line-height: 20px;
349
369
  color: var(--color-gray-800);
350
370
  text-decoration: underline;
351
371
  width: 100%;
@@ -354,7 +374,6 @@
354
374
 
355
375
  .SummaryCategory__content {
356
376
  position: relative;
357
- margin: var(--half-base-spacing);
358
377
  }
359
378
  .SummaryCategory__content:hover,
360
379
  .SummaryCategory__content:focus-within {
@@ -376,22 +395,33 @@
376
395
  border-radius: 3px;
377
396
  padding: var(--base-spacing);
378
397
  right: 0;
398
+ line-height: var(--summary-tooltip-line-height);
379
399
  box-shadow: 0px 4px 4px var(--summary-tooltip-box-shadow-color);
380
400
  z-index: 1;
381
401
  }
382
402
 
383
403
  .SummaryTooltip__title {
384
- font-weight: bold;
385
- margin-bottom: var(--half-base-spacing);
404
+ font-weight: var(--bold-weight);
405
+ }
406
+
407
+ .SummaryTooltip__url {
408
+ overflow-x: hidden;
409
+ text-overflow: ellipsis;
410
+ white-space: nowrap;
411
+ margin-top: calc(0.25 * var(--base-spacing));
412
+ margin-bottom: calc(0.75 * var(--base-spacing));
413
+ color: var(--color-gray-700);
386
414
  }
387
415
 
388
416
  .SummaryTooltip__category {
389
- font-weight: bold;
417
+ font-weight: var(--bold-weight);
390
418
  display: flex;
419
+ align-items: center;
391
420
  margin-top: var(--half-base-spacing);
392
421
  }
393
422
 
394
423
  .SummaryTooltip__category-title {
424
+ line-height: 24px;
395
425
  flex-grow: 1;
396
426
  }
397
427
 
@@ -406,8 +436,53 @@
406
436
  color: var(--color-fail);
407
437
  }
408
438
 
439
+ .SummaryTooltip__fraction {
440
+ color: var(--color-gray-700);
441
+ }
442
+
443
+ .SummaryTooltip__informative {
444
+ margin-top: calc(0.25 * var(--base-spacing));
445
+ color: var(--color-gray-700);
446
+ }
447
+
448
+ .SummaryTooltipAudits__title {
449
+ line-height: 24px;
450
+ margin-top: calc(0.75 * var(--base-spacing));
451
+ font-weight: var(--bold-weight);
452
+ }
453
+
454
+ .SummaryTooltipAudit {
455
+ display: flex;
456
+ margin: calc(0.25 * var(--base-spacing)) 0px;
457
+ color: var(--color-gray-700);
458
+ --score-icon-size: 10px;
459
+ }
460
+ .SummaryTooltipAudit code {
461
+ color: var(--snippet-color);
462
+ }
463
+ .SummaryTooltipAudit::before {
464
+ content: '';
465
+ height: var(--score-icon-size);
466
+ width: var(--score-icon-size);
467
+ margin-top: calc((var(--summary-tooltip-line-height) - var(--score-icon-size)) / 2);
468
+ margin-right: var(--half-base-spacing);
469
+ }
470
+ .SummaryTooltipAudit--pass::before {
471
+ background-color: var(--color-pass);
472
+ border-radius: 50%;
473
+ }
474
+ .SummaryTooltipAudit--average::before {
475
+ background-color: var(--color-average);
476
+ }
477
+ .SummaryTooltipAudit--fail::before {
478
+ border-left: calc(var(--score-icon-size) / 2) solid transparent;
479
+ border-right: calc(var(--score-icon-size) / 2) solid transparent;
480
+ border-bottom: var(--score-icon-size) solid var(--color-fail);
481
+ }
482
+
409
483
  .SummaryNavigationHeader {
410
- font-size: var(--summary-flow-step-label-font-size);
484
+ font-size: var(--summary-navigation-header-font-size);
485
+ line-height: 16px;
411
486
  display: contents;
412
487
  }
413
488
 
@@ -530,6 +605,7 @@
530
605
  .Header__prev-title {
531
606
  grid-area: prev-title;
532
607
  text-align: left;
608
+ justify-self: start;
533
609
  }
534
610
 
535
611
  .Header__next-title {
@@ -544,16 +620,17 @@
544
620
  align-self: start;
545
621
  overflow-x: hidden;
546
622
  text-overflow: ellipsis;
547
- width: 100%;
623
+ max-width: 100%;
548
624
  }
549
625
 
550
626
  .Header__current-title {
551
627
  grid-area: current-title;
552
628
  text-align: center;
553
629
  font-size: var(--header-current-title-font-size);
554
- font-weight: bold;
630
+ font-weight: var(--bold-weight);
555
631
  overflow-x: hidden;
556
632
  text-overflow: ellipsis;
633
+ margin: 0px var(--half-base-spacing);
557
634
  }
558
635
 
559
636
  .Header__current-description {
@@ -583,7 +660,7 @@
583
660
  align-items: center;
584
661
 
585
662
  font-size: var(--dialog-title-font-size);
586
- font-weight: bold;
663
+ font-weight: var(--bold-weight);
587
664
 
588
665
  margin-bottom: calc(var(--base-spacing) * 2);
589
666
  }
@@ -609,12 +686,12 @@
609
686
 
610
687
  .HelpDialogColumn__header-title {
611
688
  font-size: var(--category-summary-font-size);
612
- font-weight: bold;
689
+ font-weight: var(--bold-weight);
613
690
  }
614
691
 
615
692
  .HelpDialogColumn__legend-label {
616
693
  color: var(--color-blue-A700);
617
- font-weight: bold;
694
+ font-weight: var(--bold-weight);
618
695
  }
619
696
 
620
697
  .HelpDialogColumn ul {
@@ -623,7 +700,7 @@
623
700
 
624
701
  .HelpDialogColumn__use-cases p,
625
702
  .HelpDialogColumn__categories p {
626
- font-weight: bold;
703
+ font-weight: var(--bold-weight);
627
704
  color: var(--color-gray-700);
628
705
  }
629
706
 
@@ -5,42 +5,42 @@
5
5
  */
6
6
 
7
7
  import {FunctionComponent} from 'preact';
8
- import {useEffect, useRef, useState} from 'preact/hooks';
8
+ import {useLayoutEffect, useRef, useState} from 'preact/hooks';
9
9
 
10
10
  import {ReportRendererProvider} from './wrappers/report-renderer';
11
11
  import {Sidebar} from './sidebar/sidebar';
12
12
  import {Summary} from './summary/summary';
13
- import {classNames, FlowResultContext, useCurrentLhr, useHashParam} from './util';
13
+ import {classNames, FlowResultContext, useHashState} from './util';
14
14
  import {Report} from './wrappers/report';
15
15
  import {Topbar} from './topbar';
16
16
  import {Header} from './header';
17
17
  import {I18nProvider} from './i18n/i18n';
18
18
 
19
+ function getAnchorElement(hashState: LH.FlowResult.HashState|null) {
20
+ if (!hashState || !hashState.anchor) return null;
21
+ return document.getElementById(hashState.anchor);
22
+ }
23
+
19
24
  const Content: FunctionComponent = () => {
20
- const currentLhr = useCurrentLhr();
21
- const anchor = useHashParam('anchor');
25
+ const hashState = useHashState();
22
26
  const ref = useRef<HTMLDivElement>(null);
23
27
 
24
- useEffect(() => {
25
- if (anchor) {
26
- const el = document.getElementById(anchor);
27
- if (el) {
28
- el.scrollIntoView({behavior: 'smooth'});
29
- return;
30
- }
28
+ useLayoutEffect(() => {
29
+ const el = getAnchorElement(hashState);
30
+ if (el) {
31
+ el.scrollIntoView();
32
+ } else if (ref.current) {
33
+ ref.current.scrollTop = 0;
31
34
  }
32
-
33
- // Scroll to top no anchor is found.
34
- if (ref.current) ref.current.scrollTop = 0;
35
- }, [anchor, currentLhr]);
35
+ }, [hashState]);
36
36
 
37
37
  return (
38
38
  <div ref={ref} className="Content">
39
39
  {
40
- currentLhr ?
40
+ hashState ?
41
41
  <>
42
- <Header currentLhr={currentLhr}/>
43
- <Report currentLhr={currentLhr}/>
42
+ <Header hashState={hashState}/>
43
+ <Report hashState={hashState}/>
44
44
  </> :
45
45
  <Summary/>
46
46
  }
@@ -8,15 +8,15 @@ import {FunctionComponent} from 'preact';
8
8
  import {useEffect, useState} from 'preact/hooks';
9
9
 
10
10
  import {NavigationIcon, SnapshotIcon, TimespanIcon} from './icons';
11
- import {getFilmstripFrames, getScreenDimensions, getScreenshot} from './util';
11
+ import {getFilmstripFrames, getScreenDimensions, getFullPageScreenshot} from './util';
12
12
 
13
- const ANIMATION_FRAME_DURATION_MS = 250;
13
+ const ANIMATION_FRAME_DURATION_MS = 500;
14
14
 
15
- export const Separator: FunctionComponent = () => {
15
+ const Separator: FunctionComponent = () => {
16
16
  return <div className="Separator" role="separator"></div>;
17
17
  };
18
18
 
19
- export const FlowStepIcon: FunctionComponent<{mode: LH.Result.GatherMode}> = ({mode}) => {
19
+ const FlowStepIcon: FunctionComponent<{mode: LH.Result.GatherMode}> = ({mode}) => {
20
20
  return <>
21
21
  {
22
22
  mode === 'navigation' && <NavigationIcon/>
@@ -30,7 +30,7 @@ export const FlowStepIcon: FunctionComponent<{mode: LH.Result.GatherMode}> = ({m
30
30
  </>;
31
31
  };
32
32
 
33
- export const FlowSegment: FunctionComponent<{mode?: LH.Result.GatherMode}> = ({mode}) => {
33
+ const FlowSegment: FunctionComponent<{mode?: LH.Result.GatherMode}> = ({mode}) => {
34
34
  return (
35
35
  <div className="FlowSegment">
36
36
  <div className="FlowSegment__top-line"/>
@@ -71,16 +71,16 @@ const FlowStepAnimatedThumbnail: FunctionComponent<{
71
71
  );
72
72
  };
73
73
 
74
- export const FlowStepThumbnail: FunctionComponent<{
75
- reportResult: LH.ReportResult,
74
+ const FlowStepThumbnail: FunctionComponent<{
75
+ lhr: LH.Result,
76
76
  width?: number,
77
77
  height?: number,
78
- }> = ({reportResult, width, height}) => {
79
- const screenshot = getScreenshot(reportResult);
80
- const frames = getFilmstripFrames(reportResult);
78
+ }> = ({lhr, width, height}) => {
79
+ const fullPageScreenshot = getFullPageScreenshot(lhr);
80
+ const frames = getFilmstripFrames(lhr);
81
81
 
82
82
  // Resize the image to fit the viewport aspect ratio.
83
- const dimensions = getScreenDimensions(reportResult);
83
+ const dimensions = getScreenDimensions(lhr);
84
84
  if (width && height === undefined) {
85
85
  height = dimensions.height * width / dimensions.width;
86
86
  } else if (height && width === undefined) {
@@ -92,19 +92,32 @@ export const FlowStepThumbnail: FunctionComponent<{
92
92
  return <></>;
93
93
  }
94
94
 
95
- if (reportResult.gatherMode === 'timespan' && frames && frames.length) {
96
- return <FlowStepAnimatedThumbnail frames={frames} width={width} height={height} />;
95
+ let thumbnail;
96
+ if (frames && frames.length) {
97
+ thumbnail = frames[frames.length - 1].data;
98
+ if (lhr.gatherMode === 'timespan') {
99
+ return <FlowStepAnimatedThumbnail frames={frames} width={width} height={height} />;
100
+ }
101
+ } else {
102
+ thumbnail = fullPageScreenshot?.screenshot.data;
97
103
  }
98
104
 
99
105
  return <>
100
106
  {
101
- screenshot &&
107
+ thumbnail &&
102
108
  <img
103
109
  className="FlowStepThumbnail"
104
- src={screenshot}
110
+ src={thumbnail}
105
111
  style={{width, height}}
106
112
  alt="Screenshot of a page tested by Lighthouse"
107
113
  />
108
114
  }
109
115
  </>;
110
116
  };
117
+
118
+ export {
119
+ Separator,
120
+ FlowStepIcon,
121
+ FlowSegment,
122
+ FlowStepThumbnail,
123
+ };
@@ -6,40 +6,39 @@
6
6
 
7
7
  import {FunctionComponent} from 'preact';
8
8
 
9
- import {Util} from '../../report/renderer/util';
10
9
  import {FlowStepIcon, FlowStepThumbnail} from './common';
11
- import {useUIStrings} from './i18n/i18n';
10
+ import {useLocalizedStrings} from './i18n/i18n';
12
11
  import {getModeDescription, useFlowResult} from './util';
13
12
 
14
13
  const SIDE_THUMBNAIL_HEIGHT = 80;
15
14
  const MAIN_THUMBNAIL_HEIGHT = 120;
16
15
 
17
16
  const HeaderThumbnail: FunctionComponent<{
18
- reportResult: LH.ReportResult,
17
+ lhr: LH.Result,
19
18
  position: 'prev'|'next'|'main'
20
19
  }> =
21
- ({reportResult, position}) => {
20
+ ({lhr, position}) => {
22
21
  const height = position === 'main' ? MAIN_THUMBNAIL_HEIGHT : SIDE_THUMBNAIL_HEIGHT;
23
22
  return (
24
23
  <div className={`HeaderThumbnail HeaderThumbnail--${position}`}>
25
- <FlowStepThumbnail reportResult={reportResult} height={height}/>
24
+ <FlowStepThumbnail lhr={lhr} height={height}/>
26
25
  <div className="HeaderThumbnail__icon">
27
- <FlowStepIcon mode={reportResult.gatherMode}/>
26
+ <FlowStepIcon mode={lhr.gatherMode}/>
28
27
  </div>
29
28
  </div>
30
29
  );
31
30
  };
32
31
 
33
- export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
34
- ({currentLhr}) => {
32
+ export const Header: FunctionComponent<{hashState: LH.FlowResult.HashState}> =
33
+ ({hashState}) => {
35
34
  const flowResult = useFlowResult();
36
- const {index} = currentLhr;
35
+ const {index} = hashState;
37
36
 
38
37
  const step = flowResult.steps[index];
39
38
  const prevStep = flowResult.steps[index - 1];
40
39
  const nextStep = flowResult.steps[index + 1];
41
40
 
42
- const strings = useUIStrings();
41
+ const strings = useLocalizedStrings();
43
42
  const modeDescription = getModeDescription(step.lhr.gatherMode, strings);
44
43
 
45
44
  return (
@@ -50,7 +49,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
50
49
  flowResult.steps[index - 2] && <div className="Header__segment"/>
51
50
  }
52
51
  <div className="Header__prev-thumbnail">
53
- <HeaderThumbnail reportResult={Util.prepareReportResult(prevStep.lhr)} position="prev"/>
52
+ <HeaderThumbnail lhr={prevStep.lhr} position="prev"/>
54
53
  <div className="Header__segment"/>
55
54
  </div>
56
55
  <a
@@ -60,7 +59,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
60
59
  </>
61
60
  }
62
61
  <div className="Header__current-thumbnail">
63
- <HeaderThumbnail reportResult={Util.prepareReportResult(step.lhr)} position="main"/>
62
+ <HeaderThumbnail lhr={step.lhr} position="main"/>
64
63
  </div>
65
64
  <div className="Header__current-title">
66
65
  {step.name}
@@ -72,7 +71,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
72
71
  nextStep && <>
73
72
  <div className="Header__next-thumbnail">
74
73
  <div className="Header__segment"/>
75
- <HeaderThumbnail reportResult={Util.prepareReportResult(nextStep.lhr)} position="next"/>
74
+ <HeaderThumbnail lhr={nextStep.lhr} position="next"/>
76
75
  </div>
77
76
  <a
78
77
  className="Header__next-title"
@@ -6,7 +6,7 @@
6
6
 
7
7
  import {FunctionComponent, JSX} from 'preact';
8
8
 
9
- import {useUIStrings} from './i18n/i18n';
9
+ import {useLocalizedStrings} from './i18n/i18n';
10
10
  import {CloseIcon, NavigationIcon, SnapshotIcon, TimespanIcon} from './icons';
11
11
 
12
12
  const HelpDialogColumn: FunctionComponent<{
@@ -18,7 +18,7 @@ const HelpDialogColumn: FunctionComponent<{
18
18
  useCases: string[];
19
19
  availableCategories: string[];
20
20
  }> = (props) => {
21
- const strings = useUIStrings();
21
+ const strings = useLocalizedStrings();
22
22
 
23
23
  return (
24
24
  <div className="HelpDialogColumn">
@@ -56,7 +56,7 @@ const HelpDialogColumn: FunctionComponent<{
56
56
  export const HelpDialog: FunctionComponent<{onClose: () => void}> = ({
57
57
  onClose,
58
58
  }) => {
59
- const strings = useUIStrings();
59
+ const strings = useLocalizedStrings();
60
60
 
61
61
  return (
62
62
  <div className="HelpDialog">
@@ -97,7 +97,6 @@ export const HelpDialog: FunctionComponent<{onClose: () => void}> = ({
97
97
  availableCategories={[
98
98
  strings.categoryPerformance,
99
99
  strings.categoryBestPractices,
100
- strings.categorySeo,
101
100
  ]}
102
101
  />
103
102
  <HelpDialogColumn