@sofidevo/astro-dynamic-header 2.0.0 → 2.0.1

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.
Files changed (3) hide show
  1. package/README.md +120 -109
  2. package/package.json +1 -1
  3. package/src/Header.astro +28 -10
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  A dynamic, responsive header component for Astro projects that can switch between floating and fullscreen styles with multi-level dropdown navigation support.
4
4
 
5
+ > [!WARNING]
6
+ > **Breaking Changes**: Version 2.0+ introduces a restructured configuration object. If you are upgrading from an older version, please review the [Component Props](#component-props) and the [Comprehensive Example](#comprehensive-example) to migrate your configuration.
7
+
5
8
  ## Features
6
9
 
7
10
  - **Dynamic Styles**: Switch between floating and fullscreen header layouts
@@ -42,15 +45,15 @@ By default, the header uses `preset="auto"`, which automatically detects the the
42
45
  ---
43
46
  import Header from '@sofidevo/astro-dynamic-header/Header';
44
47
 
45
- const navigation = {
46
- menuItems: [
48
+
49
+ const = menuItems: [
47
50
  { link: '/about', text: 'About' },
48
51
  ]
49
- };
52
+
50
53
  ---
51
54
 
52
55
  <!-- Detects .dark class on root automatically -->
53
- <Header navigation={navigation} />
56
+ <Header navigation={{ menuItems }} />
54
57
  ```
55
58
 
56
59
  ### Advanced Usage (Dual-Theme Customization)
@@ -58,9 +61,14 @@ const navigation = {
58
61
  You can provide custom colors for both light and dark modes simultaneously.
59
62
 
60
63
  ```astro
64
+
61
65
  ---
62
66
  import Header from '@sofidevo/astro-dynamic-header/Header';
63
-
67
+ const navigation = {
68
+ menuItems: [
69
+ { link: '/about', text: 'About' },
70
+ ]
71
+ };
64
72
  const theme = {
65
73
  light: {
66
74
  accentColor: "#3e1c71",
@@ -104,14 +112,14 @@ const theme = {
104
112
 
105
113
  #### ThemeConfig
106
114
 
107
- | Propery | Type | Default |
108
- | ---------------------- | -------- | ---------------- |
109
- | `backgroundColor` | `string` | _Preset default_ |
110
- | `backgroundColorOpaque`| `string` | _Preset default_ |
111
- | `backdropBlur` | `string` | `"blur(20px)"` |
112
- | `zIndex` | `number` | `10` |
113
- | `textColor` | `string` | _Preset default_ |
114
- | `accentColor` | `string` | _Preset default_ |
115
+ | Propery | Type | Default |
116
+ | ----------------------- | -------- | ---------------- |
117
+ | `backgroundColor` | `string` | _Preset default_ |
118
+ | `backgroundColorOpaque` | `string` | _Preset default_ |
119
+ | `backdropBlur` | `string` | `"blur(20px)"` |
120
+ | `zIndex` | `number` | `10` |
121
+ | `textColor` | `string` | _Preset default_ |
122
+ | `accentColor` | `string` | _Preset default_ |
115
123
 
116
124
  > [!IMPORTANT]
117
125
  > **Transparency vs Solid Submenus**: To ensure the best UI and avoid rendering bugs with `backdrop-filter` on nested elements, submenus and the mobile navigation panel are **solid/opaque**.
@@ -137,6 +145,32 @@ const theme = {
137
145
  | `logoText` | `string` | Logo text class |
138
146
  | `nav` | `string` | Desktop navigation wrapper class |
139
147
 
148
+ #### LogoConfig
149
+
150
+ | Property | Type | Description |
151
+ | ----------- | -------- | ------------------------------------------------ |
152
+ | `src` | `string` | URL of the logo image |
153
+ | `alt` | `string` | Alternative text for the logo image |
154
+ | `width` | `string` | Width of the logo (e.g., "50px", "5rem") |
155
+ | `text` | `string` | Text to display next to or instead of logo image |
156
+ | `textSize` | `string` | Font size for the logo text |
157
+ | `textColor` | `string` | Color for the logo text |
158
+
159
+ #### NavConfig
160
+
161
+ | Property | Type | Description |
162
+ | ----------- | ------------ | --------------------------------------- |
163
+ | `homeUrl` | `string` | URL for the home link (defaults to `/`) |
164
+ | `menuItems` | `MenuItem[]` | Array of navigation menu items |
165
+
166
+ #### MenuItem
167
+
168
+ | Property | Type | Description |
169
+ | --------- | --------------------- | ----------------------------------- |
170
+ | `link` | `string` | URL the menu item points to |
171
+ | `text` | `string` | Label text for the menu item |
172
+ | `submenu` | `SecondaryMenuItem[]` | Optional array of nested menu items |
173
+
140
174
  ## Slots Support
141
175
 
142
176
  The Header component provides a flexible slot system that allows you to add additional content:
@@ -165,46 +199,64 @@ const navigation = {
165
199
  </Header>
166
200
  ```
167
201
 
168
- #### Styling Action Buttons
169
-
170
- ```css
171
- .header-actions {
172
- display: flex;
173
- gap: 0.5em;
174
- align-items: center;
175
- }
202
+ ## Comprehensive Example
176
203
 
177
- .btn {
178
- padding: 0.5em 1em;
179
- border: none;
180
- border-radius: 6px;
181
- cursor: pointer;
182
- font-weight: 500;
183
- text-decoration: none;
184
- display: inline-flex;
185
- align-items: center;
186
- transition: all 0.2s ease;
187
- }
204
+ Below is a complete implementation example showcasing custom logo configuration, navigation with a home URL, and theme overrides.
188
205
 
189
- .btn-outline {
190
- background: transparent;
191
- color: #ffffff;
192
- border: 1px solid #ffffff;
193
- }
206
+ ```astro
207
+ ---
208
+ import Header from '@sofidevo/astro-dynamic-header/Header';
194
209
 
195
- .btn-outline:hover {
196
- background: #ffffff;
197
- color: #000000;
198
- }
210
+ const menuItems = [
211
+ {
212
+ link: "#",
213
+ text: "Services",
214
+ submenu: [
215
+ { link: "/design", text: "Design" },
216
+ { link: "/consulting", text: "Consulting" },
217
+ {
218
+ link: "#",
219
+ text: "Web Development",
220
+ submenu: [
221
+ { link: "/web/frontend", text: "Frontend" },
222
+ { link: "/web/backend", text: "Backend" },
223
+ { link: "/web/fullstack", text: "Full Stack" },
224
+ ],
225
+ },
226
+ ],
227
+ },
228
+ { link: "/about", text: "About" },
229
+ { link: "/contact", text: "Contact" },
230
+ ];
199
231
 
200
- .btn-primary {
201
- background: #00ffff;
202
- color: #000000;
203
- }
232
+ const theme = {
233
+ light: {
234
+ accentColor: "#ff0000",
235
+ backgroundColor: "rgba(255, 255, 255, 0.8)",
236
+ },
237
+ dark: {
238
+ accentColor: "#00ffff",
239
+ backgroundColor: "rgba(20, 20, 20, 0.9)",
240
+ },
241
+ };
242
+ ---
204
243
 
205
- .btn-primary:hover {
206
- background: #00cccc;
207
- }
244
+ <Header
245
+ headerType="floating"
246
+ preset="dark"
247
+ logo={{
248
+ src: "https://itssofi.dev/img/icons/sofi-icon.webp",
249
+ alt: "My Site Logo",
250
+ width: "44px",
251
+ }}
252
+ navigation={{
253
+ homeUrl: "/",
254
+ menuItems: menuItems,
255
+ }}
256
+ theme={theme}
257
+ >
258
+ <button slot="actions">Login</button>
259
+ </Header>
208
260
  ```
209
261
 
210
262
  ## Header Types
@@ -242,17 +294,17 @@ The package provides full TypeScript support. You can import types to ensure you
242
294
  ```astro
243
295
  ---
244
296
  import Header from '@sofidevo/astro-dynamic-header/Header';
245
- import type {
246
- NavConfig,
247
- DualThemeConfig,
297
+ import type {
298
+ NavConfig,
299
+ DualThemeConfig,
248
300
  MenuItem,
249
301
  SecondaryMenuItem
250
302
  } from '@sofidevo/astro-dynamic-header';
251
303
 
252
304
  const navigation: NavConfig = {
253
305
  menuItems: [
254
- {
255
- link: '/products',
306
+ {
307
+ link: '/products',
256
308
  text: 'Products',
257
309
  submenu: [
258
310
  { link: '/software', text: 'Software' },
@@ -276,25 +328,25 @@ const theme: DualThemeConfig = {
276
328
  };
277
329
  ---
278
330
 
279
- <Header
280
- navigation={navigation}
281
- theme={theme}
282
- preset="auto"
331
+ <Header
332
+ navigation={navigation}
333
+ theme={theme}
334
+ preset="auto"
283
335
  />
284
336
  ```
285
337
 
286
338
  ### Available Types
287
339
 
288
- | Type | Description |
289
- |------|-------------|
290
- | `MenuItem` | Top-level menu item with optional properties |
291
- | `SecondaryMenuItem` | Second-level menu item |
292
- | `TertiaryMenuItem` | Third-level menu item |
293
- | `NavConfig` | Main navigation configuration object |
294
- | `ThemeConfig` | Individual theme settings (colors, blur, etc.) |
295
- | `DualThemeConfig` | Combined settings for light and dark modes |
296
- | `LogoConfig` | Logo image and text configuration |
297
- | `HeaderProps` | Main props for the Header component |
340
+ | Type | Description |
341
+ | ------------------- | ---------------------------------------------- |
342
+ | `MenuItem` | Top-level menu item with optional properties |
343
+ | `SecondaryMenuItem` | Second-level menu item |
344
+ | `TertiaryMenuItem` | Third-level menu item |
345
+ | `NavConfig` | Main navigation configuration object |
346
+ | `ThemeConfig` | Individual theme settings (colors, blur, etc.) |
347
+ | `DualThemeConfig` | Combined settings for light and dark modes |
348
+ | `LogoConfig` | Logo image and text configuration |
349
+ | `HeaderProps` | Main props for the Header component |
298
350
 
299
351
  ## Browser Support
300
352
 
@@ -324,7 +376,7 @@ If you encounter import errors, try these solutions:
324
376
  // tsconfig.json
325
377
  {
326
378
  "compilerOptions": {
327
- "moduleResolution": "bundler",
379
+ "moduleResolution": "bundler",
328
380
  "allowImportingTsExtensions": true
329
381
  }
330
382
  }
@@ -341,47 +393,6 @@ If you encounter import errors, try these solutions:
341
393
 
342
394
  Visit our demo website to see the component in action with interactive examples and complete documentation.
343
395
 
344
- ## Testing
345
-
346
- This project includes a comprehensive test suite with 34 tests covering all critical functionality.
347
-
348
- ### Running Tests
349
-
350
- ```bash
351
- # Run all tests
352
- npm test
353
-
354
- # Run tests in watch mode
355
- npm run test:watch
356
-
357
- # Run tests with coverage report
358
- npm run test:coverage
359
- ```
360
-
361
- ### Test Coverage
362
-
363
- The test suite covers:
364
-
365
- #### Component Logic Tests
366
-
367
- - **Header Component** (4 tests): Hamburger controller functionality, menu toggle behavior
368
- - **HamburgerButton Component** (10 tests): Button states, responsive behavior, accessibility
369
- - **MobileNav Component** (7 tests): Dropdown structure, nested submenus, conditional rendering
370
- - **NavMenu Component** (6 tests): Dynamic positioning, submenu interactions, viewport adjustments
371
-
372
- #### Integration Tests (7 tests)
373
-
374
- - Component interaction flows
375
- - Responsive behavior between mobile/desktop
376
- - Keyboard navigation and accessibility
377
- - Menu state management during navigation
378
-
379
- ### Test Technologies
380
-
381
- - **Vitest**: Fast testing framework
382
- - **jsdom**: DOM simulation for component testing
383
- - **TypeScript**: Type-safe test writing
384
-
385
396
  ## License
386
397
 
387
398
  MIT License - see the [LICENSE](./LICENSE) file for details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sofidevo/astro-dynamic-header",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "A dynamic Astro header component that switches between floating and fullscreen styles",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
package/src/Header.astro CHANGED
@@ -28,6 +28,20 @@ const {
28
28
  classNames = {},
29
29
  } = Astro.props;
30
30
 
31
+ if (import.meta.env.DEV) {
32
+ // Check if logo is being passed as a string (legacy)
33
+ if (typeof logo === "string") {
34
+ console.warn(
35
+ "[@sofidevo/astro-dynamic-header] BREAKING CHANGE: The 'logo' prop now expects an object. Please use logo={{ src: '...' }} instead.",
36
+ );
37
+ }
38
+ if (Array.isArray(navigation)) {
39
+ console.warn(
40
+ "[@sofidevo/astro-dynamic-header] BREAKING CHANGE: The 'navigation' prop now expects an object with 'menuItems'. Please use navigation={{ menuItems: [...] }} instead.",
41
+ );
42
+ }
43
+ }
44
+
31
45
  // Default theme configuration
32
46
  const defaultThemes = {
33
47
  light: {
@@ -119,7 +133,12 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
119
133
  style={{ zIndex: lightTheme.zIndex }}
120
134
  >
121
135
  <header
122
- class:list={["header", `header--${headerType}`, forcedClass, classNames.header]}
136
+ class:list={[
137
+ "header",
138
+ `header--${headerType}`,
139
+ forcedClass,
140
+ classNames.header,
141
+ ]}
123
142
  style={{
124
143
  "--l-bg": lightTheme.backgroundColor,
125
144
  "--l-bg-opaque": lightTheme.backgroundColorOpaque,
@@ -151,7 +170,7 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
151
170
  )
152
171
  }
153
172
  </a>
154
-
173
+
155
174
  <div class:list={["nav-menu-wrapper", classNames.nav]}>
156
175
  <NavMenu menuItems={menuItems} />
157
176
  </div>
@@ -163,13 +182,10 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
163
182
  </div>
164
183
  )
165
184
  }
166
-
185
+
167
186
  <HamburgerButton />
168
-
169
- <MobileNav
170
- menuItems={menuItems}
171
- type={headerType}
172
- >
187
+
188
+ <MobileNav menuItems={menuItems} type={headerType}>
173
189
  {
174
190
  Astro.slots.has("actions") && (
175
191
  <div class="actions-mobile" slot="slot-panel">
@@ -198,7 +214,9 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
198
214
  backdrop-filter: var(--backdrop-blur);
199
215
  -webkit-backdrop-filter: var(--backdrop-blur);
200
216
  color: var(--text-color);
201
- transition: background-color 0.3s ease, color 0.3s ease;
217
+ transition:
218
+ background-color 0.3s ease,
219
+ color 0.3s ease;
202
220
 
203
221
  @media (width < 768px) {
204
222
  align-self: flex-end;
@@ -284,7 +302,7 @@ const forcedClass = preset !== "auto" ? `header--force-${preset}` : "";
284
302
  font-weight: 600;
285
303
  }
286
304
  }
287
-
305
+
288
306
  .header__logo {
289
307
  margin-right: 1em;
290
308
  object-fit: contain;