jekyll-theme-zer0 1.24.0 → 1.26.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 (157) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +124 -0
  3. data/README.md +4 -4
  4. data/_data/authors.yml +1 -0
  5. data/_data/backlog.yml +26 -1
  6. data/_data/features.yml +73 -45
  7. data/_data/feedback_types.yml +148 -0
  8. data/_data/navigation/README.md +16 -6
  9. data/_data/navigation/main.yml +0 -8
  10. data/_data/roadmap.yml +1 -0
  11. data/_includes/README.md +10 -7
  12. data/_includes/analytics/google-analytics.html +1 -0
  13. data/_includes/analytics/google-tag-manager-body.html +1 -0
  14. data/_includes/analytics/google-tag-manager-head.html +1 -0
  15. data/_includes/analytics/posthog.html +1 -0
  16. data/_includes/components/README.md +3 -1
  17. data/_includes/components/admin-links.html +63 -0
  18. data/_includes/components/admin-tabs.html +1 -0
  19. data/_includes/components/ai-chat.html +27 -5
  20. data/_includes/components/author-eeat.html +1 -0
  21. data/_includes/components/background-customizer.html +1 -0
  22. data/_includes/components/background-settings.html +36 -37
  23. data/_includes/components/component-showcase.html +1 -0
  24. data/_includes/components/cookie-consent.html +1 -0
  25. data/_includes/components/dev-shortcuts.html +1 -8
  26. data/_includes/components/env-switcher.html +90 -138
  27. data/_includes/components/feature-card.html +1 -1
  28. data/_includes/components/halfmoon.html +22 -41
  29. data/_includes/components/info-section.html +127 -130
  30. data/_includes/components/mermaid.html +1 -0
  31. data/_includes/components/nanobar.html +1 -0
  32. data/_includes/components/page-feedback.html +252 -0
  33. data/_includes/components/post-type-badge.html +1 -0
  34. data/_includes/components/preview-image.html +1 -0
  35. data/_includes/components/search-modal.html +1 -0
  36. data/_includes/components/searchbar.html +1 -0
  37. data/_includes/components/shortcuts-modal.html +1 -0
  38. data/_includes/components/theme-info.html +21 -30
  39. data/_includes/components/theme-preview-gallery.html +1 -0
  40. data/_includes/content/backlinks.html +1 -0
  41. data/_includes/content/giscus.html +1 -0
  42. data/_includes/content/intro.html +20 -62
  43. data/_includes/content/jsonld-faq.html +1 -0
  44. data/_includes/content/seo.html +1 -0
  45. data/_includes/content/sitemap.html +1 -0
  46. data/_includes/content/toc.html +1 -0
  47. data/_includes/core/color-mode-init.html +1 -0
  48. data/_includes/core/console-capture.html +89 -0
  49. data/_includes/core/footer.html +1 -0
  50. data/_includes/core/head.html +5 -0
  51. data/_includes/core/header.html +5 -15
  52. data/_includes/navigation/admin-nav.html +1 -0
  53. data/_includes/navigation/breadcrumbs.html +1 -0
  54. data/_includes/navigation/local-graph-fab.html +3 -9
  55. data/_includes/navigation/local-graph.html +4 -9
  56. data/_includes/navigation/navbar.html +1 -0
  57. data/_includes/navigation/sidebar-categories.html +56 -14
  58. data/_includes/navigation/sidebar-config.html +115 -0
  59. data/_includes/navigation/sidebar-folders.html +168 -62
  60. data/_includes/navigation/sidebar-left.html +29 -52
  61. data/_includes/navigation/sidebar-nav.html +30 -0
  62. data/_includes/navigation/sidebar-right.html +1 -0
  63. data/_includes/navigation/toc-fab.html +3 -9
  64. data/_includes/navigation/unified-drawer.html +7 -14
  65. data/_includes/obsidian/full-graph.html +1 -0
  66. data/_includes/setup/wizard.html +1 -0
  67. data/_includes/stats/stats-categories.html +1 -0
  68. data/_includes/stats/stats-header.html +1 -0
  69. data/_includes/stats/stats-metrics.html +1 -0
  70. data/_includes/stats/stats-overview.html +1 -0
  71. data/_includes/stats/stats-tags.html +1 -0
  72. data/_layouts/admin.html +1 -0
  73. data/_layouts/article.html +1 -0
  74. data/_layouts/author.html +1 -0
  75. data/_layouts/authors.html +1 -0
  76. data/_layouts/collection.html +1 -0
  77. data/_layouts/default.html +14 -37
  78. data/_layouts/home.html +1 -0
  79. data/_layouts/index.html +1 -0
  80. data/_layouts/landing.html +1 -0
  81. data/_layouts/news.html +1 -0
  82. data/_layouts/note.html +1 -0
  83. data/_layouts/notebook.html +1 -0
  84. data/_layouts/root.html +6 -2
  85. data/_layouts/search.html +1 -0
  86. data/_layouts/section.html +1 -0
  87. data/_layouts/setup.html +1 -0
  88. data/_layouts/sitemap-collection.html +1 -0
  89. data/_layouts/stats.html +1 -0
  90. data/_layouts/tag.html +1 -0
  91. data/_layouts/welcome.html +1 -0
  92. data/_plugins/author_pages_generator.rb +1 -0
  93. data/_plugins/obsidian_links.rb +1 -0
  94. data/_plugins/preview_image_generator.rb +1 -0
  95. data/_plugins/search_and_sitemap_generator.rb +1 -0
  96. data/_plugins/theme_version.rb +1 -0
  97. data/_sass/components/_author.scss +12 -1
  98. data/_sass/components/_footer.scss +22 -0
  99. data/_sass/components/_page-feedback.scss +276 -0
  100. data/_sass/components/_ui-enhancements.scss +9 -0
  101. data/_sass/core/_docs-layout.scss +3 -78
  102. data/_sass/core/_navbar.scss +10 -27
  103. data/_sass/core/_obsidian.scss +2 -2
  104. data/_sass/core/code-copy.scss +10 -0
  105. data/_sass/custom.scss +1 -0
  106. data/_sass/notebooks.scss +1 -0
  107. data/_sass/theme/_backgrounds.scss +7 -2
  108. data/_sass/tokens/_layers.scss +4 -0
  109. data/_sass/utilities/_layout.scss +11 -0
  110. data/assets/css/main.scss +3 -1
  111. data/assets/js/ai-chat.js +1 -0
  112. data/assets/js/author-profile.js +1 -0
  113. data/assets/js/auto-hide-nav.js +1 -0
  114. data/assets/js/back-to-top.js +1 -0
  115. data/assets/js/background-customizer.js +1 -0
  116. data/assets/js/code-copy.js +1 -0
  117. data/assets/js/halfmoon.js +23 -22
  118. data/assets/js/modules/navigation/gestures.js +1 -0
  119. data/assets/js/modules/navigation/keyboard.js +1 -0
  120. data/assets/js/modules/navigation/scroll-spy.js +1 -0
  121. data/assets/js/modules/navigation/sidebar-state.js +1 -0
  122. data/assets/js/modules/navigation/sidebar-visibility.js +1 -0
  123. data/assets/js/modules/navigation/smooth-scroll.js +1 -0
  124. data/assets/js/modules/theme/appearance.js +52 -16
  125. data/assets/js/nanobar-init.js +1 -0
  126. data/assets/js/navigation.js +1 -0
  127. data/assets/js/obsidian-graph.js +1 -0
  128. data/assets/js/obsidian-wiki-links.js +1 -0
  129. data/assets/js/page-feedback.js +660 -0
  130. data/assets/js/palette-generator.js +1 -0
  131. data/assets/js/particles-source.js +1 -0
  132. data/assets/js/search-modal.js +1 -0
  133. data/assets/js/setup-wizard.js +1 -0
  134. data/assets/js/share-actions.js +1 -0
  135. data/assets/js/skin-editor.js +1 -0
  136. data/assets/js/table-copy.js +1 -0
  137. data/assets/js/theme-customizer.js +1 -0
  138. data/scripts/analyze-commits.sh +1 -0
  139. data/scripts/bin/giscus-discussions +1 -0
  140. data/scripts/bin/install +1 -0
  141. data/scripts/bin/validate +1 -0
  142. data/scripts/build +1 -0
  143. data/scripts/content-review.rb +1 -0
  144. data/scripts/convert-notebooks.sh +4 -3
  145. data/scripts/fix-markdown-format.sh +1 -0
  146. data/scripts/generate-preview-images.sh +1 -0
  147. data/scripts/generate-roadmap.sh +1 -0
  148. data/scripts/install-preview-generator.sh +1 -0
  149. data/scripts/release +1 -0
  150. data/scripts/requirements.txt +11 -0
  151. data/scripts/setup.sh +1 -0
  152. data/scripts/tag-features +136 -0
  153. data/scripts/validate-features.rb +7 -0
  154. data/scripts/vendor-install.sh +1 -0
  155. metadata +13 -4
  156. data/_data/prompts.yml +0 -302
  157. data/_plugins/admin_page_urls.rb +0 -16
@@ -804,33 +804,16 @@
804
804
  padding-top: 1rem;
805
805
  }
806
806
 
807
- // Theme switcher (halfmoon): keep dropdown positioned within offcanvas panel
808
- .bd-theme-dropdown {
809
- position: relative;
810
- }
811
-
812
- .bd-theme-menu.dropdown-menu {
813
- --bs-dropdown-min-width: 10.5rem;
814
- z-index: 1060;
815
- padding-top: 0.35rem;
816
- padding-bottom: 0.35rem;
817
- border-radius: var(--bs-border-radius, 0.375rem);
818
- border: 1px solid var(--bs-border-color-translucent);
819
- }
820
-
821
- .bd-theme-menu .dropdown-item {
822
- min-height: 0;
823
- padding: 0.45rem 0.85rem;
824
- font-size: 0.9375rem;
825
- border-radius: calc(var(--bs-border-radius, 0.375rem) - 2px);
826
- gap: 0.35rem;
827
-
828
- &.active {
829
- font-weight: 600;
830
- }
831
-
832
- .bi.ms-auto {
833
- opacity: 0.9;
807
+ // Compact tabs on narrow panels: keep the text labels (they are the
808
+ // accessible names) and drop the decorative icons instead.
809
+ @media (max-width: 575.98px) {
810
+ .nav-tabs .nav-link {
811
+ padding: 0.6rem 0.25rem;
812
+ font-size: 0.8125rem;
813
+
814
+ .bi {
815
+ display: none;
816
+ }
834
817
  }
835
818
  }
836
819
  }
@@ -204,8 +204,8 @@
204
204
  // ----------------------------------------------------------------------------
205
205
  // ID selector (not the class) is REQUIRED for the fixed position to stick:
206
206
  // the FAB is a direct child of `.zer0-bg-body`, which matches the elevation
207
- // rule `.zer0-bg-body > *:not(.fixed-top):not(.offcanvas):not(.modal)` in
208
- // _sass/theme/_backgrounds.scss (specificity 0,4,0) and forces
207
+ // rule `.zer0-bg-body > *:not(.fixed-top):not(.position-fixed):not(.offcanvas):not(.modal)`
208
+ // in _sass/theme/_backgrounds.scss (specificity 0,5,0) and forces
209
209
  // `position: relative; z-index: 1` — dropping the FAB into page flow at the
210
210
  // bottom. An id (1,0,0) wins, mirroring `#aiChatToggle`. See ai-chat.html.
211
211
  #obsidianLocalGraphFab.obsidian-local-graph-fab {
@@ -197,6 +197,12 @@
197
197
 
198
198
  // Copy button — shared base
199
199
  .copy {
200
+ display: inline-flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ // WCAG 2.5.8 target size: text metrics alone yield a ~22px-tall button;
204
+ // guarantee the 24px minimum, and a comfortable 32px on touch screens.
205
+ min-height: 1.5rem;
200
206
  flex-shrink: 0;
201
207
  color: var(--bs-light);
202
208
  opacity: 0.75;
@@ -229,6 +235,10 @@
229
235
  border-color: transparent;
230
236
  opacity: 1;
231
237
  }
238
+
239
+ @media (pointer: coarse) {
240
+ min-height: 2rem;
241
+ }
232
242
  }
233
243
 
234
244
  // Header-mounted copy button (Rouge blocks) — never overlaps code
data/_sass/custom.scss CHANGED
@@ -1,3 +1,4 @@
1
+ // Features: ZER0-001, ZER0-008, ZER0-010, ZER0-011
1
2
  // ==============================================================================
2
3
  // CUSTOM STYLES barrel — Zer0-Mistakes "custom layer"
3
4
  // ==============================================================================
data/_sass/notebooks.scss CHANGED
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-012
1
2
  // ==============================================================================
2
3
  // NOTEBOOK STYLES - Jupyter Notebook Display Styling
3
4
  // ==============================================================================
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-065
1
2
  // ==========================================================================
2
3
  // Backgrounds — fffuel-style SVG background system for zer0-mistakes theme
3
4
  // ==========================================================================
@@ -108,8 +109,12 @@
108
109
 
109
110
  // Elevate children above the ::before / ::after pseudo-element backgrounds,
110
111
  // but exclude fixed-position, offcanvas, and modal elements whose
111
- // positioning must not be overridden.
112
- > *:not(.fixed-top):not(.offcanvas):not(.modal) { position: relative; z-index: 1; }
112
+ // positioning must not be overridden. `.position-fixed` matters as much as
113
+ // `.fixed-top`: without it this rule (specificity 0,4,0) flattens the
114
+ // cookie-consent banner and the TOC FAB to z-index 1, letting the chat and
115
+ // local-graph FABs paint over — and steal taps from — the banner's buttons
116
+ // on mobile (their `--zer0-layer-*` tokens exist precisely to prevent this).
117
+ > *:not(.fixed-top):not(.position-fixed):not(.offcanvas):not(.modal) { position: relative; z-index: 1; }
113
118
  }
114
119
 
115
120
  .zer0-bg-surface {
@@ -18,6 +18,7 @@
18
18
 
19
19
  // Floating action buttons (stack bottom-to-top) --------------------------
20
20
  --zer0-layer-fab-back-to-top: 1050;
21
+ --zer0-layer-fab-feedback: 1051; // page-feedback FAB (bottom-left)
21
22
  --zer0-layer-fab-chat: 1052;
22
23
  --zer0-layer-fab-toc: 1055;
23
24
  --zer0-layer-fab-local-graph: 1060;
@@ -25,6 +26,9 @@
25
26
  // Overlay surfaces -------------------------------------------------------
26
27
  --zer0-layer-offcanvas: 1045;
27
28
  --zer0-layer-modal: 1055;
29
+ --zer0-layer-feedback-modal: 1096; // page-feedback dialog — a focused dialog wins over
30
+ // every FAB, toast, AND the cookie banner (1095) so its
31
+ // controls are never intercepted; still below skip-link (1100)
28
32
  --zer0-layer-popover: 1070;
29
33
  --zer0-layer-tooltip: 1080;
30
34
 
@@ -0,0 +1,11 @@
1
+ // Feature: ZER0-077
2
+ // =============================================================================
3
+ // Layout utilities — small structural helpers Bootstrap does not ship
4
+ // =============================================================================
5
+
6
+ // Allow a flex child to shrink below its content size so text-truncate can
7
+ // work (flex items default to min-width: auto). Used by the navbar leading
8
+ // cluster, branding, and the settings panel quick-link rows.
9
+ .min-w-0 {
10
+ min-width: 0 !important;
11
+ }
data/assets/css/main.scss CHANGED
@@ -22,9 +22,10 @@
22
22
  // it so the concatenated cascade order is unchanged.
23
23
  @import "core/docs-code-examples";
24
24
 
25
- // 4. Reusable utilities (motion, focus rings) — used by components below
25
+ // 4. Reusable utilities (motion, focus rings, layout helpers) — used by components below
26
26
  @import "utilities/motion";
27
27
  @import "utilities/focus";
28
+ @import "utilities/layout";
28
29
 
29
30
  // 5. Component partials (formerly inside custom.scss + new primitives)
30
31
  @import "components/cookie-banner";
@@ -38,6 +39,7 @@
38
39
  @import "components/theme-preview";
39
40
  @import "components/content-tables";
40
41
  @import "components/search-modal";
42
+ @import "components/page-feedback";
41
43
 
42
44
  // 6. Layout partials
43
45
  @import "layouts/landing";
data/assets/js/ai-chat.js CHANGED
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-060
1
2
  /**
2
3
  * ===================================================================
3
4
  * AI Chat Widget — Claude Messages API client with GitHub tool use
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-061
1
2
  /*
2
3
  * author-profile.js
3
4
  * ---------------------------------------------------------------------------
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-033
1
2
  /**
2
3
  * Auto-hide navbar on scroll with enhanced UX
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-029
1
2
  document.addEventListener('DOMContentLoaded', () => {
2
3
  const btn = document.getElementById('backToTopBtn');
3
4
  if (!btn) return;
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-065
1
2
  /**
2
3
  * background-customizer.js
3
4
  * Runtime switching of theme skin and fffuel-style SVG backgrounds.
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-030
1
2
  document.addEventListener('DOMContentLoaded', function () {
2
3
  var LANG_LABELS = {
3
4
  shell: 'bash',
@@ -30,36 +30,37 @@
30
30
  setTheme(getPreferredTheme())
31
31
 
32
32
  const showActiveTheme = (theme, focus = false) => {
33
- const themeSwitcher = document.querySelector('#bd-theme')
34
-
35
- if (!themeSwitcher) {
36
- return
37
- }
38
-
39
- const themeSwitcherText = document.querySelector('#bd-theme-text')
40
- const activeThemeIcon = document.querySelector('.theme-icon-active use')
41
- const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
42
- const themeIconUse = btnToActive?.querySelector('svg use')
43
- if (!btnToActive || !themeIconUse || !activeThemeIcon) {
33
+ const activeButtons = document.querySelectorAll(`[data-bs-theme-value="${theme}"]`)
34
+ if (!activeButtons.length) {
44
35
  return
45
36
  }
46
37
 
47
- const svgOfActiveBtn = themeIconUse.getAttribute('href')
48
-
38
+ // The control can render more than once per page (settings offcanvas +
39
+ // theme-controls-bar), so sync active state across every instance.
49
40
  document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
50
41
  element.classList.remove('active')
51
42
  element.setAttribute('aria-pressed', 'false')
52
43
  })
44
+ activeButtons.forEach(element => {
45
+ element.classList.add('active')
46
+ element.setAttribute('aria-pressed', 'true')
47
+ })
53
48
 
54
- btnToActive.classList.add('active')
55
- btnToActive.setAttribute('aria-pressed', 'true')
56
- activeThemeIcon.setAttribute('href', svgOfActiveBtn)
57
- const baseLabel = themeSwitcherText?.textContent?.trim() || 'Toggle theme'
58
- const themeSwitcherLabel = `${baseLabel} (${btnToActive.dataset.bsThemeValue})`
59
- themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
60
-
61
- if (focus) {
62
- themeSwitcher.focus()
49
+ // Legacy dropdown affordances (#bd-theme toggle with a mirrored icon)
50
+ // updated only when that markup is present.
51
+ const themeSwitcher = document.querySelector('#bd-theme')
52
+ const activeThemeIcon = document.querySelector('.theme-icon-active use')
53
+ const themeIconUse = activeButtons[0].querySelector('svg use')
54
+ if (activeThemeIcon && themeIconUse) {
55
+ activeThemeIcon.setAttribute('href', themeIconUse.getAttribute('href'))
56
+ }
57
+ if (themeSwitcher) {
58
+ const themeSwitcherText = document.querySelector('#bd-theme-text')
59
+ const baseLabel = themeSwitcherText?.textContent?.trim() || 'Toggle theme'
60
+ themeSwitcher.setAttribute('aria-label', `${baseLabel} (${theme})`)
61
+ if (focus) {
62
+ themeSwitcher.focus()
63
+ }
63
64
  }
64
65
  }
65
66
 
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-009
1
2
  /**
2
3
  * ===================================================================
3
4
  * SWIPE GESTURES - Mobile Offcanvas Control
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-009
1
2
  /**
2
3
  * ===================================================================
3
4
  * KEYBOARD SHORTCUTS - Navigation Enhancements
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-008
1
2
  /**
2
3
  * ===================================================================
3
4
  * SCROLL SPY - Intersection Observer Implementation
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-008
1
2
  /**
2
3
  * ===================================================================
3
4
  * SIDEBAR STATE - Persistence and State Management
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-008
1
2
  /**
2
3
  * ===================================================================
3
4
  * SIDEBAR VISIBILITY - Hide/show left docs sidebar with persistence
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-008
1
2
  /**
2
3
  * ===================================================================
3
4
  * SMOOTH SCROLL - Enhanced Anchor Navigation
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-031
1
2
  /**
2
3
  * ===================================================================
3
4
  * APPEARANCE — Runtime theme controls (color mode + primary color)
@@ -11,13 +12,20 @@
11
12
  *
12
13
  * - Color mode buttons (light / dark / auto) — writes data-bs-theme
13
14
  * to <html> and persists to localStorage["theme"] (compatible with
14
- * halfmoon.js so both stay in sync).
15
+ * halfmoon.js so both stay in sync). Skipped in the settings
16
+ * offcanvas (compact mode), where the halfmoon segmented control
17
+ * directly above already owns color mode.
15
18
  *
16
19
  * - Primary color picker — writes to localStorage["zer0-appearance"]
17
20
  * and updates --zer0-color-primary live so every component that uses
18
21
  * the token (buttons, callouts, FABs, focus rings) reflects the
19
22
  * change without a reload. Cleared by the Reset button.
20
23
  *
24
+ * Host resolution: an explicit [data-appearance-panel-host] (e.g. the
25
+ * theme-preview sidebar) gets the full panel; otherwise the panel
26
+ * mounts compactly into #zer0AppearanceSlot inside the Settings
27
+ * offcanvas Appearance tab (legacy fallback: the offcanvas body).
28
+ *
21
29
  * Initial paint is already handled by the script emitted in
22
30
  * _includes/core/tokens-inline.html so there is no flash of default
23
31
  * color when the page loads.
@@ -33,6 +41,7 @@
33
41
  const STORAGE_KEY = 'zer0-appearance';
34
42
  const THEME_KEY = 'theme';
35
43
  const PANEL_HOST_SELECTOR = '[data-appearance-panel-host]';
44
+ const SLOT_HOST_SELECTOR = '#zer0AppearanceSlot';
36
45
  const FALLBACK_HOST_SELECTOR = '#info-section .offcanvas-body';
37
46
 
38
47
  function readPrefs() {
@@ -75,18 +84,15 @@
75
84
  try { localStorage.setItem(THEME_KEY, mode); } catch (e) { /* ignore */ }
76
85
  }
77
86
 
78
- function buildPanel(host) {
87
+ function buildPanel(host, compact) {
79
88
  const prefs = readPrefs();
80
89
  const mode = resolveColorMode();
81
90
  const primary = prefs.primary || getInitialPrimary();
82
91
 
83
92
  const wrapper = document.createElement('section');
84
- wrapper.className = 'zer0-appearance-panel border rounded p-3 mt-3';
85
93
  wrapper.setAttribute('aria-labelledby', 'zer0-appearance-heading');
86
- wrapper.innerHTML =
87
- '<h3 id="zer0-appearance-heading" class="h6 mb-3">' +
88
- '<i class="bi bi-palette me-2" aria-hidden="true"></i>Appearance' +
89
- '</h3>' +
94
+
95
+ const modeGroupHtml =
90
96
  '<div class="mb-3" role="group" aria-label="Color mode">' +
91
97
  '<label class="form-label small text-body-secondary mb-2">Color mode</label>' +
92
98
  '<div class="btn-group w-100" role="group">' +
@@ -97,18 +103,45 @@
97
103
  '<button type="button" class="btn btn-outline-secondary btn-sm" data-mode="auto">' +
98
104
  '<i class="bi bi-circle-half me-1" aria-hidden="true"></i>Auto</button>' +
99
105
  '</div>' +
100
- '</div>' +
106
+ '</div>';
107
+
108
+ // In compact mode the section heading is the visible label, so the
109
+ // <label> stays for assistive tech but is visually hidden.
110
+ const pickerHtml = (labelClass) =>
101
111
  '<div class="mb-3">' +
102
- '<label for="zer0-appearance-primary" class="form-label small text-body-secondary">' +
112
+ '<label for="zer0-appearance-primary" class="' + labelClass + '">' +
103
113
  'Primary color</label>' +
104
114
  '<input type="color" id="zer0-appearance-primary" class="form-control form-control-color" ' +
105
115
  'aria-describedby="zer0-appearance-primary-help">' +
106
116
  '<div id="zer0-appearance-primary-help" class="form-text small">' +
107
117
  'Overrides <code>--zer0-color-primary</code> across the theme.</div>' +
108
- '</div>' +
109
- '<button type="button" class="btn btn-link btn-sm p-0" data-appearance-reset>' +
110
- '<i class="bi bi-arrow-counterclockwise me-1" aria-hidden="true"></i>Reset to defaults' +
111
- '</button>';
118
+ '</div>';
119
+
120
+ if (compact) {
121
+ // Settings offcanvas: color mode lives in the halfmoon control just
122
+ // above, so render only the primary-color section, styled to match
123
+ // the panel's other h6 section headings.
124
+ wrapper.className = 'zer0-appearance-panel mb-4';
125
+ wrapper.innerHTML =
126
+ '<h6 id="zer0-appearance-heading" class="text-body-secondary small text-uppercase fw-semibold mb-2">' +
127
+ '<i class="bi bi-eyedropper me-1" aria-hidden="true"></i>Primary Color' +
128
+ '</h6>' +
129
+ pickerHtml('visually-hidden') +
130
+ '<button type="button" class="btn btn-link btn-sm p-0" data-appearance-reset>' +
131
+ '<i class="bi bi-arrow-counterclockwise me-1" aria-hidden="true"></i>Reset color' +
132
+ '</button>';
133
+ } else {
134
+ wrapper.className = 'zer0-appearance-panel border rounded p-3 mt-3';
135
+ wrapper.innerHTML =
136
+ '<h3 id="zer0-appearance-heading" class="h6 mb-3">' +
137
+ '<i class="bi bi-palette me-2" aria-hidden="true"></i>Appearance' +
138
+ '</h3>' +
139
+ modeGroupHtml +
140
+ pickerHtml('form-label small text-body-secondary') +
141
+ '<button type="button" class="btn btn-link btn-sm p-0" data-appearance-reset>' +
142
+ '<i class="bi bi-arrow-counterclockwise me-1" aria-hidden="true"></i>Reset to defaults' +
143
+ '</button>';
144
+ }
112
145
 
113
146
  host.appendChild(wrapper);
114
147
 
@@ -116,7 +149,7 @@
116
149
  const picker = wrapper.querySelector('#zer0-appearance-primary');
117
150
  picker.value = hexishOrDefault(primary, '#007bff');
118
151
 
119
- // Wire color-mode buttons
152
+ // Wire color-mode buttons (full panel only)
120
153
  wrapper.querySelectorAll('[data-mode]').forEach((btn) => {
121
154
  const m = btn.dataset.mode;
122
155
  btn.setAttribute('aria-pressed', String(m === mode));
@@ -183,10 +216,13 @@
183
216
  }
184
217
 
185
218
  function mount() {
186
- const host = document.querySelector(PANEL_HOST_SELECTOR) || document.querySelector(FALLBACK_HOST_SELECTOR);
219
+ const explicitHost = document.querySelector(PANEL_HOST_SELECTOR);
220
+ const host = explicitHost
221
+ || document.querySelector(SLOT_HOST_SELECTOR)
222
+ || document.querySelector(FALLBACK_HOST_SELECTOR);
187
223
  if (!host) return; // info-section not present on this page
188
224
  if (host.querySelector('.zer0-appearance-panel')) return; // already mounted
189
- buildPanel(host);
225
+ buildPanel(host, !explicitHost);
190
226
  }
191
227
 
192
228
  if (document.readyState === 'loading') {
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-066
1
2
  /**
2
3
  * Nanobar Initialization — config-driven page-load progress bar.
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-055
1
2
  /**
2
3
  * ==============================================================================
3
4
  * NAVIGATION SCRIPTS — DEPRECATED
@@ -1,3 +1,4 @@
1
+ // Features: ZER0-044, ZER0-045
1
2
  /*
2
3
  * obsidian-graph.js
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-044
1
2
  /*
2
3
  * obsidian-wiki-links.js
3
4
  *