jekyll-theme-zer0 1.27.0 → 1.29.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +812 -13
- data/_data/backlog.yml +356 -2
- data/_data/consumers.yml +252 -0
- data/_data/features.yml +234 -5
- data/_data/i18n/fr.yml +103 -0
- data/_data/i18n/manifest.yml +1529 -0
- data/_data/ingredient_densities.yml +122 -0
- data/_data/navigation/docs.yml +2 -0
- data/_data/navigation/main.yml +22 -0
- data/_data/recipe_courses.yml +64 -0
- data/_data/series.yml +19 -0
- data/_data/theme-manifest.yml +387 -277
- data/_data/ui-text.yml +8 -0
- data/_includes/README.md +36 -3
- data/_includes/analytics/google-tag-manager-body.html +11 -2
- data/_includes/analytics/google-tag-manager-head.html +16 -6
- data/_includes/analytics/posthog.html +33 -4
- data/_includes/components/abc-letter.html +43 -0
- data/_includes/components/background-customizer.html +2 -2
- data/_includes/components/book-card.html +42 -0
- data/_includes/components/book-nav.html +80 -0
- data/_includes/components/book-plate.html +31 -0
- data/_includes/components/book-toc.html +47 -0
- data/_includes/components/bookshelf.html +68 -0
- data/_includes/components/card-grid.html +60 -0
- data/_includes/components/cookie-consent.html +4 -4
- data/_includes/components/data-card.html +95 -0
- data/_includes/components/halfmoon.html +5 -1
- data/_includes/components/info-section.html +8 -3
- data/_includes/components/language-toggle.html +168 -21
- data/_includes/components/page-feedback.html +65 -2
- data/_includes/components/page-views-init.html +55 -0
- data/_includes/components/page-views.html +33 -0
- data/_includes/components/recipe-card.html +67 -0
- data/_includes/components/recipe-duration.html +50 -0
- data/_includes/components/recipe-grams.html +58 -0
- data/_includes/components/recipe-index.html +96 -0
- data/_includes/components/recipe-ingredients.html +90 -0
- data/_includes/components/recipe-meta.html +96 -0
- data/_includes/components/recipe-nutrition.html +57 -0
- data/_includes/components/recipe-qty.html +73 -0
- data/_includes/components/recipe-ratio.html +151 -0
- data/_includes/components/recipe-scaler.html +73 -0
- data/_includes/components/recipe-steps.html +86 -0
- data/_includes/components/recipe-temp.html +45 -0
- data/_includes/components/search-modal.html +2 -2
- data/_includes/components/shortcuts-modal.html +3 -0
- data/_includes/components/theme-controls-bar.html +10 -2
- data/_includes/components/theme-customizer.html +8 -2
- data/_includes/components/theme-info.html +8 -1
- data/_includes/content/jsonld-software.html +22 -3
- data/_includes/content/seo.html +9 -3
- data/_includes/core/color-mode-init.html +13 -4
- data/_includes/core/favicon.html +46 -0
- data/_includes/core/footer.html +18 -16
- data/_includes/core/head.html +21 -0
- data/_includes/core/header.html +7 -4
- data/_includes/custom/body-end.html +18 -0
- data/_includes/custom/body-start.html +17 -0
- data/_includes/custom/footer.html +18 -0
- data/_includes/custom/head.html +18 -0
- data/_includes/navigation/local-graph.html +28 -2
- data/_includes/navigation/nav-tree.html +3 -3
- data/_includes/navigation/section-sidebar.html +93 -11
- data/_includes/navigation/sidebar-config.html +21 -0
- data/_includes/navigation/sidebar-left.html +2 -1
- data/_includes/navigation/sidebar-nav.html +4 -0
- data/_includes/navigation/sidebar-pagetree.html +150 -0
- data/_includes/navigation/sidebar-right.html +2 -1
- data/_includes/navigation/unified-drawer.html +8 -2
- data/_includes/obsidian/full-graph.html +165 -136
- data/_includes/setup/wizard.html +173 -86
- data/_includes/stats/stats-metrics.html +2 -2
- data/_layouts/404.html +260 -0
- data/_layouts/README.md +4 -0
- data/_layouts/admin.html +2 -2
- data/_layouts/article.html +5 -0
- data/_layouts/book-abc.html +106 -0
- data/_layouts/book-story.html +91 -0
- data/_layouts/book.html +113 -0
- data/_layouts/collection.html +17 -5
- data/_layouts/cookbook.html +88 -0
- data/_layouts/default.html +4 -4
- data/_layouts/home.html +5 -2
- data/_layouts/landing.html +9 -0
- data/_layouts/news.html +155 -31
- data/_layouts/recipe.html +274 -0
- data/_layouts/root.html +38 -5
- data/_layouts/section.html +96 -25
- data/_sass/components/_book.scss +423 -0
- data/_sass/components/_callout.scss +1 -1
- data/_sass/components/_footer.scss +37 -1
- data/_sass/components/_page-views.scss +36 -0
- data/_sass/components/_recipe.scss +506 -0
- data/_sass/components/_setup-wizard.scss +235 -0
- data/_sass/components/_ui-enhancements.scss +6 -6
- data/_sass/core/_navbar.scss +263 -15
- data/_sass/core/_obsidian.scss +286 -6
- data/_sass/layouts/_landing.scss +2 -2
- data/_sass/theme/_backgrounds.scss +21 -8
- data/_sass/tokens/_color.scss +6 -0
- data/_sass/tokens/_index.scss +2 -0
- data/_sass/tokens/_radius.scss +21 -0
- data/_sass/tokens/_typography.scss +4 -0
- data/_sass/utilities/_focus.scss +14 -0
- data/assets/css/main.scss +4 -0
- data/assets/js/auto-hide-nav.js +5 -1
- data/assets/js/halfmoon.js +26 -0
- data/assets/js/modules/navigation/navbar.js +55 -0
- data/assets/js/obsidian-graph.js +702 -264
- data/assets/js/obsidian-local-graph.js +161 -54
- data/assets/js/page-views.js +372 -0
- data/assets/js/recipe-scaler.js +501 -0
- data/assets/js/search-modal.js +14 -1
- data/assets/js/setup-wizard.js +322 -20
- data/scripts/README.md +29 -0
- data/scripts/bin/audit-consumer +39 -7
- data/scripts/bin/giscus-discussions +213 -14
- data/scripts/bin/manifest +66 -16
- data/scripts/bin/validate +5 -1
- data/scripts/ci/agent_review_result.py +164 -0
- data/scripts/ci/test_agent_review_result.py +172 -0
- data/scripts/design-system-check.rb +170 -0
- data/scripts/install/README.md +47 -6
- data/scripts/install/ai/client.sh +302 -93
- data/scripts/install/ai/prompts/spec.schema.json +1 -1
- data/scripts/install/ai/wizard.sh +10 -5
- data/scripts/install/apply.sh +7 -3
- data/scripts/install/cli.sh +54 -4
- data/scripts/install/config.sh +167 -0
- data/scripts/install/doctor.sh +38 -0
- data/scripts/install/plan.sh +10 -0
- data/scripts/install/spec.sh +15 -7
- data/scripts/install/template.sh +4 -0
- data/scripts/lib/audit.sh +42 -2
- data/scripts/lint-liquid-raw.rb +137 -0
- data/scripts/propagate.rb +277 -0
- data/scripts/test/lib/run_tests.sh +2 -1
- data/scripts/test/lib/test_agent_review_result.sh +27 -0
- data/scripts/translate.rb +161 -15
- metadata +56 -2
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Feature: ZER0-084
|
|
3
|
+
layout: default
|
|
4
|
+
---
|
|
5
|
+
{%- comment -%}
|
|
6
|
+
Layout: cookbook.html
|
|
7
|
+
Extends: default.html
|
|
8
|
+
Purpose: Landing page for one cookbook — cover, introduction, a jump-nav of
|
|
9
|
+
its courses, and the full recipe index grouped by course.
|
|
10
|
+
Front matter required: layout, title, cookbook (slug shared with its recipes)
|
|
11
|
+
Front matter optional: subtitle, description, image/preview, author,
|
|
12
|
+
grouped (false for one flat grid)
|
|
13
|
+
Notes: Recipes belong to a cookbook by matching its `cookbook:` slug. Omit
|
|
14
|
+
`cookbook:` here and the page indexes EVERY recipe on the site, which
|
|
15
|
+
is what a single-cookbook site wants.
|
|
16
|
+
{%- endcomment -%}
|
|
17
|
+
|
|
18
|
+
{%- assign _cb_slug = page.cookbook -%}
|
|
19
|
+
{%- if _cb_slug -%}
|
|
20
|
+
{%- assign _cb_recipes = site.recipes | where_exp: "doc", "doc.layout != 'cookbook'" | where: "cookbook", _cb_slug -%}
|
|
21
|
+
{%- else -%}
|
|
22
|
+
{%- assign _cb_recipes = site.recipes | where_exp: "doc", "doc.layout != 'cookbook'" -%}
|
|
23
|
+
{%- endif -%}
|
|
24
|
+
{%- assign _cb_courses = _cb_recipes | map: "course" | compact | uniq -%}
|
|
25
|
+
{%- assign _cb_image = page.image | default: page.preview -%}
|
|
26
|
+
|
|
27
|
+
<div class="cookbook">
|
|
28
|
+
<!-- ================================ -->
|
|
29
|
+
<!-- COVER -->
|
|
30
|
+
<!-- ================================ -->
|
|
31
|
+
<header class="cookbook-header">
|
|
32
|
+
<div class="row g-4 align-items-center">
|
|
33
|
+
{%- if _cb_image -%}
|
|
34
|
+
<div class="col-8 col-sm-5 col-md-4 col-lg-3">
|
|
35
|
+
<div class="cookbook-cover">
|
|
36
|
+
{%- include components/preview-image.html src=_cb_image alt=page.title class="" loading="eager" -%}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
{%- endif -%}
|
|
40
|
+
<div class="col">
|
|
41
|
+
<h1 id="page-title" class="cookbook-title">{{ page.title }}</h1>
|
|
42
|
+
{%- if page.subtitle -%}
|
|
43
|
+
<p class="lead mb-2">{{ page.subtitle }}</p>
|
|
44
|
+
{%- endif -%}
|
|
45
|
+
{%- if page.author -%}
|
|
46
|
+
<p class="text-body-secondary small mb-2">By {{ page.author }}</p>
|
|
47
|
+
{%- endif -%}
|
|
48
|
+
<p class="text-body-secondary mb-3">
|
|
49
|
+
<i class="bi bi-egg-fried me-1" aria-hidden="true"></i>{{ _cb_recipes.size }} {% if _cb_recipes.size == 1 %}recipe{% else %}recipes{% endif %}
|
|
50
|
+
{%- if _cb_courses.size > 0 %} <span class="mx-1" aria-hidden="true">•</span> {{ _cb_courses.size }} {% if _cb_courses.size == 1 %}course{% else %}courses{% endif %}{% endif -%}
|
|
51
|
+
</p>
|
|
52
|
+
{%- if page.description -%}
|
|
53
|
+
<p class="cookbook-description">{{ page.description }}</p>
|
|
54
|
+
{%- endif -%}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</header>
|
|
58
|
+
|
|
59
|
+
<!-- ================================ -->
|
|
60
|
+
<!-- ABOUT (the markdown body) -->
|
|
61
|
+
<!-- ================================ -->
|
|
62
|
+
{%- assign _cb_body = content | strip -%}
|
|
63
|
+
{%- if _cb_body != "" -%}
|
|
64
|
+
<section class="cookbook-about">
|
|
65
|
+
{{ content }}
|
|
66
|
+
</section>
|
|
67
|
+
{%- endif -%}
|
|
68
|
+
|
|
69
|
+
<!-- ================================ -->
|
|
70
|
+
<!-- COURSE JUMP NAV -->
|
|
71
|
+
<!-- ================================ -->
|
|
72
|
+
{%- if _cb_courses.size > 1 and page.grouped != false -%}
|
|
73
|
+
<nav class="cookbook-jump" aria-label="Jump to a course">
|
|
74
|
+
{%- for _cb_pair in site.data.recipe_courses -%}
|
|
75
|
+
{%- if _cb_courses contains _cb_pair[0] -%}
|
|
76
|
+
<a class="btn btn-sm btn-outline-secondary" href="#course-{{ _cb_pair[0] }}">
|
|
77
|
+
<i class="bi {{ _cb_pair[1].icon | default: 'bi-journal-bookmark' }} me-1" aria-hidden="true"></i>{{ _cb_pair[1].title | default: _cb_pair[0] | escape }}
|
|
78
|
+
</a>
|
|
79
|
+
{%- endif -%}
|
|
80
|
+
{%- endfor -%}
|
|
81
|
+
</nav>
|
|
82
|
+
{%- endif -%}
|
|
83
|
+
|
|
84
|
+
<!-- ================================ -->
|
|
85
|
+
<!-- RECIPE INDEX -->
|
|
86
|
+
<!-- ================================ -->
|
|
87
|
+
{%- include components/recipe-index.html cookbook=_cb_slug grouped=page.grouped heading_level="h2" -%}
|
|
88
|
+
</div>
|
data/_layouts/default.html
CHANGED
|
@@ -93,12 +93,12 @@ layout: root
|
|
|
93
93
|
|
|
94
94
|
{%- comment -%}
|
|
95
95
|
Page introduction: title, breadcrumbs, metadata.
|
|
96
|
-
Skipped on layouts that render their own page header (article, note
|
|
97
|
-
to avoid duplicate H1s. Authors can also opt-out
|
|
98
|
-
`hide_intro: true` in front matter.
|
|
96
|
+
Skipped on layouts that render their own page header (article, note,
|
|
97
|
+
recipe, cookbook) to avoid duplicate H1s. Authors can also opt-out
|
|
98
|
+
per page via `hide_intro: true` in front matter.
|
|
99
99
|
{%- endcomment -%}
|
|
100
100
|
{% assign _skip_intro = false %}
|
|
101
|
-
{% if page.layout == "article" or page.layout == "note" or page.hide_intro %}
|
|
101
|
+
{% if page.layout == "article" or page.layout == "note" or page.layout == "recipe" or page.layout == "cookbook" or page.hide_intro %}
|
|
102
102
|
{% assign _skip_intro = true %}
|
|
103
103
|
{% endif %}
|
|
104
104
|
{% unless _skip_intro %}
|
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
|
-
|
|
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
|
|
data/_layouts/landing.html
CHANGED
|
@@ -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 -->
|
data/_layouts/news.html
CHANGED
|
@@ -15,11 +15,27 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
15
15
|
|
|
16
16
|
Front Matter Variables:
|
|
17
17
|
- section_style: Display style (magazine, grid, list) - default: magazine
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
Section Styles:
|
|
20
20
|
- magazine (default): Hero + category blocks + featured grid
|
|
21
21
|
- grid: All posts in unified card grid
|
|
22
22
|
- list: Chronological list view across all sections
|
|
23
|
+
|
|
24
|
+
Site Config (`news:` block in _config.yml — every key optional):
|
|
25
|
+
- news.category_base : base path for per-category section pages
|
|
26
|
+
(default "/news/"; e.g. "/categories/")
|
|
27
|
+
- news.hero : false to disable the latest-post hero fallback
|
|
28
|
+
(hero still shows for breaking/featured posts)
|
|
29
|
+
- news.archives_url : path of an archives page to deep-link months to;
|
|
30
|
+
defaults to "/archives/" WHEN that page exists,
|
|
31
|
+
otherwise month entries render unlinked
|
|
32
|
+
- news.newsletter : { enabled: false } hides the subscribe band;
|
|
33
|
+
{ endpoint: "https://..." } posts the form there;
|
|
34
|
+
with no endpoint it falls back to a mailto:
|
|
35
|
+
subscribe link (site.email) or hides itself
|
|
36
|
+
Sections come from _data/navigation/posts.yml when present; otherwise
|
|
37
|
+
they are derived automatically from site.categories, so the layout
|
|
38
|
+
renders fully on a data-less consumer site.
|
|
23
39
|
|
|
24
40
|
Layout Structure (NO SIDEBAR - Full Width):
|
|
25
41
|
1. News Header: Dark header with title and section navigation
|
|
@@ -41,12 +57,41 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
41
57
|
{% endcomment %}
|
|
42
58
|
{% assign section_style = page.section_style %}
|
|
43
59
|
|
|
44
|
-
{% comment %}
|
|
60
|
+
{% comment %}
|
|
45
61
|
Filter posts: exclude index files
|
|
46
62
|
Index files are marked with index: true in front matter
|
|
47
63
|
{% endcomment %}
|
|
48
64
|
{% assign all_posts = site.posts | where_exp: "post", "post.index != true" %}
|
|
49
65
|
|
|
66
|
+
{% comment %}
|
|
67
|
+
Resolve the news config surface once (see the header block above).
|
|
68
|
+
news_sections is a list of section NAMES: data-driven from
|
|
69
|
+
_data/navigation/posts.yml when that file exists, otherwise derived from
|
|
70
|
+
site.categories so a consumer without vendored nav data still gets a
|
|
71
|
+
fully working news homepage. Per-section url/icon are resolved at each
|
|
72
|
+
use site via section-nav lookup with a derived fallback.
|
|
73
|
+
{% endcomment %}
|
|
74
|
+
{% assign news_cfg = site.news %}
|
|
75
|
+
{% assign news_base = news_cfg.category_base | default: "/news/" %}
|
|
76
|
+
{% capture _sec_names %}{% for item in site.data.navigation.posts %}{{ item.title }}{% unless forloop.last %}|{% endunless %}{% endfor %}{% endcapture %}
|
|
77
|
+
{% if _sec_names == "" %}{% capture _sec_names %}{% for cat in site.categories limit: 8 %}{{ cat[0] }}{% unless forloop.last %}|{% endunless %}{% endfor %}{% endcapture %}{% endif %}
|
|
78
|
+
{% assign news_sections = _sec_names | split: "|" %}
|
|
79
|
+
|
|
80
|
+
{% comment %}
|
|
81
|
+
Tags index: honor the same site.tags_page convention as article.html.
|
|
82
|
+
When the key is not set explicitly, only link to /tags/ if such a page
|
|
83
|
+
actually exists in the build — a consumer without one gets unlinked tag
|
|
84
|
+
badges instead of site-wide 404 links.
|
|
85
|
+
{% endcomment %}
|
|
86
|
+
{% assign tags_base = site.tags_page | default: "/tags/" %}
|
|
87
|
+
{% assign _tags_linkable = false %}
|
|
88
|
+
{% if site.tags_page %}
|
|
89
|
+
{% assign _tags_linkable = true %}
|
|
90
|
+
{% else %}
|
|
91
|
+
{% assign _tags_index_page = site.html_pages | where: "url", tags_base | first %}
|
|
92
|
+
{% if _tags_index_page %}{% assign _tags_linkable = true %}{% endif %}
|
|
93
|
+
{% endif %}
|
|
94
|
+
|
|
50
95
|
<!-- ================================ -->
|
|
51
96
|
<!-- NEWS HEADER -->
|
|
52
97
|
<!-- ================================ -->
|
|
@@ -60,18 +105,26 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
60
105
|
</div>
|
|
61
106
|
<div class="col-md-8">
|
|
62
107
|
<nav class="nav nav-pills justify-content-md-end flex-wrap">
|
|
63
|
-
<a class="nav-link text-white active" href="{{
|
|
108
|
+
<a class="nav-link text-white active" href="{{ page.url | relative_url }}">
|
|
64
109
|
<i class="bi bi-house me-1"></i>Home
|
|
65
110
|
</a>
|
|
66
|
-
{% for
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{
|
|
111
|
+
{% for sec_name in news_sections %}
|
|
112
|
+
{% assign _sec_nav = site.data.navigation.posts | where: "title", sec_name | first %}
|
|
113
|
+
{% if _sec_nav %}
|
|
114
|
+
{% assign _sec_url = _sec_nav.url | replace: '/posts/', news_base %}
|
|
115
|
+
{% else %}
|
|
116
|
+
{% capture _sec_url %}{{ news_base }}{{ sec_name | slugify }}/{% endcapture %}
|
|
117
|
+
{% endif %}
|
|
118
|
+
<a class="nav-link text-white-50" href="{{ _sec_url | relative_url }}">
|
|
119
|
+
{% if _sec_nav.icon %}<i class="bi {{ _sec_nav.icon }} me-1"></i>{% endif %}
|
|
120
|
+
{{ sec_name }}
|
|
70
121
|
</a>
|
|
71
122
|
{% endfor %}
|
|
72
|
-
|
|
123
|
+
{% if _tags_linkable %}
|
|
124
|
+
<a class="nav-link text-white-50" href="{{ tags_base | relative_url }}">
|
|
73
125
|
<i class="bi bi-tags me-1"></i>Tags
|
|
74
126
|
</a>
|
|
127
|
+
{% endif %}
|
|
75
128
|
</nav>
|
|
76
129
|
</div>
|
|
77
130
|
</div>
|
|
@@ -92,11 +145,22 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
92
145
|
<!-- ================================ -->
|
|
93
146
|
{% assign breaking_posts = all_posts | where: "breaking", true %}
|
|
94
147
|
{% assign hero_post = breaking_posts | first %}
|
|
95
|
-
|
|
148
|
+
|
|
96
149
|
{% unless hero_post %}
|
|
97
150
|
{% assign hero_post = all_posts | where: "featured", true | first %}
|
|
98
151
|
{% endunless %}
|
|
99
|
-
|
|
152
|
+
|
|
153
|
+
{% comment %}
|
|
154
|
+
No post is marked breaking/featured: fall back to the newest post so the
|
|
155
|
+
hero never silently vanishes on sites that don't curate front matter.
|
|
156
|
+
Opt out with `news: { hero: false }` in _config.yml.
|
|
157
|
+
{% endcomment %}
|
|
158
|
+
{% unless hero_post %}
|
|
159
|
+
{% unless news_cfg.hero == false %}
|
|
160
|
+
{% assign hero_post = all_posts | first %}
|
|
161
|
+
{% endunless %}
|
|
162
|
+
{% endunless %}
|
|
163
|
+
|
|
100
164
|
{% if hero_post %}
|
|
101
165
|
<section class="hero-section mb-5">
|
|
102
166
|
<div class="row g-0 bg-body-secondary rounded-4 overflow-hidden shadow">
|
|
@@ -128,7 +192,8 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
128
192
|
</small>
|
|
129
193
|
{% endif %}
|
|
130
194
|
{% if hero_post.categories.size > 0 %}
|
|
131
|
-
|
|
195
|
+
{% capture _hero_cat_url %}{{ news_base }}{{ hero_post.categories | first | slugify }}/{% endcapture %}
|
|
196
|
+
<a href="{{ _hero_cat_url | relative_url }}" class="badge bg-primary text-decoration-none">
|
|
132
197
|
{{ hero_post.categories | first }}
|
|
133
198
|
</a>
|
|
134
199
|
{% endif %}
|
|
@@ -155,14 +220,20 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
155
220
|
<!-- ================================ -->
|
|
156
221
|
<section class="section-nav mb-5">
|
|
157
222
|
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-6 g-3">
|
|
158
|
-
{% for
|
|
159
|
-
{% assign section_posts = all_posts | where_exp: "post", "post.categories contains
|
|
223
|
+
{% for sec_name in news_sections %}
|
|
224
|
+
{% assign section_posts = all_posts | where_exp: "post", "post.categories contains sec_name" %}
|
|
225
|
+
{% assign _sec_nav = site.data.navigation.posts | where: "title", sec_name | first %}
|
|
226
|
+
{% if _sec_nav %}
|
|
227
|
+
{% assign _sec_url = _sec_nav.url | replace: '/posts/', news_base %}
|
|
228
|
+
{% else %}
|
|
229
|
+
{% capture _sec_url %}{{ news_base }}{{ sec_name | slugify }}/{% endcapture %}
|
|
230
|
+
{% endif %}
|
|
160
231
|
<div class="col">
|
|
161
|
-
<a href="{{
|
|
232
|
+
<a href="{{ _sec_url | relative_url }}"
|
|
162
233
|
class="card text-center h-100 text-decoration-none border-0 shadow-sm hover-lift">
|
|
163
234
|
<div class="card-body py-4">
|
|
164
|
-
<i class="bi {{
|
|
165
|
-
<h6 class="card-title mb-1">{{
|
|
235
|
+
<i class="bi {{ _sec_nav.icon | default: 'bi-folder' }} fs-2 text-primary mb-2 d-block"></i>
|
|
236
|
+
<h6 class="card-title mb-1">{{ sec_name }}</h6>
|
|
166
237
|
<small class="text-muted">{{ section_posts.size }} articles</small>
|
|
167
238
|
</div>
|
|
168
239
|
</a>
|
|
@@ -204,7 +275,8 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
204
275
|
</div>
|
|
205
276
|
<div class="card-body">
|
|
206
277
|
{% if main_featured.categories.size > 0 %}
|
|
207
|
-
|
|
278
|
+
{% capture _mf_cat_url %}{{ news_base }}{{ main_featured.categories | first | slugify }}/{% endcapture %}
|
|
279
|
+
<a href="{{ _mf_cat_url | relative_url }}"
|
|
208
280
|
class="badge bg-primary text-decoration-none mb-2">
|
|
209
281
|
{{ main_featured.categories | first }}
|
|
210
282
|
</a>
|
|
@@ -265,16 +337,22 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
265
337
|
<!-- ================================ -->
|
|
266
338
|
<!-- POSTS BY SECTION -->
|
|
267
339
|
<!-- ================================ -->
|
|
268
|
-
{% for
|
|
269
|
-
{% assign section_posts = all_posts | where_exp: "post", "post.categories contains
|
|
340
|
+
{% for sec_name in news_sections limit: 3 %}
|
|
341
|
+
{% assign section_posts = all_posts | where_exp: "post", "post.categories contains sec_name" %}
|
|
342
|
+
{% assign _sec_nav = site.data.navigation.posts | where: "title", sec_name | first %}
|
|
343
|
+
{% if _sec_nav %}
|
|
344
|
+
{% assign _sec_url = _sec_nav.url | replace: '/posts/', news_base %}
|
|
345
|
+
{% else %}
|
|
346
|
+
{% capture _sec_url %}{{ news_base }}{{ sec_name | slugify }}/{% endcapture %}
|
|
347
|
+
{% endif %}
|
|
270
348
|
{% if section_posts.size > 0 %}
|
|
271
349
|
<section class="section-posts mb-5 pb-4 border-bottom">
|
|
272
350
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
273
351
|
<h2 class="h4 mb-0">
|
|
274
|
-
<i class="bi {{
|
|
352
|
+
<i class="bi {{ _sec_nav.icon | default: 'bi-folder' }} text-primary me-2"></i>{{ sec_name }}
|
|
275
353
|
</h2>
|
|
276
|
-
<a href="{{
|
|
277
|
-
View All {{
|
|
354
|
+
<a href="{{ _sec_url | relative_url }}" class="btn btn-outline-secondary btn-sm">
|
|
355
|
+
View All {{ sec_name }} <i class="bi bi-arrow-right ms-1"></i>
|
|
278
356
|
</a>
|
|
279
357
|
</div>
|
|
280
358
|
|
|
@@ -351,7 +429,8 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
351
429
|
</div>
|
|
352
430
|
<div class="card-body">
|
|
353
431
|
{% if gpost.categories.size > 0 %}
|
|
354
|
-
|
|
432
|
+
{% capture _gpost_cat_url %}{{ news_base }}{{ gpost.categories | first | slugify }}/{% endcapture %}
|
|
433
|
+
<a href="{{ _gpost_cat_url | relative_url }}" class="badge bg-primary text-decoration-none mb-2">
|
|
355
434
|
{{ gpost.categories | first }}
|
|
356
435
|
</a>
|
|
357
436
|
{% endif %}
|
|
@@ -394,7 +473,8 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
394
473
|
<div class="card-body">
|
|
395
474
|
<div class="d-flex gap-2 mb-2 flex-wrap">
|
|
396
475
|
{% if lpost.categories.size > 0 %}
|
|
397
|
-
|
|
476
|
+
{% capture _lpost_cat_url %}{{ news_base }}{{ lpost.categories | first | slugify }}/{% endcapture %}
|
|
477
|
+
<a href="{{ _lpost_cat_url | relative_url }}" class="badge bg-primary text-decoration-none">
|
|
398
478
|
{{ lpost.categories | first }}
|
|
399
479
|
</a>
|
|
400
480
|
{% endif %}
|
|
@@ -511,15 +591,21 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
511
591
|
{% assign unique_tags = all_tags | uniq | slice: 0, 15 %}
|
|
512
592
|
<div class="d-flex flex-wrap gap-2">
|
|
513
593
|
{% for tag in unique_tags %}
|
|
514
|
-
|
|
594
|
+
{% if _tags_linkable %}
|
|
595
|
+
<a href="{{ tags_base | relative_url }}#{{ tag | slugify }}"
|
|
515
596
|
class="badge bg-secondary text-decoration-none fs-6">
|
|
516
597
|
{{ tag }}
|
|
517
598
|
</a>
|
|
599
|
+
{% else %}
|
|
600
|
+
<span class="badge bg-secondary fs-6">{{ tag }}</span>
|
|
601
|
+
{% endif %}
|
|
518
602
|
{% endfor %}
|
|
519
603
|
</div>
|
|
520
|
-
|
|
604
|
+
{% if _tags_linkable %}
|
|
605
|
+
<a href="{{ tags_base | relative_url }}" class="btn btn-sm btn-outline-primary mt-3">
|
|
521
606
|
Browse All Tags <i class="bi bi-arrow-right ms-1"></i>
|
|
522
607
|
</a>
|
|
608
|
+
{% endif %}
|
|
523
609
|
</div>
|
|
524
610
|
</div>
|
|
525
611
|
</div>
|
|
@@ -531,6 +617,17 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
531
617
|
<h5 class="card-title mb-3">
|
|
532
618
|
<i class="bi bi-archive me-2"></i>Archives
|
|
533
619
|
</h5>
|
|
620
|
+
{% comment %}
|
|
621
|
+
Month entries deep-link into an archives page only when one is
|
|
622
|
+
configured (news.archives_url) or a /archives/ page actually
|
|
623
|
+
exists — the theme ships no archives page, so an unconditional
|
|
624
|
+
link 404s on every consumer site.
|
|
625
|
+
{% endcomment %}
|
|
626
|
+
{% assign archives_url = news_cfg.archives_url %}
|
|
627
|
+
{% unless archives_url %}
|
|
628
|
+
{% assign _archives_page = site.html_pages | where: "url", "/archives/" | first %}
|
|
629
|
+
{% if _archives_page %}{% assign archives_url = "/archives/" %}{% endif %}
|
|
630
|
+
{% endunless %}
|
|
534
631
|
{% assign posts_by_year = all_posts | group_by_exp: "post", "post.date | date: '%Y'" %}
|
|
535
632
|
<div class="row">
|
|
536
633
|
{% for year in posts_by_year limit: 2 %}
|
|
@@ -540,11 +637,18 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
540
637
|
<ul class="list-unstyled small">
|
|
541
638
|
{% for month in months limit: 6 %}
|
|
542
639
|
<li class="mb-1">
|
|
543
|
-
|
|
640
|
+
{% if archives_url %}
|
|
641
|
+
<a href="{{ archives_url | relative_url }}#{{ month.name | slugify }}-{{ year.name }}"
|
|
544
642
|
class="text-decoration-none">
|
|
545
643
|
{{ month.name }}
|
|
546
644
|
<span class="badge bg-secondary text-body">{{ month.items.size }}</span>
|
|
547
645
|
</a>
|
|
646
|
+
{% else %}
|
|
647
|
+
<span>
|
|
648
|
+
{{ month.name }}
|
|
649
|
+
<span class="badge bg-secondary text-body">{{ month.items.size }}</span>
|
|
650
|
+
</span>
|
|
651
|
+
{% endif %}
|
|
548
652
|
</li>
|
|
549
653
|
{% endfor %}
|
|
550
654
|
</ul>
|
|
@@ -560,15 +664,28 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
560
664
|
<!-- ================================ -->
|
|
561
665
|
<!-- NEWSLETTER SIGNUP -->
|
|
562
666
|
<!-- ================================ -->
|
|
667
|
+
{% comment %}
|
|
668
|
+
Renders only when it can actually do something: a configured form
|
|
669
|
+
endpoint (news.newsletter.endpoint) posts for real; otherwise a
|
|
670
|
+
mailto: subscribe link on site.email. With neither — or with
|
|
671
|
+
news.newsletter.enabled: false — the band is omitted entirely
|
|
672
|
+
(the old markup shipped a form that submitted nowhere).
|
|
673
|
+
{% endcomment %}
|
|
674
|
+
{% assign _nl = news_cfg.newsletter %}
|
|
675
|
+
{% unless _nl.enabled == false %}
|
|
676
|
+
{% if _nl.endpoint or site.email %}
|
|
563
677
|
<section class="newsletter-section mb-5">
|
|
564
678
|
<div class="card border-0 bg-primary text-white">
|
|
565
679
|
<div class="card-body p-4 p-lg-5 text-center">
|
|
566
680
|
<i class="bi bi-envelope-paper fs-1 mb-3 d-block"></i>
|
|
567
|
-
<h3 class="mb-3">Stay Updated</h3>
|
|
568
|
-
<p class="mb-4 opacity-75">Subscribe to get the latest news and updates delivered to your inbox
|
|
569
|
-
|
|
681
|
+
<h3 class="mb-3">{{ _nl.heading | default: "Stay Updated" }}</h3>
|
|
682
|
+
<p class="mb-4 opacity-75">{{ _nl.lead | default: "Subscribe to get the latest news and updates delivered to your inbox." }}</p>
|
|
683
|
+
{% if _nl.endpoint %}
|
|
684
|
+
<form class="row g-2 justify-content-center" method="post" action="{{ _nl.endpoint }}">
|
|
570
685
|
<div class="col-md-4">
|
|
571
|
-
<
|
|
686
|
+
<label for="news-newsletter-email" class="visually-hidden">Email address</label>
|
|
687
|
+
<input type="email" id="news-newsletter-email" name="email" required
|
|
688
|
+
class="form-control form-control-lg" placeholder="Enter your email">
|
|
572
689
|
</div>
|
|
573
690
|
<div class="col-auto">
|
|
574
691
|
<button type="submit" class="btn btn-light btn-lg">
|
|
@@ -576,9 +693,16 @@ source: "https://getbootstrap.com/docs/5.3/examples/blog/#"
|
|
|
576
693
|
</button>
|
|
577
694
|
</div>
|
|
578
695
|
</form>
|
|
696
|
+
{% else %}
|
|
697
|
+
<a class="btn btn-light btn-lg" href="mailto:{{ site.email }}?subject=Subscribe%20to%20{{ site.title | uri_escape }}">
|
|
698
|
+
Subscribe <i class="bi bi-send ms-1"></i>
|
|
699
|
+
</a>
|
|
700
|
+
{% endif %}
|
|
579
701
|
</div>
|
|
580
702
|
</div>
|
|
581
703
|
</section>
|
|
704
|
+
{% endif %}
|
|
705
|
+
{% endunless %}
|
|
582
706
|
|
|
583
707
|
</div>
|
|
584
708
|
|