jekyll-theme-zer0 1.28.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1143 -13
- data/_data/README.md +2 -0
- data/_data/ai.yml +5 -3
- data/_data/ai_pricing.yml +36 -0
- data/_data/backlog.yml +507 -2
- data/_data/consumers.yml +157 -9
- data/_data/features.yml +303 -20
- data/_data/feedback_types.yml +17 -12
- data/_data/i18n/fr.yml +12 -7
- data/_data/i18n/manifest.yml +39 -12
- data/_data/ingredient_densities.yml +122 -0
- data/_data/landing.yml +5 -2
- data/_data/navigation/main.yml +16 -0
- data/_data/navigation/quickstart.yml +4 -0
- data/_data/recipe_courses.yml +64 -0
- data/_data/site_builder.yml +874 -0
- data/_data/theme-manifest.yml +160 -124
- data/_data/ui-text.yml +26 -0
- data/_includes/README.md +26 -2
- data/_includes/analytics/posthog.html +2 -2
- data/_includes/components/admin-links.html +2 -2
- data/_includes/components/admin-tabs.html +2 -2
- data/_includes/components/ai-chat.html +14 -11
- data/_includes/components/analytics-dashboard.html +8 -8
- data/_includes/components/author-bio.html +1 -1
- data/_includes/components/author-card.html +10 -2
- data/_includes/components/author-eeat.html +4 -4
- data/_includes/components/background-customizer.html +10 -10
- data/_includes/components/background-image.html +114 -0
- data/_includes/components/background-settings.html +28 -15
- data/_includes/components/collection-manager.html +5 -5
- data/_includes/components/component-showcase.html +13 -13
- data/_includes/components/config-editor.html +12 -12
- data/_includes/components/config-viewer.html +8 -8
- data/_includes/components/cookie-consent.html +15 -15
- data/_includes/components/cta-button.html +7 -2
- data/_includes/components/dev-shortcuts.html +7 -7
- data/_includes/components/env-dashboard.html +8 -8
- data/_includes/components/env-switcher.html +9 -9
- data/_includes/components/feature-card.html +2 -2
- data/_includes/components/halfmoon.html +2 -2
- data/_includes/components/info-section.html +42 -37
- data/_includes/components/js-cdn.html +15 -15
- data/_includes/components/language-toggle.html +168 -21
- data/_includes/components/mermaid.html +72 -435
- data/_includes/components/nanobar.html +5 -5
- data/_includes/components/nav-editor.html +2 -2
- data/_includes/components/nav-export.html +2 -2
- data/_includes/components/nav-overview.html +2 -2
- data/_includes/components/page-feedback.html +45 -30
- data/_includes/components/page-views-init.html +55 -0
- data/_includes/components/page-views.html +33 -0
- data/_includes/components/post-card.html +22 -22
- data/_includes/components/post-type-badge.html +2 -2
- data/_includes/components/powered-by.html +2 -2
- data/_includes/components/preview-image.html +6 -0
- data/_includes/components/quick-index.html +2 -2
- 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 +29 -4
- data/_includes/components/searchbar.html +2 -2
- data/_includes/components/shortcuts-modal.html +3 -0
- data/_includes/components/svg-background.html +2 -2
- data/_includes/components/theme-customizer.html +2 -2
- data/_includes/components/theme-info.html +14 -7
- data/_includes/components/theme-preview-gallery.html +22 -22
- data/_includes/content/giscus.html +2 -2
- data/_includes/content/intro.html +8 -8
- data/_includes/content/jsonld-faq.html +2 -2
- data/_includes/content/jsonld-software.html +24 -5
- data/_includes/content/seo.html +4 -4
- data/_includes/content/sitemap.html +27 -27
- data/_includes/content/toc.html +183 -183
- data/_includes/core/branding.html +6 -6
- data/_includes/core/console-capture.html +32 -74
- data/_includes/core/favicon.html +49 -7
- data/_includes/core/footer-fabs.html +17 -3
- data/_includes/core/footer.html +49 -34
- data/_includes/core/head.html +110 -86
- data/_includes/core/header.html +76 -54
- data/_includes/docs/bootstrap-docs.html +8 -8
- data/_includes/landing/landing-install-cards.html +2 -2
- data/_includes/landing/landing-quick-links.html +1 -1
- data/_includes/navigation/admin-nav.html +2 -2
- data/_includes/navigation/nav-tree.html +8 -8
- data/_includes/navigation/navbar.html +12 -12
- data/_includes/navigation/section-sidebar.html +109 -27
- data/_includes/navigation/sidebar-config.html +36 -2
- data/_includes/navigation/sidebar-left.html +17 -16
- data/_includes/navigation/sidebar-right.html +8 -7
- data/_includes/obsidian/full-graph.html +2 -2
- data/_includes/setup/claude-session.html +72 -0
- data/_includes/setup/prereq-checklist.html +90 -0
- data/_includes/setup/wizard.html +924 -222
- data/_includes/stats/stats-categories.html +8 -8
- data/_includes/stats/stats-header.html +14 -14
- data/_includes/stats/stats-metrics.html +14 -14
- data/_includes/stats/stats-no-data.html +12 -12
- data/_includes/stats/stats-overview.html +6 -6
- data/_includes/stats/stats-tags.html +8 -8
- data/_layouts/404.html +38 -24
- data/_layouts/README.md +2 -0
- data/_layouts/admin.html +24 -24
- data/_layouts/article.html +43 -33
- data/_layouts/author.html +20 -20
- data/_layouts/authors.html +2 -2
- data/_layouts/book-abc.html +12 -12
- data/_layouts/book-story.html +15 -15
- data/_layouts/book.html +12 -12
- data/_layouts/collection.html +33 -33
- data/_layouts/cookbook.html +88 -0
- data/_layouts/default.html +31 -28
- data/_layouts/home.html +23 -23
- data/_layouts/index.html +10 -10
- data/_layouts/landing.html +17 -17
- data/_layouts/news.html +44 -44
- data/_layouts/note.html +38 -38
- data/_layouts/notebook.html +34 -34
- data/_layouts/recipe.html +274 -0
- data/_layouts/root.html +92 -55
- data/_layouts/section.html +62 -33
- data/_layouts/setup.html +3 -3
- data/_layouts/sitemap-collection.html +49 -49
- data/_layouts/stats.html +40 -40
- data/_layouts/tag.html +12 -12
- data/_layouts/welcome.html +21 -21
- data/_sass/components/_callout.scss +1 -1
- data/_sass/components/_footer.scss +37 -1
- data/_sass/components/_mermaid.scss +375 -0
- data/_sass/components/_page-views.scss +36 -0
- data/_sass/components/_recipe.scss +506 -0
- data/_sass/components/_setup-wizard.scss +764 -0
- data/_sass/components/_ui-enhancements.scss +6 -6
- data/_sass/core/_navbar.scss +261 -46
- data/_sass/layouts/_landing.scss +2 -2
- data/_sass/layouts/_navbar-extras.scss +14 -4
- 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/ai-chat.js +47 -5
- data/assets/js/fleet-feedback-capture.js +124 -0
- data/assets/js/fleet-feedback.js +853 -0
- data/assets/js/mermaid-diagrams.js +1267 -0
- data/assets/js/modules/navigation/config.js +9 -6
- data/assets/js/modules/navigation/navbar.js +55 -0
- data/assets/js/modules/navigation/scroll-spy.js +315 -80
- data/assets/js/modules/theme/appearance.js +8 -2
- data/assets/js/obsidian-wiki-links.js +8 -3
- data/assets/js/page-feedback.js +125 -192
- data/assets/js/page-views.js +372 -0
- data/assets/js/recipe-scaler.js +501 -0
- data/assets/js/search-modal.js +36 -0
- data/assets/js/setup-wizard.js +2279 -226
- data/assets/js/site-builder.js +1834 -0
- data/assets/js/ui-enhancements.js +11 -3
- data/scripts/README.md +44 -0
- data/scripts/ai/README.md +38 -0
- data/scripts/ai/api_call.rb +124 -0
- data/scripts/ai/usage.rb +314 -0
- data/scripts/ai/usage_report.rb +225 -0
- data/scripts/bin/audit-consumer +39 -7
- data/scripts/bin/giscus-discussions +213 -14
- data/scripts/bin/manifest +35 -12
- data/scripts/ci/agent_review_result.py +164 -0
- data/scripts/ci/test_agent_review_result.py +172 -0
- data/scripts/ci/test_visual_evidence_autogen.py +341 -0
- data/scripts/ci/visual_evidence_autogen.py +1060 -0
- data/scripts/content-review.rb +20 -1
- data/scripts/design-system-check.rb +170 -0
- data/scripts/lib/audit.sh +42 -2
- data/scripts/lint-liquid-raw.rb +137 -0
- data/scripts/test/integration/mermaid +22 -8
- data/scripts/test/lib/run_tests.sh +3 -1
- data/scripts/test/lib/test_agent_review_result.sh +27 -0
- data/scripts/test/lib/test_visual_evidence_autogen.sh +24 -0
- data/scripts/translate.rb +94 -16
- metadata +48 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% comment %} Feature: ZER0-046 {% endcomment %}
|
|
2
|
-
|
|
2
|
+
{% comment %}
|
|
3
3
|
===================================================================
|
|
4
4
|
INFO SECTION - Settings Offcanvas with Tabbed Interface
|
|
5
5
|
===================================================================
|
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
File: info-section.html
|
|
8
8
|
Path: _includes/components/info-section.html
|
|
9
9
|
Purpose: Unified settings offcanvas panel with three tabs —
|
|
10
|
-
Appearance (color mode, skin, backgrounds, primary color),
|
|
10
|
+
Appearance (language, color mode, skin, backgrounds, primary color),
|
|
11
11
|
Site (environment, theme & build info, admin links) and
|
|
12
12
|
Developer (page location, metadata, source shortcuts).
|
|
13
13
|
|
|
14
14
|
Dependencies:
|
|
15
15
|
- Bootstrap 5 Offcanvas, Tabs
|
|
16
16
|
- _includes/components/env-detect.html (sets is_production/build_env)
|
|
17
|
+
- _includes/components/language-toggle.html (panel variant — Language)
|
|
17
18
|
- _includes/components/halfmoon.html (color-mode segmented control)
|
|
18
19
|
- _includes/components/background-settings.html (skin + backgrounds)
|
|
19
20
|
- _includes/components/env-switcher.html
|
|
@@ -34,23 +35,23 @@
|
|
|
34
35
|
- https://getbootstrap.com/docs/5.3/components/offcanvas/
|
|
35
36
|
- https://getbootstrap.com/docs/5.3/components/navs-tabs/
|
|
36
37
|
===================================================================
|
|
37
|
-
|
|
38
|
+
{% endcomment %}
|
|
38
39
|
|
|
39
40
|
{% include components/env-detect.html %}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
{% comment %} Settings Offcanvas {% endcomment %}
|
|
42
43
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="info-section" aria-labelledby="infoSectionLabel">
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
{% comment %} Offcanvas Header {% endcomment %}
|
|
45
46
|
<div class="offcanvas-header border-bottom pb-0 d-block">
|
|
46
47
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
|
47
|
-
<
|
|
48
|
+
<h2 class="offcanvas-title h5" id="infoSectionLabel">
|
|
48
49
|
<i class="bi bi-gear-wide-connected me-2" aria-hidden="true"></i>Settings
|
|
49
|
-
</
|
|
50
|
+
</h2>
|
|
50
51
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
51
52
|
</div>
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
{% comment %} Tab Navigation {% endcomment %}
|
|
54
55
|
<ul class="nav nav-tabs nav-fill" id="infoTabs" role="tablist">
|
|
55
56
|
<li class="nav-item" role="presentation">
|
|
56
57
|
<button class="nav-link active" id="appearance-tab" data-bs-toggle="tab" data-bs-target="#appearance-pane" type="button" role="tab" aria-controls="appearance-pane" aria-selected="true">
|
|
@@ -75,25 +76,29 @@
|
|
|
75
76
|
</ul>
|
|
76
77
|
</div>
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
{% comment %} Offcanvas Body with Tab Content {% endcomment %}
|
|
79
80
|
<div class="offcanvas-body">
|
|
80
81
|
<div class="tab-content" id="infoTabContent">
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
{% comment %} Appearance Tab — everything that changes how the site looks {% endcomment %}
|
|
83
84
|
<div class="tab-pane fade show active" id="appearance-pane" role="tabpanel" aria-labelledby="appearance-tab" tabindex="0">
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
{% comment %} Language — renders its own heading, and nothing at all when
|
|
87
|
+
site.translation is disabled. NOT cached: page-dependent. {% endcomment %}
|
|
88
|
+
{% include components/language-toggle.html variant="panel" %}
|
|
89
|
+
|
|
90
|
+
{% comment %} Color Mode {% endcomment %}
|
|
86
91
|
<div class="mb-4">
|
|
87
|
-
<
|
|
92
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
88
93
|
<i class="bi bi-moon-stars me-1" aria-hidden="true"></i>Color Mode
|
|
89
|
-
</
|
|
94
|
+
</h3>
|
|
90
95
|
{% include components/halfmoon.html class="w-100" %}
|
|
91
96
|
</div>
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
{% comment %} Theme skin + SVG backgrounds (skin buttons, toggle, opacity) {% endcomment %}
|
|
94
99
|
{% include_cached components/background-settings.html %}
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
{% comment %} Primary color picker mounts here (appearance.js, optional) {% endcomment %}
|
|
97
102
|
<div id="zer0AppearanceSlot"></div>
|
|
98
103
|
|
|
99
104
|
<p class="text-body-secondary small mb-0 mt-4">
|
|
@@ -102,49 +107,49 @@
|
|
|
102
107
|
</p>
|
|
103
108
|
</div>
|
|
104
109
|
|
|
105
|
-
|
|
110
|
+
{% comment %} Site Tab — where the site runs and what it is built from {% endcomment %}
|
|
106
111
|
<div class="tab-pane fade" id="site-pane" role="tabpanel" aria-labelledby="site-tab" tabindex="0">
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
{% comment %} Environment {% endcomment %}
|
|
109
114
|
<div class="mb-4">
|
|
110
|
-
<
|
|
115
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
111
116
|
<i class="bi bi-hdd-network me-1" aria-hidden="true"></i>Environment
|
|
112
|
-
</
|
|
117
|
+
</h3>
|
|
113
118
|
{% include components/env-switcher.html %}
|
|
114
119
|
</div>
|
|
115
120
|
|
|
116
|
-
|
|
121
|
+
{% comment %} Theme & Build {% endcomment %}
|
|
117
122
|
<div class="mb-4">
|
|
118
|
-
<
|
|
123
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
119
124
|
<i class="bi bi-info-circle me-1" aria-hidden="true"></i>Theme & Build
|
|
120
|
-
</
|
|
125
|
+
</h3>
|
|
121
126
|
{% include components/theme-info.html %}
|
|
122
127
|
</div>
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
that exist in the build (see components/admin-links.html)
|
|
129
|
+
{% comment %} Admin quick links — cached include; renders only links to pages
|
|
130
|
+
that exist in the build (see components/admin-links.html) {% endcomment %}
|
|
126
131
|
{% include_cached components/admin-links.html %}
|
|
127
132
|
</div>
|
|
128
133
|
|
|
129
|
-
|
|
134
|
+
{% comment %} Developer Tab — tools scoped to the current page {% endcomment %}
|
|
130
135
|
<div class="tab-pane fade" id="developer-pane" role="tabpanel" aria-labelledby="developer-tab" tabindex="0">
|
|
131
136
|
|
|
132
|
-
|
|
133
|
-
when site.breadcrumbs is off, so the section mirrors that gate
|
|
137
|
+
{% comment %} Page Location — breadcrumbs render nothing on the homepage or
|
|
138
|
+
when site.breadcrumbs is off, so the section mirrors that gate {% endcomment %}
|
|
134
139
|
{% if page.url != "/" and site.breadcrumbs %}
|
|
135
140
|
<div class="mb-4">
|
|
136
|
-
<
|
|
141
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
137
142
|
<i class="bi bi-signpost-split me-1" aria-hidden="true"></i>Page Location
|
|
138
|
-
</
|
|
143
|
+
</h3>
|
|
139
144
|
{% include navigation/breadcrumbs.html %}
|
|
140
145
|
</div>
|
|
141
146
|
{% endif %}
|
|
142
147
|
|
|
143
|
-
|
|
148
|
+
{% comment %} Page Metadata {% endcomment %}
|
|
144
149
|
<div class="mb-4">
|
|
145
|
-
<
|
|
150
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
146
151
|
<i class="bi bi-file-earmark-code me-1" aria-hidden="true"></i>Page Info
|
|
147
|
-
</
|
|
152
|
+
</h3>
|
|
148
153
|
<div class="table-responsive">
|
|
149
154
|
<table class="table table-sm table-hover mb-0 small">
|
|
150
155
|
<tbody>
|
|
@@ -175,11 +180,11 @@
|
|
|
175
180
|
</div>
|
|
176
181
|
</div>
|
|
177
182
|
|
|
178
|
-
|
|
183
|
+
{% comment %} Source Code Shortcuts {% endcomment %}
|
|
179
184
|
<div class="mb-3">
|
|
180
|
-
<
|
|
185
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
181
186
|
<i class="bi bi-code-square me-1" aria-hidden="true"></i>Source Code
|
|
182
|
-
</
|
|
187
|
+
</h3>
|
|
183
188
|
{% include components/dev-shortcuts.html %}
|
|
184
189
|
</div>
|
|
185
190
|
</div>
|
|
@@ -189,9 +194,9 @@
|
|
|
189
194
|
|
|
190
195
|
</div>
|
|
191
196
|
|
|
192
|
-
|
|
197
|
+
{% comment %} Copy-to-clipboard for the panel's URL fields (event delegation; no
|
|
193
198
|
inline handlers). Buttons declare data-zer0-copy="<text>" or
|
|
194
|
-
data-zer0-copy-target="#input-id".
|
|
199
|
+
data-zer0-copy-target="#input-id". {% endcomment %}
|
|
195
200
|
<script>
|
|
196
201
|
document.addEventListener("click", function (e) {
|
|
197
202
|
var btn = e.target.closest("[data-zer0-copy], [data-zer0-copy-target]");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
{% comment %}
|
|
2
2
|
===================================================================
|
|
3
3
|
JAVASCRIPT - Local vendor libraries
|
|
4
4
|
===================================================================
|
|
@@ -12,43 +12,43 @@
|
|
|
12
12
|
|
|
13
13
|
Refresh: ./scripts/vendor-install.sh (see vendor-manifest.json)
|
|
14
14
|
===================================================================
|
|
15
|
-
|
|
15
|
+
{% endcomment %}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
{% comment %} Bootstrap 5.3.3 Bundle (includes Popper.js) {% endcomment %}
|
|
18
18
|
<script src="{{ '/assets/vendor/bootstrap/js/bootstrap.bundle.min.js' | relative_url }}"></script>
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
{% comment %} Navigation ES Modules — orchestrator for sidebar, scroll spy, keyboard
|
|
21
21
|
shortcuts, gestures, focus, AND the navbar dropdowns/mobile menu that
|
|
22
|
-
formerly lived in /assets/js/navigation.js (now deprecated).
|
|
22
|
+
formerly lived in /assets/js/navigation.js (now deprecated). {% endcomment %}
|
|
23
23
|
<script type="module" src="{{ '/assets/js/modules/navigation/index.js' | relative_url }}?v={{ site.time | date: '%s' }}"></script>
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
{% comment %} Generic UI helpers (toast, copy-to-clipboard, image fade-in) {% endcomment %}
|
|
26
26
|
<script defer src="{{ '/assets/js/ui-helpers.js' | relative_url }}"></script>
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
[data-posts-archive] container; safe to load globally).
|
|
28
|
+
{% comment %} Posts-archive pagination (auto-activates only on pages with a
|
|
29
|
+
[data-posts-archive] container; safe to load globally). {% endcomment %}
|
|
30
30
|
<script defer src="{{ '/assets/js/posts-pagination.js' | relative_url }}"></script>
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
{% comment %} Search modal controller {% endcomment %}
|
|
33
33
|
<script src="{{ '/assets/js/search-modal.js' | relative_url }}"></script>
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
{% comment %} Share helpers {% endcomment %}
|
|
36
36
|
<script src="{{ '/assets/js/share-actions.js' | relative_url }}"></script>
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
{% comment %} fffuel-style background customizer (skin switching, toggle, opacity) {% endcomment %}
|
|
39
39
|
<script src="{{ '/assets/js/background-customizer.js' | relative_url }}"></script>
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
{% comment %} Optional runtime Appearance panel (enabled via site.appearance_panel) {% endcomment %}
|
|
42
42
|
{% if site.appearance_panel %}
|
|
43
43
|
<script defer src="{{ '/assets/js/modules/theme/appearance.js' | relative_url }}"></script>
|
|
44
44
|
{% endif %}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
{% comment %} Obsidian wiki-link / embed / tag client-side resolver (fallback for the
|
|
47
47
|
remote_theme GH Pages build, where _plugins/obsidian_links.rb cannot run).
|
|
48
48
|
Honours `obsidian: { enabled: false }` in _config.yml — when disabled the
|
|
49
49
|
resolver script is not loaded and the flag self-disables any fork that
|
|
50
50
|
loads it another way. Note: `| default: true` would flip `false` back to
|
|
51
|
-
true (Liquid treats false as falsy), so test enabled == false explicitly.
|
|
51
|
+
true (Liquid treats false as falsy), so test enabled == false explicitly. {% endcomment %}
|
|
52
52
|
{%- assign obsidian_attachments_path = site.obsidian.attachments_path | default: '/assets/images/notes' -%}
|
|
53
53
|
<script>
|
|
54
54
|
window.OBSIDIAN_CONFIG = window.OBSIDIAN_CONFIG || {};
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
<script defer src="{{ '/assets/js/obsidian-wiki-links.js' | relative_url }}?v={{ site.time | date: '%s' }}"></script>
|
|
63
63
|
{%- endif -%}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
{% comment %} Optional fork overrides: opt-in via `site.user_overrides: true` in _config.yml. {% endcomment %}
|
|
66
66
|
{% if site.user_overrides %}
|
|
67
67
|
<script defer src="{{ '/assets/js/user-overrides.js' | relative_url }}"></script>
|
|
68
68
|
{% endif %}
|
|
@@ -2,24 +2,61 @@
|
|
|
2
2
|
{%- comment -%}
|
|
3
3
|
Component: language-toggle
|
|
4
4
|
Path: _includes/components/language-toggle.html
|
|
5
|
-
Purpose:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
Purpose: Switches between the English original and its machine-generated
|
|
6
|
+
translations (scripts/translate.rb). Shows the source language
|
|
7
|
+
plus every configured target language. Every entry is a live
|
|
8
|
+
link: a target without a generated translation for the current
|
|
9
|
+
page falls back to the source page and is explained by one
|
|
10
|
+
footnote (it used to render as a disabled entry — see T-038).
|
|
11
|
+
Params: variant (string, optional, default "navbar")
|
|
12
|
+
- "navbar" — compact dropdown for the header utility cluster
|
|
13
|
+
- "panel" — self-contained "Language" section for the
|
|
14
|
+
Settings offcanvas (components/info-section.html),
|
|
15
|
+
rendered as an always-visible list of choices
|
|
16
|
+
with its own section heading
|
|
17
|
+
Reads: page.lang / page.url / page.translation_source_url and the
|
|
18
|
+
generated _data/i18n/manifest.yml.
|
|
12
19
|
Depends on: site.translation.* config, site.data.i18n.manifest,
|
|
13
20
|
_data/i18n/languages.yml (display names), core/i18n.html,
|
|
14
|
-
Bootstrap 5 dropdown, Bootstrap Icons
|
|
21
|
+
Bootstrap 5 dropdown (navbar variant only), Bootstrap Icons
|
|
22
|
+
(bi-translate)
|
|
15
23
|
Notes: Renders nothing when translation is disabled or no target
|
|
16
24
|
languages are configured. The chosen language is remembered in
|
|
17
25
|
localStorage("zer0-lang") for future UX (no auto-redirect).
|
|
18
26
|
Must NOT be include_cached — the menu is page-dependent.
|
|
27
|
+
The theme ships the "panel" variant (the navbar is reserved for
|
|
28
|
+
main navigation); "navbar" stays for consumers that prefer the
|
|
29
|
+
header dropdown.
|
|
30
|
+
|
|
31
|
+
MENU CONTRACT (T-038 / #406) — shared by both variants:
|
|
32
|
+
* No DISABLED rows. A target language without a generated
|
|
33
|
+
translation is still a link; it goes to the source-language
|
|
34
|
+
page and still records the preference in zer0-lang, so the
|
|
35
|
+
menu never contains a dead end.
|
|
36
|
+
* The current language is marked with a check icon and a
|
|
37
|
+
subtle tint — NOT Bootstrap's `.active` primary fill, which
|
|
38
|
+
read as a selected nav item rather than "you are here".
|
|
39
|
+
* Machine-generated translations carry a small "auto" chip.
|
|
40
|
+
The source language never does (a human wrote it), and
|
|
41
|
+
neither do untranslated rows (nothing was generated).
|
|
42
|
+
* The per-row "(Not yet translated)" text is replaced by ONE
|
|
43
|
+
footnote under a divider, referenced from each untranslated
|
|
44
|
+
row via aria-describedby. Per-row text was the single
|
|
45
|
+
biggest contributor to menu width.
|
|
46
|
+
Trigger changes (icon-only, no caret) apply to the navbar
|
|
47
|
+
variant only — the panel has a section heading, not a button.
|
|
48
|
+
|
|
49
|
+
New ui keys (lang_machine_translated, lang_machine_translated_title,
|
|
50
|
+
lang_untranslated_note) live in _data/ui-text.yml `en`. core/i18n.html
|
|
51
|
+
REPLACES the whole `ui` map on a translated page rather than merging
|
|
52
|
+
it, so until scripts/translate.rb regenerates _data/i18n/<lang>.yml
|
|
53
|
+
these keys are absent there — every use below therefore carries a
|
|
54
|
+
literal `| default:` fallback. Do not remove them.
|
|
19
55
|
{%- endcomment -%}
|
|
20
56
|
{%- assign _lt_langs = site.translation.languages -%}
|
|
21
57
|
{%- if site.translation.enabled and _lt_langs and _lt_langs.size > 0 -%}
|
|
22
58
|
{%- include core/i18n.html -%}
|
|
59
|
+
{%- assign _lt_variant = include.variant | default: 'navbar' -%}
|
|
23
60
|
{%- assign _lt_source = site.translation.source_lang | default: 'en' -%}
|
|
24
61
|
{%- assign _lt_current = page.lang | default: _lt_source -%}
|
|
25
62
|
{%- if _lt_current == _lt_source -%}
|
|
@@ -30,25 +67,117 @@
|
|
|
30
67
|
{%- assign _lt_entry = site.data.i18n.manifest.pages[_lt_src_url] -%}
|
|
31
68
|
{%- assign _lt_names = site.data.i18n.languages -%}
|
|
32
69
|
{%- assign _lt_source_name = _lt_names[_lt_source].native | default: _lt_source -%}
|
|
70
|
+
{%- comment -%}
|
|
71
|
+
Display name of the language being read, for the trigger's title/aria — the
|
|
72
|
+
icon-only button has no visible text, so the accessible name has to carry it.
|
|
73
|
+
{%- endcomment -%}
|
|
74
|
+
{%- if _lt_current == _lt_source -%}
|
|
75
|
+
{%- assign _lt_current_name = _lt_source_name -%}
|
|
76
|
+
{%- else -%}
|
|
77
|
+
{%- assign _lt_current_name = _lt_names[_lt_current].native | default: _lt_current -%}
|
|
78
|
+
{%- endif -%}
|
|
79
|
+
{%- comment -%}
|
|
80
|
+
Does ANY target language lack a translation of this page? Drives whether the
|
|
81
|
+
footnote + divider render at all — an all-translated menu shows neither.
|
|
82
|
+
A target we are currently reading is by definition translated.
|
|
83
|
+
{%- endcomment -%}
|
|
84
|
+
{%- assign _lt_untranslated = 0 -%}
|
|
85
|
+
{%- for _lt_l in _lt_langs -%}
|
|
86
|
+
{%- unless _lt_l == _lt_current or _lt_entry[_lt_l] -%}
|
|
87
|
+
{%- assign _lt_untranslated = _lt_untranslated | plus: 1 -%}
|
|
88
|
+
{%- endunless -%}
|
|
89
|
+
{%- endfor -%}
|
|
90
|
+
{%- assign _lt_note_id = 'zer0-lang-untranslated-note' -%}
|
|
91
|
+
{%- assign _lt_auto_label = ui.lang_machine_translated | default: 'auto' -%}
|
|
92
|
+
{%- assign _lt_auto_title = ui.lang_machine_translated_title | default: 'Machine-generated translation' -%}
|
|
93
|
+
{%- assign _lt_note_text = ui.lang_untranslated_note | default: 'Marked languages are not yet translated — those links open the original.' -%}
|
|
94
|
+
{%- assign _lt_fallback_url = _lt_src_url | default: '/' | relative_url -%}
|
|
95
|
+
{%- if _lt_variant == 'panel' -%}
|
|
96
|
+
<div class="mb-4 nav-lang-panel" id="zer0-lang-toggle">
|
|
97
|
+
<h3 class="h6 text-body-secondary small text-uppercase fw-semibold mb-2">
|
|
98
|
+
<i class="bi bi-translate me-1" aria-hidden="true"></i>{{ ui.lang_toggle_label | default: "Language" }}
|
|
99
|
+
</h3>
|
|
100
|
+
<div class="list-group nav-lang-options" role="group" aria-label="{{ ui.lang_toggle_aria | default: 'Change language' }}">
|
|
101
|
+
{%- if _lt_current == _lt_source %}
|
|
102
|
+
<span class="list-group-item nav-lang-item is-current" aria-current="true">
|
|
103
|
+
<span class="nav-lang-code">{{ _lt_source | slice: 0, 2 | upcase }}</span>
|
|
104
|
+
<span class="nav-lang-name">{{ _lt_source_name }}</span>
|
|
105
|
+
<i class="bi bi-check2 nav-lang-check" aria-hidden="true"></i>
|
|
106
|
+
</span>
|
|
107
|
+
{%- else %}
|
|
108
|
+
<a class="list-group-item list-group-item-action nav-lang-item" data-lang="{{ _lt_source }}" hreflang="{{ _lt_source }}" href="{{ _lt_fallback_url }}">
|
|
109
|
+
<span class="nav-lang-code">{{ _lt_source | slice: 0, 2 | upcase }}</span>
|
|
110
|
+
<span class="nav-lang-name">{{ _lt_source_name }}</span>
|
|
111
|
+
</a>
|
|
112
|
+
{%- endif %}
|
|
113
|
+
{%- for _lt_lang in _lt_langs -%}
|
|
114
|
+
{%- assign _lt_name = _lt_names[_lt_lang].native | default: _lt_lang -%}
|
|
115
|
+
{%- assign _lt_t = _lt_entry[_lt_lang] %}
|
|
116
|
+
{%- if _lt_current == _lt_lang %}
|
|
117
|
+
<span class="list-group-item nav-lang-item is-current" aria-current="true">
|
|
118
|
+
<span class="nav-lang-code">{{ _lt_lang | slice: 0, 2 | upcase }}</span>
|
|
119
|
+
<span class="nav-lang-name">{{ _lt_name }}</span>
|
|
120
|
+
<span class="nav-lang-auto" title="{{ _lt_auto_title }}">{{ _lt_auto_label }}</span>
|
|
121
|
+
<i class="bi bi-check2 nav-lang-check" aria-hidden="true"></i>
|
|
122
|
+
</span>
|
|
123
|
+
{%- elsif _lt_t %}
|
|
124
|
+
<a class="list-group-item list-group-item-action nav-lang-item" data-lang="{{ _lt_lang }}" hreflang="{{ _lt_lang }}" href="{{ _lt_t.url | relative_url }}">
|
|
125
|
+
<span class="nav-lang-code">{{ _lt_lang | slice: 0, 2 | upcase }}</span>
|
|
126
|
+
<span class="nav-lang-name">{{ _lt_name }}</span>
|
|
127
|
+
<span class="nav-lang-auto" title="{{ _lt_auto_title }}">{{ _lt_auto_label }}</span>
|
|
128
|
+
</a>
|
|
129
|
+
{%- else %}
|
|
130
|
+
{%- comment -%}
|
|
131
|
+
No translation yet — still a LINK, not a disabled row. It goes to the
|
|
132
|
+
source page and records the preference, so the reader lands on real
|
|
133
|
+
content instead of a dead entry. hreflang describes the DESTINATION,
|
|
134
|
+
which is the source language, not the one that was clicked.
|
|
135
|
+
{%- endcomment -%}
|
|
136
|
+
<a class="list-group-item list-group-item-action nav-lang-item is-untranslated" data-lang="{{ _lt_lang }}" hreflang="{{ _lt_source }}" href="{{ _lt_fallback_url }}" aria-describedby="{{ _lt_note_id }}-panel">
|
|
137
|
+
<span class="nav-lang-code">{{ _lt_lang | slice: 0, 2 | upcase }}</span>
|
|
138
|
+
<span class="nav-lang-name">{{ _lt_name }}</span>
|
|
139
|
+
<span class="nav-lang-mark" aria-hidden="true">*</span>
|
|
140
|
+
</a>
|
|
141
|
+
{%- endif %}
|
|
142
|
+
{%- endfor %}
|
|
143
|
+
</div>
|
|
144
|
+
{%- if _lt_untranslated > 0 %}
|
|
145
|
+
<hr class="nav-lang-divider">
|
|
146
|
+
<p class="nav-lang-note" id="{{ _lt_note_id }}-panel">{{ _lt_note_text }}</p>
|
|
147
|
+
{%- endif %}
|
|
148
|
+
</div>
|
|
149
|
+
{%- else -%}
|
|
33
150
|
<div class="dropdown nav-lang-toggle" id="zer0-lang-toggle">
|
|
151
|
+
{%- comment -%}
|
|
152
|
+
Icon-only, square, and caret-free. `dropdown-toggle` is what draws the
|
|
153
|
+
Bootstrap caret; it is NOT what wires the dropdown — Bootstrap binds on
|
|
154
|
+
[data-bs-toggle="dropdown"], so dropping the class costs no behaviour.
|
|
155
|
+
The visible EN/FR label is gone at every width (it was already hidden
|
|
156
|
+
below xl), so title + aria-label are the only accessible name and both
|
|
157
|
+
name the language being read.
|
|
158
|
+
{%- endcomment -%}
|
|
34
159
|
<button
|
|
35
|
-
class="btn nav-lang-button
|
|
160
|
+
class="btn nav-lang-button"
|
|
36
161
|
type="button"
|
|
37
162
|
id="langToggleButton"
|
|
38
163
|
data-bs-toggle="dropdown"
|
|
39
164
|
aria-expanded="false"
|
|
40
165
|
aria-label="{{ ui.lang_toggle_aria | default: 'Change language' }}"
|
|
41
|
-
title="{{ ui.lang_toggle_label | default: 'Language' }}"
|
|
166
|
+
title="{{ ui.lang_toggle_label | default: 'Language' }}: {{ _lt_current_name }}"
|
|
42
167
|
>
|
|
43
168
|
<i class="{{ site.default_icon }} bi-translate" aria-hidden="true"></i>
|
|
44
|
-
<span class="nav-link-text d-none d-xl-inline ms-1 text-uppercase">{{ _lt_current | slice: 0, 2 }}</span>
|
|
45
169
|
</button>
|
|
46
|
-
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="langToggleButton">
|
|
170
|
+
<ul class="dropdown-menu dropdown-menu-end nav-lang-menu" aria-labelledby="langToggleButton">
|
|
47
171
|
<li>
|
|
48
172
|
{%- if _lt_current == _lt_source %}
|
|
49
|
-
<span class="dropdown-item
|
|
173
|
+
<span class="dropdown-item nav-lang-item is-current" aria-current="true">
|
|
174
|
+
<span class="nav-lang-name">{{ _lt_source_name }}</span>
|
|
175
|
+
<i class="bi bi-check2 nav-lang-check" aria-hidden="true"></i>
|
|
176
|
+
</span>
|
|
50
177
|
{%- else %}
|
|
51
|
-
<a class="dropdown-item" data-lang="{{ _lt_source }}" hreflang="{{ _lt_source }}" href="{{
|
|
178
|
+
<a class="dropdown-item nav-lang-item" data-lang="{{ _lt_source }}" hreflang="{{ _lt_source }}" href="{{ _lt_fallback_url }}">
|
|
179
|
+
<span class="nav-lang-name">{{ _lt_source_name }}</span>
|
|
180
|
+
</a>
|
|
52
181
|
{%- endif %}
|
|
53
182
|
</li>
|
|
54
183
|
{%- for _lt_lang in _lt_langs -%}
|
|
@@ -56,23 +185,41 @@
|
|
|
56
185
|
{%- assign _lt_t = _lt_entry[_lt_lang] %}
|
|
57
186
|
<li>
|
|
58
187
|
{%- if _lt_current == _lt_lang %}
|
|
59
|
-
<span class="dropdown-item
|
|
188
|
+
<span class="dropdown-item nav-lang-item is-current" aria-current="true">
|
|
189
|
+
<span class="nav-lang-name">{{ _lt_name }}</span>
|
|
190
|
+
<span class="nav-lang-auto" title="{{ _lt_auto_title }}">{{ _lt_auto_label }}</span>
|
|
191
|
+
<i class="bi bi-check2 nav-lang-check" aria-hidden="true"></i>
|
|
192
|
+
</span>
|
|
60
193
|
{%- elsif _lt_t %}
|
|
61
|
-
<a class="dropdown-item" data-lang="{{ _lt_lang }}" hreflang="{{ _lt_lang }}" href="{{ _lt_t.url | relative_url }}">
|
|
194
|
+
<a class="dropdown-item nav-lang-item" data-lang="{{ _lt_lang }}" hreflang="{{ _lt_lang }}" href="{{ _lt_t.url | relative_url }}">
|
|
195
|
+
<span class="nav-lang-name">{{ _lt_name }}</span>
|
|
196
|
+
<span class="nav-lang-auto" title="{{ _lt_auto_title }}">{{ _lt_auto_label }}</span>
|
|
197
|
+
</a>
|
|
62
198
|
{%- else %}
|
|
63
|
-
|
|
199
|
+
{%- comment -%} See the panel variant above — link, never a dead row. {%- endcomment -%}
|
|
200
|
+
<a class="dropdown-item nav-lang-item is-untranslated" data-lang="{{ _lt_lang }}" hreflang="{{ _lt_source }}" href="{{ _lt_fallback_url }}" aria-describedby="{{ _lt_note_id }}">
|
|
201
|
+
<span class="nav-lang-name">{{ _lt_name }}</span>
|
|
202
|
+
<span class="nav-lang-mark" aria-hidden="true">*</span>
|
|
203
|
+
</a>
|
|
64
204
|
{%- endif %}
|
|
65
205
|
</li>
|
|
66
206
|
{%- endfor %}
|
|
207
|
+
{%- if _lt_untranslated > 0 %}
|
|
208
|
+
<li><hr class="dropdown-divider"></li>
|
|
209
|
+
<li><p class="nav-lang-note" id="{{ _lt_note_id }}">{{ _lt_note_text }}</p></li>
|
|
210
|
+
{%- endif %}
|
|
67
211
|
</ul>
|
|
68
212
|
</div>
|
|
213
|
+
{%- endif -%}
|
|
69
214
|
<script>
|
|
70
215
|
// Remember the visitor's language pick (no auto-redirect — just preference).
|
|
216
|
+
// Delegated at document level so it covers both variants and stays correct
|
|
217
|
+
// if a consumer renders the component more than once per page.
|
|
71
218
|
(function () {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
var item = event.target.closest('a
|
|
219
|
+
if (window.__zer0LangPrefWired) return;
|
|
220
|
+
window.__zer0LangPrefWired = true;
|
|
221
|
+
document.addEventListener('click', function (event) {
|
|
222
|
+
var item = event.target.closest('#zer0-lang-toggle a[data-lang]');
|
|
76
223
|
if (!item) return;
|
|
77
224
|
try { localStorage.setItem('zer0-lang', item.getAttribute('data-lang')); } catch (e) { /* private mode */ }
|
|
78
225
|
});
|