jekyll-theme-zer0 1.16.0 → 1.17.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/README.md +4 -4
- data/_data/backlog.yml +77 -9
- data/_includes/components/theme-preview-gallery.html +2 -2
- data/_includes/core/branding.html +4 -3
- data/_includes/navigation/admin-nav.html +1 -1
- data/_includes/navigation/navbar.html +14 -14
- data/_sass/core/_docs-layout.scss +11 -0
- data/_sass/core/code-copy.scss +2 -2
- data/assets/js/code-copy.js +11 -0
- data/scripts/bin/validate +17 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 50907837fd27d28fa1bea1cf163d7e2d71a4a848266c861656b8d8ebdb2e3d78
|
|
4
|
+
data.tar.gz: e3853573f9cca38ec51ce145a8279aedf221035afac88cf9cfc77d220dee23e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b1dcd28c12fd2c48e14463bf4e7db63ed3c024262ca3bc04ba98a9ce8b3b53affef695846681fee898584184a58790a86361e00940d89a0ecbe76e0dddb54496
|
|
7
|
+
data.tar.gz: e28d9a6a97edefc45d7b772e363a1826b3a96e00de15e58e90be84cae1c7fa2ad23a24198769ea4f13cdbeac138cbf4f02fd75356d8066e8cb5c69ae9b40558a
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.17.1] - 2026-06-13
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Version bump: patch release
|
|
12
|
+
|
|
13
|
+
### Commits in this release
|
|
14
|
+
- f2657b68 fix(a11y): resolve all navbar & site WCAG 2.1 AA violations (T-007) (#149)
|
|
15
|
+
- 30d836cb fix(admin): sync config-page copy with live _config.yml and redact the Raw tab (T-018) (#148)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Navbar & site accessibility (T-007)**: resolved all WCAG 2.1 AA violations that kept three axe-core audits frozen — dropped the redundant ARIA `menubar`/`menuitem` roles from the nav (the nav landmark already provides semantics; menubars require menuitem children the search/settings buttons weren't), added an `aria-label` to the site-subtitle home link, kept the admin/footer separator a list item, gave the theme-preview disabled tab a `role="tab"` and an icon-only button an `aria-label`, made code blocks a single keyboard-focusable scroll region, and underlined prose links so they're distinguishable without color. The three `test.fixme` blocks in `test/visual/accessibility.spec.js` are now live `test()` calls — verified 0 violations across the homepage, FAQ, and all 8 admin pages (23/23 a11y, 223/223 smoke tier)
|
|
19
|
+
|
|
20
|
+
## [1.17.0] - 2026-06-12
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Version bump: minor release
|
|
24
|
+
|
|
25
|
+
### Commits in this release
|
|
26
|
+
- ac36e1a3 feat(tests): plugin unit specs and coverage baseline — T-011, T-005 (#145)
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- **Admin config page sync (T-018)**: the page's config copy is now byte-synced with the live `_config.yml` (raw-wrapped so Liquid-looking comment text renders literally) and `validate` fails on drift; the **visible Raw-YAML tab** now applies the same sensitive-line redaction as the hidden copy element (it previously showed the raw file — the stale copy was the only thing keeping the live PostHog key off that tab); the raw-tab security test targets the real `code#cfg-raw-yaml` element and asserts presence instead of silently skipping
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- **Plugin unit specs (T-011)**: 19 Minitest specs for the previously-untested `preview_image_generator.rb`, `content_statistics_generator.rb`, and `admin_page_urls.rb` plugins (config merge, path normalization, index dedupe by relative path, hook output, edge cases); wired into the core suite as "Plugin Unit Specs"
|
|
33
|
+
- **Coverage baseline (T-005)**: structural survey recorded at `docs/development/coverage-baseline.md` — 10/10 suites green; the two remaining zero-coverage subsystems filed as T-019 (migrate.sh + theme_version.rb) and T-020 (installer wizard/upgrade)
|
|
34
|
+
|
|
8
35
|
## [1.16.0] - 2026-06-12
|
|
9
36
|
|
|
10
37
|
### Changed
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: zer0-mistakes
|
|
3
3
|
sub-title: AI-Native Jekyll Theme
|
|
4
4
|
description: AI-native Jekyll theme for GitHub Pages — Docker-first development, AI-powered installation, multi-agent integration (Copilot, Codex, Cursor, Claude), AI preview-image generation, and AIEO content optimization with Bootstrap 5.3.
|
|
5
|
-
version: 1.
|
|
5
|
+
version: 1.17.1
|
|
6
6
|
layout: landing
|
|
7
7
|
tags:
|
|
8
8
|
- jekyll
|
|
@@ -20,7 +20,7 @@ categories:
|
|
|
20
20
|
- bootstrap
|
|
21
21
|
- ai-tooling
|
|
22
22
|
created: 2024-02-10T23:51:11.480Z
|
|
23
|
-
lastmod: 2026-06-
|
|
23
|
+
lastmod: 2026-06-13T04:17:52.000Z
|
|
24
24
|
draft: false
|
|
25
25
|
permalink: /
|
|
26
26
|
slug: zer0
|
|
@@ -911,7 +911,7 @@ git push origin feature/awesome-feature
|
|
|
911
911
|
|
|
912
912
|
| Metric | Value |
|
|
913
913
|
|--------|-------|
|
|
914
|
-
| **Current Version** | 1.
|
|
914
|
+
| **Current Version** | 1.17.1 ([RubyGems](https://rubygems.org/gems/jekyll-theme-zer0), [CHANGELOG](/CHANGELOG)) |
|
|
915
915
|
| **Documented Features** | 43 ([Feature Registry](https://github.com/bamr87/zer0-mistakes/blob/main/_data/features.yml)) |
|
|
916
916
|
| **Setup Time** | 2-5 minutes ([install.sh benchmarks](https://github.com/bamr87/zer0-mistakes/blob/main/install.sh)) |
|
|
917
917
|
| **Documentation Pages** | 70+ ([browse docs](https://zer0-mistakes.com/pages/)) |
|
|
@@ -966,6 +966,6 @@ And these AI partners that make zer0-mistakes truly AI-native:
|
|
|
966
966
|
|
|
967
967
|
**Built with ❤️ — and a little help from our AI partners — for the Jekyll community**
|
|
968
968
|
|
|
969
|
-
**v1.
|
|
969
|
+
**v1.17.1** • [Changelog](CHANGELOG.md) • [License](LICENSE) • [Contributing](CONTRIBUTING.md) • [AI Agent Guide](AGENTS.md)
|
|
970
970
|
|
|
971
971
|
|
data/_data/backlog.yml
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
meta:
|
|
57
57
|
title: "zer0-mistakes Backlog"
|
|
58
58
|
updated: 2026-06-12
|
|
59
|
-
next_id:
|
|
59
|
+
next_id: 21
|
|
60
60
|
|
|
61
61
|
tasks:
|
|
62
62
|
# --- Housekeeping (seeded so the loop has work on day one) ------------------
|
|
@@ -155,7 +155,7 @@ tasks:
|
|
|
155
155
|
|
|
156
156
|
- id: T-005
|
|
157
157
|
title: "Coverage baseline: identify the lowest-covered subsystems toward the 90% goal"
|
|
158
|
-
status:
|
|
158
|
+
status: done
|
|
159
159
|
priority: P1
|
|
160
160
|
area: tests
|
|
161
161
|
risk: standard
|
|
@@ -166,19 +166,23 @@ tasks:
|
|
|
166
166
|
Zer0-Mistake Quality Framework starts with knowing where coverage stands.
|
|
167
167
|
Produce a coverage baseline and file follow-up tasks for the lowest-covered
|
|
168
168
|
areas (start with the modular installer and the Obsidian resolver paths).
|
|
169
|
+
Done 2026-06-12: baseline recorded at docs/development/coverage-baseline.md
|
|
170
|
+
(refreshed from the closed PR #122 survey against the current tree);
|
|
171
|
+
remaining gaps filed as T-019 (migrate.sh + theme_version.rb) and
|
|
172
|
+
T-020 (installer wizard/upgrade CI coverage).
|
|
169
173
|
acceptance:
|
|
170
174
|
- "A coverage baseline is recorded (test/coverage or a docs note)."
|
|
171
175
|
- "The 2–3 lowest-covered subsystems are identified and filed as new backlog tasks."
|
|
172
176
|
- "No reduction in existing passing tests (`./scripts/bin/test` stays green)."
|
|
173
177
|
links: { issue: null, pr: null, roadmap: "1.13" }
|
|
174
178
|
created: 2026-05-31
|
|
175
|
-
updated: 2026-06-
|
|
179
|
+
updated: 2026-06-12
|
|
176
180
|
|
|
177
181
|
# --- 2026-06-01 audit -------------------------------------------------------
|
|
178
182
|
|
|
179
183
|
- id: T-007
|
|
180
184
|
title: "Fix global navbar WCAG 2.1 AA violations to enable axe-core full-audit tests"
|
|
181
|
-
status:
|
|
185
|
+
status: done
|
|
182
186
|
priority: P1
|
|
183
187
|
area: a11y
|
|
184
188
|
risk: standard
|
|
@@ -190,6 +194,14 @@ tasks:
|
|
|
190
194
|
`aria-required-children` (menubar/button nesting), `link-name` (icon-only nav links),
|
|
191
195
|
`list` (footer list structure), and `scrollable-region-focusable` (code blocks).
|
|
192
196
|
Fix the HTML/ARIA in `_includes/` and `_layouts/` to make the full axe-core audit green.
|
|
197
|
+
Done 2026-06-13: all WCAG 2.1 AA violations resolved and verified with a
|
|
198
|
+
live axe-core run plus the unfrozen Playwright a11y spec (23/23 pass,
|
|
199
|
+
223/223 smoke tier). The actual violations differed from the stale TODO:
|
|
200
|
+
dropped redundant ARIA menubar/menuitem roles (navbar.html), aria-label
|
|
201
|
+
on the site-subtitle home link, listitem-preserving admin separator,
|
|
202
|
+
role="tab" on the disabled preview tab + aria-label on an icon-only
|
|
203
|
+
button, single focusable scroll region for code blocks (code-copy.js +
|
|
204
|
+
.scss), and underlined prose links across content wrappers.
|
|
193
205
|
acceptance:
|
|
194
206
|
- "All four violations listed in the `test.fixme` comment are resolved in `_includes/` / `_layouts/`."
|
|
195
207
|
- "The three `test.fixme` blocks in `test/visual/accessibility.spec.js` are changed to live `test()` calls and pass in CI."
|
|
@@ -197,7 +209,7 @@ tasks:
|
|
|
197
209
|
- "No visual regression in smoke snapshot tests."
|
|
198
210
|
links: { issue: null, pr: null, roadmap: "1.9" }
|
|
199
211
|
created: 2026-06-01
|
|
200
|
-
updated: 2026-06-
|
|
212
|
+
updated: 2026-06-13
|
|
201
213
|
|
|
202
214
|
- id: T-008
|
|
203
215
|
title: "Fix theme-customizer YAML export to quote hex color values"
|
|
@@ -273,7 +285,7 @@ tasks:
|
|
|
273
285
|
|
|
274
286
|
- id: T-011
|
|
275
287
|
title: "Add Ruby unit tests for uncovered _plugins/ generators"
|
|
276
|
-
status:
|
|
288
|
+
status: done
|
|
277
289
|
priority: P2
|
|
278
290
|
area: tests
|
|
279
291
|
risk: standard
|
|
@@ -285,6 +297,11 @@ tasks:
|
|
|
285
297
|
URL-pattern checks (`test_preview_image_urls`) but no specs that exercise the
|
|
286
298
|
generator logic in isolation. This is a concrete gap on the path to the
|
|
287
299
|
3.0-milestone 90% coverage target.
|
|
300
|
+
Done 2026-06-12: test/test_plugins.rb — 19 Minitest specs covering all
|
|
301
|
+
three plugins (config merge, path normalization, index dedupe by
|
|
302
|
+
relative_path, filename sanitization, hook output/filtering/sorting,
|
|
303
|
+
script discovery with theme fallback); wired into test_core.sh as the
|
|
304
|
+
"Plugin Unit Specs" unit test; runs standalone without a Jekyll server.
|
|
288
305
|
acceptance:
|
|
289
306
|
- "`test/test_ruby_converter.rb`-style RSpec or Minitest specs exist for all three plugins."
|
|
290
307
|
- "Each spec runs independently without a running Jekyll server (`bundle exec ruby -Itest`)."
|
|
@@ -292,7 +309,7 @@ tasks:
|
|
|
292
309
|
- "Edge cases covered: empty collections, missing front-matter keys, and duplicate slug detection."
|
|
293
310
|
links: { issue: null, pr: null, roadmap: "3.0" }
|
|
294
311
|
created: 2026-06-01
|
|
295
|
-
updated: 2026-06-
|
|
312
|
+
updated: 2026-06-12
|
|
296
313
|
|
|
297
314
|
# --- 2026-06-10 Zer0-Mistake Quality Framework (roadmap v1.13) --------------
|
|
298
315
|
#
|
|
@@ -456,7 +473,7 @@ tasks:
|
|
|
456
473
|
|
|
457
474
|
- id: T-018
|
|
458
475
|
title: "Admin config page displays a stale copy of _config.yml — keep it in sync safely"
|
|
459
|
-
status:
|
|
476
|
+
status: done
|
|
460
477
|
priority: P2
|
|
461
478
|
area: feat
|
|
462
479
|
risk: standard
|
|
@@ -470,10 +487,61 @@ tasks:
|
|
|
470
487
|
refresh would inject the live `phc_` api_key into the *visible* Raw-YAML
|
|
471
488
|
tab — any sync mechanism must sanitize the visible tab the same way
|
|
472
489
|
T-009 sanitizes the hidden copy element, or redact at sync time.
|
|
490
|
+
Done 2026-06-12: copy synced (wrapped in Liquid raw markers so config
|
|
491
|
+
comments mentioning Liquid render literally); scripts/bin/validate
|
|
492
|
+
gains a drift check that fails when the copy diverges; the visible
|
|
493
|
+
Raw-YAML tab now renders the same sanitized capture as the hidden
|
|
494
|
+
element (live phc_ key verified redacted in both); the raw-tab
|
|
495
|
+
Playwright test targets code#cfg-raw-yaml and asserts presence
|
|
496
|
+
instead of silently skipping.
|
|
473
497
|
acceptance:
|
|
474
498
|
- "The config shown at /about/config/ matches the live `_config.yml` (automated sync step or build-time check that fails on drift)."
|
|
475
499
|
- "The visible Raw-YAML tab applies the same sensitive-line redaction as the hidden `cfg-full-yaml` element."
|
|
476
500
|
- "`test/visual/security.spec.js` raw-tab test passes without its silent skip path (locator matches the actual `code#cfg-raw-yaml` element)."
|
|
477
501
|
links: { issue: null, pr: null, roadmap: "1.13" }
|
|
478
502
|
created: 2026-06-11
|
|
479
|
-
updated: 2026-06-
|
|
503
|
+
updated: 2026-06-12
|
|
504
|
+
|
|
505
|
+
- id: T-019
|
|
506
|
+
title: "Unit tests for migrate.sh and theme_version.rb (coverage rank #1)"
|
|
507
|
+
status: open
|
|
508
|
+
priority: P2
|
|
509
|
+
area: tests
|
|
510
|
+
risk: standard
|
|
511
|
+
effort: M
|
|
512
|
+
source: audit
|
|
513
|
+
summary: >-
|
|
514
|
+
The 2026-06-12 coverage baseline (docs/development/coverage-baseline.md,
|
|
515
|
+
T-005) ranks scripts/lib/migrate.sh (265 lines, 5 functions: site
|
|
516
|
+
detection, theme connection, admin-page install/verify, version-gap
|
|
517
|
+
detection) plus _plugins/theme_version.rb (88 lines) as the largest
|
|
518
|
+
remaining zero-coverage surface (353 lines).
|
|
519
|
+
acceptance:
|
|
520
|
+
- "scripts/test/lib/test_migrate.sh exercises detect_jekyll_site, validate_theme_connection, and detect_version_gap against fixture directories."
|
|
521
|
+
- "test/test_plugins.rb (or a sibling spec) covers theme_version.rb's version resolution."
|
|
522
|
+
- "./scripts/bin/test stays green with the new specs included."
|
|
523
|
+
links: { issue: null, pr: null, roadmap: "1.14" }
|
|
524
|
+
created: 2026-06-12
|
|
525
|
+
updated: 2026-06-12
|
|
526
|
+
|
|
527
|
+
- id: T-020
|
|
528
|
+
title: "CI coverage for installer interactive wizard and upgrade path (coverage rank #2)"
|
|
529
|
+
status: open
|
|
530
|
+
priority: P2
|
|
531
|
+
area: tests
|
|
532
|
+
risk: standard
|
|
533
|
+
effort: M
|
|
534
|
+
source: audit
|
|
535
|
+
summary: >-
|
|
536
|
+
Per the T-005 baseline, scripts/lib/install/wizard_interactive.sh (189
|
|
537
|
+
lines — prompt helpers need a TTY) and scripts/lib/install/upgrade.sh
|
|
538
|
+
(184 lines) have effectively no CI coverage. Drive the wizard with
|
|
539
|
+
scripted stdin (the suite pattern in test_install_legacy_flags.sh) and
|
|
540
|
+
add an upgrade-path fixture (old-version site → upgrade → assert state).
|
|
541
|
+
acceptance:
|
|
542
|
+
- "Wizard prompt helpers exercised non-interactively (piped answers) in a test_install_* suite."
|
|
543
|
+
- "An upgrade fixture covers detect→migrate→verify for at least one version gap."
|
|
544
|
+
- "Suites run in CI via the standard installer e2e discovery (test_install_*.sh)."
|
|
545
|
+
links: { issue: null, pr: null, roadmap: "1.14" }
|
|
546
|
+
created: 2026-06-12
|
|
547
|
+
updated: 2026-06-12
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
<button class="nav-link" type="button" role="tab" aria-selected="false">Hover me</button>
|
|
147
147
|
</li>
|
|
148
148
|
<li class="nav-item" role="presentation">
|
|
149
|
-
<button class="nav-link disabled" type="button" disabled>Disabled</button>
|
|
149
|
+
<button class="nav-link disabled" type="button" role="tab" aria-selected="false" disabled>Disabled</button>
|
|
150
150
|
</li>
|
|
151
151
|
</ul>
|
|
152
152
|
</section>
|
|
@@ -528,7 +528,7 @@ docker-compose up
|
|
|
528
528
|
<div class="d-flex flex-wrap gap-3 mt-3">
|
|
529
529
|
<span class="badge bg-primary p-2"><i class="bi bi-lightning-charge me-1"></i>Badge icon</span>
|
|
530
530
|
<button class="btn btn-outline-primary btn-sm"><i class="bi bi-download me-1"></i>Icon button</button>
|
|
531
|
-
<button class="btn btn-primary btn-sm"><i class="bi bi-arrow-right"></i></button>
|
|
531
|
+
<button class="btn btn-primary btn-sm" aria-label="Continue"><i class="bi bi-arrow-right" aria-hidden="true"></i></button>
|
|
532
532
|
</div>
|
|
533
533
|
</div>
|
|
534
534
|
</div>
|
|
@@ -44,11 +44,12 @@
|
|
|
44
44
|
</div>
|
|
45
45
|
|
|
46
46
|
<!-- If a subtitle exists -->
|
|
47
|
-
{%-
|
|
47
|
+
{%- assign _subtitle = site.subtitle | strip -%}
|
|
48
|
+
{%- if _subtitle != "" -%}
|
|
48
49
|
<div class="navbar-brand site-subtitle d-none d-lg-inline">
|
|
49
|
-
<a class="nav-link" href="{{ '/' | relative_url }}">
|
|
50
|
+
<a class="nav-link" href="{{ '/' | relative_url }}" aria-label="{{ _subtitle }} — {{ site.title }} home">
|
|
50
51
|
<span class="site-subtitle-text">
|
|
51
|
-
{{
|
|
52
|
+
{{ _subtitle }}
|
|
52
53
|
</span>
|
|
53
54
|
</a>
|
|
54
55
|
</div>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
{% if item.external and rendered_separator == false %}
|
|
28
28
|
{% assign rendered_separator = true %}
|
|
29
|
-
<li
|
|
29
|
+
<li class="nav-item" aria-hidden="true"><hr class="my-2"></li>
|
|
30
30
|
{% endif %}
|
|
31
31
|
|
|
32
32
|
{% comment %} Active detection: exact URL match or admin_section match {% endcomment %}
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
<div class="offcanvas-body">
|
|
20
20
|
<!-- Desktop: width is the grid middle track; labels ellipsis or icon-only via container query -->
|
|
21
21
|
<div class="bd-navbar-nav-viewport">
|
|
22
|
-
<ul class="navbar-nav justify-content-lg-center text-start flex-grow-1"
|
|
23
|
-
<li class="nav-item d-lg-none"
|
|
24
|
-
<a class="nav-link" href="{{ '/' | relative_url }}"
|
|
22
|
+
<ul class="navbar-nav justify-content-lg-center text-start flex-grow-1">
|
|
23
|
+
<li class="nav-item d-lg-none">
|
|
24
|
+
<a class="nav-link" href="{{ '/' | relative_url }}" {% if page.url == '/' %}aria-current="page"{% endif %}>
|
|
25
25
|
<i class="{{site.default_icon}} bi-house" aria-hidden="true"></i>
|
|
26
26
|
Home
|
|
27
27
|
</a>
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
{%- assign items_remaining = nav_main.size | minus: forloop.index -%}
|
|
42
42
|
|
|
43
43
|
{%- if has_children -%}
|
|
44
|
-
<li class="nav-item dropdown d-flex align-items-center nav-hover-dropdown"
|
|
44
|
+
<li class="nav-item dropdown d-flex align-items-center nav-hover-dropdown">
|
|
45
45
|
<!-- Parent link navigates directly -->
|
|
46
46
|
<a
|
|
47
47
|
class="nav-link"
|
|
48
48
|
href="{{ link.url | relative_url }}"
|
|
49
|
-
|
|
49
|
+
aria-label="{{ link.title }}"
|
|
50
50
|
{%- if link.url == page.url -%} aria-current="page"{%- endif -%}
|
|
51
51
|
title="{{ link.title }}"
|
|
52
52
|
>
|
|
@@ -70,13 +70,13 @@
|
|
|
70
70
|
<span class="visually-hidden">Toggle {{ link.title }} submenu</span>
|
|
71
71
|
</button>
|
|
72
72
|
|
|
73
|
-
<ul class="dropdown-menu {% if items_remaining < 2 %}dropdown-menu-end{% else %}dropdown-menu-start{% endif %}" aria-labelledby="dropdown-{{ link.title | slugify }}"
|
|
73
|
+
<ul class="dropdown-menu {% if items_remaining < 2 %}dropdown-menu-end{% else %}dropdown-menu-start{% endif %}" aria-labelledby="dropdown-{{ link.title | slugify }}">
|
|
74
74
|
{%- for child in link.children -%}
|
|
75
|
-
<li
|
|
75
|
+
<li>
|
|
76
76
|
<a
|
|
77
77
|
class="dropdown-item"
|
|
78
78
|
href="{{ child.url | relative_url }}"
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
{%- if child.url == page.url -%} aria-current="page"{%- endif -%}
|
|
81
81
|
>
|
|
82
82
|
{%- if child.icon -%}
|
|
@@ -89,11 +89,11 @@
|
|
|
89
89
|
</ul>
|
|
90
90
|
</li>
|
|
91
91
|
{%- else -%}
|
|
92
|
-
<li class="nav-item"
|
|
92
|
+
<li class="nav-item">
|
|
93
93
|
<a
|
|
94
94
|
class="nav-link"
|
|
95
95
|
href="{{ link.url | relative_url }}"
|
|
96
|
-
|
|
96
|
+
aria-label="{{ link.title }}"
|
|
97
97
|
{%- if link.url == page.url -%} aria-current="page"{%- endif -%}
|
|
98
98
|
title="{{ link.title }}"
|
|
99
99
|
>
|
|
@@ -117,11 +117,11 @@
|
|
|
117
117
|
{%- if collection.docs.size > 0 -%}
|
|
118
118
|
{%- assign col_title = collection.label | replace: "-", " " | replace: "_", " " | capitalize -%}
|
|
119
119
|
{%- assign col_url = "/" | append: collection.label | append: "/" -%}
|
|
120
|
-
<li class="nav-item"
|
|
120
|
+
<li class="nav-item">
|
|
121
121
|
<a
|
|
122
122
|
class="nav-link"
|
|
123
123
|
href="{{ col_url | relative_url }}"
|
|
124
|
-
|
|
124
|
+
aria-label="{{ col_title }}"
|
|
125
125
|
title="{{ col_title }}"
|
|
126
126
|
{%- if page.collection == collection.label -%} aria-current="page"{%- endif -%}
|
|
127
127
|
>
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
{%- endfor -%}
|
|
134
134
|
|
|
135
135
|
{%- endif -%}
|
|
136
|
-
<li class="nav-item d-lg-none"
|
|
136
|
+
<li class="nav-item d-lg-none">
|
|
137
137
|
<button
|
|
138
138
|
class="nav-link btn btn-link text-start w-100"
|
|
139
139
|
type="button"
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
Search
|
|
146
146
|
</button>
|
|
147
147
|
</li>
|
|
148
|
-
<li class="nav-item d-lg-none"
|
|
148
|
+
<li class="nav-item d-lg-none">
|
|
149
149
|
<button
|
|
150
150
|
class="nav-link btn btn-link text-start w-100"
|
|
151
151
|
type="button"
|
|
@@ -641,6 +641,17 @@ a.bd-intro-badge--tag:focus {
|
|
|
641
641
|
min-width: 1px
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
/* a11y (WCAG 1.4.1 link-in-text-block): prose links must be distinguishable
|
|
645
|
+
without relying on color. Underline inline content links; exclude links
|
|
646
|
+
that already carry their own non-color affordance (buttons, badges, nav
|
|
647
|
+
pills/tabs, card and icon links). */
|
|
648
|
+
.bd-content :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
|
|
649
|
+
.post-content :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
|
|
650
|
+
.landing-content-body :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
|
|
651
|
+
#admin-content :is(p, li, blockquote, td, dd, .alert) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not(.alert-link):not([class*="text-decoration"]) {
|
|
652
|
+
text-decoration: underline;
|
|
653
|
+
}
|
|
654
|
+
|
|
644
655
|
@media (min-width: 992px) {
|
|
645
656
|
.bd-toc {
|
|
646
657
|
position:-webkit-sticky;
|
data/_sass/core/code-copy.scss
CHANGED
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
display: block;
|
|
90
90
|
padding: 0;
|
|
91
91
|
border: 0;
|
|
92
|
-
overflow
|
|
92
|
+
// overflow on the parent <pre> only (single focusable scroll region, WCAG 2.1.1)
|
|
93
93
|
white-space: pre;
|
|
94
94
|
font-family: var(--zer0-font-mono);
|
|
95
95
|
font-size: 0.8125rem;
|
|
@@ -254,7 +254,7 @@ pre.highlight,
|
|
|
254
254
|
border: 0;
|
|
255
255
|
padding: 0;
|
|
256
256
|
padding-right: calc(var(--zer0-space-3) + var(--zer0-code-copy-width));
|
|
257
|
-
|
|
257
|
+
// overflow on the parent <pre> only (single focusable scroll region, WCAG 2.1.1)
|
|
258
258
|
white-space: pre;
|
|
259
259
|
background-color: transparent;
|
|
260
260
|
font-family: var(--zer0-font-mono);
|
data/assets/js/code-copy.js
CHANGED
|
@@ -108,6 +108,17 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
108
108
|
|
|
109
109
|
ensureLineNumbers(preElement, codeElement);
|
|
110
110
|
|
|
111
|
+
// a11y (WCAG 2.1.1 scrollable-region-focusable): a code block that can
|
|
112
|
+
// scroll horizontally must be reachable by keyboard. Make every <pre> a
|
|
113
|
+
// focusable region with a discernible name.
|
|
114
|
+
if (!preElement.hasAttribute('tabindex')) {
|
|
115
|
+
preElement.setAttribute('tabindex', '0');
|
|
116
|
+
if (!preElement.hasAttribute('role')) preElement.setAttribute('role', 'region');
|
|
117
|
+
if (!preElement.hasAttribute('aria-label')) {
|
|
118
|
+
preElement.setAttribute('aria-label', (getLanguageLabel(preElement) || 'Code') + ' code block');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
111
122
|
if (preElement.querySelector('.copy')) return;
|
|
112
123
|
|
|
113
124
|
var rougeWrapper = preElement.closest('.highlighter-rouge > .highlight');
|
data/scripts/bin/validate
CHANGED
|
@@ -404,6 +404,23 @@ classified_files = %w[
|
|
|
404
404
|
pages/_about/settings/_config.yml
|
|
405
405
|
.github/ISSUE_TEMPLATE/config.yml
|
|
406
406
|
]
|
|
407
|
+
|
|
408
|
+
# T-018: the admin config page renders pages/_about/settings/_config.yml via
|
|
409
|
+
# include_relative (Liquid cannot reach the repo root). Fail on drift so the
|
|
410
|
+
# page never shows a stale copy; refresh with:
|
|
411
|
+
# cp _config.yml pages/_about/settings/_config.yml
|
|
412
|
+
settings_copy = 'pages/_about/settings/_config.yml'
|
|
413
|
+
if File.file?(settings_copy)
|
|
414
|
+
live = File.read('_config.yml', encoding: 'UTF-8')
|
|
415
|
+
copy_lines = File.read(settings_copy, encoding: 'UTF-8').lines
|
|
416
|
+
# The copy is wrapped in {% raw %}/{% endraw %} so include_relative renders
|
|
417
|
+
# the config text literally (the live file mentions Liquid tags in comments).
|
|
418
|
+
refresh = "{ echo '{% raw %}'; cat _config.yml; echo '{% endraw %}'; } > #{settings_copy}"
|
|
419
|
+
assert(copy_lines.first.to_s.strip == '{% raw %}' && copy_lines.last.to_s.strip == '{% endraw %}',
|
|
420
|
+
"#{settings_copy} must be wrapped in raw/endraw; refresh it: #{refresh}")
|
|
421
|
+
assert(copy_lines[1..-2].join == live,
|
|
422
|
+
"#{settings_copy} has drifted from _config.yml; refresh it: #{refresh}")
|
|
423
|
+
end
|
|
407
424
|
classified_files.concat(Dir.glob('_data/**/*config*.{yml,yaml}'))
|
|
408
425
|
|
|
409
426
|
unclassified_files = config_like_files.sort - classified_files.select { |file| File.file?(file) }
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-theme-zer0
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.17.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Amr Abdel
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|