jekyll-theme-zer0 1.26.0 → 1.28.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +558 -5
  3. data/README.md +10 -27
  4. data/_data/authors.yml +4 -3
  5. data/_data/backlog.yml +28 -0
  6. data/_data/consumers.yml +147 -0
  7. data/_data/features.yml +142 -23
  8. data/_data/i18n/fr.yml +98 -0
  9. data/_data/i18n/languages.yml +36 -0
  10. data/_data/i18n/manifest.yml +1502 -0
  11. data/_data/navigation/docs.yml +2 -0
  12. data/_data/navigation/main.yml +6 -0
  13. data/_data/series.yml +19 -0
  14. data/_data/theme-manifest.yml +348 -268
  15. data/_data/ui-text.yml +36 -246
  16. data/_includes/README.md +25 -2
  17. data/_includes/analytics/google-tag-manager-body.html +11 -2
  18. data/_includes/analytics/google-tag-manager-head.html +16 -6
  19. data/_includes/analytics/posthog.html +33 -4
  20. data/_includes/components/abc-letter.html +43 -0
  21. data/_includes/components/author-avatar-url.html +4 -2
  22. data/_includes/components/book-card.html +42 -0
  23. data/_includes/components/book-nav.html +80 -0
  24. data/_includes/components/book-plate.html +31 -0
  25. data/_includes/components/book-toc.html +47 -0
  26. data/_includes/components/bookshelf.html +68 -0
  27. data/_includes/components/card-grid.html +60 -0
  28. data/_includes/components/data-card.html +95 -0
  29. data/_includes/components/env-switcher.html +3 -1
  30. data/_includes/components/halfmoon.html +5 -1
  31. data/_includes/components/language-toggle.html +81 -0
  32. data/_includes/components/page-feedback.html +65 -2
  33. data/_includes/components/search-modal.html +2 -2
  34. data/_includes/components/shortcuts-modal.html +1 -1
  35. data/_includes/components/theme-controls-bar.html +10 -2
  36. data/_includes/components/theme-customizer.html +8 -2
  37. data/_includes/components/translation-notice.html +27 -0
  38. data/_includes/content/intro.html +16 -15
  39. data/_includes/content/seo.html +9 -3
  40. data/_includes/core/color-mode-init.html +13 -4
  41. data/_includes/core/favicon.html +46 -0
  42. data/_includes/core/footer.html +9 -4
  43. data/_includes/core/head.html +18 -0
  44. data/_includes/core/header.html +9 -4
  45. data/_includes/core/hreflang.html +33 -0
  46. data/_includes/core/i18n.html +36 -0
  47. data/_includes/custom/body-end.html +18 -0
  48. data/_includes/custom/body-start.html +17 -0
  49. data/_includes/custom/footer.html +18 -0
  50. data/_includes/custom/head.html +18 -0
  51. data/_includes/navigation/breadcrumbs.html +1 -1
  52. data/_includes/navigation/local-graph.html +28 -2
  53. data/_includes/navigation/nav-tree.html +3 -3
  54. data/_includes/navigation/navbar.html +5 -4
  55. data/_includes/navigation/sidebar-config.html +21 -0
  56. data/_includes/navigation/sidebar-nav.html +4 -0
  57. data/_includes/navigation/sidebar-pagetree.html +150 -0
  58. data/_includes/navigation/sidebar-right.html +3 -2
  59. data/_includes/navigation/unified-drawer.html +9 -3
  60. data/_includes/obsidian/full-graph.html +165 -136
  61. data/_layouts/404.html +260 -0
  62. data/_layouts/README.md +2 -0
  63. data/_layouts/article.html +7 -1
  64. data/_layouts/book-abc.html +106 -0
  65. data/_layouts/book-story.html +91 -0
  66. data/_layouts/book.html +113 -0
  67. data/_layouts/collection.html +17 -5
  68. data/_layouts/default.html +5 -3
  69. data/_layouts/home.html +5 -2
  70. data/_layouts/landing.html +9 -0
  71. data/_layouts/news.html +159 -33
  72. data/_layouts/root.html +29 -9
  73. data/_layouts/section.html +61 -17
  74. data/_sass/components/_book.scss +423 -0
  75. data/_sass/core/_navbar.scss +13 -0
  76. data/_sass/core/_obsidian.scss +295 -7
  77. data/_sass/layouts/_navbar-extras.scss +6 -1
  78. data/_sass/theme/_backgrounds.scss +21 -8
  79. data/assets/css/main.scss +1 -0
  80. data/assets/js/auto-hide-nav.js +5 -1
  81. data/assets/js/halfmoon.js +26 -0
  82. data/assets/js/obsidian-graph.js +707 -265
  83. data/assets/js/obsidian-local-graph.js +161 -54
  84. data/assets/js/search-modal.js +4 -1
  85. data/scripts/README.md +20 -26
  86. data/scripts/bin/audit-consumer +1 -1
  87. data/scripts/bin/manifest +31 -5
  88. data/scripts/bin/sync-plugins +0 -1
  89. data/scripts/bin/validate +5 -1
  90. data/scripts/dev/rasterize-svg.js +65 -0
  91. data/scripts/features/generate-preview-images +49 -1390
  92. data/scripts/features/install-preview-generator +55 -33
  93. data/scripts/install/README.md +55 -25
  94. data/scripts/install/ai/client.sh +302 -93
  95. data/scripts/install/ai/prompts/spec.schema.json +1 -1
  96. data/scripts/install/ai/prompts/wizard.system.md +8 -17
  97. data/scripts/install/ai/wizard.sh +10 -5
  98. data/scripts/install/apply.sh +7 -3
  99. data/scripts/install/cli.sh +54 -4
  100. data/scripts/install/config.sh +167 -0
  101. data/scripts/install/doctor.sh +38 -0
  102. data/scripts/install/plan.sh +10 -0
  103. data/scripts/install/spec.sh +15 -7
  104. data/scripts/install/template.sh +4 -0
  105. data/scripts/lib/README.md +1 -5
  106. data/scripts/lib/install/deploy/README.md +3 -9
  107. data/scripts/lib/preview_generator.py +2261 -1341
  108. data/scripts/propagate.rb +277 -0
  109. data/scripts/translate.rb +1204 -0
  110. metadata +34 -3
  111. data/_plugins/preview_image_generator.rb +0 -351
data/_layouts/404.html ADDED
@@ -0,0 +1,260 @@
1
+ ---
2
+ # Feature: ZER0-047
3
+ layout: root
4
+ ---
5
+ <!--
6
+ ===================================================================
7
+ 404 LAYOUT - Not-found page with unconfigured-site setup mode
8
+ ===================================================================
9
+
10
+ File: 404.html
11
+ Path: _layouts/404.html
12
+ Inherits: root.html
13
+ Purpose: Full 404 experience as a THEME layout so consumer sites only
14
+ vendor a tiny stub. Jekyll cannot deliver root pages from a
15
+ (remote) theme, but it can deliver layouts — a consumer's
16
+ /404.html shrinks to:
17
+
18
+ ---
19
+ permalink: /404.html
20
+ layout: "404"
21
+ sitemap: false
22
+ ---
23
+
24
+ Behavior:
25
+ - Unconfigured site (per components/setup-check.html): step-by-step
26
+ setup guide, branded with site.title when set.
27
+ - Configured site: standard 404 with search, existence-checked quick
28
+ links, and an optional GitHub issue shortcut.
29
+
30
+ Extra content: anything in the stub page's body renders below the
31
+ standard 404 content ({{ content }} at the bottom).
32
+ ===================================================================
33
+ -->
34
+
35
+ {% include components/setup-check.html %}
36
+
37
+ {% if site_needs_setup %}
38
+ <!-- ================================================================== -->
39
+ <!-- SETUP MODE: Site is not yet configured — guide the user -->
40
+ <!-- ================================================================== -->
41
+ <div class="container-lg py-5">
42
+ <div class="text-center mb-5">
43
+ <i class="bi bi-gear-wide-connected display-1 text-primary"></i>
44
+ <h1 class="display-4 fw-bold mt-3">Welcome to {{ site.title | default: "your new site" }}</h1>
45
+ <p class="lead text-body-secondary">
46
+ Your site is live but needs a little configuration.
47
+ Follow the steps below to make it yours.
48
+ </p>
49
+ </div>
50
+
51
+ <!-- Quick-detect: user site vs project site -->
52
+ <div class="row justify-content-center mb-4">
53
+ <div class="col-lg-8">
54
+ <div class="alert alert-info d-flex align-items-start" role="alert">
55
+ <i class="bi bi-info-circle-fill me-3 fs-4 mt-1"></i>
56
+ <div>
57
+ <strong>Detected deployment type:</strong>
58
+ {% if site_is_user_repo %}
59
+ <span class="badge bg-success">User / Org Site</span>
60
+ <code>{{ site.url }}</code>
61
+ <br><small>Your site resolves at the root — <code>baseurl</code> should be <code>""</code>.</small>
62
+ {% else %}
63
+ <span class="badge bg-warning text-dark">Project Site</span>
64
+ <code>{{ site.url }}{{ site.baseurl }}</code>
65
+ <br><small>Your site lives under a subpath — <code>baseurl</code> should be <code>"{{ site.baseurl | default: '/your-repo' }}"</code>.</small>
66
+ {% endif %}
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+
72
+ <!-- Step-by-step setup instructions -->
73
+ <div class="row justify-content-center">
74
+ <div class="col-lg-8">
75
+
76
+ <div class="card mb-4 border-primary">
77
+ <div class="card-header bg-primary text-white">
78
+ <i class="bi bi-1-circle me-2"></i>Step 1 — Update <code class="text-white">_config.yml</code>
79
+ </div>
80
+ <div class="card-body">
81
+ <p>Open <code>_config.yml</code> in your repository and update these essential fields:</p>
82
+ <pre class="bg-dark text-light p-3 rounded"><code># ── Site Identity
83
+ title: "Your Site Name"
84
+ description: "A short description of your site"
85
+ founder: "Your Name"
86
+ email: "you@example.com"
87
+
88
+ # ── GitHub
89
+ github_user: "{{ 'your-username' }}"
90
+ repository_name: "{{ 'your-repo' }}"
91
+
92
+ # ── URLs &amp; Deployment
93
+ {% if site_is_user_repo -%}
94
+ # User/Org site (username.github.io)
95
+ url: "https://your-username.github.io"
96
+ baseurl: ""
97
+ {%- else -%}
98
+ # Project site (username.github.io/repo-name)
99
+ url: "https://your-username.github.io"
100
+ baseurl: "/your-repo-name"
101
+ {%- endif %}
102
+
103
+ remote_theme: "bamr87/zer0-mistakes"
104
+
105
+ # ── Mark as configured (removes this setup page)
106
+ site_configured: true</code></pre>
107
+ </div>
108
+ </div>
109
+
110
+ <div class="card mb-4">
111
+ <div class="card-header">
112
+ <i class="bi bi-2-circle me-2"></i>Step 2 — Add a Home Page
113
+ </div>
114
+ <div class="card-body">
115
+ <p>If you don't have one yet, create <code>pages/index.html</code> (or <code>index.md</code>) with:</p>
116
+ <pre class="bg-dark text-light p-3 rounded"><code>---
117
+ layout: home
118
+ title: Home
119
+ ---
120
+
121
+ Welcome to my site!</code></pre>
122
+ </div>
123
+ </div>
124
+
125
+ <div class="card mb-4">
126
+ <div class="card-header">
127
+ <i class="bi bi-3-circle me-2"></i>Step 3 — Commit &amp; Push
128
+ </div>
129
+ <div class="card-body">
130
+ <pre class="bg-dark text-light p-3 rounded"><code>git add _config.yml pages/index.html
131
+ git commit -m "feat: configure site identity and home page"
132
+ git push origin main</code></pre>
133
+ <p class="mb-0 mt-2">
134
+ GitHub Pages will rebuild your site automatically. Within a few
135
+ minutes, your configured site will be live.
136
+ </p>
137
+ </div>
138
+ </div>
139
+
140
+ <div class="card mb-4 border-secondary">
141
+ <div class="card-header">
142
+ <i class="bi bi-lightbulb me-2"></i>Optional — Advanced Setup
143
+ </div>
144
+ <div class="card-body">
145
+ <div class="row g-3">
146
+ <div class="col-md-6">
147
+ <h6><i class="bi bi-palette me-1"></i> Personalization</h6>
148
+ <p class="small text-body-secondary mb-0">
149
+ Customise colors, navigation, analytics, and more.
150
+ </p>
151
+ <a href="{{ '/quickstart/personalization/' | relative_url }}" class="btn btn-sm btn-outline-primary mt-2">Personalization Guide</a>
152
+ </div>
153
+ <div class="col-md-6">
154
+ <h6><i class="bi bi-collection me-1"></i> Content Collections</h6>
155
+ <p class="small text-body-secondary mb-0">
156
+ Set up posts, docs, quests, and more content types.
157
+ </p>
158
+ <a href="{{ '/quickstart/' | relative_url }}" class="btn btn-sm btn-outline-primary mt-2">Quick Start Guide</a>
159
+ </div>
160
+ </div>
161
+ {% if jekyll.environment == "development" %}
162
+ <hr>
163
+ <p class="mb-0 small">
164
+ <i class="bi bi-tools me-1"></i>
165
+ <strong>Dev mode:</strong> You can use the
166
+ <a href="{{ '/setup/' | relative_url }}">interactive Setup Wizard</a>
167
+ to generate your config file.
168
+ </p>
169
+ {% endif %}
170
+ </div>
171
+ </div>
172
+
173
+ <!-- Resources -->
174
+ <div class="text-center mt-4">
175
+ <a href="https://github.com/bamr87/zer0-mistakes" class="btn btn-dark me-2" target="_blank" rel="noopener">
176
+ <i class="bi bi-github me-1"></i> Theme Repository
177
+ </a>
178
+ <a href="https://github.com/bamr87/zer0-mistakes/blob/main/README.md" class="btn btn-outline-secondary me-2" target="_blank" rel="noopener">
179
+ <i class="bi bi-book me-1"></i> Documentation
180
+ </a>
181
+ <a href="https://github.com/bamr87/zer0-mistakes/issues" class="btn btn-outline-danger" target="_blank" rel="noopener">
182
+ <i class="bi bi-bug me-1"></i> Report Issue
183
+ </a>
184
+ </div>
185
+
186
+ </div>
187
+ </div>
188
+ </div>
189
+
190
+ {% else %}
191
+ <!-- ================================================================== -->
192
+ <!-- NORMAL 404: Site is configured — show standard error page -->
193
+ <!-- ================================================================== -->
194
+ <div class="container text-center mt-5">
195
+ <h1 class="display-1 text-danger">404</h1>
196
+
197
+ <p class="h4 mt-4"><strong>Page not found 😿</strong></p>
198
+ <p class="lead">The requested page could not be found.</p>
199
+
200
+ <div class="my-4">
201
+ <p class="h5">Try searching for what you are looking for:</p>
202
+ <button class="btn btn-danger" type="button" data-search-toggle aria-label="Open search">
203
+ <i class="bi bi-search me-1"></i> Search
204
+ </button>
205
+ </div>
206
+
207
+ <div class="my-4">
208
+ <p class="h5">Or navigate to one of these pages:</p>
209
+ <div class="nav justify-content-center">
210
+ {% assign _404_candidates = "Home,/|About,/about/|Contact,/contact/" | split: "|" %}
211
+ {% for entry in _404_candidates %}
212
+ {% assign _parts = entry | split: "," %}
213
+ {% assign _label = _parts[0] %}
214
+ {% assign _url = _parts[1] %}
215
+ {% assign _page = site.html_pages | where: "url", _url | first %}
216
+ {% unless _page %}
217
+ {% for col in site.collections %}
218
+ {% assign _page = col.docs | where: "url", _url | first %}
219
+ {% if _page %}{% break %}{% endif %}
220
+ {% endfor %}
221
+ {% endunless %}
222
+ {% if _page or _url == "/" %}
223
+ <a class="nav-link" href="{{ _url | relative_url }}">{{ _label }}</a>
224
+ {% endif %}
225
+ {% endfor %}
226
+ </div>
227
+ </div>
228
+
229
+ <a class="btn btn-danger mt-4" href="{{ '/' | relative_url }}">Return to Homepage</a>
230
+ {% if site.github_user and site.repository_name %}
231
+ <div class="mt-3">
232
+ {% capture _issue_title %}404 Error{% endcapture %}
233
+ {% capture _issue_body %}I encountered a 404 error on this site. Please investigate.{% endcapture %}
234
+ <a id="github-issue-link"
235
+ class="btn btn-secondary"
236
+ href="https://github.com/{{ site.github_user }}/{{ site.repository_name }}/issues/new?title={{ _issue_title | uri_escape }}&body={{ _issue_body | uri_escape }}"
237
+ target="_blank"
238
+ rel="noopener noreferrer">
239
+ Submit an Issue on GitHub
240
+ </a>
241
+ </div>
242
+ <script>
243
+ document.addEventListener('DOMContentLoaded', function() {
244
+ var githubIssueLink = document.getElementById('github-issue-link');
245
+ if (!githubIssueLink) return;
246
+ var currentUrl = window.location.href;
247
+ var repoSlug = '{{ site.github_user }}/{{ site.repository_name }}';
248
+ githubIssueLink.href = 'https://github.com/' + repoSlug + '/issues/new?title=' + encodeURIComponent('404 Error on ' + currentUrl) + '&body=' + encodeURIComponent('I encountered a 404 error on the following page: ' + currentUrl + '. Please investigate.');
249
+ });
250
+ </script>
251
+ {% endif %}
252
+ </div>
253
+ {% endif %}
254
+
255
+ {% if content != blank %}
256
+ <!-- Extra content from the consumer's 404 stub body -->
257
+ <div class="container mt-4">
258
+ {{ content }}
259
+ </div>
260
+ {% endif %}
data/_layouts/README.md CHANGED
@@ -16,6 +16,8 @@ root.html (base template)
16
16
  ├── home.html (homepage)
17
17
  ├── news.html (news homepage - magazine/grid/list styles)
18
18
  ├── landing.html (landing pages)
19
+ ├── book.html (book landing page - cover hero + table of contents)
20
+ ├── book-story.html (immersive picture-book story pages)
19
21
  ├── stats.html (statistics dashboard)
20
22
  └── index.html (search pages)
21
23
  ```
@@ -15,6 +15,9 @@ layout: default
15
15
  Front Matter Variables:
16
16
  - post_type: Article type (standard, featured, breaking, opinion, review, tutorial, listicle, interview)
17
17
  - sidebar: Override sidebar visibility (true/false)
18
+ - show_hero: Opt into the top-of-article hero image (page.preview) for any
19
+ post_type without changing layout/sidebar/badges (true; featured and
20
+ breaking posts show the hero automatically)
18
21
 
19
22
  Post Type Variations:
20
23
  - standard (default): Normal article with sidebar
@@ -221,12 +224,15 @@ layout: default
221
224
  preview image is set. Breaking stories were previously skipped because the
222
225
  condition checked only post_type == "featured"; since breaking is mapped
223
226
  before featured (see top of file), breaking+featured posts showed no hero.
227
+ Any other post type can opt in with `show_hero: true` in front matter —
228
+ this flips only the hero, leaving sidebar, typography, and badges at their
229
+ post_type defaults (issue #303).
224
230
  Nested ifs keep the "only when page.preview exists" guard intact (Liquid has
225
231
  no parentheses, so a flat `a or b and c` would misgroup).
226
232
  {% endcomment %}
227
233
  {% assign show_hero = false %}
228
234
  {% if page.preview %}
229
- {% if post_type == "featured" or post_type == "breaking" %}
235
+ {% if post_type == "featured" or post_type == "breaking" or page.show_hero %}
230
236
  {% assign show_hero = true %}
231
237
  {% endif %}
232
238
  {% endif %}
@@ -0,0 +1,106 @@
1
+ ---
2
+ # Feature: ZER0-081
3
+ layout: root
4
+ ---
5
+ {%- comment -%}
6
+ Layout: book-abc.html
7
+ Extends: root.html
8
+ Purpose: Immersive single-scroll toddler ABC / alphabet "board book". One big
9
+ friendly letter per card — a picture, the word, and a read-aloud line
10
+ — built entirely from an `alphabet:` front-matter list (no per-letter
11
+ pages). Generated by the zer0-CMS ABC wizard.
12
+ Front matter required: layout, title, book (slug), alphabet (list of
13
+ {letter, word, tagline, image, alt, prompt, status})
14
+ Front matter optional: subtitle, series, audience, art_style (maps to a
15
+ abc-style--<id> skin), art_style_prompt, palette, cover_image, generator
16
+ Notes: Extends root directly (like book.html) for a sidebar-free surface.
17
+ Each card is anchored (#letter-a … #letter-z) for deep links.
18
+ {%- endcomment -%}
19
+
20
+ {%- assign _series = site.data.series[page.series] -%}
21
+ {%- assign _cover = page.cover_image | default: page.preview -%}
22
+ {%- assign _first = page.alphabet | first -%}
23
+
24
+ <article class="book-abc" itemscope itemtype="https://schema.org/Book">
25
+ <!-- ================================ -->
26
+ <!-- COVER HERO -->
27
+ <!-- ================================ -->
28
+ <header class="book-hero zer0-bg-hero py-5">
29
+ <div class="container-xl">
30
+ <div class="row g-5 align-items-center justify-content-center">
31
+ {%- if _cover -%}
32
+ <div class="col-8 col-sm-6 col-md-4 col-lg-3">
33
+ <div class="book-hero-cover mx-auto">
34
+ <div class="book-cover-frame">
35
+ {%- include components/preview-image.html src=_cover alt=page.title class="" loading="eager" -%}
36
+ </div>
37
+ </div>
38
+ </div>
39
+ {%- endif -%}
40
+ <div class="col-md-8 col-lg-7 text-center text-md-start">
41
+ {%- if _series -%}
42
+ <a class="badge text-bg-primary text-decoration-none mb-2" href="{{ '/books/' | relative_url }}#series-{{ page.series }}">
43
+ <i class="bi {{ _series.icon | default: 'bi-type' }} me-1" aria-hidden="true"></i>{{ _series.title | escape }}
44
+ </a>
45
+ {%- endif -%}
46
+ <h1 id="page-title" class="book-hero-title display-4 fw-bold" itemprop="name">{{ page.title }}</h1>
47
+ {%- if page.subtitle -%}
48
+ <p class="lead" itemprop="alternativeHeadline">{{ page.subtitle }}</p>
49
+ {%- endif -%}
50
+ <p class="text-body-secondary small mb-4">
51
+ <i class="bi bi-type me-1" aria-hidden="true"></i>{{ page.alphabet | size }} letters
52
+ {%- if page.audience %} <span class="mx-1" aria-hidden="true">•</span> {{ page.audience }}{% endif -%}
53
+ </p>
54
+ {%- assign _body = content | strip -%}
55
+ {%- if _body != "" -%}
56
+ <div class="fs-5" itemprop="abstract">{{ content }}</div>
57
+ {%- endif -%}
58
+ {%- if _first -%}
59
+ <a class="btn btn-primary btn-lg mt-2" href="#letter-{{ _first.letter | downcase }}">
60
+ <i class="bi bi-book-half me-2" aria-hidden="true"></i>Start at {{ _first.letter }}
61
+ </a>
62
+ {%- endif -%}
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </header>
67
+
68
+ <div class="container-xl py-5">
69
+
70
+ <!-- ================================ -->
71
+ <!-- A–Z QUICK JUMP -->
72
+ <!-- ================================ -->
73
+ <nav class="abc-jump" aria-label="Jump to a letter">
74
+ {%- for _e in page.alphabet -%}
75
+ <a class="abc-jump-link" href="#letter-{{ _e.letter | downcase }}">{{ _e.letter }}</a>
76
+ {%- endfor -%}
77
+ </nav>
78
+
79
+ <!-- ================================ -->
80
+ <!-- THE ALPHABET BOARD -->
81
+ <!-- ================================ -->
82
+ <div class="abc-board abc-style--{{ page.art_style | default: 'isometric-tech-toy' }}">
83
+ {%- for _e in page.alphabet -%}
84
+ {%- include components/abc-letter.html entry=_e -%}
85
+ {%- endfor -%}
86
+ </div>
87
+
88
+ <!-- ================================ -->
89
+ <!-- AI COLOPHON -->
90
+ <!-- ================================ -->
91
+ {%- if page.art_style_prompt or page.generator -%}
92
+ <aside class="book-colophon card border-0 bg-body-tertiary mt-5 mx-auto" style="max-width: var(--zer0-book-measure);">
93
+ <div class="card-body">
94
+ <h2 class="h6 mb-2"><i class="bi bi-stars me-2" aria-hidden="true"></i>How this book was made</h2>
95
+ {%- if page.generator -%}
96
+ <p class="small text-body-secondary mb-2">{{ page.generator }}</p>
97
+ {%- endif -%}
98
+ {%- if page.art_style_prompt -%}
99
+ <p class="small text-body-secondary mb-0"><strong>Art style ({{ page.art_style }}):</strong> {{ page.art_style_prompt }}</p>
100
+ {%- endif -%}
101
+ </div>
102
+ </aside>
103
+ {%- endif -%}
104
+
105
+ </div>
106
+ </article>
@@ -0,0 +1,91 @@
1
+ ---
2
+ # Feature: ZER0-080
3
+ layout: root
4
+ ---
5
+ {%- comment -%}
6
+ Layout: book-story.html
7
+ Extends: root.html
8
+ Purpose: Immersive picture-book reading page for one story/chapter — big
9
+ friendly type, illustration plates, prev/next story navigation,
10
+ and a collapsed illustration-prompt colophon.
11
+ Front matter required: layout, title, book (slug), chapter (number)
12
+ Front matter optional: chapter_label (e.g. "January"), description, preview,
13
+ illustrations (list of {beat, title, prompt, image}), the_end (false to
14
+ hide the closing flourish), comments
15
+ Notes: Extends root directly for a sidebar-free reading surface. Prev/next
16
+ come from numeric `chapter:` ordering via components/book-nav.html.
17
+ {%- endcomment -%}
18
+
19
+ {%- assign _slug = page.book -%}
20
+ {%- assign _book_page = site.books | where: "book", _slug | where: "layout", "book" | first -%}
21
+
22
+ <article class="book-story container-xl py-4 py-md-5" itemscope itemtype="https://schema.org/Chapter">
23
+ <!-- ================================ -->
24
+ <!-- STORY HEADER -->
25
+ <!-- ================================ -->
26
+ <header class="book-story-header text-center mb-4 mb-md-5">
27
+ {%- if _book_page -%}
28
+ <nav aria-label="Book">
29
+ <a class="text-decoration-none small" href="{{ _book_page.url | relative_url }}">
30
+ <i class="bi bi-book me-1" aria-hidden="true"></i>{{ _book_page.title }}
31
+ </a>
32
+ </nav>
33
+ {%- endif -%}
34
+ {%- if page.chapter_label -%}
35
+ <p class="text-uppercase small text-body-secondary mt-2 mb-1">{{ page.chapter_label }}</p>
36
+ {%- endif -%}
37
+ <h1 id="page-title" class="book-hero-title display-5 fw-bold" itemprop="name">{{ page.title }}</h1>
38
+ {%- if page.description -%}
39
+ <p class="lead text-body-secondary mx-auto" style="max-width: 42rem;">{{ page.description }}</p>
40
+ {%- endif -%}
41
+ </header>
42
+
43
+ <!-- ================================ -->
44
+ <!-- STORY BODY -->
45
+ <!-- ================================ -->
46
+ <div class="book-story-content" itemprop="text">
47
+ {{ content }}
48
+ </div>
49
+
50
+ {%- unless page.the_end == false -%}
51
+ <p class="book-the-end fs-4 mt-5">The End</p>
52
+ {%- endunless -%}
53
+
54
+ <!-- ================================ -->
55
+ <!-- STORY NAVIGATION -->
56
+ <!-- ================================ -->
57
+ {%- if page.chapter -%}
58
+ {%- include components/book-nav.html book=_slug chapter=page.chapter -%}
59
+ {%- endif -%}
60
+
61
+ <!-- ================================ -->
62
+ <!-- ILLUSTRATION COLOPHON -->
63
+ <!-- ================================ -->
64
+ {%- if page.illustrations and page.illustrations.size > 0 -%}
65
+ <details class="book-colophon mt-4">
66
+ <summary class="small"><i class="bi bi-stars me-1" aria-hidden="true"></i>How the illustrations in this story were made</summary>
67
+ <div class="mt-3 d-flex flex-column gap-3">
68
+ {%- for _ill in page.illustrations -%}
69
+ <div class="book-colophon-prompt">
70
+ <p class="mb-1 fw-semibold">
71
+ {%- if _ill.beat -%}{{ _ill.beat }}{%- if _ill.title %} — {% endif -%}{%- endif -%}
72
+ {{- _ill.title -}}
73
+ {%- if _ill.image == nil or _ill.status == "planned" %} <span class="badge text-bg-secondary ms-1">not yet generated</span>{% endif -%}
74
+ </p>
75
+ <p class="mb-0">{{ _ill.prompt | escape }}</p>
76
+ </div>
77
+ {%- endfor -%}
78
+ </div>
79
+ </details>
80
+ {%- endif -%}
81
+
82
+ <!-- ================================ -->
83
+ <!-- COMMENTS -->
84
+ <!-- ================================ -->
85
+ {%- if page.comments and site.giscus.enabled -%}
86
+ <section class="post-comments mt-5 pt-4 border-top" id="comments">
87
+ <h2 class="h4 mb-4"><i class="bi bi-chat-dots me-2" aria-hidden="true"></i>Comments</h2>
88
+ {%- include content/giscus.html -%}
89
+ </section>
90
+ {%- endif -%}
91
+ </article>
@@ -0,0 +1,113 @@
1
+ ---
2
+ # Feature: ZER0-080
3
+ layout: root
4
+ ---
5
+ {%- comment -%}
6
+ Layout: book.html
7
+ Extends: root.html
8
+ Purpose: Landing page for one book in the `books` collection — cover hero,
9
+ synopsis, table of contents, and an AI-provenance colophon.
10
+ Front matter required: layout, title, book (slug shared with its chapters)
11
+ Front matter optional: subtitle, author, illustrator, audience, synopsis,
12
+ cover_image, back_cover_image, illustration_style, status
13
+ Notes: Extends root directly (like landing.html) for an immersive,
14
+ sidebar-free presentation. Chapters are books-collection docs whose
15
+ `book:` matches and that set a numeric `chapter:`.
16
+ {%- endcomment -%}
17
+
18
+ {%- assign _slug = page.book | default: page.slug -%}
19
+ {%- assign _chapters = site.books | where: "book", _slug | where_exp: "doc", "doc.chapter" | sort: "chapter" -%}
20
+ {%- assign _first_chapter = _chapters | first -%}
21
+ {%- assign _cover = page.cover_image | default: page.preview -%}
22
+
23
+ <article class="book-landing" itemscope itemtype="https://schema.org/Book">
24
+ <!-- ================================ -->
25
+ <!-- COVER HERO -->
26
+ <!-- ================================ -->
27
+ <header class="book-hero zer0-bg-hero py-5">
28
+ <div class="container-xl">
29
+ <div class="row g-5 align-items-center justify-content-center">
30
+ {%- if _cover -%}
31
+ <div class="col-8 col-sm-6 col-md-4 col-lg-3">
32
+ <div class="book-hero-cover mx-auto">
33
+ <div class="book-cover-frame">
34
+ {%- include components/preview-image.html src=_cover alt=page.title class="" loading="eager" -%}
35
+ </div>
36
+ </div>
37
+ </div>
38
+ {%- endif -%}
39
+ <div class="col-md-8 col-lg-7 text-center text-md-start">
40
+ {%- if page.status and page.status != "complete" -%}
41
+ <span class="badge text-bg-warning mb-2">{{ page.status | capitalize }}</span>
42
+ {%- endif -%}
43
+ <h1 id="page-title" class="book-hero-title display-4 fw-bold" itemprop="name">{{ page.title }}</h1>
44
+ {%- if page.subtitle -%}
45
+ <p class="lead" itemprop="alternativeHeadline">{{ page.subtitle }}</p>
46
+ {%- endif -%}
47
+ <p class="text-body-secondary mb-1">
48
+ {%- if page.author -%}<span itemprop="author">{{ page.author }}</span>{%- endif -%}
49
+ {%- if page.illustrator %} <span class="mx-1" aria-hidden="true">•</span> Illustrated by {{ page.illustrator }}{%- endif -%}
50
+ </p>
51
+ <p class="text-body-secondary small mb-4">
52
+ <i class="bi bi-book me-1" aria-hidden="true"></i>{{ _chapters.size }} {% if _chapters.size == 1 %}story{% else %}stories{% endif %}
53
+ {%- if page.audience %} <span class="mx-1" aria-hidden="true">•</span> {{ page.audience }}{% endif -%}
54
+ </p>
55
+ {%- if page.synopsis -%}
56
+ <p class="fs-5" itemprop="abstract">{{ page.synopsis }}</p>
57
+ {%- endif -%}
58
+ {%- if _first_chapter -%}
59
+ <a class="btn btn-primary btn-lg mt-2" href="{{ _first_chapter.url | relative_url }}">
60
+ <i class="bi bi-book-half me-2" aria-hidden="true"></i>Start reading
61
+ </a>
62
+ {%- endif -%}
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </header>
67
+
68
+ <div class="container-xl py-5">
69
+ <div class="row justify-content-center">
70
+ <div class="col-lg-9 col-xl-8">
71
+
72
+ <!-- ================================ -->
73
+ <!-- ABOUT THIS BOOK (page body) -->
74
+ <!-- ================================ -->
75
+ {%- assign _body = content | strip -%}
76
+ {%- if _body != "" -%}
77
+ <section class="book-about mb-5">
78
+ {{ content }}
79
+ </section>
80
+ {%- endif -%}
81
+
82
+ <!-- ================================ -->
83
+ <!-- TABLE OF CONTENTS -->
84
+ <!-- ================================ -->
85
+ {%- include components/book-toc.html book=_slug -%}
86
+
87
+ <!-- ================================ -->
88
+ <!-- AI COLOPHON -->
89
+ <!-- ================================ -->
90
+ {%- if page.illustration_style or page.generator -%}
91
+ <aside class="book-colophon card border-0 bg-body-tertiary mt-5">
92
+ <div class="card-body">
93
+ <h2 class="h6 mb-2"><i class="bi bi-stars me-2" aria-hidden="true"></i>How this book was made</h2>
94
+ {%- if page.generator -%}
95
+ <p class="small text-body-secondary mb-2">{{ page.generator }}</p>
96
+ {%- endif -%}
97
+ {%- if page.illustration_style -%}
98
+ <p class="small text-body-secondary mb-0"><strong>Illustration style:</strong> {{ page.illustration_style }}</p>
99
+ {%- endif -%}
100
+ </div>
101
+ </aside>
102
+ {%- endif -%}
103
+
104
+ {%- if page.back_cover_image -%}
105
+ <figure class="book-plate mt-5">
106
+ {%- include components/preview-image.html src=page.back_cover_image alt="Back cover" class="book-plate-img" -%}
107
+ </figure>
108
+ {%- endif -%}
109
+
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </article>
@@ -53,13 +53,25 @@ layout: default
53
53
  <!-- ========================== -->
54
54
  <!-- COLLECTION DATA PROCESSING -->
55
55
  <!-- ========================== -->
56
- <!-- Extract and sort collection entries based on page configuration -->
56
+ <!-- Extract and sort collection entries based on page configuration.
57
+
58
+ Jekyll sets page.collection automatically for a document inside a
59
+ collection, but a standalone page can also select this layout in its front
60
+ matter. When it does — or when it names a collection the site does not
61
+ declare — site[page.collection] is nil, and `sort` on nil raises
62
+ "Cannot sort a null object.", which aborts the ENTIRE build rather than
63
+ just this page. Resolve to an empty list instead so one misconfigured page
64
+ cannot take the site down. -->
57
65
  {% assign entries = site[page.collection] %}
58
- {% assign entries = entries | sort: page.sort_order %}
66
+ {% if entries %}
67
+ {% assign entries = entries | sort: page.sort_order %}
59
68
 
60
- <!-- Handle reverse sorting if specified -->
61
- {% if page.sort_order == 'reverse' %}
62
- {% assign entries = entries | reverse %}
69
+ <!-- Handle reverse sorting if specified -->
70
+ {% if page.sort_order == 'reverse' %}
71
+ {% assign entries = entries | reverse %}
72
+ {% endif %}
73
+ {% else %}
74
+ {% assign entries = "" | split: "" %}
63
75
  {% endif %}
64
76
 
65
77
  <!-- ========================== -->
@@ -86,8 +86,10 @@ layout: root
86
86
  <!-- ================================ -->
87
87
  <!-- MAIN CONTENT AREA -->
88
88
  <!-- ================================ -->
89
- <!-- Primary content section with scroll spy for table of contents navigation -->
90
- <main class="bd-main order-1" data-bs-spy="scroll" data-bs-target="#TableOfContents" data-bs-offset="100" data-bs-smooth-scroll="true">
89
+ <!-- Primary content section with scroll spy for table of contents navigation.
90
+ Not a <main>: root.html already provides the single <main id="main-content">
91
+ landmark; a nested <main> here would duplicate it (issue #299). -->
92
+ <div class="bd-main order-1" data-bs-spy="scroll" data-bs-target="#TableOfContents" data-bs-offset="100" data-bs-smooth-scroll="true">
91
93
 
92
94
  {%- comment -%}
93
95
  Page introduction: title, breadcrumbs, metadata.
@@ -129,5 +131,5 @@ layout: root
129
131
  {% include content/backlinks.html %}
130
132
  {% endif %}
131
133
  </div>
132
- </main>
134
+ </div>
133
135
  </div>