jekyll-theme-zer0 0.16.0 → 0.17.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.
@@ -3,6 +3,7 @@
3
3
  path: /includes/navbar.html
4
4
  includes:
5
5
  purpose: Offcanvas main navigation following Bootstrap 5 best practices
6
+ with hover-activated dropdowns for desktop
6
7
  -->
7
8
 
8
9
  <!-- Navigation Links - Offcanvas -->
@@ -18,10 +19,10 @@
18
19
  <div class="offcanvas-body">
19
20
  <ul class="navbar-nav justify-content-lg-center text-start flex-grow-1">
20
21
  {%- for link in site.data.navigation.main -%}
21
- {%- assign has_children = link.sublinks and link.sublinks.size > 0 -%}
22
+ {%- assign has_children = link.children and link.children.size > 0 -%}
22
23
 
23
24
  {%- if has_children -%}
24
- <li class="nav-item dropdown d-flex align-items-center">
25
+ <li class="nav-item dropdown d-flex align-items-center nav-hover-dropdown">
25
26
  <!-- Parent link navigates directly -->
26
27
  <a
27
28
  class="nav-link"
@@ -34,28 +35,32 @@
34
35
  {{ link.title }}
35
36
  </a>
36
37
 
37
- <!-- Split toggle opens the dropdown -->
38
+ <!-- Split toggle opens the dropdown (click on mobile, hover on desktop) -->
38
39
  <a
39
- class="nav-link dropdown-toggle dropdown-toggle-split ms-2"
40
+ class="nav-link dropdown-toggle dropdown-toggle-split ms-1 px-1"
40
41
  href="#"
41
42
  id="dropdown-{{ link.title | slugify }}"
42
43
  role="button"
43
44
  data-bs-toggle="dropdown"
45
+ data-bs-auto-close="outside"
44
46
  aria-expanded="false"
45
47
  aria-label="Toggle {{ link.title }} menu"
46
48
  >
47
49
  <span class="visually-hidden">Toggle dropdown</span>
48
50
  </a>
49
51
 
50
- <ul class="dropdown-menu dropdown-menu-start w-100" aria-labelledby="dropdown-{{ link.title | slugify }}">
51
- {%- for sublink in link.sublinks -%}
52
+ <ul class="dropdown-menu dropdown-menu-start" aria-labelledby="dropdown-{{ link.title | slugify }}">
53
+ {%- for child in link.children -%}
52
54
  <li>
53
55
  <a
54
56
  class="dropdown-item"
55
- href="{{ sublink.url | relative_url }}"
56
- {%- if sublink.url == page.url -%} aria-current="page"{%- endif -%}
57
+ href="{{ child.url | relative_url }}"
58
+ {%- if child.url == page.url -%} aria-current="page"{%- endif -%}
57
59
  >
58
- {{ sublink.title }}
60
+ {%- if child.icon -%}
61
+ <i class="{{site.default_icon}} {{ child.icon }} me-2"></i>
62
+ {%- endif -%}
63
+ {{ child.title }}
59
64
  </a>
60
65
  </li>
61
66
  {%- endfor -%}
@@ -80,6 +85,168 @@
80
85
  </div>
81
86
  </div>
82
87
 
88
+ <!-- Styles for hover-activated dropdowns on desktop -->
89
+ <style>
90
+ /* Desktop: Show navigation inline in header (not offcanvas) */
91
+ @media (min-width: 992px) {
92
+ /* Make offcanvas behave as regular inline content on desktop */
93
+ #bdNavbar {
94
+ position: static !important;
95
+ transform: none !important;
96
+ visibility: visible !important;
97
+ background: transparent !important;
98
+ border: none !important;
99
+ width: auto !important;
100
+ flex-grow: 0 !important;
101
+ }
102
+
103
+ #bdNavbar .offcanvas-header {
104
+ display: none !important;
105
+ }
106
+
107
+ #bdNavbar .offcanvas-body {
108
+ padding: 0 !important;
109
+ overflow: visible !important;
110
+ }
111
+
112
+ /* Horizontal nav layout */
113
+ #bdNavbar .navbar-nav {
114
+ flex-direction: row !important;
115
+ gap: 0.25rem;
116
+ }
117
+
118
+ /* Dropdown positioning - ensure it appears BELOW the nav item */
119
+ .nav-hover-dropdown {
120
+ position: relative;
121
+ }
122
+
123
+ .nav-hover-dropdown > .dropdown-menu {
124
+ position: absolute;
125
+ top: 100% !important;
126
+ left: 0;
127
+ margin-top: 0.125rem !important;
128
+ min-width: 12rem;
129
+ z-index: 1050;
130
+ }
131
+
132
+ /* Hover behavior for dropdowns */
133
+ .nav-hover-dropdown:hover > .dropdown-menu {
134
+ display: block;
135
+ }
136
+
137
+ /* Smooth fade-in animation */
138
+ .nav-hover-dropdown .dropdown-menu {
139
+ opacity: 0;
140
+ visibility: hidden;
141
+ transition: opacity 0.15s ease-in-out, visibility 0.15s ease-in-out;
142
+ display: block !important;
143
+ }
144
+
145
+ .nav-hover-dropdown:hover .dropdown-menu,
146
+ .nav-hover-dropdown .dropdown-menu.show {
147
+ opacity: 1;
148
+ visibility: visible;
149
+ }
150
+
151
+ /* Ensure dropdown toggle caret is subtle */
152
+ .nav-hover-dropdown .dropdown-toggle-split {
153
+ padding-left: 0.25rem;
154
+ padding-right: 0.5rem;
155
+ }
156
+
157
+ .nav-hover-dropdown .dropdown-toggle-split::after {
158
+ vertical-align: 0.15em;
159
+ font-size: 0.75em;
160
+ }
161
+ }
162
+
163
+ /* Mobile: Standard offcanvas behavior with stacked dropdowns */
164
+ @media (max-width: 991.98px) {
165
+ #bdNavbar .navbar-nav {
166
+ flex-direction: column !important;
167
+ }
168
+
169
+ /* Fix mobile nav item layout - keep toggle next to link text */
170
+ .nav-hover-dropdown {
171
+ flex-wrap: wrap !important;
172
+ justify-content: flex-start !important;
173
+ }
174
+
175
+ /* Parent link should not stretch - stay with its content width */
176
+ .nav-hover-dropdown > .nav-link:first-child {
177
+ flex: 0 0 auto !important;
178
+ }
179
+
180
+ /* Toggle button stays next to link */
181
+ .nav-hover-dropdown > .dropdown-toggle-split {
182
+ flex: 0 0 auto;
183
+ }
184
+
185
+ /* Rotate caret on open */
186
+ .nav-hover-dropdown > .dropdown-toggle-split::after {
187
+ transition: transform 0.25s ease;
188
+ }
189
+
190
+ .nav-hover-dropdown > .dropdown-toggle-split.show::after {
191
+ transform: rotate(180deg);
192
+ }
193
+
194
+ /* Stack dropdown below parent in mobile offcanvas - full width on new row */
195
+ .nav-hover-dropdown .dropdown-menu {
196
+ position: static !important;
197
+ float: none;
198
+ flex-basis: 100% !important;
199
+ width: 100%;
200
+ margin-top: 0;
201
+ border: none;
202
+ box-shadow: none;
203
+ background-color: var(--bs-tertiary-bg);
204
+ padding-left: 1rem;
205
+ /* Transition for smooth open/close */
206
+ max-height: 0;
207
+ overflow: hidden;
208
+ opacity: 0;
209
+ transition: max-height 0.3s ease, opacity 0.25s ease, padding 0.3s ease;
210
+ padding-top: 0;
211
+ padding-bottom: 0;
212
+ display: block !important;
213
+ }
214
+
215
+ /* Show dropdown on click with animation */
216
+ .nav-hover-dropdown .dropdown-menu.show {
217
+ max-height: 500px;
218
+ opacity: 1;
219
+ padding-top: 0.5rem;
220
+ padding-bottom: 0.5rem;
221
+ }
222
+ }
223
+
224
+ /* Active dropdown item styling */
225
+ .dropdown-item[aria-current="page"] {
226
+ background-color: var(--bs-primary);
227
+ color: var(--bs-white);
228
+ }
229
+
230
+ .dropdown-item[aria-current="page"]:hover {
231
+ background-color: var(--bs-primary);
232
+ filter: brightness(0.9);
233
+ }
234
+
235
+ /* Dropdown menu styling */
236
+ .nav-hover-dropdown .dropdown-menu {
237
+ border-radius: 0.375rem;
238
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
239
+ }
240
+
241
+ .nav-hover-dropdown .dropdown-item {
242
+ padding: 0.5rem 1rem;
243
+ }
244
+
245
+ .nav-hover-dropdown .dropdown-item:hover {
246
+ background-color: var(--bs-tertiary-bg);
247
+ }
248
+ </style>
249
+
83
250
  <!-- Script to handle offcanvas navigation -->
84
251
  <script>
85
252
  document.addEventListener('DOMContentLoaded', function() {
@@ -98,5 +265,91 @@ document.addEventListener('DOMContentLoaded', function() {
98
265
  }, 100);
99
266
  });
100
267
  });
268
+
269
+ // Desktop: Add keyboard accessibility for hover dropdowns
270
+ const hoverDropdowns = document.querySelectorAll('.nav-hover-dropdown');
271
+ hoverDropdowns.forEach(dropdown => {
272
+ const toggle = dropdown.querySelector('.dropdown-toggle');
273
+ const menu = dropdown.querySelector('.dropdown-menu');
274
+
275
+ // Show on focus (keyboard navigation)
276
+ toggle?.addEventListener('focus', () => {
277
+ menu?.classList.add('show');
278
+ });
279
+
280
+ // Hide when focus leaves the dropdown entirely
281
+ dropdown.addEventListener('focusout', (e) => {
282
+ if (!dropdown.contains(e.relatedTarget)) {
283
+ menu?.classList.remove('show');
284
+ }
285
+ });
286
+ });
287
+
288
+ // Mobile: Custom dropdown handling to prevent glitches
289
+ // Only apply on mobile breakpoint
290
+ const isMobile = () => window.innerWidth < 992;
291
+
292
+ hoverDropdowns.forEach(dropdown => {
293
+ const toggle = dropdown.querySelector('.dropdown-toggle-split');
294
+ const menu = dropdown.querySelector('.dropdown-menu');
295
+
296
+ if (!toggle || !menu) return;
297
+
298
+ // Prevent Bootstrap's default dropdown behavior on mobile
299
+ toggle.addEventListener('click', function(e) {
300
+ if (!isMobile()) return; // Let desktop use default behavior
301
+
302
+ e.preventDefault();
303
+ e.stopPropagation();
304
+
305
+ // Toggle this dropdown
306
+ const isOpen = menu.classList.contains('show');
307
+
308
+ if (isOpen) {
309
+ // Close this dropdown
310
+ menu.classList.remove('show');
311
+ toggle.classList.remove('show');
312
+ toggle.setAttribute('aria-expanded', 'false');
313
+ } else {
314
+ // Open this dropdown (don't close others - allow multiple open)
315
+ menu.classList.add('show');
316
+ toggle.classList.add('show');
317
+ toggle.setAttribute('aria-expanded', 'true');
318
+ }
319
+ });
320
+ });
321
+
322
+ // Close dropdowns when clicking outside on mobile
323
+ document.addEventListener('click', function(e) {
324
+ if (!isMobile()) return;
325
+
326
+ // If click is outside all dropdowns, close them all
327
+ const clickedInsideDropdown = e.target.closest('.nav-hover-dropdown');
328
+ if (!clickedInsideDropdown) {
329
+ hoverDropdowns.forEach(dropdown => {
330
+ const toggle = dropdown.querySelector('.dropdown-toggle-split');
331
+ const menu = dropdown.querySelector('.dropdown-menu');
332
+ if (menu && toggle) {
333
+ menu.classList.remove('show');
334
+ toggle.classList.remove('show');
335
+ toggle.setAttribute('aria-expanded', 'false');
336
+ }
337
+ });
338
+ }
339
+ });
340
+
341
+ // Reset dropdowns when offcanvas closes
342
+ const offcanvasEl = document.getElementById('bdNavbar');
343
+ offcanvasEl?.addEventListener('hide.bs.offcanvas', function() {
344
+ hoverDropdowns.forEach(dropdown => {
345
+ const toggle = dropdown.querySelector('.dropdown-toggle-split');
346
+ const menu = dropdown.querySelector('.dropdown-menu');
347
+ if (menu && toggle) {
348
+ menu.classList.remove('show');
349
+ toggle.classList.remove('show');
350
+ toggle.setAttribute('aria-expanded', 'false');
351
+ }
352
+ });
353
+ });
101
354
  });
102
355
  </script>
@@ -4,27 +4,26 @@
4
4
  ===================================================================
5
5
 
6
6
  File: sidebar-left.html
7
- Path: _includes/sidebar-left.html
8
- Purpose: Left sidebar navigation with multiple content modes including
9
- dynamic page listing, category browsing, and manual navigation
7
+ Path: _includes/navigation/sidebar-left.html
8
+ Purpose: Left sidebar navigation with three standardized content modes
10
9
 
11
10
  Template Logic:
12
11
  - Responsive offcanvas sidebar for mobile devices
13
12
  - Three navigation modes based on page.sidebar.nav:
14
- * "dynamic": Auto-generated folder structure from pages
15
- * "searchCats": Category-based navigation from site categories
16
- * Manual: Predefined navigation from _data files
13
+ * "auto": Auto-generated folder structure from collection documents
14
+ * "tree": YAML-defined hierarchical navigation from _data/navigation/
15
+ * "categories": Category-based navigation from site categories
17
16
 
18
17
  Dependencies:
19
- - sidebar-folders.html: Dynamic folder structure generation
20
- - sidebar-categories.html: Category-based navigation
21
- - nav_list.html: Manual navigation list rendering
18
+ - sidebar-folders.html: Dynamic folder structure generation (auto mode)
19
+ - sidebar-categories.html: Category-based navigation (categories mode)
20
+ - nav-tree.html: YAML-based hierarchical tree (tree mode)
22
21
  - Bootstrap 5 offcanvas component
23
22
 
24
23
  Navigation Modes:
25
- 1. Dynamic: Scans site.pages for index.md files to build folder structure
26
- 2. Categories: Groups content by Jekyll categories
27
- 3. Manual: Uses predefined navigation from _data/navigation.yml
24
+ 1. auto: Scans collection documents to build folder structure
25
+ 2. tree: Uses predefined YAML navigation from _data/navigation/*.yml
26
+ 3. categories: Groups content by Jekyll categories
28
27
  ===================================================================
29
28
  -->
30
29
 
@@ -50,32 +49,32 @@
50
49
  <div class="offcanvas-body overflow-auto">
51
50
 
52
51
  <!-- ========================== -->
53
- <!-- DYNAMIC PAGE LISTING -->
52
+ <!-- AUTO MODE: Collection Docs -->
54
53
  <!-- ========================== -->
55
- <!-- Auto-generates folder structure from pages containing index.md -->
56
- {% if page.sidebar.nav == "dynamic" %}
57
- <div class="list-group" id="sidebar-content">
54
+ <!-- Auto-generates folder structure from collection documents -->
55
+ {% if page.sidebar.nav == "auto" %}
56
+ <div class="list-group nav-tree" id="sidebar-content" data-nav-tree>
58
57
  {% assign folders = site.pages | where_exp: "item", "item.path contains 'index.md'" | sort: 'path' %}
59
58
  {% include navigation/sidebar-folders.html folders=folders %}
60
59
  </div>
61
60
 
62
61
  <!-- ========================== -->
63
- <!-- CATEGORY-BASED NAVIGATION -->
62
+ <!-- CATEGORIES MODE -->
64
63
  <!-- ========================== -->
65
64
  <!-- Creates navigation from Jekyll post/page categories -->
66
- {% elsif page.sidebar.nav == "searchCats" %}
67
- <div class="list-group" id="sidebar-content">
65
+ {% elsif page.sidebar.nav == "categories" %}
66
+ <div class="list-group nav-tree" id="sidebar-content" data-nav-tree>
68
67
  {% assign categories = site.categories | sort %}
69
68
  {% include navigation/sidebar-categories.html categories=categories %}
70
69
  </div>
71
70
 
72
71
  <!-- ========================== -->
73
- <!-- MANUAL NAVIGATION LIST -->
72
+ <!-- TREE MODE: YAML Navigation -->
74
73
  <!-- ========================== -->
75
- <!-- Uses predefined navigation structure from _data files -->
74
+ <!-- Uses predefined YAML navigation structure from _data files -->
76
75
  {% elsif page.sidebar.nav %}
77
- <nav class="w-100">
78
- {% include navigation/nav_list.html nav=page.sidebar.nav %}
76
+ <nav class="w-100 nav-tree" data-nav-tree>
77
+ {% include navigation/nav-tree.html nav=page.sidebar.nav %}
79
78
  </nav>
80
79
  {% endif %}
81
80
 
@@ -78,7 +78,7 @@ layout: root
78
78
  <!-- MAIN CONTENT BODY -->
79
79
  <!-- =============================== -->
80
80
  <!-- Where the actual page content is rendered -->
81
- <div id="main-content" class="bd-content ps-lg-2">
81
+ <div class="bd-content ps-lg-2">
82
82
  {{ content }}
83
83
  </div>
84
84
  </main>
@@ -60,7 +60,7 @@ layout: root
60
60
  <a href="#features" class="btn btn-outline-light btn-lg">
61
61
  <i class="bi bi-list-check me-2"></i>Features
62
62
  </a>
63
- <a href="{{ site.resources.github_repo }}" class="btn btn-outline-light btn-lg">
63
+ <a href="{{ site.resources.github_repo | default: '' | join: '' }}" class="btn btn-outline-light btn-lg">
64
64
  <i class="bi bi-github me-2"></i>GitHub
65
65
  </a>
66
66
  </div>
@@ -95,7 +95,7 @@ layout: default
95
95
  {% if page.tags and page.tags.size > 0 %}
96
96
  <div class="notebook-tags mb-3">
97
97
  {% for tag in page.tags %}
98
- <a href="{{ site.baseurl }}/tags/{{ tag | slugify }}/" class="badge bg-secondary text-decoration-none me-1">
98
+ <a href="{{ '/tags/' | relative_url }}#{{ tag | slugify }}" class="badge bg-secondary text-decoration-none me-1">
99
99
  {{ tag }}
100
100
  </a>
101
101
  {% endfor %}
@@ -107,7 +107,7 @@ layout: default
107
107
  <div class="notebook-categories mb-3">
108
108
  <i class="bi bi-folder me-1"></i>
109
109
  {% for category in page.categories %}
110
- <a href="{{ site.baseurl }}/categories/{{ category | slugify }}/" class="text-decoration-none">
110
+ <a href="{{ '/categories/' | relative_url }}#{{ category | slugify }}" class="text-decoration-none">
111
111
  {{ category }}
112
112
  </a>
113
113
  {% unless forloop.last %}<span class="mx-1">/</span>{% endunless %}
@@ -148,7 +148,7 @@ layout: default
148
148
  class="btn btn-outline-primary btn-sm" target="_blank" rel="noopener noreferrer">
149
149
  <i class="bi bi-linkedin"></i> LinkedIn
150
150
  </a>
151
- <a href="mailto:?subject={{ page.title | uri_escape }}&body={{ site.url | append: page.url | uri_escape }}"
151
+ <a href="mailto:{{ site.email | escape }}?subject={{ page.title | uri_escape }}&body={{ site.url | append: page.url | uri_escape }}"
152
152
  class="btn btn-outline-primary btn-sm">
153
153
  <i class="bi bi-envelope"></i> Email
154
154
  </a>
@@ -158,7 +158,7 @@ layout: default
158
158
 
159
159
  <!-- Download Original Notebook -->
160
160
  <div class="download-notebook mb-4">
161
- <a href="{{ site.baseurl }}/pages/_notebooks/{{ page.slug }}.ipynb"
161
+ <a href="https://raw.githubusercontent.com/{{ site.repository }}/{{ site.branch | default: 'main' }}/pages/_notebooks/{{ page.slug }}.ipynb"
162
162
  class="btn btn-outline-secondary btn-sm" download>
163
163
  <i class="bi bi-download"></i> Download Original Notebook
164
164
  </a>
data/_layouts/root.html CHANGED
@@ -65,8 +65,8 @@
65
65
  <!-- ======================== -->
66
66
  <!-- MAIN CONTENT AREA -->
67
67
  <!-- ======================== -->
68
- <!-- This is where child layouts inject their specific content -->
69
- <div>
68
+ <!-- Skip-link target: keep a single, consistent #main-content anchor site-wide -->
69
+ <div id="main-content">
70
70
  {{ content }}
71
71
  </div>
72
72
 
@@ -0,0 +1,145 @@
1
+ // ===================================================================
2
+ // NAV TREE - Sidebar Navigation Tree Styles
3
+ // ===================================================================
4
+ //
5
+ // File: _nav-tree.scss
6
+ // Path: _sass/core/_nav-tree.scss
7
+ // Purpose: Styles for the hierarchical navigation tree component
8
+ //
9
+ // Features:
10
+ // - Collapsible tree nodes with smooth transitions
11
+ // - Active state highlighting
12
+ // - Hover effects
13
+ // - Chevron rotation on expand/collapse
14
+ // - Nested indentation
15
+ //
16
+ // ===================================================================
17
+
18
+ // Navigation Tree Container
19
+ .nav-tree {
20
+ font-size: 0.875rem;
21
+ }
22
+
23
+ .nav-tree-root {
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+ // Navigation Tree Items
29
+ .nav-tree-item {
30
+ margin-bottom: 0.125rem;
31
+
32
+ // Nested items get additional indentation via ps-3 class
33
+ }
34
+
35
+ // Navigation Tree Links
36
+ .nav-tree-link {
37
+ color: var(--bs-body-color);
38
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
39
+
40
+ &:hover {
41
+ color: var(--bs-primary);
42
+ background-color: var(--bs-tertiary-bg);
43
+ }
44
+
45
+ &.active {
46
+ color: var(--bs-primary);
47
+ background-color: var(--bs-primary-bg-subtle);
48
+ font-weight: 500;
49
+ }
50
+ }
51
+
52
+ // Navigation Tree Text (non-link items)
53
+ .nav-tree-text {
54
+ color: var(--bs-secondary-color);
55
+ }
56
+
57
+ // Navigation Tree Toggle Buttons
58
+ .nav-tree-toggle {
59
+ color: var(--bs-body-color);
60
+ text-decoration: none;
61
+ border: none;
62
+ background: transparent;
63
+ transition: color 0.15s ease-in-out;
64
+
65
+ &:hover {
66
+ color: var(--bs-primary);
67
+ }
68
+
69
+ &:focus {
70
+ outline: none;
71
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-primary-rgb), 0.25);
72
+ }
73
+
74
+ // Chevron rotation
75
+ .bi-chevron-down,
76
+ .nav-tree-chevron {
77
+ transition: transform 0.2s ease-in-out;
78
+ }
79
+
80
+ &.collapsed {
81
+ .bi-chevron-down,
82
+ .nav-tree-chevron {
83
+ transform: rotate(-90deg);
84
+ }
85
+ }
86
+ }
87
+
88
+ // Children container
89
+ .nav-tree-children {
90
+ margin-top: 0.25rem;
91
+ border-left: 1px solid var(--bs-border-color);
92
+ margin-left: 0.5rem;
93
+ padding-left: 0.75rem;
94
+ }
95
+
96
+ // Collapse animation
97
+ .nav-tree .collapse {
98
+ transition: height 0.2s ease-in-out;
99
+ }
100
+
101
+ // Depth-based styling
102
+ .nav-tree-item[data-depth="0"] > .nav-tree-link,
103
+ .nav-tree-item[data-depth="0"] > div > .nav-tree-link,
104
+ .nav-tree-item[data-depth="0"] > .nav-tree-toggle {
105
+ font-weight: 500;
106
+ }
107
+
108
+ .nav-tree-item[data-depth="1"] > .nav-tree-link,
109
+ .nav-tree-item[data-depth="1"] > div > .nav-tree-link {
110
+ font-weight: normal;
111
+ }
112
+
113
+ .nav-tree-item[data-depth="2"] > .nav-tree-link,
114
+ .nav-tree-item[data-depth="2"] > div > .nav-tree-link {
115
+ font-size: 0.8125rem;
116
+ color: var(--bs-secondary-color);
117
+
118
+ &.active {
119
+ color: var(--bs-primary);
120
+ }
121
+ }
122
+
123
+ // Keyboard navigation focus state
124
+ .keyboard-nav .nav-tree-link:focus,
125
+ .keyboard-nav .nav-tree-toggle:focus {
126
+ outline: 2px solid var(--bs-primary);
127
+ outline-offset: 2px;
128
+ }
129
+
130
+ // Dark mode adjustments
131
+ [data-bs-theme="dark"] {
132
+ .nav-tree-link {
133
+ &:hover {
134
+ background-color: rgba(255, 255, 255, 0.05);
135
+ }
136
+
137
+ &.active {
138
+ background-color: rgba(var(--bs-primary-rgb), 0.15);
139
+ }
140
+ }
141
+
142
+ .nav-tree-children {
143
+ border-left-color: var(--bs-border-color);
144
+ }
145
+ }
data/_sass/custom.scss CHANGED
@@ -5,6 +5,9 @@
5
5
  // Import notebook-specific styles
6
6
  @import "notebooks";
7
7
 
8
+ // Import navigation tree styles
9
+ @import "core/nav-tree";
10
+
8
11
  html, body {
9
12
  max-width: 100%;
10
13
  // overflow-x: hidden;