jekyll-theme-zer0 1.27.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +386 -4
  3. data/_data/consumers.yml +147 -0
  4. data/_data/features.yml +77 -5
  5. data/_data/i18n/fr.yml +98 -0
  6. data/_data/i18n/manifest.yml +1502 -0
  7. data/_data/navigation/docs.yml +2 -0
  8. data/_data/navigation/main.yml +6 -0
  9. data/_data/series.yml +19 -0
  10. data/_data/theme-manifest.yml +348 -266
  11. data/_includes/README.md +21 -2
  12. data/_includes/analytics/google-tag-manager-body.html +11 -2
  13. data/_includes/analytics/google-tag-manager-head.html +16 -6
  14. data/_includes/analytics/posthog.html +33 -4
  15. data/_includes/components/abc-letter.html +43 -0
  16. data/_includes/components/book-card.html +42 -0
  17. data/_includes/components/book-nav.html +80 -0
  18. data/_includes/components/book-plate.html +31 -0
  19. data/_includes/components/book-toc.html +47 -0
  20. data/_includes/components/bookshelf.html +68 -0
  21. data/_includes/components/card-grid.html +60 -0
  22. data/_includes/components/data-card.html +95 -0
  23. data/_includes/components/halfmoon.html +5 -1
  24. data/_includes/components/page-feedback.html +65 -2
  25. data/_includes/components/theme-controls-bar.html +10 -2
  26. data/_includes/components/theme-customizer.html +8 -2
  27. data/_includes/content/seo.html +9 -3
  28. data/_includes/core/color-mode-init.html +13 -4
  29. data/_includes/core/favicon.html +46 -0
  30. data/_includes/core/head.html +9 -0
  31. data/_includes/custom/body-end.html +18 -0
  32. data/_includes/custom/body-start.html +17 -0
  33. data/_includes/custom/footer.html +18 -0
  34. data/_includes/custom/head.html +18 -0
  35. data/_includes/navigation/local-graph.html +28 -2
  36. data/_includes/navigation/nav-tree.html +3 -3
  37. data/_includes/navigation/sidebar-config.html +21 -0
  38. data/_includes/navigation/sidebar-nav.html +4 -0
  39. data/_includes/navigation/sidebar-pagetree.html +150 -0
  40. data/_includes/navigation/unified-drawer.html +8 -2
  41. data/_includes/obsidian/full-graph.html +165 -136
  42. data/_layouts/404.html +260 -0
  43. data/_layouts/README.md +2 -0
  44. data/_layouts/book-abc.html +106 -0
  45. data/_layouts/book-story.html +91 -0
  46. data/_layouts/book.html +113 -0
  47. data/_layouts/collection.html +17 -5
  48. data/_layouts/home.html +5 -2
  49. data/_layouts/landing.html +9 -0
  50. data/_layouts/news.html +155 -31
  51. data/_layouts/root.html +16 -2
  52. data/_layouts/section.html +57 -15
  53. data/_sass/components/_book.scss +423 -0
  54. data/_sass/core/_navbar.scss +13 -0
  55. data/_sass/core/_obsidian.scss +286 -6
  56. data/_sass/theme/_backgrounds.scss +21 -8
  57. data/assets/css/main.scss +1 -0
  58. data/assets/js/auto-hide-nav.js +5 -1
  59. data/assets/js/halfmoon.js +26 -0
  60. data/assets/js/obsidian-graph.js +702 -264
  61. data/assets/js/obsidian-local-graph.js +161 -54
  62. data/assets/js/search-modal.js +4 -1
  63. data/scripts/bin/manifest +31 -4
  64. data/scripts/bin/validate +5 -1
  65. data/scripts/install/README.md +47 -6
  66. data/scripts/install/ai/client.sh +302 -93
  67. data/scripts/install/ai/prompts/spec.schema.json +1 -1
  68. data/scripts/install/ai/wizard.sh +10 -5
  69. data/scripts/install/apply.sh +7 -3
  70. data/scripts/install/cli.sh +54 -4
  71. data/scripts/install/config.sh +167 -0
  72. data/scripts/install/doctor.sh +38 -0
  73. data/scripts/install/plan.sh +10 -0
  74. data/scripts/install/spec.sh +15 -7
  75. data/scripts/install/template.sh +4 -0
  76. data/scripts/propagate.rb +277 -0
  77. data/scripts/translate.rb +90 -0
  78. metadata +27 -2
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
  ```
@@ -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
  <!-- ========================== -->
data/_layouts/home.html CHANGED
@@ -34,8 +34,11 @@ layout: root
34
34
  - title: displayed as <h1> (and used for SEO) when present
35
35
  - hide_title:true keep `title` for SEO but suppress the visible <h1>
36
36
  (useful when a custom hero provides its own heading)
37
+ - hide_intro:true accepted as an alias of hide_title — other layouts use
38
+ `hide_intro` for "suppress the generated page header",
39
+ and consumers reasonably reach for it here too
37
40
  - rss_subscribe:false hide the RSS subscribe link on landing/showcase homepages
38
- Both default to the original behavior, so existing homepages are unaffected.
41
+ All default to the original behavior, so existing homepages are unaffected.
39
42
 
40
43
  Design Philosophy:
41
44
  - Minimal structure allows for maximum content flexibility
@@ -56,7 +59,7 @@ layout: root
56
59
  <!-- Landing/showcase pages can keep `title` for SEO but suppress the -->
57
60
  <!-- visible heading (e.g. when a custom hero supplies its own <h1>) -->
58
61
  <!-- with `hide_title: true`. -->
59
- {%- if page.title and page.hide_title != true -%}
62
+ {%- if page.title and page.hide_title != true and page.hide_intro != true -%}
60
63
  <h1 class="page-heading">{{ page.title }}</h1>
61
64
  {%- endif -%}
62
65
 
@@ -182,6 +182,14 @@ layout: root
182
182
  <!-- ================================ -->
183
183
  <!-- QUICK START SECTION (data-driven)-->
184
184
  <!-- ================================ -->
185
+ {%- comment -%}
186
+ Rendered only when the site ships a `get_started` block in
187
+ _data/landing.yml. The install cards advertise THEME installation
188
+ (gem / Docker / fork), which is right for the theme's own site but wrong
189
+ boilerplate on a consumer landing page — a data-less consumer gets a
190
+ clean page instead of another site's marketing.
191
+ {%- endcomment -%}
192
+ {%- if landing.get_started -%}
185
193
  <section id="get-started" class="zer0-section" aria-labelledby="get-started-heading">
186
194
  <div class="container-xl py-5 px-4 px-md-5">
187
195
  <div class="row">
@@ -193,6 +201,7 @@ layout: root
193
201
  </div>
194
202
  </div>
195
203
  </section>
204
+ {%- endif -%}
196
205
 
197
206
  <!-- ================================ -->
198
207
  <!-- AUTHOR / E-E-A-T SECTION -->