jekyll-theme-zer0 1.30.0 → 1.31.1
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 +748 -571
- data/README.md +17 -3
- data/_data/backlog.yml +33 -10
- data/_data/consumers.yml +99 -0
- data/_data/features.yml +1 -1
- data/_data/i18n/fr.yml +30 -14
- data/_data/i18n/manifest.yml +63 -45
- data/_data/theme-manifest.yml +41 -39
- data/_data/ui-text.yml +1 -0
- data/_includes/README.md +1 -1
- data/_includes/analytics/posthog.html +28 -9
- data/_includes/components/README.md +1 -1
- data/_includes/components/background-image.html +7 -1
- data/_includes/components/cookie-consent.html +30 -30
- data/_includes/components/halfmoon.html +5 -3
- data/_includes/components/mermaid.html +14 -7
- data/_includes/components/preview-image.html +22 -3
- data/_includes/components/theme-preview-gallery.html +1 -1
- data/_includes/content/intro.html +21 -3
- data/_includes/content/seo.html +8 -0
- data/_includes/content/sitemap.html +220 -263
- data/_includes/core/branding.html +8 -15
- data/_includes/core/footer.html +3 -1
- data/_includes/core/head.html +33 -22
- data/_includes/core/header.html +14 -2
- data/_includes/core/tokens-inline.html +16 -1
- data/_includes/navigation/breadcrumbs.html +21 -15
- data/_includes/navigation/navbar.html +9 -6
- data/_includes/setup/wizard.html +5 -1
- data/_layouts/article.html +15 -3
- data/_layouts/home.html +13 -1
- data/_layouts/note.html +2 -1
- data/_layouts/notebook.html +2 -1
- data/_layouts/root.html +22 -0
- data/_sass/components/_cookie-banner.scss +48 -0
- data/_sass/components/_setup-wizard.scss +19 -1
- data/_sass/components/_ui-enhancements.scss +11 -0
- data/_sass/core/_navbar.scss +163 -70
- data/_sass/core/_sidebar-extras.scss +2 -14
- data/_sass/core/code-copy.scss +27 -8
- data/_sass/theme/_skins.scss +6 -2
- data/assets/css/extension-points-demo.css +27 -0
- data/assets/data/wiki-index.json +19 -0
- data/assets/js/auto-hide-nav.js +53 -13
- data/assets/js/code-copy.js +72 -1
- data/assets/js/extension-points-demo.js +48 -0
- data/assets/js/halfmoon.js +11 -1
- data/assets/js/mermaid-diagrams.js +128 -22
- data/assets/js/obsidian-local-graph.js +27 -5
- data/assets/js/search-modal.js +35 -3
- data/assets/js/setup-wizard.js +7 -2
- data/scripts/bin/validate +1 -0
- data/scripts/ci/test_visual_evidence_autogen.py +64 -2
- data/scripts/ci/visual_evidence_autogen.py +14 -4
- data/scripts/features/install-preview-generator +1 -1
- data/scripts/lib/README.md +12 -0
- data/scripts/lib/preview_generator.py +2 -2
- data/scripts/validate-features.rb +5 -8
- metadata +4 -2
|
@@ -50,36 +50,36 @@ Usage: Include in root.html layout
|
|
|
50
50
|
Configuration: Uses site.posthog settings from _config.yml
|
|
51
51
|
{% endcomment %}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
</
|
|
53
|
+
{% comment %}
|
|
54
|
+
Compact bottom bar. One row from md up (copy left, actions right); on phones
|
|
55
|
+
a two-line summary over a single row of three equal buttons. The banner used
|
|
56
|
+
to stack full-width buttons under a heading and a long sentence: 324px tall
|
|
57
|
+
at 400px wide (most of the first screen) and 94px on desktop, covering hero
|
|
58
|
+
copy. The per-category detail lives in the Manage modal.
|
|
59
|
+
{% endcomment %}
|
|
60
|
+
<div id="cookieConsent" class="cookie-consent-banner position-fixed bottom-0 start-0 end-0 shadow-lg" role="region" aria-label="Cookie consent" hidden>
|
|
61
|
+
<div class="container-xl cookie-consent-banner__inner">
|
|
62
|
+
<p class="cookie-consent-banner__text small mb-0">
|
|
63
|
+
<i class="bi bi-shield-check me-1" aria-hidden="true"></i>
|
|
64
|
+
<strong class="fw-semibold">We value your privacy.</strong>
|
|
65
|
+
<span class="text-body-secondary">
|
|
66
|
+
We use cookies to analyze traffic and improve the site.
|
|
67
|
+
{% assign cookie_page_urls = site.html_pages | map: "url" | join: "|" | prepend: "|" | append: "|" %}
|
|
68
|
+
{% if site.privacy_policy_url or cookie_page_urls contains "|/privacy-policy/|" or cookie_page_urls contains "|/privacy-policy|" %}
|
|
69
|
+
<a href="{{ site.privacy_policy_url | default: '/privacy-policy/' | relative_url }}" class="link-body-emphasis text-decoration-underline">Privacy Policy</a>
|
|
70
|
+
{% endif %}
|
|
71
|
+
</span>
|
|
72
|
+
</p>
|
|
73
|
+
<div class="cookie-consent-banner__actions">
|
|
74
|
+
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#cookieSettingsModal">
|
|
75
|
+
<i class="bi bi-gear me-1" aria-hidden="true"></i>Manage<span class="d-none d-sm-inline"> Cookies</span>
|
|
76
|
+
</button>
|
|
77
|
+
<button type="button" class="btn btn-sm btn-secondary" id="rejectAllCookies">
|
|
78
|
+
Reject All
|
|
79
|
+
</button>
|
|
80
|
+
<button type="button" class="btn btn-sm btn-primary" id="acceptAllCookies">
|
|
81
|
+
Accept All
|
|
82
|
+
</button>
|
|
83
83
|
</div>
|
|
84
84
|
</div>
|
|
85
85
|
</div>
|
|
@@ -14,16 +14,18 @@
|
|
|
14
14
|
(halfmoon.js + core/color-mode-init.html enforce the same).
|
|
15
15
|
{% endcomment %}
|
|
16
16
|
{% unless site.color_mode_lock %}
|
|
17
|
+
{% comment %} Server-render the configured mode as selected (#521) so no-JS and pre-hydration state is right; halfmoon.js then applies any stored preference. {% endcomment %}
|
|
18
|
+
{%- assign _cm = site.color_mode_default | default: 'auto' -%}
|
|
17
19
|
<div class="btn-group bd-theme-switch {{ include.class | default: '' }}" role="group" aria-label="Color mode">
|
|
18
|
-
<button type="button" class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-center gap-1" data-bs-theme-value="light" aria-pressed="false">
|
|
20
|
+
<button type="button" class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-center gap-1{% if _cm == 'light' %} active{% endif %}" data-bs-theme-value="light" aria-pressed="{% if _cm == 'light' %}true{% else %}false{% endif %}">
|
|
19
21
|
<svg class="bi flex-shrink-0" width="1em" height="1em" fill="currentColor" aria-hidden="true"><use href="#sun-fill"></use></svg>
|
|
20
22
|
<span>Light</span>
|
|
21
23
|
</button>
|
|
22
|
-
<button type="button" class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-center gap-1" data-bs-theme-value="dark" aria-pressed="false">
|
|
24
|
+
<button type="button" class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-center gap-1{% if _cm == 'dark' %} active{% endif %}" data-bs-theme-value="dark" aria-pressed="{% if _cm == 'dark' %}true{% else %}false{% endif %}">
|
|
23
25
|
<svg class="bi flex-shrink-0" width="1em" height="1em" fill="currentColor" aria-hidden="true"><use href="#moon-stars-fill"></use></svg>
|
|
24
26
|
<span>Dark</span>
|
|
25
27
|
</button>
|
|
26
|
-
<button type="button" class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-center gap-1" data-bs-theme-value="auto" aria-pressed="false">
|
|
28
|
+
<button type="button" class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-center gap-1{% if _cm == 'auto' %} active{% endif %}" data-bs-theme-value="auto" aria-pressed="{% if _cm == 'auto' %}true{% else %}false{% endif %}">
|
|
27
29
|
<svg class="bi flex-shrink-0" width="1em" height="1em" fill="currentColor" aria-hidden="true"><use href="#circle-half"></use></svg>
|
|
28
30
|
<span>Auto</span>
|
|
29
31
|
</button>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Path: _includes/components/mermaid.html
|
|
5
5
|
Purpose: Load Mermaid and the theme's diagram-figure behaviour on pages
|
|
6
6
|
that opt in with `mermaid: true` (gated in core/head.html).
|
|
7
|
-
Emits a config block and
|
|
7
|
+
Emits a config block and one deferred script; renders no
|
|
8
8
|
markup itself — every ```mermaid fence (and legacy
|
|
9
9
|
<div class="mermaid">) becomes an accessible <figure> with a
|
|
10
10
|
toolbar (zoom, fullscreen, copy source, download SVG), a
|
|
@@ -22,11 +22,15 @@
|
|
|
22
22
|
Depends on: assets/vendor/mermaid/mermaid.min.js (vendored, no CDN —
|
|
23
23
|
GitHub Pages-safe), assets/js/mermaid-diagrams.js,
|
|
24
24
|
_sass/components/_mermaid.scss
|
|
25
|
-
Notes:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
Notes: The Mermaid bundle (~1 MB) is NOT emitted as a <script> any
|
|
26
|
+
more. mermaid-diagrams.js (deferred) converts fences into
|
|
27
|
+
figures at execution time, before code-copy.js's
|
|
28
|
+
DOMContentLoaded pass decorates <pre> blocks, and injects the
|
|
29
|
+
bundle from `src` below only when the page has a diagram and
|
|
30
|
+
the first one nears the viewport (IntersectionObserver). A
|
|
31
|
+
`mermaid: true` page without fences never downloads it. It used
|
|
32
|
+
to be a parse-time `defer` script on every opted-in page, and
|
|
33
|
+
before that a synchronous one in <head>. Diagram colours
|
|
30
34
|
are not configured here: the script derives them from the live
|
|
31
35
|
--zer0-*/--bs-* tokens so light/dark/wizard modes and skins
|
|
32
36
|
work without per-mode overrides.
|
|
@@ -71,5 +75,8 @@
|
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
</script>
|
|
74
|
-
|
|
78
|
+
{% comment %} Bundle URL for the lazy loader. Passed as a script global rather than
|
|
79
|
+
through the JSON block above: a URL read back out of DOM text and assigned
|
|
80
|
+
to script.src is a script-injection sink (CodeQL js/xss-through-dom). {% endcomment %}
|
|
81
|
+
<script>window.zer0MermaidSrc = {{ mm_src | relative_url | jsonify }};</script>
|
|
75
82
|
<script defer src="{{ '/assets/js/mermaid-diagrams.js' | relative_url }}"></script>
|
|
@@ -7,9 +7,18 @@
|
|
|
7
7
|
src=post.preview
|
|
8
8
|
alt=post.title
|
|
9
9
|
class="card-img-top"
|
|
10
|
-
style="height: 180px; object-fit: cover;"
|
|
10
|
+
style="height: 180px; object-fit: cover;"
|
|
11
11
|
-%}
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
Optional: loading (default "lazy"), fetchpriority, decoding, width, height.
|
|
14
|
+
All but `loading` are emitted only when passed, so existing call sites
|
|
15
|
+
render unchanged. width/height are the image's intrinsic size (or its
|
|
16
|
+
aspect ratio): they let the browser reserve the box before the file
|
|
17
|
+
arrives (Lighthouse `unsized-images`) and never distort the image, since
|
|
18
|
+
CSS height:auto / object-fit still win once it has loaded.
|
|
19
|
+
An above-the-fold hero (the LCP element) should pass loading="eager"
|
|
20
|
+
fetchpriority="high" -- see the article.html hero.
|
|
21
|
+
|
|
13
22
|
WHICH INCLUDE: this one renders an <img> in the content flow. For cover art
|
|
14
23
|
painted as a CSS background on an otherwise empty box, use the sibling
|
|
15
24
|
components/background-image.html -- a background image is invisible to
|
|
@@ -20,6 +29,8 @@
|
|
|
20
29
|
The component will auto-prepend the assets_prefix from _config.yml.
|
|
21
30
|
Examples:
|
|
22
31
|
- /images/previews/my-image.png → /assets/images/previews/my-image.png
|
|
32
|
+
- images/previews/my-image.png → /assets/images/previews/my-image.png
|
|
33
|
+
(a missing leading slash used to produce /assetsimages/previews/…)
|
|
23
34
|
- /assets/images/previews/my-image.png → unchanged
|
|
24
35
|
- https://example.com/image.png → unchanged (external URL)
|
|
25
36
|
{% endcomment %}
|
|
@@ -33,6 +44,14 @@
|
|
|
33
44
|
{% assign assets_prefix = site.preview_images.assets_prefix | default: '/assets' %}
|
|
34
45
|
{% assign auto_prefix = site.preview_images.auto_prefix | default: true %}
|
|
35
46
|
|
|
47
|
+
{% comment %} Normalise a site-relative path to start with "/" so joining it to
|
|
48
|
+
assets_prefix can never glue two segments together ("images/x.png" became
|
|
49
|
+
"/assetsimages/x.png"). URLs and data: URIs are left alone. {% endcomment %}
|
|
50
|
+
{% unless img == nil or img == "" or img contains '://' or img contains 'data:' %}
|
|
51
|
+
{% assign img_first = img | slice: 0 %}
|
|
52
|
+
{% if img_first != '/' %}{% assign img = '/' | append: img %}{% endif %}
|
|
53
|
+
{% endunless %}
|
|
54
|
+
|
|
36
55
|
{% comment %} Determine final image source {% endcomment %}
|
|
37
56
|
{% if img contains '://' %}
|
|
38
57
|
{% comment %} External URL - use as-is {% endcomment %}
|
|
@@ -53,4 +72,4 @@
|
|
|
53
72
|
class="{{ class }}"
|
|
54
73
|
alt="{{ alt | escape }}"
|
|
55
74
|
{% if style %}style="{{ style }}"{% endif %}
|
|
56
|
-
loading="{{ loading }}">
|
|
75
|
+
loading="{{ loading }}"{% if include.width %} width="{{ include.width }}"{% endif %}{% if include.height %} height="{{ include.height }}"{% endif %}{% if include.fetchpriority %} fetchpriority="{{ include.fetchpriority }}"{% endif %}{% if include.decoding %} decoding="{{ include.decoding }}"{% endif %}>
|
|
@@ -519,7 +519,7 @@ docker-compose up
|
|
|
519
519
|
<i class="bi bi-person-circle" title="bi-person-circle"></i>
|
|
520
520
|
<i class="bi bi-palette" title="bi-palette"></i>
|
|
521
521
|
<i class="bi bi-code-slash" title="bi-code-slash"></i>
|
|
522
|
-
<i class="bi bi-file-earmark-text"title="bi-file-earmark-text"></i>
|
|
522
|
+
<i class="bi bi-file-earmark-text" title="bi-file-earmark-text"></i>
|
|
523
523
|
<i class="bi bi-check-circle text-success" title="success"></i>
|
|
524
524
|
<i class="bi bi-x-circle text-danger" title="danger"></i>
|
|
525
525
|
<i class="bi bi-exclamation-triangle text-warning" title="warning"></i>
|
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
{% assign assets_prefix = site.preview_images.assets_prefix | default: '/assets' %}
|
|
30
30
|
{% assign auto_prefix = site.preview_images.auto_prefix | default: true %}
|
|
31
31
|
|
|
32
|
+
{% comment %} Leading-slash normalisation, as in components/preview-image.html:
|
|
33
|
+
`preview: images/x.png` used to resolve to /assetsimages/x.png. {% endcomment %}
|
|
34
|
+
{% unless preview_image == nil or preview_image == "" or preview_image contains '://' or preview_image contains 'data:' %}
|
|
35
|
+
{% assign preview_first = preview_image | slice: 0 %}
|
|
36
|
+
{% if preview_first != '/' %}{% assign preview_image = '/' | append: preview_image %}{% endif %}
|
|
37
|
+
{% endunless %}
|
|
38
|
+
|
|
32
39
|
{% if preview_image contains '://' %}
|
|
33
40
|
{% assign preview_path = preview_image %}
|
|
34
41
|
{% elsif auto_prefix and preview_image != blank %}
|
|
@@ -45,7 +52,16 @@
|
|
|
45
52
|
Build the file path, branch, and repo owner for action buttons.
|
|
46
53
|
{% endcomment %}
|
|
47
54
|
{% assign repo_branch = site.branch | default: "main" %}
|
|
48
|
-
{%
|
|
55
|
+
{% comment %}
|
|
56
|
+
Only join with "/" when there is a collection directory. Pages outside a
|
|
57
|
+
collection have an empty page_dir, and the unconditional join produced
|
|
58
|
+
".../blob/main//pages/tags.md" (double slash) in the edit/source links.
|
|
59
|
+
{% endcomment %}
|
|
60
|
+
{% if page_dir and page_dir != "" %}
|
|
61
|
+
{% assign file_path = page_dir | append: "/" | append: page.path %}
|
|
62
|
+
{% else %}
|
|
63
|
+
{% assign file_path = page.path %}
|
|
64
|
+
{% endif %}
|
|
49
65
|
{% assign repo_parts = site.repository | split: "/" %}
|
|
50
66
|
{% assign repo_owner = repo_parts[0] %}
|
|
51
67
|
{% assign page_absolute_url = page.url | absolute_url %}
|
|
@@ -232,7 +248,8 @@
|
|
|
232
248
|
<div class="bd-intro-actions">
|
|
233
249
|
{% comment %} Share Button {% endcomment %}
|
|
234
250
|
<div class="dropdown">
|
|
235
|
-
|
|
251
|
+
{%- comment -%} aria-label keeps an accessible name below 576px, where the visible text is d-none. {%- endcomment -%}
|
|
252
|
+
<button class="btn btn-sm btn-info dropdown-toggle" type="button" id="shareDropdownBottom" data-bs-toggle="dropdown" aria-expanded="false" aria-label="{{ ui.share_label | default: 'Share' }}">
|
|
236
253
|
<i class="bi bi-share" aria-hidden="true"></i>
|
|
237
254
|
<span class="d-none d-sm-inline ms-1">{{ ui.share_label | default: "Share" }}</span>
|
|
238
255
|
</button>
|
|
@@ -293,7 +310,8 @@
|
|
|
293
310
|
<a href="https://github.com/{{ site.repository }}/blob/{{ repo_branch }}/{{ file_path }}"
|
|
294
311
|
class="btn btn-sm btn-dark bd-intro-action-link"
|
|
295
312
|
target="_blank"
|
|
296
|
-
rel="noopener noreferrer"
|
|
313
|
+
rel="noopener noreferrer"
|
|
314
|
+
aria-label="{{ ui.edit_on_github | default: 'Edit on GitHub' }}">
|
|
297
315
|
<i class="bi bi-github" aria-hidden="true"></i>
|
|
298
316
|
<span class="d-none d-sm-inline ms-1">{{ ui.edit_on_github | default: "Edit on GitHub" }}</span>
|
|
299
317
|
</a>
|
data/_includes/content/seo.html
CHANGED
|
@@ -43,6 +43,14 @@
|
|
|
43
43
|
nil seo_image — og:image was silently dropped on every page without a
|
|
44
44
|
page.header image, defeating the site.og_image fallback entirely.
|
|
45
45
|
{%- endcomment -%}
|
|
46
|
+
{%- comment -%} Leading-slash normalisation, as in components/preview-image.html:
|
|
47
|
+
`preview: images/x.png` used to become og:image …/assetsimages/x.png. {%- endcomment -%}
|
|
48
|
+
{%- if page_teaser_image and page_teaser_image != "" -%}
|
|
49
|
+
{%- unless page_teaser_image contains '://' or page_teaser_image contains 'data:' -%}
|
|
50
|
+
{%- assign teaser_first = page_teaser_image | slice: 0 -%}
|
|
51
|
+
{%- if teaser_first != '/' -%}{%- assign page_teaser_image = '/' | append: page_teaser_image -%}{%- endif -%}
|
|
52
|
+
{%- endunless -%}
|
|
53
|
+
{%- endif -%}
|
|
46
54
|
{%- if page_teaser_image contains '://' -%}
|
|
47
55
|
{%- comment -%} External URL - use as-is {%- endcomment -%}
|
|
48
56
|
{%- elsif auto_prefix and page_teaser_image and page_teaser_image != blank -%}
|