jekyll-theme-zer0 1.28.0 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1143 -13
  3. data/_data/README.md +2 -0
  4. data/_data/ai.yml +5 -3
  5. data/_data/ai_pricing.yml +36 -0
  6. data/_data/backlog.yml +507 -2
  7. data/_data/consumers.yml +157 -9
  8. data/_data/features.yml +303 -20
  9. data/_data/feedback_types.yml +17 -12
  10. data/_data/i18n/fr.yml +12 -7
  11. data/_data/i18n/manifest.yml +39 -12
  12. data/_data/ingredient_densities.yml +122 -0
  13. data/_data/landing.yml +5 -2
  14. data/_data/navigation/main.yml +16 -0
  15. data/_data/navigation/quickstart.yml +4 -0
  16. data/_data/recipe_courses.yml +64 -0
  17. data/_data/site_builder.yml +874 -0
  18. data/_data/theme-manifest.yml +160 -124
  19. data/_data/ui-text.yml +26 -0
  20. data/_includes/README.md +26 -2
  21. data/_includes/analytics/posthog.html +2 -2
  22. data/_includes/components/admin-links.html +2 -2
  23. data/_includes/components/admin-tabs.html +2 -2
  24. data/_includes/components/ai-chat.html +14 -11
  25. data/_includes/components/analytics-dashboard.html +8 -8
  26. data/_includes/components/author-bio.html +1 -1
  27. data/_includes/components/author-card.html +10 -2
  28. data/_includes/components/author-eeat.html +4 -4
  29. data/_includes/components/background-customizer.html +10 -10
  30. data/_includes/components/background-image.html +114 -0
  31. data/_includes/components/background-settings.html +28 -15
  32. data/_includes/components/collection-manager.html +5 -5
  33. data/_includes/components/component-showcase.html +13 -13
  34. data/_includes/components/config-editor.html +12 -12
  35. data/_includes/components/config-viewer.html +8 -8
  36. data/_includes/components/cookie-consent.html +15 -15
  37. data/_includes/components/cta-button.html +7 -2
  38. data/_includes/components/dev-shortcuts.html +7 -7
  39. data/_includes/components/env-dashboard.html +8 -8
  40. data/_includes/components/env-switcher.html +9 -9
  41. data/_includes/components/feature-card.html +2 -2
  42. data/_includes/components/halfmoon.html +2 -2
  43. data/_includes/components/info-section.html +42 -37
  44. data/_includes/components/js-cdn.html +15 -15
  45. data/_includes/components/language-toggle.html +168 -21
  46. data/_includes/components/mermaid.html +72 -435
  47. data/_includes/components/nanobar.html +5 -5
  48. data/_includes/components/nav-editor.html +2 -2
  49. data/_includes/components/nav-export.html +2 -2
  50. data/_includes/components/nav-overview.html +2 -2
  51. data/_includes/components/page-feedback.html +45 -30
  52. data/_includes/components/page-views-init.html +55 -0
  53. data/_includes/components/page-views.html +33 -0
  54. data/_includes/components/post-card.html +22 -22
  55. data/_includes/components/post-type-badge.html +2 -2
  56. data/_includes/components/powered-by.html +2 -2
  57. data/_includes/components/preview-image.html +6 -0
  58. data/_includes/components/quick-index.html +2 -2
  59. data/_includes/components/recipe-card.html +67 -0
  60. data/_includes/components/recipe-duration.html +50 -0
  61. data/_includes/components/recipe-grams.html +58 -0
  62. data/_includes/components/recipe-index.html +96 -0
  63. data/_includes/components/recipe-ingredients.html +90 -0
  64. data/_includes/components/recipe-meta.html +96 -0
  65. data/_includes/components/recipe-nutrition.html +57 -0
  66. data/_includes/components/recipe-qty.html +73 -0
  67. data/_includes/components/recipe-ratio.html +151 -0
  68. data/_includes/components/recipe-scaler.html +73 -0
  69. data/_includes/components/recipe-steps.html +86 -0
  70. data/_includes/components/recipe-temp.html +45 -0
  71. data/_includes/components/search-modal.html +29 -4
  72. data/_includes/components/searchbar.html +2 -2
  73. data/_includes/components/shortcuts-modal.html +3 -0
  74. data/_includes/components/svg-background.html +2 -2
  75. data/_includes/components/theme-customizer.html +2 -2
  76. data/_includes/components/theme-info.html +14 -7
  77. data/_includes/components/theme-preview-gallery.html +22 -22
  78. data/_includes/content/giscus.html +2 -2
  79. data/_includes/content/intro.html +8 -8
  80. data/_includes/content/jsonld-faq.html +2 -2
  81. data/_includes/content/jsonld-software.html +24 -5
  82. data/_includes/content/seo.html +4 -4
  83. data/_includes/content/sitemap.html +27 -27
  84. data/_includes/content/toc.html +183 -183
  85. data/_includes/core/branding.html +6 -6
  86. data/_includes/core/console-capture.html +32 -74
  87. data/_includes/core/favicon.html +49 -7
  88. data/_includes/core/footer-fabs.html +17 -3
  89. data/_includes/core/footer.html +49 -34
  90. data/_includes/core/head.html +110 -86
  91. data/_includes/core/header.html +76 -54
  92. data/_includes/docs/bootstrap-docs.html +8 -8
  93. data/_includes/landing/landing-install-cards.html +2 -2
  94. data/_includes/landing/landing-quick-links.html +1 -1
  95. data/_includes/navigation/admin-nav.html +2 -2
  96. data/_includes/navigation/nav-tree.html +8 -8
  97. data/_includes/navigation/navbar.html +12 -12
  98. data/_includes/navigation/section-sidebar.html +109 -27
  99. data/_includes/navigation/sidebar-config.html +36 -2
  100. data/_includes/navigation/sidebar-left.html +17 -16
  101. data/_includes/navigation/sidebar-right.html +8 -7
  102. data/_includes/obsidian/full-graph.html +2 -2
  103. data/_includes/setup/claude-session.html +72 -0
  104. data/_includes/setup/prereq-checklist.html +90 -0
  105. data/_includes/setup/wizard.html +924 -222
  106. data/_includes/stats/stats-categories.html +8 -8
  107. data/_includes/stats/stats-header.html +14 -14
  108. data/_includes/stats/stats-metrics.html +14 -14
  109. data/_includes/stats/stats-no-data.html +12 -12
  110. data/_includes/stats/stats-overview.html +6 -6
  111. data/_includes/stats/stats-tags.html +8 -8
  112. data/_layouts/404.html +38 -24
  113. data/_layouts/README.md +2 -0
  114. data/_layouts/admin.html +24 -24
  115. data/_layouts/article.html +43 -33
  116. data/_layouts/author.html +20 -20
  117. data/_layouts/authors.html +2 -2
  118. data/_layouts/book-abc.html +12 -12
  119. data/_layouts/book-story.html +15 -15
  120. data/_layouts/book.html +12 -12
  121. data/_layouts/collection.html +33 -33
  122. data/_layouts/cookbook.html +88 -0
  123. data/_layouts/default.html +31 -28
  124. data/_layouts/home.html +23 -23
  125. data/_layouts/index.html +10 -10
  126. data/_layouts/landing.html +17 -17
  127. data/_layouts/news.html +44 -44
  128. data/_layouts/note.html +38 -38
  129. data/_layouts/notebook.html +34 -34
  130. data/_layouts/recipe.html +274 -0
  131. data/_layouts/root.html +92 -55
  132. data/_layouts/section.html +62 -33
  133. data/_layouts/setup.html +3 -3
  134. data/_layouts/sitemap-collection.html +49 -49
  135. data/_layouts/stats.html +40 -40
  136. data/_layouts/tag.html +12 -12
  137. data/_layouts/welcome.html +21 -21
  138. data/_sass/components/_callout.scss +1 -1
  139. data/_sass/components/_footer.scss +37 -1
  140. data/_sass/components/_mermaid.scss +375 -0
  141. data/_sass/components/_page-views.scss +36 -0
  142. data/_sass/components/_recipe.scss +506 -0
  143. data/_sass/components/_setup-wizard.scss +764 -0
  144. data/_sass/components/_ui-enhancements.scss +6 -6
  145. data/_sass/core/_navbar.scss +261 -46
  146. data/_sass/layouts/_landing.scss +2 -2
  147. data/_sass/layouts/_navbar-extras.scss +14 -4
  148. data/_sass/tokens/_color.scss +6 -0
  149. data/_sass/tokens/_index.scss +2 -0
  150. data/_sass/tokens/_radius.scss +21 -0
  151. data/_sass/tokens/_typography.scss +4 -0
  152. data/_sass/utilities/_focus.scss +14 -0
  153. data/assets/css/main.scss +4 -0
  154. data/assets/js/ai-chat.js +47 -5
  155. data/assets/js/fleet-feedback-capture.js +124 -0
  156. data/assets/js/fleet-feedback.js +853 -0
  157. data/assets/js/mermaid-diagrams.js +1267 -0
  158. data/assets/js/modules/navigation/config.js +9 -6
  159. data/assets/js/modules/navigation/navbar.js +55 -0
  160. data/assets/js/modules/navigation/scroll-spy.js +315 -80
  161. data/assets/js/modules/theme/appearance.js +8 -2
  162. data/assets/js/obsidian-wiki-links.js +8 -3
  163. data/assets/js/page-feedback.js +125 -192
  164. data/assets/js/page-views.js +372 -0
  165. data/assets/js/recipe-scaler.js +501 -0
  166. data/assets/js/search-modal.js +36 -0
  167. data/assets/js/setup-wizard.js +2279 -226
  168. data/assets/js/site-builder.js +1834 -0
  169. data/assets/js/ui-enhancements.js +11 -3
  170. data/scripts/README.md +44 -0
  171. data/scripts/ai/README.md +38 -0
  172. data/scripts/ai/api_call.rb +124 -0
  173. data/scripts/ai/usage.rb +314 -0
  174. data/scripts/ai/usage_report.rb +225 -0
  175. data/scripts/bin/audit-consumer +39 -7
  176. data/scripts/bin/giscus-discussions +213 -14
  177. data/scripts/bin/manifest +35 -12
  178. data/scripts/ci/agent_review_result.py +164 -0
  179. data/scripts/ci/test_agent_review_result.py +172 -0
  180. data/scripts/ci/test_visual_evidence_autogen.py +341 -0
  181. data/scripts/ci/visual_evidence_autogen.py +1060 -0
  182. data/scripts/content-review.rb +20 -1
  183. data/scripts/design-system-check.rb +170 -0
  184. data/scripts/lib/audit.sh +42 -2
  185. data/scripts/lint-liquid-raw.rb +137 -0
  186. data/scripts/test/integration/mermaid +22 -8
  187. data/scripts/test/lib/run_tests.sh +3 -1
  188. data/scripts/test/lib/test_agent_review_result.sh +27 -0
  189. data/scripts/test/lib/test_visual_evidence_autogen.sh +24 -0
  190. data/scripts/translate.rb +94 -16
  191. metadata +48 -2
@@ -0,0 +1,86 @@
1
+ {% comment %} Feature: ZER0-084 {% endcomment %}
2
+ {%- comment -%}
3
+ Component: recipe-steps
4
+ Path: _includes/components/recipe-steps.html
5
+ Purpose: The numbered method for one recipe — optionally split into
6
+ sections ("Day 1", "Assembly"), with per-step timings,
7
+ convertible temperatures, and step photos.
8
+ Params: steps (array, optional, default: page.steps)
9
+ heading (string, optional, default: "Method")
10
+ heading_level (string, optional, default: "h2")
11
+ Depends on: components/recipe-temp.html, components/recipe-duration.html,
12
+ _sass/components/_recipe.scss
13
+ Notes: A step is either a plain string or a hash of
14
+ {text, title, time, temp_f, temp_c, image, image_alt, note}.
15
+ Sections are {section, items} hashes; numbering continues across
16
+ them via the <ol start> attribute so "step 7" means step 7 no
17
+ matter which section it lives in. Step text is markdownified, so
18
+ links and emphasis work. itemprop="recipeInstructions" marks
19
+ each step for schema.org.
20
+ {%- endcomment -%}
21
+ {%- assign _rs_steps = include.steps | default: page.steps -%}
22
+ {%- if _rs_steps == nil or _rs_steps.size == 0 -%}
23
+ {%- comment -%} recipe-steps: no `steps` front matter — skipping render {%- endcomment -%}
24
+ {%- else -%}
25
+ {%- assign _rs_hl = include.heading_level | default: "h2" -%}
26
+ {%- assign _rs_sub = _rs_hl | remove: "h" | plus: 1 -%}
27
+ {%- assign _rs_n = 0 -%}
28
+ <section class="recipe-steps">
29
+ <{{ _rs_hl }} class="recipe-section-heading">
30
+ <i class="bi bi-list-ol me-2" aria-hidden="true"></i>{{ include.heading | default: "Method" }}
31
+ </{{ _rs_hl }}>
32
+
33
+ {%- for _rs_entry in _rs_steps -%}
34
+ {%- if _rs_entry.items -%}
35
+ {%- assign _rs_section = _rs_entry.section | default: _rs_entry.group | default: _rs_entry.title -%}
36
+ {%- assign _rs_loop_steps = _rs_entry.items -%}
37
+ {%- else -%}
38
+ {%- assign _rs_section = nil -%}
39
+ {%- assign _rs_loop_steps = "" | split: "" | push: _rs_entry -%}
40
+ {%- endif -%}
41
+
42
+ {%- if _rs_section -%}
43
+ <h{{ _rs_sub }} class="recipe-steps-section-title">{{ _rs_section | escape }}</h{{ _rs_sub }}>
44
+ {%- endif -%}
45
+
46
+ <ol class="recipe-step-list" start="{{ _rs_n | plus: 1 }}">
47
+ {%- for _rs_s in _rs_loop_steps -%}
48
+ {%- assign _rs_n = _rs_n | plus: 1 -%}
49
+ {%- if _rs_s.text or _rs_s.title or _rs_s.image -%}
50
+ {%- assign _rs_text = _rs_s.text -%}
51
+ {%- else -%}
52
+ {%- assign _rs_text = _rs_s -%}
53
+ {%- endif -%}
54
+ <li class="recipe-step" itemprop="recipeInstructions">
55
+ {%- if _rs_s.title -%}
56
+ <p class="recipe-step-title">{{ _rs_s.title | escape }}</p>
57
+ {%- endif -%}
58
+ {%- if _rs_text -%}
59
+ <div class="recipe-step-text">{{ _rs_text | markdownify }}</div>
60
+ {%- endif -%}
61
+ {%- if _rs_s.time or _rs_s.temp_f or _rs_s.temp_c -%}
62
+ <p class="recipe-step-facts">
63
+ {%- if _rs_s.time -%}
64
+ {%- capture _rs_dur -%}{%- include components/recipe-duration.html minutes=_rs_s.time -%}{%- endcapture -%}
65
+ <span class="recipe-step-fact"><i class="bi bi-stopwatch me-1" aria-hidden="true"></i>{{ _rs_dur | strip }}</span>
66
+ {%- endif -%}
67
+ {%- if _rs_s.temp_f or _rs_s.temp_c -%}
68
+ <span class="recipe-step-fact"><i class="bi bi-thermometer-half me-1" aria-hidden="true"></i>{%- include components/recipe-temp.html f=_rs_s.temp_f c=_rs_s.temp_c -%}</span>
69
+ {%- endif -%}
70
+ </p>
71
+ {%- endif -%}
72
+ {%- if _rs_s.image -%}
73
+ <figure class="recipe-step-figure">
74
+ <img src="{{ _rs_s.image | relative_url }}" alt="{{ _rs_s.image_alt | default: '' | escape }}" loading="lazy" decoding="async" class="img-fluid rounded">
75
+ {%- if _rs_s.caption -%}<figcaption class="small text-body-secondary mt-1">{{ _rs_s.caption | escape }}</figcaption>{%- endif -%}
76
+ </figure>
77
+ {%- endif -%}
78
+ {%- if _rs_s.note -%}
79
+ <p class="recipe-step-note small">{{ _rs_s.note | escape }}</p>
80
+ {%- endif -%}
81
+ </li>
82
+ {%- endfor -%}
83
+ </ol>
84
+ {%- endfor -%}
85
+ </section>
86
+ {%- endif -%}
@@ -0,0 +1,45 @@
1
+ {% comment %} Feature: ZER0-084 {% endcomment %}
2
+ {%- comment -%}
3
+ Component: recipe-temp
4
+ Path: _includes/components/recipe-temp.html
5
+ Purpose: A temperature that follows the reader's unit choice — oven
6
+ settings, water temperature, doneness targets. Renders BOTH
7
+ scales by default so the page is complete without JavaScript;
8
+ the scaler then narrows it to whichever system is selected.
9
+ Params: f (number, optional) — degrees Fahrenheit
10
+ c (number, optional) — degrees Celsius
11
+ (give either one; the other is derived)
12
+ label (string, optional, default: "") — prefix, e.g. "Oven"
13
+ class (string, optional, default: "")
14
+ Depends on: assets/js/recipe-scaler.js, _sass/components/_recipe.scss
15
+ Notes: Derived values round to the nearest 5° above 100° — the
16
+ precision an oven dial actually has — and to the nearest degree
17
+ below it. Author both `f:` and `c:` to pin exact values.
18
+ Drop it straight into recipe prose:
19
+ include components/recipe-temp.html f=375
20
+ {%- endcomment -%}
21
+ {%- if include.f == nil and include.c == nil -%}
22
+ {%- comment -%} ERROR: recipe-temp requires `f` or `c` {%- endcomment -%}
23
+ {%- else -%}
24
+ {%- if include.f != nil -%}
25
+ {%- assign _rt_f = include.f | round -%}
26
+ {%- else -%}
27
+ {%- assign _rt_fraw = include.c | times: 9.0 | divided_by: 5.0 | plus: 32 -%}
28
+ {%- if _rt_fraw >= 100 -%}
29
+ {%- assign _rt_f = _rt_fraw | divided_by: 5.0 | round | times: 5 -%}
30
+ {%- else -%}
31
+ {%- assign _rt_f = _rt_fraw | round -%}
32
+ {%- endif -%}
33
+ {%- endif -%}
34
+ {%- if include.c != nil -%}
35
+ {%- assign _rt_c = include.c | round -%}
36
+ {%- else -%}
37
+ {%- assign _rt_craw = include.f | minus: 32 | times: 5.0 | divided_by: 9.0 -%}
38
+ {%- if _rt_craw >= 100 -%}
39
+ {%- assign _rt_c = _rt_craw | divided_by: 5.0 | round | times: 5 -%}
40
+ {%- else -%}
41
+ {%- assign _rt_c = _rt_craw | round -%}
42
+ {%- endif -%}
43
+ {%- endif -%}
44
+ <span class="recipe-temp {{ include.class | default: '' }}" data-recipe-temp data-temp-f="{{ _rt_f }}" data-temp-c="{{ _rt_c }}">{% if include.label %}{{ include.label | escape }} {% endif %}{{ _rt_f }} °F ({{ _rt_c }} °C)</span>
45
+ {%- endif -%}
@@ -1,5 +1,5 @@
1
1
  {% comment %} Feature: ZER0-032 {% endcomment %}
2
- <!--
2
+ {% comment %}
3
3
  ===================================================================
4
4
  SEARCH MODAL - Site-wide Search Popup
5
5
  ===================================================================
@@ -16,7 +16,7 @@
16
16
  prevents a dead link on remote-theme Pages builds that lack /sitemap/.
17
17
  - Keyboard shortcut handled by navigation keyboard module ("/")
18
18
  ===================================================================
19
- -->
19
+ {% endcomment %}
20
20
 
21
21
  {%- include core/i18n.html lang=include.lang -%}
22
22
  {%- assign search_placeholder = ui.search_placeholder_text | default: "Enter your search term..." -%}
@@ -45,9 +45,9 @@
45
45
  <div class="modal-dialog modal-dialog-centered">
46
46
  <div class="modal-content">
47
47
  <div class="modal-header">
48
- <h5 class="modal-title" id="siteSearchModalLabel">
48
+ <h2 class="modal-title h5" id="siteSearchModalLabel">
49
49
  <i class="bi bi-search me-2"></i>Search
50
- </h5>
50
+ </h2>
51
51
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
52
52
  </div>
53
53
  <div class="modal-body">
@@ -72,6 +72,31 @@
72
72
  Press <kbd>/</kbd> or <kbd>⌘</kbd>/<kbd>Ctrl</kbd>+<kbd>K</kbd> to open search, <kbd>Esc</kbd> to close.
73
73
  </div>
74
74
  </form>
75
+ {%- comment -%}
76
+ Results were never announced (issue #279): search rewrites the
77
+ container below without moving focus, so a screen-reader user
78
+ got silence — the visible list changed with nothing entering
79
+ the accessibility tree's notification queue.
80
+
81
+ The live region is this dedicated, visually-hidden element
82
+ rather than the results container itself. Marking the
83
+ container live would announce all eight result titles and
84
+ their snippets on every keystroke, which is unusable; a
85
+ screen-reader user wants "7 results for jekyll", then to
86
+ navigate the list on their own terms.
87
+
88
+ polite, not assertive: results land on each keystroke and an
89
+ assertive region would interrupt the user mid-word, cutting
90
+ off the query they are still typing.
91
+
92
+ aria-atomic so the summary is read as one message even when
93
+ only part of the string changes (8 results -> 7 results).
94
+ {%- endcomment -%}
95
+ <div class="visually-hidden"
96
+ role="status"
97
+ aria-live="polite"
98
+ aria-atomic="true"
99
+ data-search-status></div>
75
100
  <div class="search-results mt-3" data-search-results>
76
101
  <div class="text-muted small" data-search-empty>Start typing to see results.</div>
77
102
  </div>
@@ -1,9 +1,9 @@
1
1
  {% comment %} Feature: ZER0-032 {% endcomment %}
2
2
 
3
- <!--
3
+ {% comment %}
4
4
  title: Searchbar and hits
5
5
  source: Theme component
6
- -->
6
+ {% endcomment %}
7
7
  <div class="container order-1">
8
8
  <div id="searchbox" class="" ></div>
9
9
  <div id="hits" class="text-start"></div>
@@ -30,6 +30,9 @@
30
30
  <dt class="col-4 col-sm-3 text-end"><kbd>/</kbd></dt>
31
31
  <dd class="col-8 col-sm-9 mb-2">{{ ui.shortcuts_search | default: "Open search" }}</dd>
32
32
 
33
+ <dt class="col-4 col-sm-3 text-end"><kbd>⌘</kbd>/<kbd>Ctrl</kbd>+<kbd>K</kbd></dt>
34
+ <dd class="col-8 col-sm-9 mb-2">{{ ui.shortcuts_search | default: "Open search" }}</dd>
35
+
33
36
  <dt class="col-4 col-sm-3 text-end"><kbd>[</kbd></dt>
34
37
  <dd class="col-8 col-sm-9 mb-2">{{ ui.shortcuts_prev_section | default: "Previous section" }}</dd>
35
38
 
@@ -1,4 +1,4 @@
1
- <!--
1
+ {% comment %}
2
2
  ===================================================================
3
3
  SVG-BACKGROUND — Apply fffuel-style SVG background to a zone
4
4
  ===================================================================
@@ -20,7 +20,7 @@
20
20
  - _data/theme_backgrounds.yml (asset paths)
21
21
  - _config.yml theme_background (opacity / blend settings)
22
22
  ===================================================================
23
- -->
23
+ {% endcomment %}
24
24
 
25
25
  {% assign zone = include.zone | default: "body" %}
26
26
  {% assign skin = site.theme_skin | default: "dark" %}
@@ -1,4 +1,4 @@
1
- <!--
1
+ {% comment %}
2
2
  ===================================================================
3
3
  THEME CUSTOMIZER — Skin preview grid with live class swapping
4
4
  ===================================================================
@@ -12,7 +12,7 @@
12
12
  Dependencies: Bootstrap 5 grid/card, Bootstrap Icons
13
13
  Used by: pages/_about/settings/theme.md (Skin Preview tab)
14
14
  ===================================================================
15
- -->
15
+ {% endcomment %}
16
16
 
17
17
  {%- comment -%}
18
18
  _data/theme_skins.yml is optional for consumers (remote_theme cannot ship
@@ -1,5 +1,5 @@
1
1
  {% comment %} Feature: ZER0-021 {% endcomment %}
2
- <!--
2
+ {% comment %}
3
3
  ===================================================================
4
4
  THEME INFO - Compact Theme and Build Information
5
5
  ===================================================================
@@ -15,12 +15,12 @@
15
15
  Note: environment (Prod/Dev) is shown by env-switcher.html in the
16
16
  same Site tab — not duplicated here.
17
17
  ===================================================================
18
- -->
18
+ {% endcomment %}
19
19
 
20
20
  <div class="theme-info-compact">
21
21
  <div class="row g-2">
22
22
 
23
- <!-- Theme -->
23
+ {% comment %} Theme {% endcomment %}
24
24
  <div class="col-12">
25
25
  <div class="d-flex align-items-center justify-content-between p-2 bg-body-tertiary rounded">
26
26
  <div class="d-flex align-items-center">
@@ -44,7 +44,7 @@
44
44
  </div>
45
45
  </div>
46
46
 
47
- <!-- Jekyll & Last Build -->
47
+ {% comment %} Jekyll & Last Build {% endcomment %}
48
48
  <div class="col-6">
49
49
  <div class="p-2 bg-body-tertiary rounded text-center">
50
50
  <small class="text-body-secondary d-block">Jekyll</small>
@@ -54,12 +54,19 @@
54
54
  <div class="col-6">
55
55
  <div class="p-2 bg-body-tertiary rounded text-center">
56
56
  <small class="text-body-secondary d-block">Last Build</small>
57
- <code class="small">{{ site.time | date: "%b %d, %H:%M" }}</code>
57
+ {%- comment -%}
58
+ data-testid is the stable hook the pixel-snapshot tier masks on
59
+ (test/visual/features/appearance-snapshot.spec.js). This stamp has
60
+ minute resolution, so it becomes an unconditional snapshot flake the
61
+ moment this panel is shown by default rather than inside a collapsed
62
+ offcanvas. Don't remove the attribute without updating that mask.
63
+ {%- endcomment -%}
64
+ <code class="small" data-testid="theme-build-stamp">{{ site.time | date: "%b %d, %H:%M" }}</code>
58
65
  </div>
59
66
  </div>
60
67
 
61
68
  {% if site.repository %}
62
- <!-- Repository -->
69
+ {% comment %} Repository {% endcomment %}
63
70
  <div class="col-12">
64
71
  <div class="d-flex align-items-center justify-content-between p-2 bg-body-tertiary rounded">
65
72
  <div class="d-flex align-items-center">
@@ -74,7 +81,7 @@
74
81
  </div>
75
82
  {% endif %}
76
83
 
77
- <!-- Quick Links -->
84
+ {% comment %} Quick Links {% endcomment %}
78
85
  <div class="col-12 mt-2">
79
86
  <div class="d-flex flex-wrap gap-2 justify-content-center">
80
87
  {% if site.remote_theme %}
@@ -1,8 +1,8 @@
1
1
  {% comment %} Feature: ZER0-065 {% endcomment %}
2
- <!--
2
+ {% comment %}
3
3
  Theme Preview — component gallery for live skin / mode testing.
4
4
  Pair with theme-controls-bar.html and theme-customizer.js.
5
- -->
5
+ {% endcomment %}
6
6
  <div class="theme-preview-gallery" id="theme-preview-gallery">
7
7
 
8
8
  <p class="text-body-secondary">
@@ -11,7 +11,7 @@
11
11
  <code>theme_color</code> may take precedence over skin tokens for <code>--zer0-color-*</code> variables.
12
12
  </p>
13
13
 
14
- <!-- Typography -->
14
+ {% comment %} Typography {% endcomment %}
15
15
  <section class="theme-preview-section" id="preview-typography" aria-labelledby="preview-typography-heading">
16
16
  <h2 class="h4 theme-preview-heading" id="preview-typography-heading">
17
17
  <i class="bi bi-fonts me-2" aria-hidden="true"></i>Typography
@@ -33,7 +33,7 @@
33
33
  </div>
34
34
  </section>
35
35
 
36
- <!-- Buttons -->
36
+ {% comment %} Buttons {% endcomment %}
37
37
  <section class="theme-preview-section" id="preview-buttons" aria-labelledby="preview-buttons-heading">
38
38
  <h2 class="h4 theme-preview-heading" id="preview-buttons-heading">
39
39
  <i class="bi bi-hand-index-thumb me-2" aria-hidden="true"></i>Buttons
@@ -59,7 +59,7 @@
59
59
  </div>
60
60
  </section>
61
61
 
62
- <!-- Alerts -->
62
+ {% comment %} Alerts {% endcomment %}
63
63
  <section class="theme-preview-section" id="preview-alerts" aria-labelledby="preview-alerts-heading">
64
64
  <h2 class="h4 theme-preview-heading" id="preview-alerts-heading">
65
65
  <i class="bi bi-exclamation-triangle me-2" aria-hidden="true"></i>Alerts
@@ -72,7 +72,7 @@
72
72
  <div class="alert alert-info" role="alert">Info alert</div>
73
73
  </section>
74
74
 
75
- <!-- Cards -->
75
+ {% comment %} Cards {% endcomment %}
76
76
  <section class="theme-preview-section" id="preview-cards" aria-labelledby="preview-cards-heading">
77
77
  <h2 class="h4 theme-preview-heading" id="preview-cards-heading">
78
78
  <i class="bi bi-card-heading me-2" aria-hidden="true"></i>Cards
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
  </section>
102
102
 
103
- <!-- Forms -->
103
+ {% comment %} Forms {% endcomment %}
104
104
  <section class="theme-preview-section" id="preview-forms" aria-labelledby="preview-forms-heading">
105
105
  <h2 class="h4 theme-preview-heading" id="preview-forms-heading">
106
106
  <i class="bi bi-input-cursor-text me-2" aria-hidden="true"></i>Forms
@@ -134,7 +134,7 @@
134
134
  </div>
135
135
  </section>
136
136
 
137
- <!-- Nav tabs -->
137
+ {% comment %} Nav tabs {% endcomment %}
138
138
  <section class="theme-preview-section" id="preview-tabs" aria-labelledby="preview-tabs-heading">
139
139
  <h2 class="h4 theme-preview-heading" id="preview-tabs-heading">
140
140
  <i class="bi bi-layout-text-window-reverse me-2" aria-hidden="true"></i>Nav tabs
@@ -152,7 +152,7 @@
152
152
  </ul>
153
153
  </section>
154
154
 
155
- <!-- Badges -->
155
+ {% comment %} Badges {% endcomment %}
156
156
  <section class="theme-preview-section" id="preview-badges" aria-labelledby="preview-badges-heading">
157
157
  <h2 class="h4 theme-preview-heading" id="preview-badges-heading">
158
158
  <i class="bi bi-award me-2" aria-hidden="true"></i>Badges
@@ -168,7 +168,7 @@
168
168
  </p>
169
169
  </section>
170
170
 
171
- <!-- Code blocks -->
171
+ {% comment %} Code blocks {% endcomment %}
172
172
  <section class="theme-preview-section" id="preview-code" aria-labelledby="preview-code-heading">
173
173
  <h2 class="h4 theme-preview-heading" id="preview-code-heading">
174
174
  <i class="bi bi-code-slash me-2" aria-hidden="true"></i>Code blocks
@@ -214,7 +214,7 @@ docker-compose up
214
214
  {% endhighlight %}
215
215
  </section>
216
216
 
217
- <!-- Links -->
217
+ {% comment %} Links {% endcomment %}
218
218
  <section class="theme-preview-section" id="preview-links" aria-labelledby="preview-links-heading">
219
219
  <h2 class="h4 theme-preview-heading" id="preview-links-heading">
220
220
  <i class="bi bi-link-45deg me-2" aria-hidden="true"></i>Links
@@ -226,7 +226,7 @@ docker-compose up
226
226
  </p>
227
227
  </section>
228
228
 
229
- <!-- Navbar snippet -->
229
+ {% comment %} Navbar snippet {% endcomment %}
230
230
  <section class="theme-preview-section" id="preview-navbar" aria-labelledby="preview-navbar-heading">
231
231
  <h2 class="h4 theme-preview-heading" id="preview-navbar-heading">
232
232
  <i class="bi bi-layout-navbar me-2" aria-hidden="true"></i>Navbar snippet
@@ -244,7 +244,7 @@ docker-compose up
244
244
  </nav>
245
245
  </section>
246
246
 
247
- <!-- Footer snippet -->
247
+ {% comment %} Footer snippet {% endcomment %}
248
248
  <section class="theme-preview-section" id="preview-footer" aria-labelledby="preview-footer-heading">
249
249
  <h2 class="h4 theme-preview-heading" id="preview-footer-heading">
250
250
  <i class="bi bi-layout-text-sidebar-reverse me-2" aria-hidden="true"></i>Footer snippet
@@ -269,7 +269,7 @@ docker-compose up
269
269
  </footer>
270
270
  </section>
271
271
 
272
- <!-- Table -->
272
+ {% comment %} Table {% endcomment %}
273
273
  <section class="theme-preview-section" id="preview-table" aria-labelledby="preview-table-heading">
274
274
  <h2 class="h4 theme-preview-heading" id="preview-table-heading">
275
275
  <i class="bi bi-table me-2" aria-hidden="true"></i>Table
@@ -288,7 +288,7 @@ docker-compose up
288
288
  </div>
289
289
  </section>
290
290
 
291
- <!-- List group -->
291
+ {% comment %} List group {% endcomment %}
292
292
  <section class="theme-preview-section" id="preview-list-group" aria-labelledby="preview-list-group-heading">
293
293
  <h2 class="h4 theme-preview-heading" id="preview-list-group-heading">
294
294
  <i class="bi bi-list-ul me-2" aria-hidden="true"></i>List group
@@ -300,7 +300,7 @@ docker-compose up
300
300
  </ul>
301
301
  </section>
302
302
 
303
- <!-- Backgrounds -->
303
+ {% comment %} Backgrounds {% endcomment %}
304
304
  <section class="theme-preview-section" id="preview-backgrounds" aria-labelledby="preview-backgrounds-heading">
305
305
  <h2 class="h4 theme-preview-heading" id="preview-backgrounds-heading">
306
306
  <i class="bi bi-image me-2" aria-hidden="true"></i>Background layers
@@ -324,7 +324,7 @@ docker-compose up
324
324
  </div>
325
325
  </section>
326
326
 
327
- <!-- Callouts -->
327
+ {% comment %} Callouts {% endcomment %}
328
328
  <section class="theme-preview-section" id="preview-callouts" aria-labelledby="preview-callouts-heading">
329
329
  <h2 class="h4 theme-preview-heading" id="preview-callouts-heading">
330
330
  <i class="bi bi-chat-square-text me-2" aria-hidden="true"></i>Callouts
@@ -341,7 +341,7 @@ docker-compose up
341
341
  {% include components/callout.html type="danger" title="Danger" content=_danger_body %}
342
342
  </section>
343
343
 
344
- <!-- Accordion -->
344
+ {% comment %} Accordion {% endcomment %}
345
345
  <section class="theme-preview-section" id="preview-accordion" aria-labelledby="preview-accordion-heading">
346
346
  <h2 class="h4 theme-preview-heading" id="preview-accordion-heading">
347
347
  <i class="bi bi-chevron-bar-expand me-2" aria-hidden="true"></i>Accordion
@@ -382,7 +382,7 @@ docker-compose up
382
382
  </div>
383
383
  </section>
384
384
 
385
- <!-- Progress & Spinners -->
385
+ {% comment %} Progress & Spinners {% endcomment %}
386
386
  <section class="theme-preview-section" id="preview-progress" aria-labelledby="preview-progress-heading">
387
387
  <h2 class="h4 theme-preview-heading" id="preview-progress-heading">
388
388
  <i class="bi bi-hourglass-split me-2" aria-hidden="true"></i>Progress &amp; Spinners
@@ -434,7 +434,7 @@ docker-compose up
434
434
  </div>
435
435
  </section>
436
436
 
437
- <!-- Breadcrumb & Pagination -->
437
+ {% comment %} Breadcrumb & Pagination {% endcomment %}
438
438
  <section class="theme-preview-section" id="preview-breadcrumb" aria-labelledby="preview-breadcrumb-heading">
439
439
  <h2 class="h4 theme-preview-heading" id="preview-breadcrumb-heading">
440
440
  <i class="bi bi-signpost-split me-2" aria-hidden="true"></i>Breadcrumb &amp; Pagination
@@ -479,7 +479,7 @@ docker-compose up
479
479
  </div>
480
480
  </section>
481
481
 
482
- <!-- Tooltips & Popovers -->
482
+ {% comment %} Tooltips & Popovers {% endcomment %}
483
483
  <section class="theme-preview-section" id="preview-tooltips" aria-labelledby="preview-tooltips-heading">
484
484
  <h2 class="h4 theme-preview-heading" id="preview-tooltips-heading">
485
485
  <i class="bi bi-chat-dots me-2" aria-hidden="true"></i>Tooltips &amp; Popovers
@@ -503,7 +503,7 @@ docker-compose up
503
503
  </div>
504
504
  </section>
505
505
 
506
- <!-- Icons showcase -->
506
+ {% comment %} Icons showcase {% endcomment %}
507
507
  <section class="theme-preview-section" id="preview-icons" aria-labelledby="preview-icons-heading">
508
508
  <h2 class="h4 theme-preview-heading" id="preview-icons-heading">
509
509
  <i class="bi bi-grid me-2" aria-hidden="true"></i>Bootstrap Icons
@@ -1,5 +1,5 @@
1
1
  {% comment %} Feature: ZER0-035 {% endcomment %}
2
- <!--
2
+ {% comment %}
3
3
  giscus.html — GitHub Discussions comment system
4
4
  ===============================================
5
5
 
@@ -30,7 +30,7 @@
30
30
  NOTE: do not write a bare `include giscus.html` example with live Liquid
31
31
  braces inside this file — Liquid evaluates tags even inside HTML comments,
32
32
  which would recursively (and wrongly) try to include "giscus.html".
33
- -->
33
+ {% endcomment %}
34
34
 
35
35
  <script src="https://giscus.app/client.js"
36
36
  data-repo="{{ site.repository }}"
@@ -1,4 +1,4 @@
1
- <!--
1
+ {% comment %}
2
2
  file: _includes/content/intro.html
3
3
  description: Enhanced intro section with share, edit, and improve/report buttons
4
4
  path: _includes/content/intro.html
@@ -12,14 +12,14 @@
12
12
  - Responsive flex layout: full-width content block, frosted metadata footer with reading time and action buttons
13
13
  - Balanced padding and typography hierarchy via bd-intro-* classes
14
14
  - Metadata row: author, dates, category, difficulty, tags, view source
15
- -->
15
+ {% endcomment %}
16
16
  {%- include core/i18n.html -%}
17
17
  {% if page.collection %}
18
18
  {% capture page_dir %}{{ site.collections_dir }}{% endcapture %}
19
19
  {% assign testvar = "collection exists" %}
20
20
  {% endif %}
21
21
 
22
- <!-- Intro Section -->
22
+ {% comment %} Intro Section {% endcomment %}
23
23
 
24
24
  {% comment %}
25
25
  Determine the preview image path. Preview paths can omit the /assets/ prefix.
@@ -228,9 +228,9 @@
228
228
  {% endif %}
229
229
  </p>
230
230
 
231
- <!-- Action Buttons Group -->
231
+ {% comment %} Action Buttons Group {% endcomment %}
232
232
  <div class="bd-intro-actions">
233
- <!-- Share Button -->
233
+ {% comment %} Share Button {% endcomment %}
234
234
  <div class="dropdown">
235
235
  <button class="btn btn-sm btn-info dropdown-toggle" type="button" id="shareDropdownBottom" data-bs-toggle="dropdown" aria-expanded="false">
236
236
  <i class="bi bi-share" aria-hidden="true"></i>
@@ -273,10 +273,10 @@
273
273
  </ul>
274
274
  </div>
275
275
 
276
- <!-- Improve / Report — opens the page-feedback widget (assets/js/page-feedback.js).
276
+ {% comment %} Improve / Report — opens the page-feedback widget (assets/js/page-feedback.js).
277
277
  Progressive enhancement: this is a real link to the issue form, so it
278
278
  works without JavaScript; page-feedback.js intercepts [data-pf-open]
279
- clicks and opens the richer capture modal (context + logs + AI) instead. -->
279
+ clicks and opens the richer capture modal (context + logs + AI) instead. {% endcomment %}
280
280
  {% if site.page_feedback.enabled %}
281
281
  <a class="btn btn-sm btn-success bd-intro-action-link"
282
282
  href="https://github.com/{{ site.repository }}/issues/new?template=page_improvement.yml&labels=page-feedback"
@@ -289,7 +289,7 @@
289
289
  </a>
290
290
  {% endif %}
291
291
 
292
- <!-- Edit on GitHub Button -->
292
+ {% comment %} Edit on GitHub Button {% endcomment %}
293
293
  <a href="https://github.com/{{ site.repository }}/blob/{{ repo_branch }}/{{ file_path }}"
294
294
  class="btn btn-sm btn-dark bd-intro-action-link"
295
295
  target="_blank"
@@ -1,5 +1,5 @@
1
1
  {% comment %} Feature: ZER0-054 {% endcomment %}
2
- <!--
2
+ {% comment %}
3
3
  ===================================================================
4
4
  JSON-LD FAQ SCHEMA - FAQPage Structured Data
5
5
  ===================================================================
@@ -24,7 +24,7 @@
24
24
  Dependencies:
25
25
  - Page front matter with faq_items array
26
26
  ===================================================================
27
- -->
27
+ {% endcomment %}
28
28
 
29
29
  {% if page.faq_items and page.faq_items.size > 0 %}
30
30
  <script type="application/ld+json">
@@ -1,4 +1,4 @@
1
- <!--
1
+ {% comment %}
2
2
  ===================================================================
3
3
  JSON-LD STRUCTURED DATA - SoftwareApplication + WebPage Schema
4
4
  ===================================================================
@@ -9,22 +9,41 @@
9
9
  engines to accurately cite and describe the zer0-mistakes
10
10
  Jekyll theme as a SoftwareApplication entity.
11
11
 
12
+ OPT-IN ONLY — this describes THE THEME, not the site rendering it.
13
+ The payload below is hardcoded to zer0-mistakes: its RubyGems download
14
+ URL, its GitHub repository, its MIT licence, its feature list, its
15
+ mascot screenshot, and a Person node naming the theme's author. Emitted
16
+ from a consumer's homepage it asserts, in machine-readable form, that
17
+ THAT site is a free open-source Ruby gem authored by someone else — e.g.
18
+ a consulting practice's homepage claiming to be a developer tool.
19
+
20
+ It therefore renders only when a site explicitly opts in with
21
+ `jsonld_software_application: true` in _config.yml, which the theme's own
22
+ site does. Consumers get no software schema (their standard SEO metadata
23
+ is unaffected) unless they deliberately turn this on.
24
+
12
25
  Template Logic:
26
+ - Requires site.jsonld_software_application == true
13
27
  - Renders SoftwareApplication schema on the homepage only
14
28
  - Links to a WebPage wrapper via @id references
15
29
  - Pulls version, author, and description from site config
16
30
 
17
31
  Dependencies:
18
- - _config.yml: site.url, site.title, site.description, site.author
32
+ - _config.yml: jsonld_software_application, site.url, site.title,
33
+ site.description, site.author
19
34
  - lib/jekyll-theme-zer0/version.rb (version referenced in config)
20
35
 
21
36
  Usage:
22
37
  - Included automatically in _includes/core/head.html
23
- - Conditional: only renders when page.permalink == "/"
38
+ - Conditional: opted in AND page.permalink == "/"
24
39
  ===================================================================
25
- -->
40
+ {% endcomment %}
26
41
 
27
- {% if page.permalink == "/" or page.url == "/" %}
42
+ {%- assign _is_homepage = false -%}
43
+ {%- if page.permalink == "/" or page.url == "/" -%}
44
+ {%- assign _is_homepage = true -%}
45
+ {%- endif -%}
46
+ {% if site.jsonld_software_application and _is_homepage %}
28
47
  <script type="application/ld+json">
29
48
  {
30
49
  "@context": "https://schema.org",