@sofidevo/astro-dynamic-header 3.1.0 → 4.0.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.
- package/README.md +474 -38
- package/package.json +15 -14
- package/src/ChevronIcon.astro +13 -5
- package/src/HamburgerButton.astro +100 -92
- package/src/Header.astro +103 -156
- package/src/MobileNav.astro +122 -114
- package/src/MoonIcon.astro +63 -55
- package/src/NavMenu.astro +165 -273
- package/src/SunIcon.astro +23 -15
- package/src/index.ts +6 -6
- package/src/scripts/hamburger.ts +55 -0
- package/src/scripts/nav-menu.ts +119 -0
package/src/ChevronIcon.astro
CHANGED
|
@@ -16,10 +16,18 @@ const content = `<path class="hlhawq"/>`;
|
|
|
16
16
|
/>
|
|
17
17
|
|
|
18
18
|
<style is:inline>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/*
|
|
20
|
+
* base (resets) < components (ours) < utilities (consumer classNames).
|
|
21
|
+
* Order statement keeps it deterministic regardless of bundling order.
|
|
22
|
+
*/
|
|
23
|
+
@layer theme, base, components, utilities;
|
|
24
|
+
|
|
25
|
+
@layer components {
|
|
26
|
+
.hlhawq {
|
|
27
|
+
fill: currentColor;
|
|
28
|
+
d: path(
|
|
29
|
+
"M11.646 15.146L5.854 9.354a.5.5 0 0 1 .353-.854h11.586a.5.5 0 0 1 .353.854l-5.793 5.792a.5.5 0 0 1-.707 0"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
24
32
|
}
|
|
25
33
|
</style>
|
|
@@ -13,110 +13,118 @@ export interface Props {}
|
|
|
13
13
|
</button>
|
|
14
14
|
|
|
15
15
|
<style>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
16
|
+
/*
|
|
17
|
+
* base (resets) < components (ours) < utilities (consumer classNames).
|
|
18
|
+
* Order statement keeps it deterministic regardless of bundling order.
|
|
19
|
+
*/
|
|
20
|
+
@layer theme, base, components, utilities;
|
|
21
|
+
|
|
22
|
+
@layer components {
|
|
23
|
+
.hamburger {
|
|
24
|
+
display: none;
|
|
25
|
+
font: inherit;
|
|
26
|
+
overflow: visible;
|
|
27
|
+
margin: 0;
|
|
28
|
+
padding: 10px;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
transition-timing-function: linear;
|
|
31
|
+
transition-duration: 0.15s;
|
|
32
|
+
transition-property: opacity, filter, border-color;
|
|
33
|
+
text-transform: none;
|
|
34
|
+
color: inherit;
|
|
35
|
+
border: 1px solid
|
|
36
|
+
color-mix(in srgb, var(--text-color, #fff) 25%, transparent);
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
background-color: transparent;
|
|
39
|
+
|
|
40
|
+
@media screen and (max-width: 768px) {
|
|
41
|
+
z-index: 1000;
|
|
42
|
+
display: inline-block;
|
|
43
|
+
}
|
|
36
44
|
}
|
|
37
|
-
}
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
.hamburger-box {
|
|
47
|
+
position: relative;
|
|
48
|
+
display: inline-block;
|
|
49
|
+
width: 40px;
|
|
50
|
+
height: 24px;
|
|
51
|
+
}
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
.hamburger-inner {
|
|
54
|
+
top: 50%;
|
|
55
|
+
display: block;
|
|
56
|
+
margin-top: -2px;
|
|
57
|
+
}
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
.hamburger-inner:after,
|
|
60
|
+
.hamburger-inner:before {
|
|
61
|
+
display: block;
|
|
62
|
+
content: "";
|
|
63
|
+
}
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
.hamburger-inner,
|
|
66
|
+
.hamburger-inner::before,
|
|
67
|
+
.hamburger-inner::after {
|
|
68
|
+
background-color: var(--text-color, inherit);
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: 40px;
|
|
71
|
+
height: 4px;
|
|
72
|
+
transition-timing-function: ease;
|
|
73
|
+
transition-duration: 0.15s;
|
|
74
|
+
transition-property: transform;
|
|
75
|
+
border-radius: 4px;
|
|
76
|
+
}
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
.hamburger-inner:before {
|
|
79
|
+
top: -10px;
|
|
80
|
+
}
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
.hamburger-inner:after {
|
|
83
|
+
bottom: -10px;
|
|
84
|
+
}
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
.hamburger--collapse .hamburger-inner {
|
|
87
|
+
top: auto;
|
|
88
|
+
bottom: 0;
|
|
89
|
+
transition-delay: 0.13s;
|
|
90
|
+
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
91
|
+
transition-duration: 0.13s;
|
|
92
|
+
}
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
.hamburger--collapse .hamburger-inner:before {
|
|
95
|
+
transition:
|
|
96
|
+
top 0.12s cubic-bezier(0.33333, 0.66667, 0.66667, 1) 0.2s,
|
|
97
|
+
transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
98
|
+
}
|
|
92
99
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
.hamburger--collapse .hamburger-inner:after {
|
|
101
|
+
top: -20px;
|
|
102
|
+
transition:
|
|
103
|
+
top 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1) 0.2s,
|
|
104
|
+
opacity 0.1s linear;
|
|
105
|
+
}
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
/* Animation */
|
|
108
|
+
.hamburger--collapse.is-active .hamburger-inner {
|
|
109
|
+
transition-delay: 0.22s;
|
|
110
|
+
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
111
|
+
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
|
112
|
+
}
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
.hamburger--collapse.is-active .hamburger-inner:before {
|
|
115
|
+
top: 0;
|
|
116
|
+
transition:
|
|
117
|
+
top 0.1s cubic-bezier(0.33333, 0, 0.66667, 0.33333) 0.16s,
|
|
118
|
+
transform 0.13s cubic-bezier(0.215, 0.61, 0.355, 1) 0.25s;
|
|
119
|
+
transform: rotate(-90deg);
|
|
120
|
+
}
|
|
114
121
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
.hamburger--collapse.is-active .hamburger-inner:after {
|
|
123
|
+
top: 0;
|
|
124
|
+
transition:
|
|
125
|
+
top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333),
|
|
126
|
+
opacity 0.1s linear 0.22s;
|
|
127
|
+
opacity: 0;
|
|
128
|
+
}
|
|
121
129
|
}
|
|
122
130
|
</style>
|
package/src/Header.astro
CHANGED
|
@@ -10,32 +10,10 @@ import type {
|
|
|
10
10
|
} from "./index.js";
|
|
11
11
|
|
|
12
12
|
export interface Props {
|
|
13
|
-
/**
|
|
14
|
-
* Layout style.
|
|
15
|
-
* - "floating": Centered with max-width and rounded corners.
|
|
16
|
-
* - "fullscreen": Full width with no border radius.
|
|
17
|
-
* @default "floating"
|
|
18
|
-
*/
|
|
19
13
|
headerType?: "floating" | "fullscreen";
|
|
20
|
-
/**
|
|
21
|
-
* Theme behavior.
|
|
22
|
-
* - "light": Force light mode.
|
|
23
|
-
* - "dark": Force dark mode.
|
|
24
|
-
* - "auto": Detects .dark class on the root element.
|
|
25
|
-
* @default "auto"
|
|
26
|
-
*/
|
|
27
14
|
preset?: "light" | "dark" | "auto";
|
|
28
|
-
|
|
29
|
-
/** Navigation links and structure. */
|
|
30
15
|
navigation?: NavConfig;
|
|
31
|
-
/** Custom theme overrides for light and dark modes. */
|
|
32
16
|
theme?: DualThemeConfig;
|
|
33
|
-
/**
|
|
34
|
-
* High-level CSS class overrides for structural wrapper elements.
|
|
35
|
-
* For fine-grained nav/logo element classes, use the nested `xxx__class`
|
|
36
|
-
* props inside `navigation` or `logo` instead.
|
|
37
|
-
* @example { header: "shadow-lg", container: "top-4" }
|
|
38
|
-
*/
|
|
39
17
|
classNames?: HeaderClassNames;
|
|
40
18
|
}
|
|
41
19
|
|
|
@@ -57,7 +35,7 @@ if (import.meta.env.DEV) {
|
|
|
57
35
|
}
|
|
58
36
|
}
|
|
59
37
|
|
|
60
|
-
|
|
38
|
+
|
|
61
39
|
const inlineStyles: Record<string, string> = {};
|
|
62
40
|
|
|
63
41
|
if (theme.light) {
|
|
@@ -75,7 +53,7 @@ if (theme.dark) {
|
|
|
75
53
|
if (theme.dark.backdropBlur) inlineStyles["--d-blur"] = theme.dark.backdropBlur;
|
|
76
54
|
}
|
|
77
55
|
|
|
78
|
-
const zIndex = theme.light?.zIndex ?? 10;
|
|
56
|
+
const zIndex = theme.light?.zIndex ?? theme.dark?.zIndex ?? 10;
|
|
79
57
|
|
|
80
58
|
// Navigation configuration
|
|
81
59
|
const {
|
|
@@ -92,45 +70,9 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
|
|
|
92
70
|
---
|
|
93
71
|
|
|
94
72
|
<script>
|
|
95
|
-
|
|
96
|
-
private hamburgerBtn: HTMLElement | null;
|
|
97
|
-
private mobileMenu: HTMLElement | null;
|
|
98
|
-
private links: NodeListOf<HTMLElement>;
|
|
99
|
-
|
|
100
|
-
constructor() {
|
|
101
|
-
this.hamburgerBtn = document.getElementById("hamburger-btn");
|
|
102
|
-
this.mobileMenu = document.getElementById("mobile-header-menu");
|
|
103
|
-
this.links = document.querySelectorAll(".mobile-menu__link");
|
|
104
|
-
this.init();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private init(): void {
|
|
108
|
-
if (this.hamburgerBtn && this.mobileMenu) {
|
|
109
|
-
this.hamburgerBtn.addEventListener("click", () => this.toggleMenu());
|
|
110
|
-
this.links.forEach((link) => {
|
|
111
|
-
link.addEventListener("click", () => this.closeMenu());
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private closeMenu(): void {
|
|
117
|
-
if (this.hamburgerBtn && this.mobileMenu) {
|
|
118
|
-
this.hamburgerBtn.classList.remove("is-active");
|
|
119
|
-
this.mobileMenu.classList.remove("is-active");
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
private toggleMenu(): void {
|
|
124
|
-
if (this.hamburgerBtn && this.mobileMenu) {
|
|
125
|
-
this.hamburgerBtn.classList.toggle("is-active");
|
|
126
|
-
this.mobileMenu.classList.toggle("is-active");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
73
|
+
import { initHamburger } from "./scripts/hamburger.js";
|
|
130
74
|
|
|
131
|
-
|
|
132
|
-
new HamburgerController();
|
|
133
|
-
});
|
|
75
|
+
initHamburger();
|
|
134
76
|
</script>
|
|
135
77
|
|
|
136
78
|
<div
|
|
@@ -189,118 +131,123 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
|
|
|
189
131
|
</header>
|
|
190
132
|
</div>
|
|
191
133
|
|
|
192
|
-
<style
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
134
|
+
<style>
|
|
135
|
+
/*
|
|
136
|
+
* Cascade layers keep this component overridable:
|
|
137
|
+
* base (resets/preflight) < components (ours) < utilities (your classNames)
|
|
138
|
+
* The order statement below makes that order deterministic no matter how
|
|
139
|
+
* the consumer's CSS is bundled. No `!important` is needed to override us.
|
|
140
|
+
*/
|
|
141
|
+
@layer theme, base, components, utilities;
|
|
142
|
+
|
|
143
|
+
@layer components {
|
|
144
|
+
.header {
|
|
145
|
+
--bg-color: var(--l-bg, rgba(255, 255, 255, 0.9));
|
|
146
|
+
--bg-color-opaque: var(--l-bg-opaque, rgb(255, 255, 255));
|
|
147
|
+
--text-color: var(--l-text, #1a1a1a);
|
|
148
|
+
--accent-color: var(--l-accent, #3e1c71);
|
|
149
|
+
--backdrop-blur: var(--l-blur, blur(20px));
|
|
150
|
+
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
width: 100%;
|
|
154
|
+
justify-content: space-between;
|
|
155
|
+
padding: 1em 2em;
|
|
156
|
+
background-color: var(--bg-color);
|
|
157
|
+
backdrop-filter: var(--backdrop-blur);
|
|
158
|
+
-webkit-backdrop-filter: var(--backdrop-blur);
|
|
159
|
+
color: var(--text-color);
|
|
160
|
+
transition:
|
|
161
|
+
background-color 0.3s ease,
|
|
162
|
+
color 0.3s ease;
|
|
163
|
+
|
|
164
|
+
@media (width < 768px) {
|
|
165
|
+
align-self: flex-end;
|
|
166
|
+
padding: 0.4em;
|
|
167
|
+
margin: 0 auto;
|
|
168
|
+
}
|
|
217
169
|
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/* Automatic dark mode detection via root class */
|
|
221
|
-
:root.dark .header:not(.header--force-light) {
|
|
222
|
-
--bg-color: var(--d-bg, #0d0d0dcc);
|
|
223
|
-
--bg-color-opaque: var(--d-bg-opaque, #0d0d0d);
|
|
224
|
-
--text-color: var(--d-text, #ffffff);
|
|
225
|
-
--accent-color: var(--d-accent, #00ffff);
|
|
226
|
-
--backdrop-blur: var(--d-blur, blur(20px));
|
|
227
|
-
}
|
|
228
170
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
171
|
+
/* Automatic dark mode detection via root class */
|
|
172
|
+
:root.dark .header:not(.header--force-light):not(.header--force-dark) {
|
|
173
|
+
--bg-color: var(--d-bg, #0d0d0dcc);
|
|
174
|
+
--bg-color-opaque: var(--d-bg-opaque, #0d0d0d);
|
|
175
|
+
--text-color: var(--d-text, #ffffff);
|
|
176
|
+
--accent-color: var(--d-accent, #00ffff);
|
|
177
|
+
--backdrop-blur: var(--d-blur, blur(20px));
|
|
178
|
+
}
|
|
237
179
|
|
|
238
|
-
|
|
239
|
-
--
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
180
|
+
/* Forced themes: higher specificity than .header, no !important needed */
|
|
181
|
+
.header.header--force-dark {
|
|
182
|
+
--bg-color: var(--d-bg, #0d0d0dcc);
|
|
183
|
+
--bg-color-opaque: var(--d-bg-opaque, #0d0d0d);
|
|
184
|
+
--text-color: var(--d-text, #ffffff);
|
|
185
|
+
--accent-color: var(--d-accent, #00ffff);
|
|
186
|
+
--backdrop-blur: var(--d-blur, blur(30px));
|
|
187
|
+
}
|
|
245
188
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
position: fixed;
|
|
253
|
-
|
|
254
|
-
@media (width < 768px) {
|
|
255
|
-
justify-content: flex-end;
|
|
256
|
-
align-items: flex-end;
|
|
189
|
+
.header.header--force-light {
|
|
190
|
+
--bg-color: var(--l-bg, rgba(255, 255, 255, 0.9));
|
|
191
|
+
--bg-color-opaque: var(--l-bg-opaque, rgb(255, 255, 255));
|
|
192
|
+
--text-color: var(--l-text, #1a1a1a);
|
|
193
|
+
--accent-color: var(--l-accent, #3e1c71);
|
|
194
|
+
--backdrop-blur: var(--l-blur, blur(30px));
|
|
257
195
|
}
|
|
258
|
-
}
|
|
259
196
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
197
|
+
.header__container {
|
|
198
|
+
width: 100%;
|
|
199
|
+
display: flex;
|
|
200
|
+
justify-content: center;
|
|
201
|
+
align-items: center;
|
|
202
|
+
margin: 0 auto;
|
|
203
|
+
position: fixed;
|
|
263
204
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
205
|
+
@media (width < 768px) {
|
|
206
|
+
justify-content: flex-end;
|
|
207
|
+
align-items: flex-end;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
267
210
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
padding: 0.7em 1em;
|
|
211
|
+
.header__container--floating {
|
|
212
|
+
padding: 0.5em;
|
|
213
|
+
}
|
|
272
214
|
|
|
273
|
-
|
|
274
|
-
|
|
215
|
+
.header__container--fullscreen {
|
|
216
|
+
padding: 0;
|
|
275
217
|
}
|
|
276
|
-
}
|
|
277
218
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
219
|
+
.header--floating {
|
|
220
|
+
max-width: 1100px;
|
|
221
|
+
border-radius: 20px;
|
|
222
|
+
padding: 0.7em 1em;
|
|
281
223
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
224
|
+
@media (width < 768px) {
|
|
225
|
+
max-width: 95%;
|
|
226
|
+
}
|
|
285
227
|
}
|
|
286
|
-
}
|
|
287
228
|
|
|
229
|
+
.header--fullscreen {
|
|
230
|
+
border-radius: 0;
|
|
231
|
+
padding: 1em 2em;
|
|
288
232
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
233
|
+
@media (width < 768px) {
|
|
234
|
+
max-width: 100%;
|
|
235
|
+
padding: 0.8em 1em;
|
|
236
|
+
}
|
|
293
237
|
}
|
|
294
|
-
}
|
|
295
238
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
239
|
+
.actions-desktop {
|
|
240
|
+
@media (width < 768px) {
|
|
241
|
+
display: none;
|
|
242
|
+
}
|
|
300
243
|
}
|
|
301
|
-
}
|
|
302
244
|
|
|
303
|
-
|
|
304
|
-
|
|
245
|
+
.actions-mobile {
|
|
246
|
+
margin-top: 20px;
|
|
247
|
+
|
|
248
|
+
@media (width >= 768px) {
|
|
249
|
+
display: none;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
305
252
|
}
|
|
306
253
|
</style>
|