pandorga 1.7.0 → 1.7.1
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 +27 -0
- data/DESIGN.md +9 -9
- data/_includes/content-runtime/30-includes.html +1 -1
- data/_includes/content-runtime/43-blocks.html +1 -1
- data/_includes/content-runtime/50-detail.html +5 -5
- data/_includes/content-runtime/60-fragments.html +1 -1
- data/_includes/page/network-graph.html +2 -2
- data/_includes/page/site-footer.html +2 -2
- data/_layouts/articles.html +1 -1
- data/_layouts/projects.html +2 -2
- data/_layouts/resources.html +1 -1
- data/_layouts/shell.html +1 -1
- data/_layouts/text.html +4 -4
- data/_plugins/lib/writing_entry.rb +1 -1
- data/assets/css/article.css +3 -3
- data/assets/css/base.css +0 -79
- data/assets/css/global-link.css +0 -1
- data/assets/css/ledger/chrome.css +1 -1
- data/assets/css/ledger/cv.css +1 -1
- data/assets/css/ledger/detail.css +1 -1
- data/assets/css/ledger/footer.css +1 -1
- data/assets/css/ledger/home.css +13 -42
- data/assets/css/ledger/projects.css +2 -2
- data/assets/css/ledger/sources.css +3 -3
- data/assets/css/ledger/writing.css +1 -1
- data/lib/pandorga/jekyll/plugins/lib/writing_entry.rb +1 -1
- data/lib/pandorga/version.rb +1 -1
- data/scripts/content/export-content-json.rb +1 -1
- data/scripts/test/render-parity/load-runtime.mjs +1 -1
- data/scripts/test/test-css-structure.rb +20 -0
- data/scripts/test/test-discovery.rb +5 -0
- data/scripts/test/test-fonts.rb +14 -0
- data/scripts/test/test-listing-filter-contract.rb +1 -1
- data/scripts/test/test-shell-a11y.rb +21 -0
- 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: aa9e02cc789f512401bb4e9bdbc28c732dff0f3849bbf055d0cd546678cbdd1d
|
|
4
|
+
data.tar.gz: 8a17699ce008fa34e5114f9b4e8e643d0d754f7620ed3b0357aeb2cc9a4c201e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c6e5413b160b64e546f4aa7c80f1e45bb8c5716336593984e4f1f14e642ed444adba3dc5261d08d31257367060dab631777f744f6126c38df1c264e7259d139
|
|
7
|
+
data.tar.gz: 21588e084fe1f417a4f9fa55e532c8ebca01930ea95ad740ecafece15578df4c237461e0213a9328526b982847dcb4bff07d47f1a182a50a36a9fb5348f9cb74
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.7.1] — 2026-10-11
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Decorative Material Symbols beside a label no longer expose the ligature
|
|
8
|
+
(`arrow_left_alt`, `shuffle`, a contact icon, a missing-media mark).
|
|
9
|
+
The public detail path and the private layout agree. Nine spans.
|
|
10
|
+
- The shell published two `og:image` properties. The second meta element
|
|
11
|
+
carried both `name="image"` and `property="og:image"`. `name="image"`
|
|
12
|
+
stays on its own element, so a page has one Open Graph image.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Unused ledger selectors are gone. `assets/css/base.css` drops 2,041
|
|
17
|
+
bytes: `.page-title` (404), `.ledger-marker--primary` (616),
|
|
18
|
+
`.ledger-card--edge-*` (462), and `.ledger-section-rule` (559).
|
|
19
|
+
`assets/css/ledger/home.css` drops 577 bytes of rules that no band
|
|
20
|
+
uses: `.home-band--ruled` (310), `.home-index-shard--gamma` (163),
|
|
21
|
+
and `.home-index-note` (104). `assets/css/global-link.css` drops the
|
|
22
|
+
`.post-content` hover selector (23 bytes). None of them matched a
|
|
23
|
+
template, the runtime, or current content. 2,641 bytes in all.
|
|
24
|
+
- Comments that a font rename had rewritten, eating the letters inside
|
|
25
|
+
the word "behind", read "behind" again. 45 occurrences in 21 files.
|
|
26
|
+
|
|
27
|
+
No `pandorga:` config keys were added or renamed. Font roles and the
|
|
28
|
+
ledger fallbacks are unchanged.
|
|
29
|
+
|
|
3
30
|
## [1.7.0] — 2026-10-10
|
|
4
31
|
|
|
5
32
|
### Added
|
data/DESIGN.md
CHANGED
|
@@ -436,7 +436,7 @@ motion:
|
|
|
436
436
|
mediaFilter: "0.4s ease"
|
|
437
437
|
mediaTransform: ["0.6s ease", "0.7s ease"]
|
|
438
438
|
lightbox: ["160ms ease-out", "180ms ease-out"]
|
|
439
|
-
readingProgress: "scroll(root block) timeline,
|
|
439
|
+
readingProgress: "scroll(root block) timeline, behind @supports"
|
|
440
440
|
reducedMotion: "5 rules — see Motion below"
|
|
441
441
|
---
|
|
442
442
|
|
|
@@ -568,7 +568,7 @@ mix — and on the article detail view.
|
|
|
568
568
|
|
|
569
569
|
`renderPosterMedia` extends the rule to runtime failure: a thumbnail that
|
|
570
570
|
404s removes its own `.ledger-poster` wrapper via an inline `onerror`, so a
|
|
571
|
-
dead third-party image leaves no empty plate
|
|
571
|
+
dead third-party image leaves no empty plate behind.
|
|
572
572
|
|
|
573
573
|
### Where the library is not yet the only source
|
|
574
574
|
|
|
@@ -972,7 +972,7 @@ Letter-spacing in use, by frequency: `0.1em` (12), `0.08em` (10), `0.12em` (7),
|
|
|
972
972
|
table of contents appears in that sidebar only from `1024px`; below it, the
|
|
973
973
|
same list is mounted as a `<details>` disclosure instead. A 2px `primary`
|
|
974
974
|
reading-progress bar is drawn on a pseudo-element of the detail section with
|
|
975
|
-
`animation-timeline: scroll(root block)`,
|
|
975
|
+
`animation-timeline: scroll(root block)`, behind an `@supports` guard, so
|
|
976
976
|
engines without scroll-driven animation simply get no bar.
|
|
977
977
|
* **CV.** A `panelContrast` dossier band with two shards, then five
|
|
978
978
|
`.cv-register` sections and a timeline band. Each register is a 3/9 grid at
|
|
@@ -1035,7 +1035,7 @@ linear` on the reading-progress bar, where the duration is a placeholder that
|
|
|
1035
1035
|
`animation-timeline: scroll(root block)` overrides.
|
|
1036
1036
|
|
|
1037
1037
|
**Scroll-driven animation** is new: the reading-progress bar in
|
|
1038
|
-
`ledger/detail.css` uses `animation-timeline: scroll(root block)`
|
|
1038
|
+
`ledger/detail.css` uses `animation-timeline: scroll(root block)` behind an
|
|
1039
1039
|
`@supports` guard, with a 1ms `linear` animation scaling a fixed 2px `primary`
|
|
1040
1040
|
bar from 0 to 1.
|
|
1041
1041
|
|
|
@@ -1117,7 +1117,7 @@ everything else, so the query catches them too.
|
|
|
1117
1117
|
carries both class names, so any media query that repositions the pair has to
|
|
1118
1118
|
restate the base rule's `auto` offsets on the beta: leave all four set and
|
|
1119
1119
|
the browser resolves to top and left, and the pair collapses into one corner.
|
|
1120
|
-
And a shard
|
|
1120
|
+
And a shard behind an opaque plate is a shard nobody sees, which is why the
|
|
1121
1121
|
home featured pair goes around its poster rather than across the card.
|
|
1122
1122
|
|
|
1123
1123
|
On the writing index the shard was for a long time written to stand down
|
|
@@ -1152,7 +1152,7 @@ everything else, so the query catches them too.
|
|
|
1152
1152
|
`overflow: hidden` and lifts its content clear with `position: relative;
|
|
1153
1153
|
z-index: 1`. The filter decks and `.rascunhos-pagination` are plain
|
|
1154
1154
|
`panelContrast` strips. `.home-hero-plate` and `.home-graph-plate` sit a rung
|
|
1155
|
-
lower, on `surfaceCard`,
|
|
1155
|
+
lower, on `surfaceCard`, behind a `gentleSubtle` hairline.
|
|
1156
1156
|
|
|
1157
1157
|
### Filter deck
|
|
1158
1158
|
|
|
@@ -1311,11 +1311,11 @@ as enforced by [`_plugins/lib/tag_validator.rb`](_plugins/lib/tag_validator.rb):
|
|
|
1311
1311
|
mixes `--color-primary` at 40% into the border — the reference mockup's
|
|
1312
1312
|
"hairline transitions to warm antique brass at 40%", made accent-aware).
|
|
1313
1313
|
One sanctioned exception, added 2026-09: a wide, very low opacity accent
|
|
1314
|
-
pool sits *
|
|
1314
|
+
pool sits *behind* a band. It is a backdrop, not a content effect — no card,
|
|
1315
1315
|
panel or row gains a glow, and the pool is blurred past any visible edge so
|
|
1316
1316
|
it reads as ambient light in the room rather than as a shape. Three of them
|
|
1317
1317
|
ship: the home hero at 7% (`.home-band--hero::before`), the home Sources and
|
|
1318
|
-
Network band at 5% (`.home-band--index::before`), and one
|
|
1318
|
+
Network band at 5% (`.home-band--index::before`), and one behind the Network
|
|
1319
1319
|
of Ideas graph at 7%, whose centre and width are read off the settled D3
|
|
1320
1320
|
layout rather than fixed (`assets/css/ledger/network.css`).
|
|
1321
1321
|
|
|
@@ -1418,7 +1418,7 @@ them.
|
|
|
1418
1418
|
buttons, `shadow-sm`, and a `bg-gradient-to-b from-primary
|
|
1419
1419
|
to-primary-container` fill — three of the system's rules broken on one
|
|
1420
1420
|
page.
|
|
1421
|
-
11. **Navigation is still fully hidden.** A rich, deep site sits
|
|
1421
|
+
11. **Navigation is still fully hidden.** A rich, deep site sits behind one
|
|
1422
1422
|
hamburger at every breakpoint, so its structure is invisible on arrival.
|
|
1423
1423
|
This survived the redesign untouched.
|
|
1424
1424
|
12. **Tailwind runs from the Play CDN in production**
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
function placeholderHtml() {
|
|
197
|
-
return '<div class="w-full h-full flex items-center justify-center opacity-30"><span class="material-symbols-outlined text-5xl">article</span></div>';
|
|
197
|
+
return '<div class="w-full h-full flex items-center justify-center opacity-30"><span class="material-symbols-outlined text-5xl" aria-hidden="true">article</span></div>';
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
function normalizeDataPath(path, fallbackPrefix) {
|
|
@@ -317,7 +317,7 @@
|
|
|
317
317
|
'<img src="', escapeAttr(url), '" alt="', escapeAttr(alt || ''),
|
|
318
318
|
'" loading="lazy" decoding="async"',
|
|
319
319
|
// Thumbnails are frequently hotlinked to third-party hosts. When one
|
|
320
|
-
// dies, remove the frame rather than leaving an empty plate
|
|
320
|
+
// dies, remove the frame rather than leaving an empty plate behind.
|
|
321
321
|
' onerror="var p=this.closest(\'.ledger-poster\'); if (p) p.remove();"',
|
|
322
322
|
'>',
|
|
323
323
|
'</div>'
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/* The page accent, not a fixed triad role: this glyph marks a
|
|
13
13
|
project, and the projects page reads blue. text-secondary pinned
|
|
14
14
|
it green there regardless. */
|
|
15
|
-
parts.push('<span class="material-symbols-outlined text-5xl md:text-6xl text-primary mb-4 block leading-none">' + escapeHtml(fm.icon) + '</span>');
|
|
15
|
+
parts.push('<span class="material-symbols-outlined text-5xl md:text-6xl text-primary mb-4 block leading-none" aria-hidden="true">' + escapeHtml(fm.icon) + '</span>');
|
|
16
16
|
}
|
|
17
17
|
parts.push('<h1 class="text-title">' + escapeHtml(title) + '</h1>');
|
|
18
18
|
if (fm.layout === 'post' && fm.thumbnail) {
|
|
@@ -416,7 +416,7 @@
|
|
|
416
416
|
'<a href="', escapeAttr(options.backUrl || '#'), '" ',
|
|
417
417
|
'class="back-link text-sm font-label inline-flex items-center gap-2 no-underline hover:underline text-primary mb-8 block" ',
|
|
418
418
|
'id="', escapeAttr(options.id || 'runtime-back-link'), '">',
|
|
419
|
-
'<span class="material-symbols-outlined text-sm">arrow_left_alt</span>',
|
|
419
|
+
'<span class="material-symbols-outlined text-sm" aria-hidden="true">arrow_left_alt</span>',
|
|
420
420
|
escapeHtml(label),
|
|
421
421
|
'</a>'
|
|
422
422
|
].join('');
|
|
@@ -429,7 +429,7 @@
|
|
|
429
429
|
if (options.previousUrl) {
|
|
430
430
|
parts.push(
|
|
431
431
|
'<a href="', escapeAttr(options.previousUrl), '">',
|
|
432
|
-
'<span class="material-symbols-outlined text-sm">arrow_left_alt</span>',
|
|
432
|
+
'<span class="material-symbols-outlined text-sm" aria-hidden="true">arrow_left_alt</span>',
|
|
433
433
|
escapeHtml(translate('previous_text', lang)),
|
|
434
434
|
'</a>'
|
|
435
435
|
);
|
|
@@ -441,14 +441,14 @@
|
|
|
441
441
|
parts.push(
|
|
442
442
|
'<a href="', escapeAttr(options.nextUrl), '">',
|
|
443
443
|
escapeHtml(translate('next_text', lang)),
|
|
444
|
-
'<span class="material-symbols-outlined text-sm">arrow_right_alt</span>',
|
|
444
|
+
'<span class="material-symbols-outlined text-sm" aria-hidden="true">arrow_right_alt</span>',
|
|
445
445
|
'</a>'
|
|
446
446
|
);
|
|
447
447
|
} else if (options.showRandom) {
|
|
448
448
|
parts.push(
|
|
449
449
|
'<a href="#" id="random-post-link">',
|
|
450
450
|
escapeHtml(translate('random_text', lang)),
|
|
451
|
-
'<span class="material-symbols-outlined text-sm">shuffle</span>',
|
|
451
|
+
'<span class="material-symbols-outlined text-sm" aria-hidden="true">shuffle</span>',
|
|
452
452
|
'</a>'
|
|
453
453
|
);
|
|
454
454
|
} else {
|
|
@@ -461,7 +461,7 @@
|
|
|
461
461
|
'<a href="', escapeAttr(href), '"', targetRel,
|
|
462
462
|
' class="group flex h-full items-center gap-3 no-underline">',
|
|
463
463
|
'<div class="w-12 h-12 rounded-[9999px] bg-surface-container-highest flex items-center justify-center group-hover:bg-primary-container transition-colors">',
|
|
464
|
-
'<span class="material-symbols-outlined text-on-surface group-hover:text-on-primary-container">',
|
|
464
|
+
'<span class="material-symbols-outlined text-on-surface group-hover:text-on-primary-container" aria-hidden="true">',
|
|
465
465
|
escapeHtml(contact.icon || ''),
|
|
466
466
|
'</span></div><div>',
|
|
467
467
|
'<span class="block marginalia text-tertiary">',
|
|
@@ -723,7 +723,7 @@
|
|
|
723
723
|
settled layout in placePool() below.
|
|
724
724
|
|
|
725
725
|
Drawn inside the SVG because the canvas rectangle above is opaque
|
|
726
|
-
and would cover anything
|
|
726
|
+
and would cover anything behind it, and between that rectangle and
|
|
727
727
|
the zoom group so it stays a backdrop: every edge, mark and label is
|
|
728
728
|
painted over it. It sits in screen space rather than in graph space,
|
|
729
729
|
like the hover card, so the blur is the same 60px at every
|
|
@@ -1182,7 +1182,7 @@
|
|
|
1182
1182
|
}
|
|
1183
1183
|
|
|
1184
1184
|
/* Screen space, like the hover card: the pools track their clusters
|
|
1185
|
-
under panning and scale with the zoom, but the blur
|
|
1185
|
+
under panning and scale with the zoom, but the blur behind them stays
|
|
1186
1186
|
the same 60px at every magnification instead of dissolving as the
|
|
1187
1187
|
reader pulls back. */
|
|
1188
1188
|
function placePool() {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
Five of the six mockups draw the same footer: a wide masthead, a colophon
|
|
6
6
|
with a typeset line, an index of external repositories, and a mono imprint
|
|
7
7
|
carrying coordinates and an edition number. Almost none of that has a field
|
|
8
|
-
|
|
8
|
+
behind it. What is left after the hard rule is three blocks over one
|
|
9
9
|
imprint, and every one of them reads a value that already exists:
|
|
10
10
|
|
|
11
11
|
Masthead site.author + the home hero catch phrase
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
Imprint site.author + site.content_license
|
|
15
15
|
|
|
16
16
|
A colophon block naming the four type roles was added and then removed at
|
|
17
|
-
the owner's request: the faces did have a field
|
|
17
|
+
the owner's request: the faces did have a field behind them, but the line
|
|
18
18
|
was not wanted in the footer. The mockup's edition number, paper stock and
|
|
19
19
|
press note have no field at all and were never drawn.
|
|
20
20
|
|
data/_layouts/articles.html
CHANGED
|
@@ -327,7 +327,7 @@ layout: shell
|
|
|
327
327
|
/* Lead panel. Binds title, date, revision, tags, description and the
|
|
328
328
|
* thumbnail — the same strip as the rows below it, language pill included
|
|
329
329
|
* in the omission. The mockup's topology figure, its DOI/arXiv line and its
|
|
330
|
-
* "Critical Notes" list have no field
|
|
330
|
+
* "Critical Notes" list have no field behind them, so none is rendered.
|
|
331
331
|
*
|
|
332
332
|
* The panel reads down the left and stops on the action: kicker, ledger
|
|
333
333
|
* line, title, summary, tags, then "Read article" — with the plate holding
|
data/_layouts/projects.html
CHANGED
|
@@ -102,7 +102,7 @@ layout: shell
|
|
|
102
102
|
|
|
103
103
|
/* ── Field readers ──────────────────────────────────────────────────
|
|
104
104
|
Each returns '' when its field is unset, so an absent field drops the
|
|
105
|
-
element rather than leaving a placeholder
|
|
105
|
+
element rather than leaving a placeholder behind. */
|
|
106
106
|
|
|
107
107
|
function projectName(item) {
|
|
108
108
|
var fm = item.front_matter || {};
|
|
@@ -297,7 +297,7 @@ layout: shell
|
|
|
297
297
|
|
|
298
298
|
/* Closing ledger. One row per repository that front matter actually
|
|
299
299
|
names — five of seven today. The mockup's licence stamp, spec download
|
|
300
|
-
and commit hashes have nothing
|
|
300
|
+
and commit hashes have nothing behind them and are not drawn. */
|
|
301
301
|
function renderRepositories(items) {
|
|
302
302
|
var rows = items.filter(function (item) {
|
|
303
303
|
return (item.front_matter || {}).github;
|
data/_layouts/resources.html
CHANGED
|
@@ -173,7 +173,7 @@ layout: shell
|
|
|
173
173
|
|
|
174
174
|
/* The four facets a source is filed under: what it is, how it is
|
|
175
175
|
classified, what language it speaks, and where it speaks from. Each
|
|
176
|
-
renders only when the field
|
|
176
|
+
renders only when the field behind it is populated, so a source missing
|
|
177
177
|
a category shows three chips and no gap where the fourth would be. */
|
|
178
178
|
function renderFacets(fm, medium) {
|
|
179
179
|
var chips = [
|
data/_layouts/shell.html
CHANGED
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
{% assign og_image_type = "image/png" %}
|
|
48
48
|
{% endif %}
|
|
49
49
|
<meta property="og:image" content="{{ og_image_url }}" />
|
|
50
|
-
<meta name="image"
|
|
50
|
+
<meta name="image" content="{{ og_image_url }}" />
|
|
51
51
|
<meta property="og:image:width" content="1200" />
|
|
52
52
|
<meta property="og:image:height" content="630" />
|
|
53
53
|
<meta property="og:image:type" content="{{ og_image_type }}" />
|
data/_layouts/text.html
CHANGED
|
@@ -69,7 +69,7 @@ layout: shell
|
|
|
69
69
|
{% if page.collection == "posts" or page.collection == "articles" or page.layout == "product" or page.layout == "project" %}
|
|
70
70
|
<div class="article-sidebar-heading mb-8">
|
|
71
71
|
{% if page.icon %}
|
|
72
|
-
<span class="material-symbols-outlined text-5xl md:text-6xl text-secondary mb-4 block leading-none">{{ page.icon }}</span>
|
|
72
|
+
<span class="material-symbols-outlined text-5xl md:text-6xl text-secondary mb-4 block leading-none" aria-hidden="true">{{ page.icon }}</span>
|
|
73
73
|
{% endif %}
|
|
74
74
|
<h1 class="text-title">{{ page.title }}</h1>
|
|
75
75
|
{% if page.collection == "posts" and page.thumbnail %}
|
|
@@ -202,7 +202,7 @@ layout: shell
|
|
|
202
202
|
<nav class="text-page-nav text-reading-column w-full" aria-label="Article navigation">
|
|
203
203
|
{% if page.previous %}
|
|
204
204
|
<a href="{{ page.previous.url }}">
|
|
205
|
-
<span class="material-symbols-outlined text-sm">arrow_left_alt</span>
|
|
205
|
+
<span class="material-symbols-outlined text-sm" aria-hidden="true">arrow_left_alt</span>
|
|
206
206
|
{{ t.previous_text[lang] }}
|
|
207
207
|
</a>
|
|
208
208
|
{% else %}
|
|
@@ -211,12 +211,12 @@ layout: shell
|
|
|
211
211
|
{% if page.next %}
|
|
212
212
|
<a href="{{ page.next.url }}">
|
|
213
213
|
{{ t.next_text[lang] }}
|
|
214
|
-
<span class="material-symbols-outlined text-sm">arrow_right_alt</span>
|
|
214
|
+
<span class="material-symbols-outlined text-sm" aria-hidden="true">arrow_right_alt</span>
|
|
215
215
|
</a>
|
|
216
216
|
{% elsif page.collection == "posts" %}
|
|
217
217
|
<a href="#" id="random-post-link">
|
|
218
218
|
{{ t.random_text[lang] }}
|
|
219
|
-
<span class="material-symbols-outlined text-sm">shuffle</span>
|
|
219
|
+
<span class="material-symbols-outlined text-sm" aria-hidden="true">shuffle</span>
|
|
220
220
|
</a>
|
|
221
221
|
{% else %}
|
|
222
222
|
<span></span>
|
|
@@ -15,7 +15,7 @@ require_relative "text_excerpt"
|
|
|
15
15
|
# (standalone, for scripts/content/export-content-json.rb). They differ only in how
|
|
16
16
|
# they derive the repo-relative path used for Git chronology, so each passes
|
|
17
17
|
# its own. Everything downstream lives here, because a field added or a bug
|
|
18
|
-
# fixed in one copy used to leave the other silently
|
|
18
|
+
# fixed in one copy used to leave the other silently behind.
|
|
19
19
|
module WritingEntry
|
|
20
20
|
XCITE_RE = /\{%-?\s*include\s+xcite\.html\s+key=["']([^"']+)["'][^%]*-?%\}/
|
|
21
21
|
|
data/assets/css/article.css
CHANGED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
justify-content: center;
|
|
187
187
|
box-sizing: border-box;
|
|
188
188
|
padding: 0.35rem 0.55rem;
|
|
189
|
-
/* A fixed dark plate
|
|
189
|
+
/* A fixed dark plate behind light-on-transparent marks. It must stay dark in
|
|
190
190
|
both themes, so no surface token fits: every one of them flips. */
|
|
191
191
|
background: #111;
|
|
192
192
|
}
|
|
@@ -349,7 +349,7 @@
|
|
|
349
349
|
|
|
350
350
|
The projects page had this to itself until now; these rules are the ones it
|
|
351
351
|
proved, moved up so the treatment is the site's rather than one page's. What
|
|
352
|
-
stayed
|
|
352
|
+
stayed behind in ledger/projects.css is the *other* thing that page does —
|
|
353
353
|
letting media out of the reading measure — which is a separate decision.
|
|
354
354
|
|
|
355
355
|
`.plotly-figure` and the videos both carry the `figure` element, so one
|
|
@@ -436,7 +436,7 @@ body.figure-lightbox-open {
|
|
|
436
436
|
.figure-lightbox-backdrop {
|
|
437
437
|
position: absolute;
|
|
438
438
|
inset: 0;
|
|
439
|
-
/* Near-opaque black so the article
|
|
439
|
+
/* Near-opaque black so the article behind never reads as “another page”. */
|
|
440
440
|
background: rgba(0, 0, 0, 0.85);
|
|
441
441
|
cursor: zoom-out;
|
|
442
442
|
animation: figure-lightbox-fade-in var(--motion-duration-fast) var(--motion-ease-out);
|
data/assets/css/base.css
CHANGED
|
@@ -208,24 +208,6 @@ html body {
|
|
|
208
208
|
letter-spacing: 0.05em;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
/* ── Display title scale (home hero, 404) ── */
|
|
212
|
-
.page-title {
|
|
213
|
-
font-family: var(--font-title);
|
|
214
|
-
font-size: var(--type-display);
|
|
215
|
-
font-weight: var(--weight-display);
|
|
216
|
-
line-height: 1.05;
|
|
217
|
-
color: var(--color-on-surface);
|
|
218
|
-
letter-spacing: normal;
|
|
219
|
-
font-synthesis: none;
|
|
220
|
-
font-optical-sizing: auto;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
@media (min-width: 768px) {
|
|
224
|
-
.page-title {
|
|
225
|
-
font-size: var(--type-display-lg);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
211
|
/* Listing page headers (CV, Articles, Portfolio, Rascunhos, …) */
|
|
230
212
|
.page-header-title {
|
|
231
213
|
font-family: var(--font-title);
|
|
@@ -345,22 +327,6 @@ html body {
|
|
|
345
327
|
color-mix(in srgb, var(--color-tertiary) 2%, transparent) 98%);
|
|
346
328
|
}
|
|
347
329
|
|
|
348
|
-
.ledger-marker--primary {
|
|
349
|
-
background: linear-gradient(104deg,
|
|
350
|
-
transparent 0.9%,
|
|
351
|
-
color-mix(in srgb, var(--color-primary) 16%, transparent) 2.4%,
|
|
352
|
-
color-mix(in srgb, var(--color-primary) 12%, transparent) 58%,
|
|
353
|
-
color-mix(in srgb, var(--color-primary) 4%, transparent) 98%);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
[data-theme="dark"] .ledger-marker--primary {
|
|
357
|
-
background: linear-gradient(104deg,
|
|
358
|
-
transparent 0.9%,
|
|
359
|
-
color-mix(in srgb, var(--color-primary) 9%, transparent) 2.4%,
|
|
360
|
-
color-mix(in srgb, var(--color-primary) 6%, transparent) 58%,
|
|
361
|
-
color-mix(in srgb, var(--color-primary) 2%, transparent) 98%);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
330
|
/* ── Page-level accent ────────────────────────────────────────────────
|
|
365
331
|
The shared triad (theme/theme-vars-block.liquid) declares one primary per
|
|
366
332
|
theme, but each section of the site reads in its own hue: Projects and
|
|
@@ -1175,25 +1141,6 @@ html[data-theme="light"] .ledger-system-card {
|
|
|
1175
1141
|
border-color: var(--border-ink);
|
|
1176
1142
|
}
|
|
1177
1143
|
|
|
1178
|
-
/* Triad top hairline — reusable edge accent (home grids + any listing). */
|
|
1179
|
-
.ledger-card--edge-primary {
|
|
1180
|
-
border-top-width: 2px;
|
|
1181
|
-
border-top-style: solid;
|
|
1182
|
-
border-top-color: var(--color-primary);
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
.ledger-card--edge-secondary {
|
|
1186
|
-
border-top-width: 2px;
|
|
1187
|
-
border-top-style: solid;
|
|
1188
|
-
border-top-color: var(--color-secondary);
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
.ledger-card--edge-tertiary {
|
|
1192
|
-
border-top-width: 2px;
|
|
1193
|
-
border-top-style: solid;
|
|
1194
|
-
border-top-color: var(--color-tertiary);
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
1144
|
/* Drafting corner brackets — four L-corners, no labels. Pure decoration.
|
|
1198
1145
|
Outline ink (not primary): the corners are drafting marks on the plate,
|
|
1199
1146
|
same register as `.ledger-frame-crosshairs`, not a brand accent. */
|
|
@@ -1234,32 +1181,6 @@ html[data-theme="light"] .ledger-system-card {
|
|
|
1234
1181
|
linear-gradient(var(--color-outline), var(--color-outline)) bottom right / var(--cross-thick) var(--cross-arm) no-repeat;
|
|
1235
1182
|
}
|
|
1236
1183
|
|
|
1237
|
-
/* Lithography section divider — double hairline with a short primary tick. */
|
|
1238
|
-
.ledger-section-rule {
|
|
1239
|
-
display: block;
|
|
1240
|
-
height: 0;
|
|
1241
|
-
margin: 0 0 var(--space-xl);
|
|
1242
|
-
border: 0;
|
|
1243
|
-
border-top: 1px solid var(--border-gentle-divider);
|
|
1244
|
-
box-shadow: 0 3px 0 -2px var(--border-gentle-faint);
|
|
1245
|
-
position: relative;
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
.ledger-section-rule::after {
|
|
1249
|
-
content: "";
|
|
1250
|
-
position: absolute;
|
|
1251
|
-
left: 0;
|
|
1252
|
-
top: -1.5px;
|
|
1253
|
-
width: 2.5rem;
|
|
1254
|
-
height: 2px;
|
|
1255
|
-
background: var(--color-primary);
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
.ledger-section-rule--dashed {
|
|
1259
|
-
border-top-style: dashed;
|
|
1260
|
-
box-shadow: none;
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
1184
|
/* Hover lifts the card one rung and warms its hairline toward the page's
|
|
1264
1185
|
accent. The reference mockup states this as "the line transitions to
|
|
1265
1186
|
subtle charcoal slate or warm antique brass at 40% opacity" — the accent
|
data/assets/css/global-link.css
CHANGED
|
@@ -22,7 +22,6 @@ a {
|
|
|
22
22
|
* titles, plus the chip exceptions that were being added one class at a time
|
|
23
23
|
* as each new piece of card chrome turned up underlined. */
|
|
24
24
|
p a:hover,
|
|
25
|
-
.post-content a:hover,
|
|
26
25
|
.article-content a:hover,
|
|
27
26
|
.description a:hover {
|
|
28
27
|
color: var(--color-link-hover);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
belong in assets/css/base.css under "Architectural Ledger blocks".
|
|
3
3
|
|
|
4
4
|
The mockups put the sections in a flat, always-visible rail rather than
|
|
5
|
-
|
|
5
|
+
behind a button. The links still come from _data/nav.yml, so the site keeps
|
|
6
6
|
one source of navigation; only the presentation changes. The Explore menu
|
|
7
7
|
stays for narrow viewports, where six links do not fit. */
|
|
8
8
|
|
data/assets/css/ledger/cv.css
CHANGED
|
@@ -347,7 +347,7 @@ html[data-theme="light"] .cv-product {
|
|
|
347
347
|
|
|
348
348
|
/* A place is prose, not notation, so it reads in the body face rather than
|
|
349
349
|
mono — and on the same left edge as every other line of the card. The pin
|
|
350
|
-
icon and the indent it sat
|
|
350
|
+
icon and the indent it sat behind said nothing the word "France" does not
|
|
351
351
|
already say, and cost the entry its one straight margin. */
|
|
352
352
|
.cv-entry-place {
|
|
353
353
|
color: var(--color-on-surface-variant);
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
to beat one are written with two compound parts on purpose. */
|
|
15
15
|
|
|
16
16
|
/* ══ Reading progress ══
|
|
17
|
-
Pure UI state, no field
|
|
17
|
+
Pure UI state, no field behind it, and no DOM hook to hang it on — the
|
|
18
18
|
runtime owns the detail markup. A scroll-driven animation on a pseudo of
|
|
19
19
|
the detail section gives the mockup's indicator with zero markup, and the
|
|
20
20
|
@supports guard means older engines simply get no bar.
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
/* A middot between items rather than a separator element, so an absent
|
|
233
|
-
license leaves no orphaned punctuation
|
|
233
|
+
license leaves no orphaned punctuation behind. */
|
|
234
234
|
.site-footer-imprint-item+.site-footer-imprint-item::before {
|
|
235
235
|
content: "·";
|
|
236
236
|
margin-right: var(--space-md);
|
data/assets/css/ledger/home.css
CHANGED
|
@@ -49,18 +49,6 @@
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/* Structural edge: the short rule the mockup runs along the top-left of the
|
|
53
|
-
featured band, marking it as the page's first statement after the hero. */
|
|
54
|
-
.home-band--ruled::before {
|
|
55
|
-
content: "";
|
|
56
|
-
position: absolute;
|
|
57
|
-
top: 0;
|
|
58
|
-
left: 0;
|
|
59
|
-
width: 6rem;
|
|
60
|
-
height: 3px;
|
|
61
|
-
background: var(--color-primary);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
52
|
/* ── Hero ── */
|
|
65
53
|
/* The band was 3rem above the name and 4.5rem below, which read as the block
|
|
66
54
|
sitting low in its own space. Equal above and below, at 60% of the larger
|
|
@@ -117,7 +105,7 @@
|
|
|
117
105
|
}
|
|
118
106
|
}
|
|
119
107
|
|
|
120
|
-
/* Ambient pool
|
|
108
|
+
/* Ambient pool behind the hero.
|
|
121
109
|
*
|
|
122
110
|
* Same weight as the earlier primary-container bloom, but keyed to neutral
|
|
123
111
|
* ink/outline so it stays grey paper depth instead of a blue spotlight. */
|
|
@@ -418,7 +406,7 @@ html[data-theme="light"] .home-hero-plate {
|
|
|
418
406
|
box-shadow: none;
|
|
419
407
|
}
|
|
420
408
|
|
|
421
|
-
/* Silk facet
|
|
409
|
+
/* Silk facet behind the portrait — restored; the Borders pass had hidden it. */
|
|
422
410
|
.home-hero-shard {
|
|
423
411
|
top: -2.25rem;
|
|
424
412
|
right: -2rem;
|
|
@@ -576,8 +564,7 @@ html[data-theme="light"] .home-hero-plate {
|
|
|
576
564
|
was the piece the band leads with, and a reader scanning down met four
|
|
577
565
|
equal entries. It now takes the card rung of the surface ladder, is fenced
|
|
578
566
|
by the same hairline every other panel on the site carries, and opens on a
|
|
579
|
-
rule in the primary
|
|
580
|
-
`.home-band--ruled` — so the eye stops at the top of it. The image inside is
|
|
567
|
+
rule in the primary, so the eye stops at the top of it. The image inside is
|
|
581
568
|
inset by the panel's own padding rather than running to the band edge, which
|
|
582
569
|
is the other half of the promotion: the lead contains its picture, the cards
|
|
583
570
|
below are contained by theirs.
|
|
@@ -646,7 +633,7 @@ html[data-theme="light"] .home-hero-plate {
|
|
|
646
633
|
cubist half of the identity.
|
|
647
634
|
|
|
648
635
|
The pair is placed around the poster rather than across the card, because
|
|
649
|
-
the poster is opaque and a shard
|
|
636
|
+
the poster is opaque and a shard behind it is a shard nobody sees. The
|
|
650
637
|
alpha takes the top-left, over the index column, where there is nothing but
|
|
651
638
|
chrome and air. The beta takes the bottom-right and comes out from *under*
|
|
652
639
|
the poster into the strip below it, which is the same move the index band
|
|
@@ -1050,8 +1037,8 @@ html[data-theme="light"] .home-hero-plate {
|
|
|
1050
1037
|
box-sizing: border-box;
|
|
1051
1038
|
}
|
|
1052
1039
|
|
|
1053
|
-
/*
|
|
1054
|
-
|
|
1040
|
+
/* A primary top rule, at a weight that beats the light-paper hairline
|
|
1041
|
+
reset on `.ledger-system-card`. */
|
|
1055
1042
|
:root .home-projects-bench .home-project-specimen,
|
|
1056
1043
|
:root .home-projects-bench .home-project-specimen:hover {
|
|
1057
1044
|
border-top: 2px solid var(--color-primary);
|
|
@@ -1568,11 +1555,11 @@ button.home-project-inventory-row {
|
|
|
1568
1555
|
The figure is hidden until the markup lands, so a plate that never arrives
|
|
1569
1556
|
leaves the panel with its title and its link rather than an empty frame. */
|
|
1570
1557
|
|
|
1571
|
-
/* Ambient pool
|
|
1558
|
+
/* Ambient pool behind the pair. Dark palette only, for the reason set out
|
|
1572
1559
|
above the hero's.
|
|
1573
1560
|
*
|
|
1574
|
-
* The two panels sat side by side with a visible seam and nothing
|
|
1575
|
-
* them. One pool centred on that seam,
|
|
1561
|
+
* The two panels sat side by side with a visible seam and nothing behind
|
|
1562
|
+
* them. One pool centred on that seam, behind both, lights the pair as a
|
|
1576
1563
|
* single object rather than giving each panel an opening of its own. Held at
|
|
1577
1564
|
* 5% against the hero's 7%: at equal strength the page reads as having two
|
|
1578
1565
|
* openings, and only one of them is where it starts.
|
|
@@ -1580,7 +1567,7 @@ button.home-project-inventory-row {
|
|
|
1580
1567
|
* Centred is right here and nowhere else — the seam is the thing being lit,
|
|
1581
1568
|
* so the offset is vertical instead, which is what keeps the pool partly
|
|
1582
1569
|
* outside the band it backs. `.home-band` already carries `position:
|
|
1583
|
-
* relative`; `isolation: isolate` is what stops `z-index: -1` escaping
|
|
1570
|
+
* relative`; `isolation: isolate` is what stops `z-index: -1` escaping behind
|
|
1584
1571
|
* the page background. */
|
|
1585
1572
|
.home-band--index {
|
|
1586
1573
|
isolation: isolate;
|
|
@@ -1642,7 +1629,7 @@ button.home-project-inventory-row {
|
|
|
1642
1629
|
the set, rotating hue the way every other shard on the site does.
|
|
1643
1630
|
*
|
|
1644
1631
|
* They sit in the foot of the panel, under the title and the link: the plate
|
|
1645
|
-
* above carries an opaque background, so a shard
|
|
1632
|
+
* above carries an opaque background, so a shard behind it would be a shard
|
|
1646
1633
|
* nobody sees. `overflow: hidden` on the panel above keeps the negative
|
|
1647
1634
|
* offsets out of the document scroll width, and the shared utility already
|
|
1648
1635
|
* unmounts both below 640px. */
|
|
@@ -1663,21 +1650,12 @@ button.home-project-inventory-row {
|
|
|
1663
1650
|
background: var(--color-primary);
|
|
1664
1651
|
}
|
|
1665
1652
|
|
|
1666
|
-
.home-index-shard--gamma {
|
|
1667
|
-
right: -3rem;
|
|
1668
|
-
bottom: -3.5rem;
|
|
1669
|
-
width: 11rem;
|
|
1670
|
-
height: 11rem;
|
|
1671
|
-
background: var(--color-tertiary);
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
1653
|
/* Between the shard cut-off and the layout each panel is the full
|
|
1675
1654
|
band wide on small screens, so a shard sized for half of it stops being a corner accent. */
|
|
1676
1655
|
@media (max-width: 899px) {
|
|
1677
1656
|
|
|
1678
1657
|
.home-index-shard,
|
|
1679
|
-
.home-index-shard--beta
|
|
1680
|
-
.home-index-shard--gamma {
|
|
1658
|
+
.home-index-shard--beta {
|
|
1681
1659
|
width: 8rem;
|
|
1682
1660
|
height: 8rem;
|
|
1683
1661
|
bottom: -2.5rem;
|
|
@@ -1688,7 +1666,7 @@ button.home-project-inventory-row {
|
|
|
1688
1666
|
padding-top: var(--space-xl);
|
|
1689
1667
|
}
|
|
1690
1668
|
|
|
1691
|
-
/* The title and the link have to sit clear of the shard
|
|
1669
|
+
/* The title and the link have to sit clear of the shard behind them. The
|
|
1692
1670
|
plate is excluded because it is the one child that must stay full-bleed,
|
|
1693
1671
|
and the shard because it is the thing being sat clear of. */
|
|
1694
1672
|
.home-index-panel> :not(.home-index-plate):not(.shard-accent) {
|
|
@@ -1697,13 +1675,6 @@ button.home-project-inventory-row {
|
|
|
1697
1675
|
margin-inline: var(--space-lg);
|
|
1698
1676
|
}
|
|
1699
1677
|
|
|
1700
|
-
.home-index-note {
|
|
1701
|
-
margin: 0;
|
|
1702
|
-
font-size: var(--type-body);
|
|
1703
|
-
line-height: 1.5;
|
|
1704
|
-
flex: 1 1 auto;
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
1678
|
.home-index-title {
|
|
1708
1679
|
margin: 0;
|
|
1709
1680
|
font-size: var(--type-card);
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
position: relative;
|
|
184
184
|
display: block;
|
|
185
185
|
text-decoration: none;
|
|
186
|
-
/* Empty blueprint as texture
|
|
186
|
+
/* Empty blueprint as texture behind the plate — not a second view mode. */
|
|
187
187
|
background-color: var(--color-panel-contrast);
|
|
188
188
|
background-image:
|
|
189
189
|
linear-gradient(color-mix(in srgb, var(--color-outline) 10%, transparent) 1px, transparent 1px),
|
|
@@ -350,7 +350,7 @@
|
|
|
350
350
|
|
|
351
351
|
/* ══ Repositories ══
|
|
352
352
|
The mockup closed on a source-code ledger. Its licence stamp, spec
|
|
353
|
-
download and commit hashes have nothing
|
|
353
|
+
download and commit hashes have nothing behind them; the repository rows
|
|
354
354
|
do — `github` is set on five of the seven projects. */
|
|
355
355
|
.projects-page .projects-repos {
|
|
356
356
|
margin-top: var(--space-3xl);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
/* ── Shards ──
|
|
11
11
|
The page had no depth treatment of any kind, and it is the wrong shape for
|
|
12
|
-
the ambient pool the home bands carry: a pool
|
|
12
|
+
the ambient pool the home bands carry: a pool behind a grid of many small
|
|
13
13
|
cards only darkens one corner of it. Shards instead, the two canonical
|
|
14
14
|
polygons from base.css, one at each end of the run — top right above the
|
|
15
15
|
grid, bottom left below it, the diagonal pair the CV dossier uses inside
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/* A card is not positioned, so without this the shard — which is — would be
|
|
59
|
-
painted over the bottom row rather than
|
|
59
|
+
painted over the bottom row rather than behind it. The rule the whole
|
|
60
60
|
family answers to is that a backdrop never touches the object in front of
|
|
61
61
|
it. */
|
|
62
62
|
.sources-body>.listing-card-grid,
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
z-index: 1;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
/* The foot of the page, beside the pagination. It reaches up
|
|
68
|
+
/* The foot of the page, beside the pagination. It reaches up behind the last
|
|
69
69
|
row of cards. In dark those cards are opaque again, so what shows is the
|
|
70
70
|
wedge in the gutter and the band across the pagination strip. */
|
|
71
71
|
.sources-foot-shard {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
The alpha sits bottom left, under the foot of the copy, the one corner the
|
|
71
71
|
plate never reaches at any width. The beta is a true corner accent at the
|
|
72
72
|
top right: it is offset far enough up that its visible part is the triangle
|
|
73
|
-
above the plate's top edge, and it tucks
|
|
73
|
+
above the plate's top edge, and it tucks behind the plate as it descends
|
|
74
74
|
rather than fighting it. Neither corner repeats the home panel's pair, and
|
|
75
75
|
the hues are the only two this page has — `.page-accent--green` rebinds
|
|
76
76
|
primary onto secondary, so green and ochre is the whole palette here. */
|
|
@@ -15,7 +15,7 @@ require_relative "text_excerpt"
|
|
|
15
15
|
# (standalone, for scripts/content/export-content-json.rb). They differ only in how
|
|
16
16
|
# they derive the repo-relative path used for Git chronology, so each passes
|
|
17
17
|
# its own. Everything downstream lives here, because a field added or a bug
|
|
18
|
-
# fixed in one copy used to leave the other silently
|
|
18
|
+
# fixed in one copy used to leave the other silently behind.
|
|
19
19
|
module WritingEntry
|
|
20
20
|
XCITE_RE = /\{%-?\s*include\s+xcite\.html\s+key=["']([^"']+)["'][^%]*-?%\}/
|
|
21
21
|
|
data/lib/pandorga/version.rb
CHANGED
|
@@ -269,7 +269,7 @@ def prune_stale_output_files!
|
|
|
269
269
|
end
|
|
270
270
|
|
|
271
271
|
stale.each(&:delete)
|
|
272
|
-
# Remove empty directories left
|
|
272
|
+
# Remove empty directories left behind by unpublish/rename.
|
|
273
273
|
OUTPUT_ROOT.find.sort.reverse_each do |path|
|
|
274
274
|
next unless path.directory?
|
|
275
275
|
next if path == OUTPUT_ROOT
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// and a Jekyll build never executes them, which is how a block that renders
|
|
6
6
|
// an element with no backing field ships green. This loader concatenates the
|
|
7
7
|
// partials in the exact order _includes/page/content-runtime.html includes
|
|
8
|
-
// them, evaluates the result
|
|
8
|
+
// them, evaluates the result behind a deliberately thin DOM shim, and hands
|
|
9
9
|
// back the same object 90-bootstrap.html returns to the browser.
|
|
10
10
|
//
|
|
11
11
|
// The shim is small on purpose: createElement, className, setAttribute,
|
|
@@ -72,6 +72,26 @@ sheets.each do |path|
|
|
|
72
72
|
if source.include?("home-profile-summary")
|
|
73
73
|
errors << "#{relative}: .home-profile-summary is unused"
|
|
74
74
|
end
|
|
75
|
+
|
|
76
|
+
# Selectors that matched no template, runtime string, or current content.
|
|
77
|
+
# A comment may still name one; a ruleset may not.
|
|
78
|
+
retired = %w[
|
|
79
|
+
page-title
|
|
80
|
+
ledger-marker--primary
|
|
81
|
+
ledger-card--edge-primary
|
|
82
|
+
ledger-card--edge-secondary
|
|
83
|
+
ledger-card--edge-tertiary
|
|
84
|
+
ledger-section-rule
|
|
85
|
+
home-band--ruled
|
|
86
|
+
home-index-shard--gamma
|
|
87
|
+
home-index-note
|
|
88
|
+
post-content
|
|
89
|
+
]
|
|
90
|
+
retired.each do |name|
|
|
91
|
+
next unless cleaned.match?(/[.#]#{Regexp.escape(name)}\b/)
|
|
92
|
+
|
|
93
|
+
errors << "#{relative}: .#{name} is unused"
|
|
94
|
+
end
|
|
75
95
|
end
|
|
76
96
|
|
|
77
97
|
fail!("CSS structure problems:\n - #{errors.join("\n - ")}") unless errors.empty?
|
|
@@ -41,6 +41,11 @@ fail!("portrait srcset is not read") unless runtime.include?("record.srcset = sr
|
|
|
41
41
|
fail!("portrait sources are not applied") unless runtime.include?("applyHeroPortraitSources")
|
|
42
42
|
shell = ROOT.join("_layouts/shell.html").read
|
|
43
43
|
fail!("shell missing JSON-LD") unless shell.include?("theme/json-ld.html")
|
|
44
|
+
og_images = shell.scan(/property="og:image"/)
|
|
45
|
+
fail!("shell emits #{og_images.size} og:image properties; one page, one image") unless og_images.size == 1
|
|
46
|
+
image_meta = shell[/<meta name="image"[^>]*>/]
|
|
47
|
+
fail!("shell missing name=image") unless image_meta
|
|
48
|
+
fail!("name=image also sets property=og:image") if image_meta.include?("property=")
|
|
44
49
|
fail!("discovery generator is not loaded from the plugin dir") unless ROOT.join("lib/pandorga/jekyll/plugins/discovery.rb").file?
|
|
45
50
|
|
|
46
51
|
puts "PASS test-discovery"
|
data/scripts/test/test-fonts.rb
CHANGED
|
@@ -47,6 +47,20 @@ fail!("body weights were not sorted") unless custom_href.include?("family=Source
|
|
|
47
47
|
fail!("mono italic axis is wrong") unless custom_href.include?("family=IBM+Plex+Mono:ital,wght@0,400;0,500;1,400;1,500")
|
|
48
48
|
fail!("unset label left Marcellus") unless custom_href.include?("family=Marcellus+SC:wght@400;700")
|
|
49
49
|
fail!("body change left the tagline on Newsreader") unless Pandorga::Fonts.css_stack(custom, "subtitle").start_with?("'Source Serif 4'")
|
|
50
|
+
|
|
51
|
+
# A font rename once replaced the letters "hind" inside the word "behind".
|
|
52
|
+
token = "be" + "Newsreader"
|
|
53
|
+
broken = []
|
|
54
|
+
Dir.glob(ROOT.join("**/*.{css,html,rb,js,mjs,md,liquid,yml}")).each do |path|
|
|
55
|
+
next if path.include?("/studio/assets/")
|
|
56
|
+
next if path.include?("/node_modules/")
|
|
57
|
+
next if path.end_with?("test-fonts.rb")
|
|
58
|
+
text = File.read(path)
|
|
59
|
+
next unless text.include?(token)
|
|
60
|
+
|
|
61
|
+
broken << Pathname.new(path).relative_path_from(ROOT).to_s
|
|
62
|
+
end
|
|
63
|
+
fail!("corrupted 'behind' left by a font rename (#{broken.size} files): #{broken.join(', ')}") unless broken.empty?
|
|
50
64
|
fail!("code face did not follow mono") unless Pandorga::Fonts.css_stack(custom, "code").start_with?("'IBM Plex Mono'")
|
|
51
65
|
|
|
52
66
|
kept = Pandorga::Fonts.resolve({ "title" => "Cinzel Decorative" }, theme)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# on click; `filterItems` reads a fixed set of names. Nothing connects the
|
|
8
8
|
# two, so renaming a facet in a layout — `category` to `tag`, say — leaves the
|
|
9
9
|
# chips rendering, highlighting and pushing a query string while the list
|
|
10
|
-
#
|
|
10
|
+
# behind them never changes. That shipped on the Sources page: every click set
|
|
11
11
|
# a key nothing read.
|
|
12
12
|
#
|
|
13
13
|
# There is no build error and no console error to notice, so the contract is
|
|
@@ -27,4 +27,25 @@ fail!("footer home link still uses site.author alone") if FOOTER.include?(bare)
|
|
|
27
27
|
fail!("shell home link needs an identity.name fallback") unless SHELL.include?("site.pandorga.identity.name")
|
|
28
28
|
fail!("footer home link needs an identity.name fallback") unless FOOTER.include?("site.pandorga.identity.name")
|
|
29
29
|
|
|
30
|
+
# Decorative Material Symbols sit beside a text label. Without aria-hidden
|
|
31
|
+
# the ligature ("arrow_left_alt", "shuffle", an icon name) is read aloud.
|
|
32
|
+
ICON_FILES = [
|
|
33
|
+
ROOT.join("_layouts/text.html"),
|
|
34
|
+
ROOT.join("_includes/content-runtime/50-detail.html"),
|
|
35
|
+
ROOT.join("_includes/content-runtime/60-fragments.html"),
|
|
36
|
+
ROOT.join("_includes/content-runtime/30-includes.html")
|
|
37
|
+
].freeze
|
|
38
|
+
|
|
39
|
+
ICON_FILES.each do |path|
|
|
40
|
+
path.read.each_line.with_index(1) do |line, number|
|
|
41
|
+
next unless line.include?("material-symbols-outlined")
|
|
42
|
+
next if line.include?("querySelector")
|
|
43
|
+
next if line.include?("aria-hidden")
|
|
44
|
+
# Class token handed to a later span that already sets aria-hidden.
|
|
45
|
+
next if line.include?("cls:")
|
|
46
|
+
|
|
47
|
+
fail!("#{path.relative_path_from(ROOT)}:#{number}: decorative icon is exposed")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
30
51
|
puts "PASS test-shell-a11y"
|