pandorga 1.6.5 → 1.6.7
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/README.md +3 -2
- data/_includes/content-runtime/00-config.html +1 -1
- data/_includes/home/band-listing.html +1 -1
- data/_includes/theme/font-loader.html +9 -2
- data/_layouts/shell.html +87 -12
- data/examples/full/content/pages/cv/summary.md +1 -1
- data/lib/pandorga/version.rb +1 -1
- data/scripts/lighthouse-home.sh +26 -5
- data/scripts/test/test-lighthouse-policy.rb +30 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28483b04968177f92f86ee26292b1bca873db8515dcb0d1735b72be27a564fb8
|
|
4
|
+
data.tar.gz: d2d20eb68479f49655c122a3948398e8e2719a27be458e27bc6f60aa002729da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 89dd79f11d075413daac4ebcda740dc4f36a426a8b11aa608570551a446c79b09fc2223a74d703a36c2cae2fdaf0a14f41b6e3cf0048261c336a3a2a082e0100
|
|
7
|
+
data.tar.gz: efeaa1c9b49c5884e19b0e778e1a7205eec1dd000dc3c8875fa62747cf3a5df813202310f2cd2092d4d71847d629e6e8d1fedbf63e6bff8c99245f568f1a73f2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.7] — 2026-10-10
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Text faces are requested after the first paint and before the load
|
|
8
|
+
event. A blocking sheet held first paint on the font host. The load
|
|
9
|
+
event held the hero summary until images finished, so the live home
|
|
10
|
+
scored about 50 while the example, which has no summary, scored 98.
|
|
11
|
+
- The icon face names the icons it needs. The full variable file is about
|
|
12
|
+
a megabyte, and decoding it blocked the main thread on the live home.
|
|
13
|
+
- The project inventory region has a role to match its accessible name.
|
|
14
|
+
- Lighthouse measures `examples/full`, whose home includes a static hero
|
|
15
|
+
summary, the element a real site paints largest.
|
|
16
|
+
|
|
17
|
+
No `pandorga:` config keys were added or renamed.
|
|
18
|
+
|
|
19
|
+
## [1.6.6] — 2026-10-10
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- The text faces and the flag stylesheet are requested after the load
|
|
24
|
+
event. A head link let a fast connection finish them before the largest
|
|
25
|
+
paint, and the simulator then counted those files as part of that paint.
|
|
26
|
+
The same templates scored 87 on the release run and 97 on the pull
|
|
27
|
+
request. `font-display: swap` stays.
|
|
28
|
+
- The markdown library loads with `defer`. The example home is already
|
|
29
|
+
HTML, so that script does not block the parser.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- A release below 90 does not publish. A bug-fix release whose notes
|
|
34
|
+
include `LIGHTHOUSE_BUGFIX=1` may still publish from 75 to 89.
|
|
35
|
+
|
|
36
|
+
No `pandorga:` config keys were added or renamed.
|
|
37
|
+
|
|
3
38
|
## [1.6.5] — 2026-10-10
|
|
4
39
|
|
|
5
40
|
### Fixed
|
data/README.md
CHANGED
|
@@ -84,8 +84,9 @@ Lighthouse mobile thresholds apply to releases. A stable release scores
|
|
|
84
84
|
and an urgent performance campaign must then bring it back to 90 or above.
|
|
85
85
|
Below 75 is never acceptable for a release. A pull request or a merge may
|
|
86
86
|
score lower when that is unavoidable to keep the work modular. The release
|
|
87
|
-
build
|
|
88
|
-
|
|
87
|
+
build publishes at 90 or above. Notes that include `LIGHTHOUSE_BUGFIX=1`
|
|
88
|
+
may publish a bug fix from 75 to 89. Pull requests and merges only warn.
|
|
89
|
+
The checklist is in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
89
90
|
|
|
90
91
|
## License
|
|
91
92
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script src="https://cdn.jsdelivr.net/npm/marked@15.0.7/marked.min.js"></script>
|
|
1
|
+
<script defer src="https://cdn.jsdelivr.net/npm/marked@15.0.7/marked.min.js"></script>
|
|
2
2
|
<script>
|
|
3
3
|
window.ContentRuntimeConfig = {
|
|
4
4
|
contentBase: '{{ site.content_api_base_url | default: "" }}',
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
data-tag-base="{{ _path }}"
|
|
55
55
|
>
|
|
56
56
|
<div class="home-project-specimen-slot" data-home-specimen></div>
|
|
57
|
-
<div class="home-project-inventory" data-home-inventory aria-label="Project inventory"></div>
|
|
57
|
+
<div class="home-project-inventory" data-home-inventory role="region" aria-label="Project inventory"></div>
|
|
58
58
|
</div>
|
|
59
59
|
{%- else -%}
|
|
60
60
|
<div
|
|
@@ -51,6 +51,13 @@
|
|
|
51
51
|
{% endunless %}
|
|
52
52
|
{% endif %}
|
|
53
53
|
{% assign fonts_href = fonts_href | append: "&display=swap" %}
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
{% comment %}
|
|
55
|
+
Not a render-blocking head link, and not the load event. A blocking
|
|
56
|
+
sheet holds first paint on the font host. The load event holds the hero
|
|
57
|
+
summary until images finish. The shell inserts this sheet after the
|
|
58
|
+
first paint. display=swap stays.
|
|
59
|
+
{% endcomment %}
|
|
60
|
+
<script>
|
|
61
|
+
window.__pandorgaFontsHref = {{ fonts_href | jsonify }};
|
|
62
|
+
</script>
|
|
56
63
|
<noscript><link rel="stylesheet" href="{{ fonts_href }}" /></noscript>
|
data/_layouts/shell.html
CHANGED
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
<!-- Canonical URL -->
|
|
60
60
|
<link rel="canonical" href="{{ canonical_path | absolute_url }}" />
|
|
61
61
|
{%- comment -%}
|
|
62
|
-
Preconnect only.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
Preconnect only. The preload script below is parser-blocking. A
|
|
63
|
+
stylesheet before that script holds the parser until the font host
|
|
64
|
+
answers, so the ledger sheets and the hero cannot paint. The text-face
|
|
65
|
+
loader sits with the local sheets.
|
|
66
66
|
{%- endcomment -%}
|
|
67
67
|
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
68
68
|
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
|
|
@@ -117,22 +117,75 @@
|
|
|
117
117
|
{%- endfor -%}
|
|
118
118
|
{% include theme/font-loader.html %}
|
|
119
119
|
{%- comment -%}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
Named icons only. The full variable face is about a megabyte, and a
|
|
121
|
+
late request for it becomes the largest paint on a real hero. Nav icons
|
|
122
|
+
from the registry join the shell set.
|
|
123
123
|
{%- endcomment -%}
|
|
124
|
-
{%- assign
|
|
124
|
+
{%- assign _icon_names = "arrow_left_alt,arrow_right_alt,architecture,article,chat,chevron_left,chevron_right,close,code,dark_mode,expand_more,filter_list,format_quote,format_size,info,light_mode,menu,picture_as_pdf,public,routine,search,share,shuffle,sync" -%}
|
|
125
|
+
{%- for _group in site.data.nav -%}
|
|
126
|
+
{%- for _item in _group.pages -%}
|
|
127
|
+
{%- if _item.icon -%}
|
|
128
|
+
{%- assign _icon_hay = "," | append: _icon_names | append: "," -%}
|
|
129
|
+
{%- assign _icon_needle = "," | append: _item.icon | append: "," -%}
|
|
130
|
+
{%- unless _icon_hay contains _icon_needle -%}
|
|
131
|
+
{%- assign _icon_names = _icon_names | append: "," | append: _item.icon -%}
|
|
132
|
+
{%- endunless -%}
|
|
133
|
+
{%- endif -%}
|
|
134
|
+
{%- endfor -%}
|
|
135
|
+
{%- endfor -%}
|
|
136
|
+
{%- assign _symbols_href = "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&icon_names=" | append: _icon_names | append: "&display=swap" -%}
|
|
137
|
+
<script>
|
|
138
|
+
window.__pandorgaIconsHref = {{ _symbols_href | jsonify }};
|
|
139
|
+
</script>
|
|
140
|
+
<noscript><link id="pandorga-icons" rel="stylesheet" href="{{ _symbols_href }}" /></noscript>
|
|
141
|
+
<script>
|
|
142
|
+
(function () {
|
|
143
|
+
var known = {{ _icon_names | split: "," | jsonify }};
|
|
144
|
+
var seen = {};
|
|
145
|
+
known.forEach(function (name) { seen[name] = true; });
|
|
146
|
+
var dirty = false;
|
|
147
|
+
var timer = 0;
|
|
148
|
+
window.__pandorgaFlushIcons = function () {
|
|
149
|
+
var link = document.getElementById('pandorga-icons');
|
|
150
|
+
if (!link || !dirty) return;
|
|
151
|
+
dirty = false;
|
|
152
|
+
link.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&icon_names=' + known.join(',') + '&display=swap';
|
|
153
|
+
};
|
|
154
|
+
function consider(root) {
|
|
155
|
+
if (!root || !root.querySelectorAll) return;
|
|
156
|
+
var nodes = root.querySelectorAll('.material-symbols-outlined');
|
|
157
|
+
var extra = false;
|
|
158
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
159
|
+
var name = (nodes[i].textContent || '').trim();
|
|
160
|
+
if (!name || seen[name] || !/^[a-z0-9_]+$/.test(name)) continue;
|
|
161
|
+
seen[name] = true;
|
|
162
|
+
known.push(name);
|
|
163
|
+
extra = true;
|
|
164
|
+
}
|
|
165
|
+
if (!extra) return;
|
|
166
|
+
dirty = true;
|
|
167
|
+
clearTimeout(timer);
|
|
168
|
+
timer = setTimeout(window.__pandorgaFlushIcons, 50);
|
|
169
|
+
}
|
|
170
|
+
function start() {
|
|
171
|
+
consider(document);
|
|
172
|
+
var obs = new MutationObserver(function () { consider(document); });
|
|
173
|
+
obs.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
174
|
+
}
|
|
175
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
|
|
176
|
+
else start();
|
|
177
|
+
})();
|
|
178
|
+
</script>
|
|
179
|
+
{%- assign _flags_href = "https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css" -%}
|
|
125
180
|
<script>
|
|
126
181
|
window.addEventListener('load', function () {
|
|
127
182
|
var link = document.createElement('link');
|
|
128
183
|
link.rel = 'stylesheet';
|
|
129
|
-
link.href = {{
|
|
184
|
+
link.href = {{ _flags_href | jsonify }};
|
|
130
185
|
document.head.appendChild(link);
|
|
131
186
|
});
|
|
132
187
|
</script>
|
|
133
|
-
<noscript><link rel="stylesheet" href="{{
|
|
134
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css" media="print" onload="this.media='all'" />
|
|
135
|
-
<noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css" /></noscript>
|
|
188
|
+
<noscript><link rel="stylesheet" href="{{ _flags_href }}" /></noscript>
|
|
136
189
|
<style>
|
|
137
190
|
:root { --drop-cap-lines: {{ site.drop_cap_lines | default: 2 }}; }
|
|
138
191
|
</style>
|
|
@@ -257,6 +310,28 @@
|
|
|
257
310
|
{% include page/site-footer.html nav_active=nav_active %}
|
|
258
311
|
|
|
259
312
|
{% include page/content-runtime.html %}
|
|
313
|
+
<script>
|
|
314
|
+
(function () {
|
|
315
|
+
var fonts = window.__pandorgaFontsHref;
|
|
316
|
+
var icons = window.__pandorgaIconsHref;
|
|
317
|
+
if (!fonts && !icons) return;
|
|
318
|
+
requestAnimationFrame(function () {
|
|
319
|
+
requestAnimationFrame(function () {
|
|
320
|
+
function sheet(href, id) {
|
|
321
|
+
if (!href) return;
|
|
322
|
+
var link = document.createElement('link');
|
|
323
|
+
link.rel = 'stylesheet';
|
|
324
|
+
link.href = href;
|
|
325
|
+
if (id) link.id = id;
|
|
326
|
+
document.head.appendChild(link);
|
|
327
|
+
}
|
|
328
|
+
sheet(fonts);
|
|
329
|
+
sheet(icons, 'pandorga-icons');
|
|
330
|
+
if (window.__pandorgaFlushIcons) window.__pandorgaFlushIcons();
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
})();
|
|
334
|
+
</script>
|
|
260
335
|
|
|
261
336
|
</body>
|
|
262
337
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Ada Example designs publishing frames. This summary is fictional.
|
|
1
|
+
Ada Example designs publishing frames. This summary is fictional. The home hero includes it as HTML, so the largest paint is this paragraph, the same element a real site measures.
|
data/lib/pandorga/version.rb
CHANGED
data/scripts/lighthouse-home.sh
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# One Lighthouse mobile run against the built example home.
|
|
3
|
-
# Thresholds apply to releases. LIGHTHOUSE_MODE=enforce
|
|
4
|
-
#
|
|
3
|
+
# Thresholds apply to releases. LIGHTHOUSE_MODE=enforce does not publish
|
|
4
|
+
# below 90 unless LIGHTHOUSE_BUGFIX=1, and that bug-fix release still
|
|
5
|
+
# fails below 75. LIGHTHOUSE_MODE=warn never fails the run. PLT-AC-24.
|
|
5
6
|
set -euo pipefail
|
|
6
7
|
|
|
7
8
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
|
-
SITE="${ROOT}/examples/
|
|
9
|
+
SITE="${ROOT}/examples/full/_site"
|
|
9
10
|
PORT="${LIGHTHOUSE_PORT:-4173}"
|
|
10
11
|
OUT="${LIGHTHOUSE_REPORT:-/tmp/lighthouse-home.json}"
|
|
11
12
|
FAIL_BELOW=75
|
|
12
13
|
WARN_BELOW=90
|
|
13
14
|
MODE="${LIGHTHOUSE_MODE:-enforce}"
|
|
15
|
+
BUGFIX="${LIGHTHOUSE_BUGFIX:-}"
|
|
14
16
|
|
|
15
17
|
fail() {
|
|
16
18
|
echo "ERROR: $1" >&2
|
|
@@ -24,6 +26,8 @@ if [[ "${MODE}" != "enforce" && "${MODE}" != "warn" ]]; then
|
|
|
24
26
|
fi
|
|
25
27
|
|
|
26
28
|
[[ -f "${SITE}/index.html" ]] || fail "missing ${SITE}/index.html (run scripts/validate.sh first)"
|
|
29
|
+
grep -q 'id="home-cv-summary"[^>]*data-content-static' "${SITE}/index.html" \
|
|
30
|
+
|| fail "example home has no static hero summary (data-content-static)"
|
|
27
31
|
|
|
28
32
|
if [[ -n "${CHROME_PATH:-}" && -x "${CHROME_PATH}" ]]; then
|
|
29
33
|
CHROME="${CHROME_PATH}"
|
|
@@ -65,11 +69,11 @@ npx --yes lighthouse@13.5.0 "http://127.0.0.1:${PORT}/" \
|
|
|
65
69
|
--chrome-path="${CHROME}" \
|
|
66
70
|
--chrome-flags="--headless=new --no-sandbox --disable-gpu"
|
|
67
71
|
|
|
68
|
-
python3 - "${OUT}" "${FAIL_BELOW}" "${WARN_BELOW}" "${MODE}" <<'PY'
|
|
72
|
+
python3 - "${OUT}" "${FAIL_BELOW}" "${WARN_BELOW}" "${MODE}" "${BUGFIX}" <<'PY'
|
|
69
73
|
import json
|
|
70
74
|
import sys
|
|
71
75
|
|
|
72
|
-
path, fail_below, warn_below, mode = sys.argv[1:]
|
|
76
|
+
path, fail_below, warn_below, mode, bugfix = sys.argv[1:]
|
|
73
77
|
fail_below = int(fail_below)
|
|
74
78
|
warn_below = int(warn_below)
|
|
75
79
|
report = json.load(open(path, encoding="utf-8"))
|
|
@@ -79,6 +83,16 @@ if raw is None:
|
|
|
79
83
|
sys.exit(1)
|
|
80
84
|
score = int(round(float(raw) * 100))
|
|
81
85
|
print(f"Lighthouse mobile performance: {score} ({mode})")
|
|
86
|
+
audits = report.get("audits", {})
|
|
87
|
+
for key in (
|
|
88
|
+
"first-contentful-paint",
|
|
89
|
+
"largest-contentful-paint",
|
|
90
|
+
"speed-index",
|
|
91
|
+
"total-blocking-time",
|
|
92
|
+
"cumulative-layout-shift",
|
|
93
|
+
):
|
|
94
|
+
display = audits.get(key, {}).get("displayValue", "?")
|
|
95
|
+
print(f" {key}: {display}")
|
|
82
96
|
campaign = (
|
|
83
97
|
"A score from 75 to 89 is acceptable only to ship a bug fix. "
|
|
84
98
|
"An urgent performance campaign must bring it back to 90 or above."
|
|
@@ -86,6 +100,13 @@ campaign = (
|
|
|
86
100
|
if score < fail_below and mode == "enforce":
|
|
87
101
|
print(f"::error::Lighthouse mobile performance {score} is below {fail_below}")
|
|
88
102
|
sys.exit(1)
|
|
103
|
+
if mode == "enforce" and score < warn_below and bugfix != "1":
|
|
104
|
+
print(
|
|
105
|
+
f"::error::Lighthouse mobile performance {score} is below {warn_below}. "
|
|
106
|
+
+ campaign
|
|
107
|
+
+ " This release is not marked LIGHTHOUSE_BUGFIX=1, so it will not publish."
|
|
108
|
+
)
|
|
109
|
+
sys.exit(1)
|
|
89
110
|
if score < fail_below:
|
|
90
111
|
print(
|
|
91
112
|
f"::warning::Lighthouse mobile performance {score} is below {fail_below}. "
|
|
@@ -49,6 +49,11 @@ fail!("lighthouse script lost the fail floor") unless script.include?("FAIL_BELO
|
|
|
49
49
|
fail!("lighthouse script lost the warn floor") unless script.include?("WARN_BELOW=90")
|
|
50
50
|
fail!("lighthouse script lost enforce mode") unless script.include?('LIGHTHOUSE_MODE:-enforce')
|
|
51
51
|
fail!("warn mode still fails the run") unless script.include?('mode == "enforce"')
|
|
52
|
+
fail!("a non-bug-fix release can publish below 90") unless script.include?('bugfix != "1"')
|
|
53
|
+
fail!("release workflow cannot mark a bug fix") unless release.include?("LIGHTHOUSE_BUGFIX")
|
|
54
|
+
fail!("spec still publishes a feature below 90") unless spec.include?("LIGHTHOUSE_BUGFIX=1")
|
|
55
|
+
fail!("contributing still publishes a feature below 90") unless contributing.include?("LIGHTHOUSE_BUGFIX=1")
|
|
56
|
+
fail!("readme still publishes a feature below 90") unless docs.fetch("readme").include?("LIGHTHOUSE_BUGFIX=1")
|
|
52
57
|
fail!("lighthouse script is not a single mobile run") unless script.include?("--form-factor=mobile")
|
|
53
58
|
fail!("lighthouse script repeats runs") if script.include?("--repeat")
|
|
54
59
|
fail!("example server is still one-thread HTTP/1.0") if script.include?("python3 -m http.server")
|
|
@@ -59,8 +64,30 @@ fail!("icon face is preloaded") if shell.include?("rel=\"preload\" as=\"style\"
|
|
|
59
64
|
|
|
60
65
|
screen = shell.sub(%r{<noscript>.*?</noscript>}m, "")
|
|
61
66
|
fail!("Material Symbols sheet is missing") unless shell.include?("Material+Symbols+Outlined")
|
|
62
|
-
fail!("
|
|
63
|
-
fail!("
|
|
67
|
+
fail!("screen still has a flag stylesheet link") if screen.match?(/<link\b[^>]*flag-icons/)
|
|
68
|
+
fail!("flag sheet is not deferred until load") unless screen.include?("flag-icons@7.2.3")
|
|
69
|
+
fail!("icon face is the full variable font") if shell.include?("0..1&display=swap")
|
|
70
|
+
fail!("icon face is not a named subset") unless shell.include?("icon_names=")
|
|
71
|
+
fail!("icon subset link has no id") unless screen.include?("pandorga-icons")
|
|
72
|
+
|
|
73
|
+
fonts = ROOT.join("_includes/theme/font-loader.html").read
|
|
74
|
+
fail!("text faces are preloaded") if fonts.include?('rel="preload"')
|
|
75
|
+
fail!("text face still waits for the load event") if fonts.include?("addEventListener('load'")
|
|
76
|
+
fail!("text face href is not handed to the shell") unless fonts.include?("__pandorgaFontsHref")
|
|
77
|
+
fail!("text face is not requested after first paint") unless screen.scan("requestAnimationFrame").length >= 2
|
|
78
|
+
|
|
79
|
+
marked = ROOT.join("_includes/content-runtime/00-config.html").read
|
|
80
|
+
fail!("markdown library still blocks parsing") unless marked.include?("<script defer ")
|
|
81
|
+
fail!("markdown library source changed") unless marked.include?("marked@15.0.7/marked.min.js")
|
|
82
|
+
|
|
83
|
+
fail!("spec still withholds the text face until load") unless spec.include?("after the first paint and before the load event")
|
|
84
|
+
fail!("lighthouse example is not the full site") unless script.include?("examples/full")
|
|
85
|
+
fail!("lighthouse example can ship without a static summary") unless script.include?("data-content-static")
|
|
86
|
+
summary = ROOT.join("examples/full/content/pages/cv/summary.md").read
|
|
87
|
+
fail!("full summary dropped the fixture sentence") unless summary.include?("Ada Example designs publishing frames")
|
|
88
|
+
fail!("full summary is too short to be the hero paint") unless summary.scan(".").length >= 3
|
|
89
|
+
fail!("spec still lets the markdown library block parsing") unless spec.include?("markdown library loads with `defer`")
|
|
90
|
+
fail!("lighthouse script hides the metric breakdown") unless script.include?("largest-contentful-paint")
|
|
64
91
|
|
|
65
92
|
icon = base[/\.material-symbols-outlined\.material-symbols-outlined \{.*?\n\}/m]
|
|
66
93
|
fail!("icon rule missing") unless icon
|
|
@@ -71,6 +98,7 @@ fail!("content runtime still precedes the page") unless shell.index("{{ content
|
|
|
71
98
|
band = File.read(File.expand_path("../../_includes/home/band-listing.html", __dir__))
|
|
72
99
|
fail!("band title is still painted by script") unless band.include?('data-content-section-title>{{ _title }}')
|
|
73
100
|
fail!("band note is still painted by script") unless band.include?("page_headers")
|
|
101
|
+
fail!("project inventory has a name and no role") unless band.include?('role="region"') && band.include?('aria-label="Project inventory"')
|
|
74
102
|
headers = File.read(File.expand_path("../../_plugins/content_headers.rb", __dir__))
|
|
75
103
|
fail!("page headers are not loaded at build time") unless headers.include?('site.data["page_headers"]')
|
|
76
104
|
home = File.read(File.expand_path("../../_layouts/home.html", __dir__))
|