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.
@@ -0,0 +1,390 @@
1
+ // ==============================================================================
2
+ // NAVBAR STYLES - Zer0-Mistakes Theme Navigation
3
+ // ==============================================================================
4
+ //
5
+ // Extracted from navbar.html inline styles for better maintainability
6
+ // Breakpoints:
7
+ // - Desktop XL >= 1200px (full labels)
8
+ // - Desktop LG 992px-1199px (icons only, labels hidden)
9
+ // - Mobile < 992px (offcanvas)
10
+ // ==============================================================================
11
+
12
+ // -----------------------------------------------------------------------------
13
+ // Compact Desktop Navigation (992px - 1199px)
14
+ // Hide labels, show icons only to prevent overflow
15
+ // -----------------------------------------------------------------------------
16
+
17
+ @media (min-width: 992px) and (max-width: 1199.98px) {
18
+ // Hide nav link text labels, keep icons visible
19
+ #bdNavbar .nav-link .nav-link-text {
20
+ display: none;
21
+ }
22
+
23
+ // Adjust icon margin when text is hidden
24
+ #bdNavbar .nav-link i {
25
+ margin-right: 0 !important;
26
+ }
27
+
28
+ // Compact nav item spacing
29
+ #bdNavbar .navbar-nav {
30
+ gap: 0;
31
+ }
32
+
33
+ #bdNavbar .nav-link {
34
+ padding: 0.5rem 0.5rem;
35
+ }
36
+
37
+ // Dropdown toggle needs less space
38
+ .nav-hover-dropdown .dropdown-toggle-split {
39
+ padding-left: 0;
40
+ padding-right: 0.25rem;
41
+
42
+ &::after {
43
+ font-size: 0.65em;
44
+ margin-left: 0;
45
+ }
46
+ }
47
+
48
+ // Keep Search button label hidden
49
+ .nav-search-button .d-lg-inline {
50
+ display: none !important;
51
+ }
52
+
53
+ .nav-search-button {
54
+ padding: 0.5rem 0.5rem !important;
55
+ }
56
+
57
+ // Hide site subtitle at compact breakpoint
58
+ .site-subtitle {
59
+ display: none !important;
60
+ }
61
+
62
+ // Reduce brand group spacing
63
+ .navbar-brand-group {
64
+ gap: 0.5rem !important;
65
+ }
66
+
67
+ // Compact home links
68
+ .navbar-home-links .btn {
69
+ padding: 0.375rem 0.5rem;
70
+ }
71
+ }
72
+
73
+ // -----------------------------------------------------------------------------
74
+ // Full Desktop Navigation (>= 1200px)
75
+ // Show full labels with icons
76
+ // -----------------------------------------------------------------------------
77
+
78
+ @media (min-width: 1200px) {
79
+ #bdNavbar .nav-link .nav-link-text {
80
+ display: inline;
81
+ margin-left: 0.5rem;
82
+ }
83
+
84
+ #bdNavbar .nav-link i {
85
+ margin-right: 0;
86
+ }
87
+ }
88
+
89
+ // -----------------------------------------------------------------------------
90
+ // Utility Controls (Search, Settings)
91
+ // -----------------------------------------------------------------------------
92
+
93
+ .navbar-utility-controls {
94
+ gap: 0.25rem;
95
+ margin-left: auto;
96
+
97
+ .nav-search-button,
98
+ .nav-settings-button {
99
+ display: inline-flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ padding: 0.5rem 0.75rem;
103
+ border: none;
104
+ background: transparent;
105
+ color: var(--bs-body-color);
106
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
107
+
108
+ &:hover {
109
+ color: var(--bs-primary);
110
+ background-color: var(--bs-tertiary-bg);
111
+ }
112
+
113
+ i {
114
+ font-size: 1.1rem;
115
+ }
116
+ }
117
+ }
118
+
119
+ @media (min-width: 992px) and (max-width: 1199.98px) {
120
+ .navbar-utility-controls {
121
+ gap: 0;
122
+
123
+ .nav-search-button,
124
+ .nav-settings-button {
125
+ padding: 0.5rem;
126
+ }
127
+
128
+ .nav-link-text {
129
+ display: none !important;
130
+ }
131
+ }
132
+ }
133
+
134
+ @media (max-width: 991.98px) {
135
+ .navbar-utility-controls {
136
+ gap: 0;
137
+
138
+ .nav-search-button {
139
+ padding: 0.5rem;
140
+ width: 2.5rem;
141
+ height: 2.5rem;
142
+ }
143
+
144
+ .nav-link-text {
145
+ display: none !important;
146
+ }
147
+ }
148
+ }
149
+
150
+ // -----------------------------------------------------------------------------
151
+ // Desktop Navigation (>= 992px) - Common styles
152
+ // -----------------------------------------------------------------------------
153
+
154
+ @media (min-width: 992px) {
155
+ // Convert offcanvas to inline navigation on desktop
156
+ #bdNavbar {
157
+ position: static !important;
158
+ transform: none !important;
159
+ visibility: visible !important;
160
+ background: transparent !important;
161
+ border: none !important;
162
+ width: auto !important;
163
+ flex-grow: 0 !important;
164
+ }
165
+
166
+ #bdNavbar .offcanvas-header {
167
+ display: none !important;
168
+ }
169
+
170
+ #bdNavbar .offcanvas-body {
171
+ padding: 0 !important;
172
+ overflow: visible !important;
173
+ }
174
+
175
+ #bdNavbar .navbar-nav {
176
+ flex-direction: row !important;
177
+ gap: 0.25rem;
178
+ }
179
+
180
+ // Dropdown positioning
181
+ .nav-hover-dropdown {
182
+ position: relative;
183
+ }
184
+
185
+ .nav-hover-dropdown > .dropdown-menu {
186
+ position: absolute;
187
+ top: 100% !important;
188
+ left: 0;
189
+ margin-top: 0.125rem !important;
190
+ min-width: 12rem;
191
+ z-index: 1050;
192
+ }
193
+
194
+ // Hover behavior
195
+ .nav-hover-dropdown:hover > .dropdown-menu {
196
+ display: block;
197
+ }
198
+
199
+ .nav-hover-dropdown .dropdown-menu {
200
+ opacity: 0;
201
+ visibility: hidden;
202
+ transition: opacity 0.15s ease-in-out, visibility 0.15s ease-in-out;
203
+ display: block !important;
204
+ }
205
+
206
+ .nav-hover-dropdown:hover .dropdown-menu,
207
+ .nav-hover-dropdown .dropdown-menu.show {
208
+ opacity: 1;
209
+ visibility: visible;
210
+ }
211
+
212
+ .nav-hover-dropdown .dropdown-toggle-split {
213
+ padding-left: 0.25rem;
214
+ padding-right: 0.5rem;
215
+ }
216
+
217
+ .nav-hover-dropdown .dropdown-toggle-split::after {
218
+ vertical-align: 0.15em;
219
+ font-size: 0.75em;
220
+ }
221
+ }
222
+
223
+ // -----------------------------------------------------------------------------
224
+ // Mobile Navigation (< 992px)
225
+ // -----------------------------------------------------------------------------
226
+
227
+ @media (max-width: 991.98px) {
228
+ #bdNavbar .navbar-nav {
229
+ flex-direction: column !important;
230
+ }
231
+
232
+ .nav-hover-dropdown {
233
+ flex-wrap: wrap !important;
234
+ justify-content: flex-start !important;
235
+ }
236
+
237
+ .nav-hover-dropdown > .nav-link:first-child {
238
+ flex: 0 0 auto !important;
239
+ }
240
+
241
+ .nav-hover-dropdown > .dropdown-toggle-split {
242
+ flex: 0 0 auto;
243
+ // Minimum touch target (44px WCAG recommendation)
244
+ min-width: 44px;
245
+ min-height: 44px;
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ }
250
+
251
+ .nav-hover-dropdown > .dropdown-toggle-split::after {
252
+ transition: transform 0.25s ease;
253
+ }
254
+
255
+ .nav-hover-dropdown > .dropdown-toggle-split.show::after {
256
+ transform: rotate(180deg);
257
+ }
258
+
259
+ .nav-hover-dropdown .dropdown-menu {
260
+ position: static !important;
261
+ float: none;
262
+ flex-basis: 100% !important;
263
+ width: 100%;
264
+ margin-top: 0;
265
+ border: none;
266
+ box-shadow: none;
267
+ background-color: var(--bs-tertiary-bg);
268
+ padding-left: 1rem;
269
+ max-height: 0;
270
+ overflow: hidden;
271
+ opacity: 0;
272
+ transition: max-height 0.3s ease, opacity 0.25s ease, padding 0.3s ease;
273
+ padding-top: 0;
274
+ padding-bottom: 0;
275
+ display: block !important;
276
+ }
277
+
278
+ .nav-hover-dropdown .dropdown-menu.show {
279
+ max-height: 500px;
280
+ opacity: 1;
281
+ padding-top: 0.5rem;
282
+ padding-bottom: 0.5rem;
283
+ }
284
+
285
+ // Larger touch targets for nav items
286
+ #bdNavbar .nav-link {
287
+ padding: 0.75rem 1rem;
288
+ min-height: 48px;
289
+ display: flex;
290
+ align-items: center;
291
+ }
292
+
293
+ // Better close button
294
+ #bdNavbar .offcanvas-header .btn-close {
295
+ width: 44px;
296
+ height: 44px;
297
+ padding: 0;
298
+ }
299
+ }
300
+
301
+ // -----------------------------------------------------------------------------
302
+ // Active States
303
+ // -----------------------------------------------------------------------------
304
+
305
+ .dropdown-item[aria-current="page"] {
306
+ background-color: var(--bs-primary);
307
+ color: var(--bs-white);
308
+ }
309
+
310
+ .dropdown-item[aria-current="page"]:hover {
311
+ background-color: var(--bs-primary);
312
+ filter: brightness(0.9);
313
+ }
314
+
315
+ // -----------------------------------------------------------------------------
316
+ // Dropdown Styling
317
+ // -----------------------------------------------------------------------------
318
+
319
+ .nav-hover-dropdown .dropdown-menu {
320
+ border-radius: 0.375rem;
321
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
322
+ }
323
+
324
+ .nav-hover-dropdown .dropdown-item {
325
+ padding: 0.5rem 1rem;
326
+ min-height: 44px;
327
+ display: flex;
328
+ align-items: center;
329
+ }
330
+
331
+ .nav-hover-dropdown .dropdown-item:hover {
332
+ background-color: var(--bs-tertiary-bg);
333
+ }
334
+
335
+ // -----------------------------------------------------------------------------
336
+ // Site Title Responsiveness
337
+ // -----------------------------------------------------------------------------
338
+
339
+ .site-title-text {
340
+ display: inline-block;
341
+ }
342
+
343
+ @media (max-width: 767.98px) {
344
+ .site-title-text {
345
+ max-width: 55vw;
346
+ overflow: hidden;
347
+ text-overflow: ellipsis;
348
+ white-space: nowrap;
349
+ }
350
+ }
351
+
352
+ @media (max-width: 575.98px) {
353
+ .site-title-text {
354
+ max-width: 45vw;
355
+ }
356
+ }
357
+
358
+ // -----------------------------------------------------------------------------
359
+ // Info Section Modal Tabs
360
+ // -----------------------------------------------------------------------------
361
+
362
+ #info-section {
363
+ .nav-tabs {
364
+ border-bottom: 2px solid var(--bs-border-color);
365
+
366
+ .nav-link {
367
+ border: none;
368
+ border-bottom: 3px solid transparent;
369
+ color: var(--bs-secondary-color);
370
+ padding: 0.75rem 1rem;
371
+ font-weight: 500;
372
+ transition: color 0.2s ease, border-color 0.2s ease;
373
+
374
+ &:hover {
375
+ color: var(--bs-primary);
376
+ border-bottom-color: var(--bs-primary-bg-subtle);
377
+ }
378
+
379
+ &.active {
380
+ color: var(--bs-primary);
381
+ border-bottom-color: var(--bs-primary);
382
+ background: transparent;
383
+ }
384
+ }
385
+ }
386
+
387
+ .tab-content {
388
+ padding-top: 1rem;
389
+ }
390
+ }
data/_sass/custom.scss CHANGED
@@ -8,6 +8,9 @@
8
8
  // Import navigation tree styles
9
9
  @import "core/nav-tree";
10
10
 
11
+ // Import navbar styles (extracted from navbar.html)
12
+ @import "core/navbar";
13
+
11
14
  html, body {
12
15
  max-width: 100%;
13
16
  // overflow-x: hidden;
@@ -0,0 +1,206 @@
1
+ /**
2
+ * ==============================================================================
3
+ * NAVIGATION SCRIPTS - Zer0-Mistakes Theme
4
+ * ==============================================================================
5
+ *
6
+ * Handles offcanvas navigation, dropdowns, and mobile interactions
7
+ * Extracted from navbar.html inline scripts
8
+ * ==============================================================================
9
+ */
10
+
11
+ (function() {
12
+ 'use strict';
13
+
14
+ const MOBILE_BREAKPOINT = 992;
15
+
16
+ function isMobile() {
17
+ return window.innerWidth < MOBILE_BREAKPOINT;
18
+ }
19
+
20
+ /**
21
+ * Initialize navigation when DOM is ready
22
+ */
23
+ function initNavigation() {
24
+ setupOffcanvasLinkClose();
25
+ setupKeyboardAccessibility();
26
+ setupMobileDropdowns();
27
+ setupOutsideClickClose();
28
+ setupOffcanvasReset();
29
+ }
30
+
31
+ /**
32
+ * Close offcanvas when navigation link is clicked
33
+ */
34
+ function setupOffcanvasLinkClose() {
35
+ const offcanvasEl = document.getElementById('bdNavbar');
36
+ if (!offcanvasEl) return;
37
+
38
+ const navLinks = offcanvasEl.querySelectorAll(
39
+ '.nav-link[href]:not(.dropdown-toggle), .dropdown-item[href]'
40
+ );
41
+
42
+ navLinks.forEach(link => {
43
+ link.addEventListener('click', () => {
44
+ setTimeout(() => {
45
+ const offcanvas = bootstrap.Offcanvas.getInstance(offcanvasEl);
46
+ if (offcanvas) {
47
+ offcanvas.hide();
48
+ }
49
+ }, 100);
50
+ });
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Desktop keyboard accessibility for hover dropdowns
56
+ */
57
+ function setupKeyboardAccessibility() {
58
+ const dropdowns = document.querySelectorAll('.nav-hover-dropdown');
59
+
60
+ dropdowns.forEach(dropdown => {
61
+ const toggle = dropdown.querySelector('.dropdown-toggle');
62
+ const menu = dropdown.querySelector('.dropdown-menu');
63
+
64
+ if (!toggle || !menu) return;
65
+
66
+ // Show on focus
67
+ toggle.addEventListener('focus', () => {
68
+ if (!isMobile()) {
69
+ menu.classList.add('show');
70
+ }
71
+ });
72
+
73
+ // Hide when focus leaves dropdown
74
+ dropdown.addEventListener('focusout', (e) => {
75
+ if (!dropdown.contains(e.relatedTarget)) {
76
+ menu.classList.remove('show');
77
+ }
78
+ });
79
+
80
+ // Arrow key navigation
81
+ dropdown.addEventListener('keydown', (e) => {
82
+ if (!menu.classList.contains('show')) return;
83
+
84
+ const items = menu.querySelectorAll('.dropdown-item:not(:disabled)');
85
+ const currentIndex = Array.from(items).indexOf(document.activeElement);
86
+
87
+ if (e.key === 'ArrowDown') {
88
+ e.preventDefault();
89
+ items[(currentIndex + 1) % items.length]?.focus();
90
+ } else if (e.key === 'ArrowUp') {
91
+ e.preventDefault();
92
+ items[(currentIndex - 1 + items.length) % items.length]?.focus();
93
+ } else if (e.key === 'Escape') {
94
+ e.preventDefault();
95
+ menu.classList.remove('show');
96
+ toggle.focus();
97
+ }
98
+ });
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Mobile dropdown toggle handling
104
+ */
105
+ function setupMobileDropdowns() {
106
+ const dropdowns = document.querySelectorAll('.nav-hover-dropdown');
107
+
108
+ dropdowns.forEach(dropdown => {
109
+ const toggle = dropdown.querySelector('.dropdown-toggle-split');
110
+ const menu = dropdown.querySelector('.dropdown-menu');
111
+
112
+ if (!toggle || !menu) return;
113
+
114
+ toggle.addEventListener('click', function(e) {
115
+ if (!isMobile()) return;
116
+
117
+ e.preventDefault();
118
+ e.stopPropagation();
119
+
120
+ const isOpen = menu.classList.contains('show');
121
+
122
+ if (isOpen) {
123
+ menu.classList.remove('show');
124
+ toggle.classList.remove('show');
125
+ toggle.setAttribute('aria-expanded', 'false');
126
+ } else {
127
+ menu.classList.add('show');
128
+ toggle.classList.add('show');
129
+ toggle.setAttribute('aria-expanded', 'true');
130
+ }
131
+ });
132
+ });
133
+ }
134
+
135
+ /**
136
+ * Close dropdowns when clicking outside on mobile
137
+ */
138
+ function setupOutsideClickClose() {
139
+ document.addEventListener('click', (e) => {
140
+ if (!isMobile()) return;
141
+
142
+ const clickedDropdown = e.target.closest('.nav-hover-dropdown');
143
+ if (clickedDropdown) return;
144
+
145
+ document.querySelectorAll('.nav-hover-dropdown').forEach(dropdown => {
146
+ const toggle = dropdown.querySelector('.dropdown-toggle-split');
147
+ const menu = dropdown.querySelector('.dropdown-menu');
148
+ if (menu && toggle) {
149
+ menu.classList.remove('show');
150
+ toggle.classList.remove('show');
151
+ toggle.setAttribute('aria-expanded', 'false');
152
+ }
153
+ });
154
+ });
155
+ }
156
+
157
+ /**
158
+ * Reset dropdowns when offcanvas closes
159
+ */
160
+ function setupOffcanvasReset() {
161
+ const offcanvasEl = document.getElementById('bdNavbar');
162
+ if (!offcanvasEl) return;
163
+
164
+ offcanvasEl.addEventListener('hide.bs.offcanvas', () => {
165
+ document.querySelectorAll('.nav-hover-dropdown').forEach(dropdown => {
166
+ const toggle = dropdown.querySelector('.dropdown-toggle-split');
167
+ const menu = dropdown.querySelector('.dropdown-menu');
168
+ if (menu && toggle) {
169
+ menu.classList.remove('show');
170
+ toggle.classList.remove('show');
171
+ toggle.setAttribute('aria-expanded', 'false');
172
+ }
173
+ });
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Initialize Bootstrap tooltips for nav links
179
+ * Shows link title on hover when labels are hidden (992px-1199px)
180
+ */
181
+ function setupNavTooltips() {
182
+ const navLinks = document.querySelectorAll('#bdNavbar .nav-link[title]');
183
+ navLinks.forEach(link => {
184
+ // Only initialize tooltip if Bootstrap is available
185
+ if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip) {
186
+ new bootstrap.Tooltip(link, {
187
+ trigger: 'hover',
188
+ placement: 'bottom',
189
+ delay: { show: 300, hide: 0 }
190
+ });
191
+ }
192
+ });
193
+ }
194
+
195
+ // Initialize
196
+ if (document.readyState === 'loading') {
197
+ document.addEventListener('DOMContentLoaded', () => {
198
+ initNavigation();
199
+ setupNavTooltips();
200
+ });
201
+ } else {
202
+ initNavigation();
203
+ setupNavTooltips();
204
+ }
205
+
206
+ })();