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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -10
- data/README.md +7 -7
- data/_data/authors.yml +2 -2
- data/_data/features.yml +676 -0
- data/_data/navigation/README.md +54 -0
- data/_data/navigation/about.yml +7 -5
- data/_data/navigation/docs.yml +77 -31
- data/_data/navigation/home.yml +4 -3
- data/_data/navigation/main.yml +16 -7
- data/_data/navigation/quickstart.yml +4 -2
- data/_includes/components/js-cdn.html +2 -2
- data/_includes/landing/landing-install-cards.html +8 -8
- data/_includes/landing/landing-quick-links.html +4 -4
- data/_includes/navigation/breadcrumbs.html +29 -6
- data/_includes/navigation/nav-tree.html +181 -0
- data/_includes/navigation/navbar.html +262 -9
- data/_includes/navigation/sidebar-left.html +22 -23
- data/_layouts/default.html +1 -1
- data/_layouts/landing.html +1 -1
- data/_layouts/notebook.html +4 -4
- data/_layouts/root.html +2 -2
- data/_sass/core/_nav-tree.scss +145 -0
- data/_sass/custom.scss +3 -0
- data/assets/js/modules/navigation/config.js +149 -0
- data/assets/js/modules/navigation/focus.js +189 -0
- data/assets/js/modules/navigation/gestures.js +179 -0
- data/assets/js/modules/navigation/index.js +227 -0
- data/assets/js/modules/navigation/keyboard.js +237 -0
- data/assets/js/modules/navigation/scroll-spy.js +219 -0
- data/assets/js/modules/navigation/sidebar-state.js +267 -0
- data/assets/js/modules/navigation/smooth-scroll.js +153 -0
- data/scripts/migrate-nav-modes.sh +146 -0
- metadata +15 -3
- data/assets/js/sidebar.js +0 -511
|
@@ -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.
|
|
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-
|
|
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
|
|
51
|
-
{%- for
|
|
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="{{
|
|
56
|
-
{%- if
|
|
57
|
+
href="{{ child.url | relative_url }}"
|
|
58
|
+
{%- if child.url == page.url -%} aria-current="page"{%- endif -%}
|
|
57
59
|
>
|
|
58
|
-
{
|
|
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
|
|
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
|
-
* "
|
|
15
|
-
* "
|
|
16
|
-
*
|
|
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
|
-
-
|
|
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.
|
|
26
|
-
2.
|
|
27
|
-
3.
|
|
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
|
-
<!--
|
|
52
|
+
<!-- AUTO MODE: Collection Docs -->
|
|
54
53
|
<!-- ========================== -->
|
|
55
|
-
<!-- Auto-generates folder structure from
|
|
56
|
-
{% if page.sidebar.nav == "
|
|
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
|
-
<!--
|
|
62
|
+
<!-- CATEGORIES MODE -->
|
|
64
63
|
<!-- ========================== -->
|
|
65
64
|
<!-- Creates navigation from Jekyll post/page categories -->
|
|
66
|
-
{% elsif page.sidebar.nav == "
|
|
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
|
-
<!--
|
|
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/
|
|
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
|
|
data/_layouts/default.html
CHANGED
|
@@ -78,7 +78,7 @@ layout: root
|
|
|
78
78
|
<!-- MAIN CONTENT BODY -->
|
|
79
79
|
<!-- =============================== -->
|
|
80
80
|
<!-- Where the actual page content is rendered -->
|
|
81
|
-
<div
|
|
81
|
+
<div class="bd-content ps-lg-2">
|
|
82
82
|
{{ content }}
|
|
83
83
|
</div>
|
|
84
84
|
</main>
|
data/_layouts/landing.html
CHANGED
|
@@ -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
|
-
|
|
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>
|
data/_layouts/notebook.html
CHANGED
|
@@ -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="{{
|
|
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="{{
|
|
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
|
|
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.
|
|
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
|
-
<!--
|
|
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
|
+
}
|