jekyll-theme-zer0 0.20.3 → 0.21.2
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 +79 -0
- data/_includes/components/dev-shortcuts.html +97 -50
- data/_includes/components/env-switcher.html +212 -0
- data/_includes/components/info-section.html +173 -32
- data/_includes/components/js-cdn.html +3 -0
- data/_includes/components/theme-info.html +65 -273
- data/_includes/core/header.html +36 -32
- data/_includes/navigation/navbar.html +11 -272
- data/_sass/core/_navbar.scss +390 -0
- data/_sass/custom.scss +3 -0
- data/assets/js/navigation.js +206 -0
- data/scripts/docker-publish +238 -0
- data/scripts/lib/common.sh +55 -0
- data/scripts/lib/gem.sh +7 -0
- data/scripts/lib/git.sh +3 -1
- data/scripts/lib/validation.sh +9 -1
- data/scripts/lib/version.sh +34 -0
- metadata +6 -2
data/_includes/core/header.html
CHANGED
|
@@ -126,40 +126,44 @@
|
|
|
126
126
|
<!-- ========================== -->
|
|
127
127
|
<!-- UTILITY CONTROLS -->
|
|
128
128
|
<!-- ========================== -->
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
<!-- Settings Modal Toggle -->
|
|
144
|
-
<div class="btn d-none d-lg-flex nav-settings"
|
|
145
|
-
data-bs-toggle="modal"
|
|
146
|
-
data-bs-target="#info-section"
|
|
147
|
-
aria-expanded="false"
|
|
148
|
-
aria-controls="#info-section"
|
|
149
|
-
role="button">
|
|
150
|
-
<i type="button" class="{{site.default_icon}} bi-gear"></i>
|
|
151
|
-
</div>
|
|
129
|
+
<div class="navbar-utility-controls d-flex align-items-center">
|
|
130
|
+
<!-- Search Modal Toggle -->
|
|
131
|
+
<button
|
|
132
|
+
class="btn nav-search-button"
|
|
133
|
+
type="button"
|
|
134
|
+
data-bs-toggle="modal"
|
|
135
|
+
data-bs-target="#siteSearchModal"
|
|
136
|
+
data-search-toggle
|
|
137
|
+
aria-label="Open search"
|
|
138
|
+
title="Search"
|
|
139
|
+
>
|
|
140
|
+
<i class="{{site.default_icon}} bi-search"></i>
|
|
141
|
+
<span class="nav-link-text d-none d-xl-inline ms-1">Search</span>
|
|
142
|
+
</button>
|
|
152
143
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
<!-- Settings Modal Toggle -->
|
|
145
|
+
<button
|
|
146
|
+
class="btn nav-settings-button d-none d-lg-inline-flex"
|
|
147
|
+
type="button"
|
|
148
|
+
data-bs-toggle="modal"
|
|
149
|
+
data-bs-target="#info-section"
|
|
150
|
+
aria-label="Settings"
|
|
151
|
+
title="Settings"
|
|
152
|
+
>
|
|
153
|
+
<i class="{{site.default_icon}} bi-gear"></i>
|
|
162
154
|
</button>
|
|
155
|
+
|
|
156
|
+
<!-- Navigation Menu Toggle - Mobile view -->
|
|
157
|
+
<div class="bd-navbar-toggle d-lg-none">
|
|
158
|
+
<button class="navbar-toggler p-2"
|
|
159
|
+
type="button"
|
|
160
|
+
data-bs-toggle="offcanvas"
|
|
161
|
+
data-bs-target="#bdNavbar"
|
|
162
|
+
aria-controls="bdNavbar"
|
|
163
|
+
aria-label="Toggle navigation">
|
|
164
|
+
<span class="bi bi-three-dots"></span>
|
|
165
|
+
</button>
|
|
166
|
+
</div>
|
|
163
167
|
</div>
|
|
164
168
|
</nav>
|
|
165
169
|
</div>
|
|
@@ -34,11 +34,12 @@
|
|
|
34
34
|
class="nav-link"
|
|
35
35
|
href="{{ link.url | relative_url }}"
|
|
36
36
|
{%- if link.url == page.url -%} aria-current="page"{%- endif -%}
|
|
37
|
+
title="{{ link.title }}"
|
|
37
38
|
>
|
|
38
39
|
{%- if link.icon -%}
|
|
39
|
-
<i class="{{site.default_icon}} {{ link.icon }}
|
|
40
|
+
<i class="{{site.default_icon}} {{ link.icon }}"></i>
|
|
40
41
|
{%- endif -%}
|
|
41
|
-
{{ link.title }}
|
|
42
|
+
<span class="nav-link-text">{{ link.title }}</span>
|
|
42
43
|
</a>
|
|
43
44
|
|
|
44
45
|
<!-- Split toggle opens the dropdown (click on mobile, hover on desktop) -->
|
|
@@ -78,11 +79,12 @@
|
|
|
78
79
|
class="nav-link"
|
|
79
80
|
href="{{ link.url | relative_url }}"
|
|
80
81
|
{%- if link.url == page.url -%} aria-current="page"{%- endif -%}
|
|
82
|
+
title="{{ link.title }}"
|
|
81
83
|
>
|
|
82
84
|
{%- if link.icon -%}
|
|
83
|
-
<i class="{{site.default_icon}} {{ link.icon }}
|
|
85
|
+
<i class="{{site.default_icon}} {{ link.icon }}"></i>
|
|
84
86
|
{%- endif -%}
|
|
85
|
-
{{ link.title }}
|
|
87
|
+
<span class="nav-link-text">{{ link.title }}</span>
|
|
86
88
|
</a>
|
|
87
89
|
</li>
|
|
88
90
|
{%- endif -%}
|
|
@@ -116,271 +118,8 @@
|
|
|
116
118
|
</div>
|
|
117
119
|
</div>
|
|
118
120
|
|
|
119
|
-
<!--
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
#bdNavbar {
|
|
125
|
-
position: static !important;
|
|
126
|
-
transform: none !important;
|
|
127
|
-
visibility: visible !important;
|
|
128
|
-
background: transparent !important;
|
|
129
|
-
border: none !important;
|
|
130
|
-
width: auto !important;
|
|
131
|
-
flex-grow: 0 !important;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
#bdNavbar .offcanvas-header {
|
|
135
|
-
display: none !important;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
#bdNavbar .offcanvas-body {
|
|
139
|
-
padding: 0 !important;
|
|
140
|
-
overflow: visible !important;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/* Horizontal nav layout */
|
|
144
|
-
#bdNavbar .navbar-nav {
|
|
145
|
-
flex-direction: row !important;
|
|
146
|
-
gap: 0.25rem;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/* Dropdown positioning - ensure it appears BELOW the nav item */
|
|
150
|
-
.nav-hover-dropdown {
|
|
151
|
-
position: relative;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.nav-hover-dropdown > .dropdown-menu {
|
|
155
|
-
position: absolute;
|
|
156
|
-
top: 100% !important;
|
|
157
|
-
left: 0;
|
|
158
|
-
margin-top: 0.125rem !important;
|
|
159
|
-
min-width: 12rem;
|
|
160
|
-
z-index: 1050;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/* Hover behavior for dropdowns */
|
|
164
|
-
.nav-hover-dropdown:hover > .dropdown-menu {
|
|
165
|
-
display: block;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/* Smooth fade-in animation */
|
|
169
|
-
.nav-hover-dropdown .dropdown-menu {
|
|
170
|
-
opacity: 0;
|
|
171
|
-
visibility: hidden;
|
|
172
|
-
transition: opacity 0.15s ease-in-out, visibility 0.15s ease-in-out;
|
|
173
|
-
display: block !important;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.nav-hover-dropdown:hover .dropdown-menu,
|
|
177
|
-
.nav-hover-dropdown .dropdown-menu.show {
|
|
178
|
-
opacity: 1;
|
|
179
|
-
visibility: visible;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/* Ensure dropdown toggle caret is subtle */
|
|
183
|
-
.nav-hover-dropdown .dropdown-toggle-split {
|
|
184
|
-
padding-left: 0.25rem;
|
|
185
|
-
padding-right: 0.5rem;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.nav-hover-dropdown .dropdown-toggle-split::after {
|
|
189
|
-
vertical-align: 0.15em;
|
|
190
|
-
font-size: 0.75em;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/* Mobile: Standard offcanvas behavior with stacked dropdowns */
|
|
195
|
-
@media (max-width: 991.98px) {
|
|
196
|
-
#bdNavbar .navbar-nav {
|
|
197
|
-
flex-direction: column !important;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/* Fix mobile nav item layout - keep toggle next to link text */
|
|
201
|
-
.nav-hover-dropdown {
|
|
202
|
-
flex-wrap: wrap !important;
|
|
203
|
-
justify-content: flex-start !important;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/* Parent link should not stretch - stay with its content width */
|
|
207
|
-
.nav-hover-dropdown > .nav-link:first-child {
|
|
208
|
-
flex: 0 0 auto !important;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/* Toggle button stays next to link */
|
|
212
|
-
.nav-hover-dropdown > .dropdown-toggle-split {
|
|
213
|
-
flex: 0 0 auto;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/* Rotate caret on open */
|
|
217
|
-
.nav-hover-dropdown > .dropdown-toggle-split::after {
|
|
218
|
-
transition: transform 0.25s ease;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
.nav-hover-dropdown > .dropdown-toggle-split.show::after {
|
|
222
|
-
transform: rotate(180deg);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/* Stack dropdown below parent in mobile offcanvas - full width on new row */
|
|
226
|
-
.nav-hover-dropdown .dropdown-menu {
|
|
227
|
-
position: static !important;
|
|
228
|
-
float: none;
|
|
229
|
-
flex-basis: 100% !important;
|
|
230
|
-
width: 100%;
|
|
231
|
-
margin-top: 0;
|
|
232
|
-
border: none;
|
|
233
|
-
box-shadow: none;
|
|
234
|
-
background-color: var(--bs-tertiary-bg);
|
|
235
|
-
padding-left: 1rem;
|
|
236
|
-
/* Transition for smooth open/close */
|
|
237
|
-
max-height: 0;
|
|
238
|
-
overflow: hidden;
|
|
239
|
-
opacity: 0;
|
|
240
|
-
transition: max-height 0.3s ease, opacity 0.25s ease, padding 0.3s ease;
|
|
241
|
-
padding-top: 0;
|
|
242
|
-
padding-bottom: 0;
|
|
243
|
-
display: block !important;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/* Show dropdown on click with animation */
|
|
247
|
-
.nav-hover-dropdown .dropdown-menu.show {
|
|
248
|
-
max-height: 500px;
|
|
249
|
-
opacity: 1;
|
|
250
|
-
padding-top: 0.5rem;
|
|
251
|
-
padding-bottom: 0.5rem;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/* Active dropdown item styling */
|
|
256
|
-
.dropdown-item[aria-current="page"] {
|
|
257
|
-
background-color: var(--bs-primary);
|
|
258
|
-
color: var(--bs-white);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
.dropdown-item[aria-current="page"]:hover {
|
|
262
|
-
background-color: var(--bs-primary);
|
|
263
|
-
filter: brightness(0.9);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/* Dropdown menu styling */
|
|
267
|
-
.nav-hover-dropdown .dropdown-menu {
|
|
268
|
-
border-radius: 0.375rem;
|
|
269
|
-
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
.nav-hover-dropdown .dropdown-item {
|
|
273
|
-
padding: 0.5rem 1rem;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
.nav-hover-dropdown .dropdown-item:hover {
|
|
277
|
-
background-color: var(--bs-tertiary-bg);
|
|
278
|
-
}
|
|
279
|
-
</style>
|
|
280
|
-
|
|
281
|
-
<!-- Script to handle offcanvas navigation -->
|
|
282
|
-
<script>
|
|
283
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
284
|
-
// Get all navigation links in the offcanvas
|
|
285
|
-
const offcanvasLinks = document.querySelectorAll('#bdNavbar .nav-link[href]:not(.dropdown-toggle), #bdNavbar .dropdown-item[href]');
|
|
286
|
-
|
|
287
|
-
offcanvasLinks.forEach(link => {
|
|
288
|
-
link.addEventListener('click', function(e) {
|
|
289
|
-
// Allow the navigation to happen
|
|
290
|
-
// Then close the offcanvas after a brief delay
|
|
291
|
-
setTimeout(() => {
|
|
292
|
-
const offcanvas = bootstrap.Offcanvas.getInstance(document.getElementById('bdNavbar'));
|
|
293
|
-
if (offcanvas) {
|
|
294
|
-
offcanvas.hide();
|
|
295
|
-
}
|
|
296
|
-
}, 100);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
// Desktop: Add keyboard accessibility for hover dropdowns
|
|
301
|
-
const hoverDropdowns = document.querySelectorAll('.nav-hover-dropdown');
|
|
302
|
-
hoverDropdowns.forEach(dropdown => {
|
|
303
|
-
const toggle = dropdown.querySelector('.dropdown-toggle');
|
|
304
|
-
const menu = dropdown.querySelector('.dropdown-menu');
|
|
305
|
-
|
|
306
|
-
// Show on focus (keyboard navigation)
|
|
307
|
-
toggle?.addEventListener('focus', () => {
|
|
308
|
-
menu?.classList.add('show');
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
// Hide when focus leaves the dropdown entirely
|
|
312
|
-
dropdown.addEventListener('focusout', (e) => {
|
|
313
|
-
if (!dropdown.contains(e.relatedTarget)) {
|
|
314
|
-
menu?.classList.remove('show');
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
// Mobile: Custom dropdown handling to prevent glitches
|
|
320
|
-
// Only apply on mobile breakpoint
|
|
321
|
-
const isMobile = () => window.innerWidth < 992;
|
|
322
|
-
|
|
323
|
-
hoverDropdowns.forEach(dropdown => {
|
|
324
|
-
const toggle = dropdown.querySelector('.dropdown-toggle-split');
|
|
325
|
-
const menu = dropdown.querySelector('.dropdown-menu');
|
|
326
|
-
|
|
327
|
-
if (!toggle || !menu) return;
|
|
328
|
-
|
|
329
|
-
// Prevent Bootstrap's default dropdown behavior on mobile
|
|
330
|
-
toggle.addEventListener('click', function(e) {
|
|
331
|
-
if (!isMobile()) return; // Let desktop use default behavior
|
|
332
|
-
|
|
333
|
-
e.preventDefault();
|
|
334
|
-
e.stopPropagation();
|
|
335
|
-
|
|
336
|
-
// Toggle this dropdown
|
|
337
|
-
const isOpen = menu.classList.contains('show');
|
|
338
|
-
|
|
339
|
-
if (isOpen) {
|
|
340
|
-
// Close this dropdown
|
|
341
|
-
menu.classList.remove('show');
|
|
342
|
-
toggle.classList.remove('show');
|
|
343
|
-
toggle.setAttribute('aria-expanded', 'false');
|
|
344
|
-
} else {
|
|
345
|
-
// Open this dropdown (don't close others - allow multiple open)
|
|
346
|
-
menu.classList.add('show');
|
|
347
|
-
toggle.classList.add('show');
|
|
348
|
-
toggle.setAttribute('aria-expanded', 'true');
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
// Close dropdowns when clicking outside on mobile
|
|
354
|
-
document.addEventListener('click', function(e) {
|
|
355
|
-
if (!isMobile()) return;
|
|
356
|
-
|
|
357
|
-
// If click is outside all dropdowns, close them all
|
|
358
|
-
const clickedInsideDropdown = e.target.closest('.nav-hover-dropdown');
|
|
359
|
-
if (!clickedInsideDropdown) {
|
|
360
|
-
hoverDropdowns.forEach(dropdown => {
|
|
361
|
-
const toggle = dropdown.querySelector('.dropdown-toggle-split');
|
|
362
|
-
const menu = dropdown.querySelector('.dropdown-menu');
|
|
363
|
-
if (menu && toggle) {
|
|
364
|
-
menu.classList.remove('show');
|
|
365
|
-
toggle.classList.remove('show');
|
|
366
|
-
toggle.setAttribute('aria-expanded', 'false');
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// Reset dropdowns when offcanvas closes
|
|
373
|
-
const offcanvasEl = document.getElementById('bdNavbar');
|
|
374
|
-
offcanvasEl?.addEventListener('hide.bs.offcanvas', function() {
|
|
375
|
-
hoverDropdowns.forEach(dropdown => {
|
|
376
|
-
const toggle = dropdown.querySelector('.dropdown-toggle-split');
|
|
377
|
-
const menu = dropdown.querySelector('.dropdown-menu');
|
|
378
|
-
if (menu && toggle) {
|
|
379
|
-
menu.classList.remove('show');
|
|
380
|
-
toggle.classList.remove('show');
|
|
381
|
-
toggle.setAttribute('aria-expanded', 'false');
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
});
|
|
385
|
-
});
|
|
386
|
-
</script>
|
|
121
|
+
<!--
|
|
122
|
+
Navigation styles are now in _sass/core/_navbar.scss
|
|
123
|
+
Navigation scripts are now in assets/js/navigation.js
|
|
124
|
+
These are loaded automatically via the theme's asset pipeline
|
|
125
|
+
-->
|