pandorga 1.6.6 → 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 +16 -0
- data/_includes/home/band-listing.html +1 -1
- data/_includes/theme/font-loader.html +5 -9
- data/_layouts/shell.html +79 -12
- data/examples/full/content/pages/cv/summary.md +1 -1
- data/lib/pandorga/version.rb +1 -1
- data/scripts/lighthouse-home.sh +3 -1
- data/scripts/test/test-lighthouse-policy.rb +13 -6
- 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,21 @@
|
|
|
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
|
+
|
|
3
19
|
## [1.6.6] — 2026-10-10
|
|
4
20
|
|
|
5
21
|
### Fixed
|
|
@@ -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
|
|
@@ -52,16 +52,12 @@
|
|
|
52
52
|
{% endif %}
|
|
53
53
|
{% assign fonts_href = fonts_href | append: "&display=swap" %}
|
|
54
54
|
{% comment %}
|
|
55
|
-
Not a head link
|
|
56
|
-
|
|
57
|
-
|
|
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.
|
|
58
59
|
{% endcomment %}
|
|
59
60
|
<script>
|
|
60
|
-
window.
|
|
61
|
-
var link = document.createElement('link');
|
|
62
|
-
link.rel = 'stylesheet';
|
|
63
|
-
link.href = {{ fonts_href | jsonify }};
|
|
64
|
-
document.head.appendChild(link);
|
|
65
|
-
});
|
|
61
|
+
window.__pandorgaFontsHref = {{ fonts_href | jsonify }};
|
|
66
62
|
</script>
|
|
67
63
|
<noscript><link rel="stylesheet" href="{{ fonts_href }}" /></noscript>
|
data/_layouts/shell.html
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
Preconnect only. The preload script below is parser-blocking. A
|
|
63
63
|
stylesheet before that script holds the parser until the font host
|
|
64
64
|
answers, so the ledger sheets and the hero cannot paint. The text-face
|
|
65
|
-
loader sits with the local sheets
|
|
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,20 +117,65 @@
|
|
|
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" -%}
|
|
125
137
|
<script>
|
|
126
|
-
window.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
+
})();
|
|
132
178
|
</script>
|
|
133
|
-
<noscript><link rel="stylesheet" href="{{ _symbols_href }}" /></noscript>
|
|
134
179
|
{%- assign _flags_href = "https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css" -%}
|
|
135
180
|
<script>
|
|
136
181
|
window.addEventListener('load', function () {
|
|
@@ -265,6 +310,28 @@
|
|
|
265
310
|
{% include page/site-footer.html nav_active=nav_active %}
|
|
266
311
|
|
|
267
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>
|
|
268
335
|
|
|
269
336
|
</body>
|
|
270
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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
|
|
8
8
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
9
|
-
SITE="${ROOT}/examples/
|
|
9
|
+
SITE="${ROOT}/examples/full/_site"
|
|
10
10
|
PORT="${LIGHTHOUSE_PORT:-4173}"
|
|
11
11
|
OUT="${LIGHTHOUSE_REPORT:-/tmp/lighthouse-home.json}"
|
|
12
12
|
FAIL_BELOW=75
|
|
@@ -26,6 +26,8 @@ if [[ "${MODE}" != "enforce" && "${MODE}" != "warn" ]]; then
|
|
|
26
26
|
fi
|
|
27
27
|
|
|
28
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)"
|
|
29
31
|
|
|
30
32
|
if [[ -n "${CHROME_PATH:-}" && -x "${CHROME_PATH}" ]]; then
|
|
31
33
|
CHROME="${CHROME_PATH}"
|
|
@@ -64,22 +64,28 @@ fail!("icon face is preloaded") if shell.include?("rel=\"preload\" as=\"style\"
|
|
|
64
64
|
|
|
65
65
|
screen = shell.sub(%r{<noscript>.*?</noscript>}m, "")
|
|
66
66
|
fail!("Material Symbols sheet is missing") unless shell.include?("Material+Symbols+Outlined")
|
|
67
|
-
fail!("icon sheet is not deferred until load") unless screen.include?("addEventListener('load'")
|
|
68
|
-
fail!("screen still has a Material Symbols stylesheet link") if screen.match?(/<link\b[^>]*Material\+Symbols/)
|
|
69
67
|
fail!("screen still has a flag stylesheet link") if screen.match?(/<link\b[^>]*flag-icons/)
|
|
70
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")
|
|
71
72
|
|
|
72
73
|
fonts = ROOT.join("_includes/theme/font-loader.html").read
|
|
73
|
-
font_screen = fonts.sub(%r{<noscript>.*?</noscript>}m, "")
|
|
74
74
|
fail!("text faces are preloaded") if fonts.include?('rel="preload"')
|
|
75
|
-
fail!("text face
|
|
76
|
-
fail!("
|
|
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
|
|
77
78
|
|
|
78
79
|
marked = ROOT.join("_includes/content-runtime/00-config.html").read
|
|
79
80
|
fail!("markdown library still blocks parsing") unless marked.include?("<script defer ")
|
|
80
81
|
fail!("markdown library source changed") unless marked.include?("marked@15.0.7/marked.min.js")
|
|
81
82
|
|
|
82
|
-
fail!("spec still
|
|
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
|
|
83
89
|
fail!("spec still lets the markdown library block parsing") unless spec.include?("markdown library loads with `defer`")
|
|
84
90
|
fail!("lighthouse script hides the metric breakdown") unless script.include?("largest-contentful-paint")
|
|
85
91
|
|
|
@@ -92,6 +98,7 @@ fail!("content runtime still precedes the page") unless shell.index("{{ content
|
|
|
92
98
|
band = File.read(File.expand_path("../../_includes/home/band-listing.html", __dir__))
|
|
93
99
|
fail!("band title is still painted by script") unless band.include?('data-content-section-title>{{ _title }}')
|
|
94
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"')
|
|
95
102
|
headers = File.read(File.expand_path("../../_plugins/content_headers.rb", __dir__))
|
|
96
103
|
fail!("page headers are not loaded at build time") unless headers.include?('site.data["page_headers"]')
|
|
97
104
|
home = File.read(File.expand_path("../../_layouts/home.html", __dir__))
|