jekyll-theme-zer0 1.23.0 → 1.25.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 (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +110 -0
  3. data/README.md +3 -3
  4. data/_data/authors.yml +1 -0
  5. data/_data/features.yml +882 -34
  6. data/_data/navigation/README.md +15 -5
  7. data/_data/navigation/main.yml +0 -8
  8. data/_data/roadmap.yml +1 -0
  9. data/_includes/README.md +10 -7
  10. data/_includes/analytics/google-analytics.html +1 -0
  11. data/_includes/analytics/google-tag-manager-body.html +1 -0
  12. data/_includes/analytics/google-tag-manager-head.html +1 -0
  13. data/_includes/analytics/posthog.html +1 -0
  14. data/_includes/components/README.md +2 -1
  15. data/_includes/components/admin-links.html +63 -0
  16. data/_includes/components/admin-tabs.html +1 -0
  17. data/_includes/components/ai-chat.html +27 -5
  18. data/_includes/components/author-eeat.html +1 -0
  19. data/_includes/components/background-customizer.html +1 -0
  20. data/_includes/components/background-settings.html +36 -37
  21. data/_includes/components/component-showcase.html +1 -0
  22. data/_includes/components/cookie-consent.html +1 -0
  23. data/_includes/components/dev-shortcuts.html +1 -8
  24. data/_includes/components/env-switcher.html +90 -138
  25. data/_includes/components/feature-card.html +16 -1
  26. data/_includes/components/halfmoon.html +22 -41
  27. data/_includes/components/info-section.html +127 -130
  28. data/_includes/components/mermaid.html +1 -0
  29. data/_includes/components/nanobar.html +1 -0
  30. data/_includes/components/post-type-badge.html +1 -0
  31. data/_includes/components/preview-image.html +1 -0
  32. data/_includes/components/search-modal.html +1 -0
  33. data/_includes/components/searchbar.html +1 -0
  34. data/_includes/components/shortcuts-modal.html +1 -0
  35. data/_includes/components/theme-info.html +21 -30
  36. data/_includes/components/theme-preview-gallery.html +1 -0
  37. data/_includes/components/zer0-env-var.html +7 -1
  38. data/_includes/content/backlinks.html +1 -0
  39. data/_includes/content/giscus.html +1 -0
  40. data/_includes/content/jsonld-faq.html +1 -0
  41. data/_includes/content/seo.html +1 -0
  42. data/_includes/content/sitemap.html +1 -0
  43. data/_includes/content/toc.html +1 -0
  44. data/_includes/core/color-mode-init.html +1 -0
  45. data/_includes/core/footer.html +1 -0
  46. data/_includes/core/head.html +1 -0
  47. data/_includes/core/header.html +5 -15
  48. data/_includes/navigation/admin-nav.html +1 -0
  49. data/_includes/navigation/breadcrumbs.html +1 -0
  50. data/_includes/navigation/local-graph-fab.html +3 -9
  51. data/_includes/navigation/local-graph.html +4 -9
  52. data/_includes/navigation/navbar.html +1 -0
  53. data/_includes/navigation/sidebar-categories.html +56 -14
  54. data/_includes/navigation/sidebar-config.html +115 -0
  55. data/_includes/navigation/sidebar-folders.html +168 -62
  56. data/_includes/navigation/sidebar-left.html +29 -52
  57. data/_includes/navigation/sidebar-nav.html +30 -0
  58. data/_includes/navigation/sidebar-right.html +1 -0
  59. data/_includes/navigation/toc-fab.html +3 -9
  60. data/_includes/navigation/unified-drawer.html +7 -14
  61. data/_includes/obsidian/full-graph.html +1 -0
  62. data/_includes/setup/wizard.html +1 -0
  63. data/_includes/stats/stats-categories.html +1 -0
  64. data/_includes/stats/stats-header.html +1 -0
  65. data/_includes/stats/stats-metrics.html +1 -0
  66. data/_includes/stats/stats-overview.html +1 -0
  67. data/_includes/stats/stats-tags.html +1 -0
  68. data/_layouts/admin.html +1 -0
  69. data/_layouts/article.html +1 -0
  70. data/_layouts/author.html +1 -0
  71. data/_layouts/authors.html +1 -0
  72. data/_layouts/collection.html +1 -0
  73. data/_layouts/default.html +14 -37
  74. data/_layouts/home.html +1 -0
  75. data/_layouts/index.html +1 -0
  76. data/_layouts/landing.html +1 -0
  77. data/_layouts/news.html +1 -0
  78. data/_layouts/note.html +1 -0
  79. data/_layouts/notebook.html +1 -0
  80. data/_layouts/root.html +3 -2
  81. data/_layouts/search.html +1 -0
  82. data/_layouts/section.html +1 -0
  83. data/_layouts/setup.html +1 -0
  84. data/_layouts/sitemap-collection.html +1 -0
  85. data/_layouts/stats.html +1 -0
  86. data/_layouts/tag.html +1 -0
  87. data/_layouts/welcome.html +1 -0
  88. data/_plugins/author_pages_generator.rb +1 -0
  89. data/_plugins/obsidian_links.rb +1 -0
  90. data/_plugins/preview_image_generator.rb +1 -0
  91. data/_plugins/search_and_sitemap_generator.rb +1 -0
  92. data/_plugins/theme_version.rb +1 -0
  93. data/_sass/components/_author.scss +12 -1
  94. data/_sass/components/_footer.scss +22 -0
  95. data/_sass/components/_ui-enhancements.scss +9 -0
  96. data/_sass/core/_docs-layout.scss +1 -0
  97. data/_sass/core/_navbar.scss +10 -27
  98. data/_sass/core/_obsidian.scss +2 -2
  99. data/_sass/core/code-copy.scss +10 -0
  100. data/_sass/custom.scss +1 -0
  101. data/_sass/notebooks.scss +1 -0
  102. data/_sass/theme/_backgrounds.scss +7 -2
  103. data/_sass/utilities/_layout.scss +11 -0
  104. data/assets/css/main.scss +2 -1
  105. data/assets/js/ai-chat.js +1 -0
  106. data/assets/js/author-profile.js +1 -0
  107. data/assets/js/auto-hide-nav.js +1 -0
  108. data/assets/js/back-to-top.js +1 -0
  109. data/assets/js/background-customizer.js +1 -0
  110. data/assets/js/code-copy.js +1 -0
  111. data/assets/js/halfmoon.js +23 -22
  112. data/assets/js/modules/navigation/gestures.js +1 -0
  113. data/assets/js/modules/navigation/keyboard.js +1 -0
  114. data/assets/js/modules/navigation/scroll-spy.js +1 -0
  115. data/assets/js/modules/navigation/sidebar-state.js +1 -0
  116. data/assets/js/modules/navigation/sidebar-visibility.js +1 -0
  117. data/assets/js/modules/navigation/smooth-scroll.js +1 -0
  118. data/assets/js/modules/theme/appearance.js +52 -16
  119. data/assets/js/nanobar-init.js +1 -0
  120. data/assets/js/navigation.js +1 -0
  121. data/assets/js/obsidian-graph.js +1 -0
  122. data/assets/js/obsidian-wiki-links.js +1 -0
  123. data/assets/js/palette-generator.js +1 -0
  124. data/assets/js/particles-source.js +1 -0
  125. data/assets/js/search-modal.js +1 -0
  126. data/assets/js/setup-wizard.js +1 -0
  127. data/assets/js/share-actions.js +1 -0
  128. data/assets/js/skin-editor.js +1 -0
  129. data/assets/js/table-copy.js +1 -0
  130. data/assets/js/theme-customizer.js +1 -0
  131. data/scripts/analyze-commits.sh +1 -0
  132. data/scripts/bin/giscus-discussions +1 -0
  133. data/scripts/bin/install +1 -0
  134. data/scripts/bin/validate +18 -1
  135. data/scripts/build +1 -0
  136. data/scripts/content-review.rb +1 -0
  137. data/scripts/convert-notebooks.sh +4 -3
  138. data/scripts/fix-markdown-format.sh +1 -0
  139. data/scripts/generate-preview-images.sh +1 -0
  140. data/scripts/generate-roadmap.sh +1 -0
  141. data/scripts/install-preview-generator.sh +1 -0
  142. data/scripts/release +1 -0
  143. data/scripts/requirements.txt +11 -0
  144. data/scripts/setup.sh +1 -0
  145. data/scripts/tag-features +136 -0
  146. data/scripts/validate-features.rb +149 -0
  147. data/scripts/vendor-install.sh +1 -0
  148. metadata +9 -3
  149. data/_plugins/admin_page_urls.rb +0 -16
@@ -19,11 +19,18 @@
19
19
  #
20
20
  # ## Navigation Modes
21
21
  #
22
- # The sidebar supports three navigation modes set via `page.sidebar.nav`:
23
- #
24
- # 1. **auto** - Auto-generates from collection documents
25
- # 2. **tree** - Uses YAML data from this directory
26
- # 3. **categories** - Groups by Jekyll categories
22
+ # The sidebar supports these navigation modes set via `page.sidebar.nav`
23
+ # (resolved by _includes/navigation/sidebar-config.html; page front matter →
24
+ # collection `sidebar:` metadata site.sidebar nothing):
25
+ #
26
+ # 1. **auto** - Best mode for the page's collection: a curated
27
+ # _data/navigation/<collection>.yml wins, then the live "collection"
28
+ # folder tree, then post "categories"
29
+ # 2. **collection** - Live folder tree of the page's (or a named) collection
30
+ # 3. **categories** - Posts grouped by Jekyll category
31
+ # 4. **tags** - Posts grouped by Jekyll tag
32
+ # 5. **<file name>** - Any other value renders _data/navigation/<value>.yml
33
+ # as a curated tree (e.g. `nav: docs` → docs.yml)
27
34
  #
28
35
  # ## Available Files
29
36
  #
@@ -42,6 +49,9 @@
42
49
  # nav: docs # Uses _data/navigation/docs.yml
43
50
  # ```
44
51
  #
52
+ # Collections named like a file here get it automatically under `nav: auto`
53
+ # (docs.yml, about.yml, quickstart.yml, posts.yml ↔ the matching collection).
54
+ #
45
55
  # ## Navbar capacity & responsive constraints (main.yml)
46
56
  #
47
57
  # The top navbar adapts the `main.yml` items to the viewport automatically:
@@ -18,8 +18,6 @@
18
18
  icon: bi-newspaper
19
19
  url: /news/
20
20
  children:
21
- - title: All News
22
- url: /news/
23
21
  - title: Categories
24
22
  url: /categories/
25
23
  - title: Tags
@@ -29,8 +27,6 @@
29
27
  icon: bi-journal-text
30
28
  url: /notes/
31
29
  children:
32
- - title: All Notes
33
- url: /notes/
34
30
  - title: Git Cheatsheet
35
31
  url: /notes/git-cheatsheet/
36
32
  - title: Docker Commands
@@ -46,8 +42,6 @@
46
42
  icon: bi-journal-code
47
43
  url: /notebooks/
48
44
  children:
49
- - title: All Notebooks
50
- url: /notebooks/
51
45
  - title: Test Notebook
52
46
  url: /notebooks/test-notebook/
53
47
 
@@ -55,8 +49,6 @@
55
49
  icon: bi-journal-bookmark
56
50
  url: /docs/
57
51
  children:
58
- - title: Documentation Home
59
- url: /docs/
60
52
  - title: Installation
61
53
  url: /docs/installation/
62
54
  - title: Jekyll Guide
data/_data/roadmap.yml CHANGED
@@ -1,3 +1,4 @@
1
+ # Feature: ZER0-052
1
2
  # =============================================================================
2
3
  # zer0-mistakes Roadmap — Single Source of Truth
3
4
  # =============================================================================
data/_includes/README.md CHANGED
@@ -18,10 +18,12 @@ Essential layout components that form the foundation of the site:
18
18
  All navigation-related components:
19
19
 
20
20
  - `navbar.html` - Main navigation menu
21
- - `sidebar-left.html` - Left sidebar with dynamic navigation
21
+ - `sidebar-left.html` - Left sidebar panel (offcanvas shell around the resolved nav)
22
+ - `sidebar-config.html` - Resolves the effective sidebar mode/title/icon (page → collection → site); shared by layout, header, sidebar, and drawer
23
+ - `sidebar-nav.html` - Renders the resolved sidebar mode (dispatches to the includes below)
22
24
  - `sidebar-right.html` - Right sidebar content
23
- - `sidebar-folders.html` - Dynamic folder structure generation
24
- - `sidebar-categories.html` - Category-based navigation
25
+ - `sidebar-folders.html` - "collection" mode: collapsible folder tree of a collection's documents
26
+ - `sidebar-categories.html` - "categories"/"tags" modes: posts grouped by taxonomy term
25
27
  - `nav_list.html` - Manual navigation list rendering
26
28
  - `breadcrumbs.html` - Navigation breadcrumbs
27
29
 
@@ -37,12 +39,13 @@ Analytics and tracking integrations:
37
39
 
38
40
  Reusable UI components and widgets:
39
41
 
40
- - `searchbar.html` - Search functionality
42
+ - `searchbar.html` - Deprecated search stub (superseded by `search-modal.html`)
41
43
  - `powered-by.html` - "Powered by" credits display
42
44
  - `quick-index.html` - Quick page index
43
45
  - `dev-shortcuts.html` - Developer shortcuts
44
- - `info-section.html` - Settings/info modal
45
- - `halfmoon.html` - Dark mode toggle
46
+ - `info-section.html` - Settings offcanvas (Appearance / Site / Developer tabs)
47
+ - `admin-links.html` - Cached admin quick links for the settings offcanvas
48
+ - `halfmoon.html` - Light/dark/auto color-mode segmented control
46
49
  - `zer0-env-var.html` - Environment variable configuration
47
50
  - `svg.html` - SVG icon definitions
48
51
  - `js-cdn.html` - CDN JavaScript libraries
@@ -79,7 +82,7 @@ When including files in layouts or other templates, use the full path:
79
82
  ```liquid
80
83
  {% include core/head.html %}
81
84
  {% include navigation/sidebar-left.html %}
82
- {% include components/searchbar.html %}
85
+ {% include components/search-modal.html %}
83
86
  {% include analytics/google-analytics.html %}
84
87
  ```
85
88
 
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-038 {% endcomment %}
1
2
  <!-- Global site tag (gtag.js) - Google Analytics -->
2
3
  <script>
3
4
  (function () {
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-039 {% endcomment %}
1
2
  <!-- Google Tag Manager (noscript) -->
2
3
  <noscript>
3
4
  <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NN8P7RZ"
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-039 {% endcomment %}
1
2
  <!--
2
3
  title: Google Tag Manager
3
4
  file:
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-006 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  POSTHOG ANALYTICS - Privacy-First Web Analytics Integration
@@ -87,7 +87,8 @@ If a component needs a token that doesn't exist yet, propose it in `_sass/tokens
87
87
  | Component | Purpose |
88
88
  |--------------------------|------------------------------------------------------|
89
89
  | `author-eeat.html` | E-E-A-T author bio with Schema.org markup. |
90
- | `info-section.html` | Settings offcanvas with theme/appearance controls. |
90
+ | `admin-links.html` | Cached admin quick links (settings offcanvas Site tab). |
91
+ | `info-section.html` | Settings offcanvas — Appearance / Site / Developer. |
91
92
  | `js-cdn.html` | Body-end script bundle. |
92
93
  | `search-modal.html` | Global search modal. |
93
94
 
@@ -0,0 +1,63 @@
1
+ {% comment %} Feature: ZER0-077 {% endcomment %}
2
+ {%- comment -%}
3
+ Component: admin-links
4
+ Path: _includes/components/admin-links.html
5
+ Purpose: "Admin" section of the settings offcanvas — quick links to the
6
+ built-in admin pages, each rendered only when the target page
7
+ exists in the build (prevents 404s on bare-minimum /
8
+ remote-theme sites that haven't created the admin pages).
9
+ Params: none — site-scoped only. Include with {% include_cached %} so
10
+ the URL scan below runs once per build, not once per page.
11
+ Depends on: site.pages, the `about` collection, Bootstrap list-group.
12
+ Notes: Pure Liquid on purpose: local _plugins never load under the
13
+ github-pages gem (it forces safe mode and randomizes
14
+ plugins_dir), so a plugin-computed lookup is dead on GitHub
15
+ Pages and in the Docker dev server. Keep page.* out of this
16
+ file — it would poison the include cache.
17
+ {%- endcomment -%}
18
+
19
+ {%- assign _page_urls = site.pages | map: "url" | join: "|" -%}
20
+ {%- assign _about_urls = "" -%}
21
+ {%- if site.about -%}
22
+ {%- assign _about_urls = site.about | map: "url" | join: "|" -%}
23
+ {%- endif -%}
24
+ {%- capture _admin_urls -%}|{{ _page_urls }}|{{ _about_urls }}|{%- endcapture -%}
25
+
26
+ {%- assign _cfg_page = false -%}
27
+ {%- assign _theme_page = false -%}
28
+ {%- assign _nav_page = false -%}
29
+ {%- assign _env_page = false -%}
30
+ {%- if _admin_urls contains "|/about/config/|" -%}{% assign _cfg_page = true %}{%- endif -%}
31
+ {%- if _admin_urls contains "|/about/settings/theme/|" -%}{% assign _theme_page = true %}{%- endif -%}
32
+ {%- if _admin_urls contains "|/about/settings/navigation/|" -%}{% assign _nav_page = true %}{%- endif -%}
33
+ {%- if _admin_urls contains "|/about/settings/environment/|" -%}{% assign _env_page = true %}{%- endif -%}
34
+
35
+ {% if _cfg_page or _theme_page or _nav_page or _env_page %}
36
+ <div class="mb-3">
37
+ <h6 class="text-body-secondary small text-uppercase fw-semibold mb-2">
38
+ <i class="bi bi-speedometer2 me-1" aria-hidden="true"></i>Admin
39
+ </h6>
40
+ <div class="list-group list-group-flush small">
41
+ {% if _cfg_page %}
42
+ <a href="{{ '/about/config/' | relative_url }}" class="list-group-item list-group-item-action d-flex align-items-center px-0">
43
+ <i class="bi bi-gear me-2 text-body-secondary" aria-hidden="true"></i>Configuration
44
+ </a>
45
+ {% endif %}
46
+ {% if _theme_page %}
47
+ <a href="{{ '/about/settings/theme/' | relative_url }}" class="list-group-item list-group-item-action d-flex align-items-center px-0">
48
+ <i class="bi bi-palette me-2 text-body-secondary" aria-hidden="true"></i>Theme Customizer
49
+ </a>
50
+ {% endif %}
51
+ {% if _nav_page %}
52
+ <a href="{{ '/about/settings/navigation/' | relative_url }}" class="list-group-item list-group-item-action d-flex align-items-center px-0">
53
+ <i class="bi bi-signpost-2 me-2 text-body-secondary" aria-hidden="true"></i>Navigation Editor
54
+ </a>
55
+ {% endif %}
56
+ {% if _env_page %}
57
+ <a href="{{ '/about/settings/environment/' | relative_url }}" class="list-group-item list-group-item-action d-flex align-items-center px-0">
58
+ <i class="bi bi-hdd-network me-2 text-body-secondary" aria-hidden="true"></i>Environment Dashboard
59
+ </a>
60
+ {% endif %}
61
+ </div>
62
+ </div>
63
+ {% endif %}
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-050 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  ADMIN TABS — Reusable tabbed interface for admin pages
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-060 {% endcomment %}
1
2
  {%- comment -%}
2
3
  Component: ai-chat
3
4
  Path: _includes/components/ai-chat.html
@@ -351,14 +352,35 @@
351
352
  @media (max-width: 576px) {
352
353
  #aiChatPanel {
353
354
  width: calc(100vw - 2rem);
354
- right: 1rem;
355
- bottom: 8rem;
355
+ right: var(--zer0-space-fab-offset, 1rem);
356
+ /* One gap above the toggle's slot (toggle is 3rem tall). */
357
+ bottom: calc(var(--zer0-space-fab-offset, 1rem) + var(--zer0-space-fab-size, 3.5rem) + var(--zer0-space-fab-gap, 0.75rem) + 3rem + var(--zer0-space-fab-gap, 0.75rem));
356
358
  max-height: 60vh;
357
359
  }
360
+ }
361
+
362
+ /* Below lg, pages with a sidebar/TOC render the mobile TOC FAB in this
363
+ same right-edge slot (offset + size + gap — see .bd-toc-fab in
364
+ _sass/layouts/_navbar-extras.scss). Step the chat toggle and panel one
365
+ slot higher there so the two buttons never overlap. */
366
+ @media (max-width: 991.98px) {
367
+ /* Cap the panel to the space between its anchored bottom (worst case:
368
+ the stepped-up slot below) and the fixed header — a 540px panel pokes
369
+ above short tablet/landscape viewports. */
370
+ #aiChatPanel {
371
+ max-height: min(60vh, calc(100vh
372
+ - var(--zer0-space-fab-offset, 1rem)
373
+ - 2 * (var(--zer0-space-fab-size, 3.5rem) + var(--zer0-space-fab-gap, 0.75rem))
374
+ - 3rem - var(--zer0-space-fab-gap, 0.75rem)
375
+ - 4rem));
376
+ }
377
+
378
+ body:has(#tocFab) #aiChatToggle {
379
+ bottom: calc(var(--zer0-space-fab-offset, 1rem) + 2 * (var(--zer0-space-fab-size, 3.5rem) + var(--zer0-space-fab-gap, 0.75rem)));
380
+ }
358
381
 
359
- #aiChatToggle {
360
- bottom: 4.5rem;
361
- right: 1rem;
382
+ body:has(#tocFab) #aiChatPanel {
383
+ bottom: calc(var(--zer0-space-fab-offset, 1rem) + 2 * (var(--zer0-space-fab-size, 3.5rem) + var(--zer0-space-fab-gap, 0.75rem)) + 3rem + var(--zer0-space-fab-gap, 0.75rem));
362
384
  }
363
385
  }
364
386
 
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-054 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  AUTHOR E-E-A-T BLOCK - Experience, Expertise, Authority, Trust
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-065 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  BACKGROUND CUSTOMIZER — fffuel-style background settings panel
@@ -1,17 +1,21 @@
1
+ {% comment %} Feature: ZER0-077 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  BACKGROUND SETTINGS — fffuel-style background controls (tab content)
4
5
  ===================================================================
5
-
6
+
6
7
  File: background-settings.html
7
8
  Path: _includes/components/background-settings.html
8
- Purpose: Background skin selector and opacity controls, rendered
9
- inside the Settings offcanvas Background tab.
10
-
9
+ Purpose: Theme-skin selector and SVG-background controls, rendered
10
+ inside the Settings offcanvas Appearance tab.
11
+
11
12
  Dependencies:
12
13
  - assets/js/background-customizer.js (zer0Bg API)
13
14
  - _sass/theme/_backgrounds.scss (CSS custom properties)
14
15
  - Bootstrap 5 form components
16
+
17
+ Section headings match the h6 pattern used by the parent
18
+ info-section.html so the Appearance tab reads as one surface.
15
19
  ===================================================================
16
20
  -->
17
21
 
@@ -21,9 +25,9 @@
21
25
  <!-- Skin selector -->
22
26
  <div class="mb-4">
23
27
  <h6 class="text-body-secondary small text-uppercase fw-semibold mb-2">
24
- <i class="bi bi-palette2 me-1"></i>Theme Skin
28
+ <i class="bi bi-palette2 me-1" aria-hidden="true"></i>Theme Skin
25
29
  </h6>
26
- <div class="d-flex flex-wrap gap-2" id="zer0SkinButtons">
30
+ <div class="d-flex flex-wrap gap-2" id="zer0SkinButtons" role="group" aria-label="Theme skin">
27
31
  {% for skin in skins %}
28
32
  <button class="btn btn-sm btn-outline-primary{% if skin == current_skin %} active{% endif %}"
29
33
  data-skin="{{ skin }}"
@@ -34,51 +38,48 @@
34
38
  </div>
35
39
  </div>
36
40
 
37
- <!-- Background toggle -->
41
+ <!-- SVG background toggle + layer opacity -->
38
42
  <div class="mb-4">
39
43
  <h6 class="text-body-secondary small text-uppercase fw-semibold mb-2">
40
- <i class="bi bi-image me-1"></i>SVG Backgrounds
44
+ <i class="bi bi-image me-1" aria-hidden="true"></i>Background
41
45
  </h6>
42
- <div class="d-flex align-items-center justify-content-between p-3 bg-body-tertiary rounded">
43
- <label class="form-check-label" for="zer0BgToggle">Enable SVG backgrounds</label>
46
+
47
+ <div class="d-flex align-items-center justify-content-between p-3 bg-body-tertiary rounded mb-3">
48
+ <label class="form-check-label" for="zer0BgToggle">SVG backgrounds</label>
44
49
  <div class="form-check form-switch mb-0">
45
50
  <input class="form-check-input" type="checkbox" id="zer0BgToggle" checked>
46
51
  </div>
47
52
  </div>
48
- </div>
49
-
50
- <!-- Opacity sliders -->
51
- <div class="mb-4">
52
- <h6 class="text-body-secondary small text-uppercase fw-semibold mb-2">
53
- <i class="bi bi-sliders2 me-1"></i>Layer Opacity
54
- </h6>
55
53
 
56
54
  <div class="mb-3">
57
- <label class="form-label small" for="zer0GradientOpacity">Gradient opacity</label>
55
+ <label class="form-label small d-flex justify-content-between mb-1" for="zer0GradientOpacity">
56
+ <span>Gradient opacity</span>
57
+ <span class="text-body-secondary" id="zer0GradientOpacityVal">0.6</span>
58
+ </label>
58
59
  <input type="range" class="form-range" id="zer0GradientOpacity"
59
60
  min="0" max="1" step="0.05" value="0.6">
60
- <small class="text-body-secondary"><span id="zer0GradientOpacityVal">0.6</span></small>
61
61
  </div>
62
62
 
63
63
  <div class="mb-3">
64
- <label class="form-label small" for="zer0TextureOpacity">Texture opacity</label>
64
+ <label class="form-label small d-flex justify-content-between mb-1" for="zer0TextureOpacity">
65
+ <span>Texture opacity</span>
66
+ <span class="text-body-secondary" id="zer0TextureOpacityVal">0.04</span>
67
+ </label>
65
68
  <input type="range" class="form-range" id="zer0TextureOpacity"
66
69
  min="0" max="0.2" step="0.005" value="0.04">
67
- <small class="text-body-secondary"><span id="zer0TextureOpacityVal">0.04</span></small>
68
70
  </div>
69
71
 
70
72
  <div class="mb-3">
71
- <label class="form-label small" for="zer0PatternOpacity">Pattern opacity</label>
73
+ <label class="form-label small d-flex justify-content-between mb-1" for="zer0PatternOpacity">
74
+ <span>Pattern opacity</span>
75
+ <span class="text-body-secondary" id="zer0PatternOpacityVal">0.08</span>
76
+ </label>
72
77
  <input type="range" class="form-range" id="zer0PatternOpacity"
73
78
  min="0" max="0.3" step="0.01" value="0.08">
74
- <small class="text-body-secondary"><span id="zer0PatternOpacityVal">0.08</span></small>
75
79
  </div>
76
- </div>
77
80
 
78
- <!-- Reset -->
79
- <div>
80
- <button class="btn btn-sm btn-outline-danger" id="zer0BgReset" type="button">
81
- <i class="bi bi-arrow-counterclockwise me-1"></i>Reset to defaults
81
+ <button class="btn btn-sm btn-outline-secondary" id="zer0BgReset" type="button">
82
+ <i class="bi bi-arrow-counterclockwise me-1" aria-hidden="true"></i>Reset background
82
83
  </button>
83
84
  </div>
84
85
 
@@ -119,15 +120,13 @@ document.addEventListener("DOMContentLoaded", function () {
119
120
  document.getElementById("zer0BgReset").addEventListener("click", function () {
120
121
  zer0Bg.setSkin("{{ current_skin }}");
121
122
  zer0Bg.toggle(true);
122
- zer0Bg.setOpacity("gradient", 0.6);
123
- zer0Bg.setOpacity("texture", 0.04);
124
- zer0Bg.setOpacity("pattern", 0.08);
125
- document.getElementById("zer0GradientOpacity").value = 0.6;
126
- document.getElementById("zer0TextureOpacity").value = 0.04;
127
- document.getElementById("zer0PatternOpacity").value = 0.08;
128
- document.getElementById("zer0GradientOpacityVal").textContent = "0.6";
129
- document.getElementById("zer0TextureOpacityVal").textContent = "0.04";
130
- document.getElementById("zer0PatternOpacityVal").textContent = "0.08";
123
+ var defaults = { zer0GradientOpacity: "0.6", zer0TextureOpacity: "0.04", zer0PatternOpacity: "0.08" };
124
+ var layers = { zer0GradientOpacity: "gradient", zer0TextureOpacity: "texture", zer0PatternOpacity: "pattern" };
125
+ Object.keys(defaults).forEach(function (id) {
126
+ zer0Bg.setOpacity(layers[id], defaults[id]);
127
+ document.getElementById(id).value = defaults[id];
128
+ document.getElementById(id + "Val").textContent = defaults[id];
129
+ });
131
130
  toggle.checked = true;
132
131
  document.querySelectorAll("#zer0SkinButtons .btn").forEach(function (b) { b.classList.remove("active"); });
133
132
  var active = document.querySelector('#zer0SkinButtons [data-skin="{{ current_skin }}"]');
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-071 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  COMPONENT SHOWCASE - Live Bootstrap 5 demo gallery
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-007 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  COOKIE CONSENT - GDPR/CCPA Compliant Privacy Management
@@ -1,3 +1,4 @@
1
+ {% comment %} Feature: ZER0-077 {% endcomment %}
1
2
  <!--
2
3
  ===================================================================
3
4
  DEV SHORTCUTS - Source Code Quick Access Links
@@ -46,8 +47,6 @@
46
47
  target="_blank"
47
48
  rel="noopener"
48
49
  class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-between"
49
- data-bs-toggle="tooltip"
50
- data-bs-placement="left"
51
50
  title="View source file on GitHub">
52
51
  <span>
53
52
  <i class="bi bi-github me-2"></i>
@@ -61,8 +60,6 @@
61
60
  target="_blank"
62
61
  rel="noopener"
63
62
  class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-between"
64
- data-bs-toggle="tooltip"
65
- data-bs-placement="left"
66
63
  title="Open in browser-based VS Code editor">
67
64
  <span>
68
65
  <i class="bi bi-cloud me-2"></i>
@@ -76,8 +73,6 @@
76
73
  {% if git_home != "" %}
77
74
  <a href="vscode://file{{ vscode_full_path }}"
78
75
  class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-between"
79
- data-bs-toggle="tooltip"
80
- data-bs-placement="left"
81
76
  title="Open in local VS Code (requires local clone at this path)">
82
77
  <span>
83
78
  <i class="bi bi-code-square me-2"></i>
@@ -102,8 +97,6 @@
102
97
  target="_blank"
103
98
  rel="noopener"
104
99
  class="btn btn-outline-secondary btn-sm d-flex align-items-center justify-content-between"
105
- data-bs-toggle="tooltip"
106
- data-bs-placement="left"
107
100
  title="View Jekyll site configuration">
108
101
  <span>
109
102
  <i class="bi bi-gear me-2"></i>