@gadagi/ui-header 1.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 +339 -0
- package/package.json +42 -0
- package/src/Header.tsx +48 -0
- package/src/UserMenu.tsx +59 -0
- package/src/index.ts +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# @gadagi/ui-header - Header Component
|
|
2
|
+
|
|
3
|
+
A flexible header component for the Gadagi platform micro-frontend architecture.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a customizable header component with navigation, user menu, and theme switching capabilities for all Gadagi micro-frontends.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @gadagi/ui-header
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Peer Dependencies
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install react react-dom @gadagi/design-system @gadagi/types
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- 🎨 **Customizable** - Flexible branding and layout options
|
|
24
|
+
- 🧠**Navigation** - Integrated navigation menu support
|
|
25
|
+
- 👤 **User Menu** - User profile and authentication controls
|
|
26
|
+
- 🌓 **Theme Switcher** - Built-in light/dark theme toggle
|
|
27
|
+
- 📱 **Responsive** - Mobile-friendly design
|
|
28
|
+
- 🎯 **TypeScript** - Full type safety
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { Header } from '@gadagi/ui-header';
|
|
34
|
+
import { ThemeProvider } from '@gadagi/design-system';
|
|
35
|
+
|
|
36
|
+
function App() {
|
|
37
|
+
return (
|
|
38
|
+
<ThemeProvider>
|
|
39
|
+
<Header
|
|
40
|
+
title="Gadagi Platform"
|
|
41
|
+
logo="/logo.svg"
|
|
42
|
+
user={{
|
|
43
|
+
name: "John Doe",
|
|
44
|
+
avatar: "/avatar.jpg"
|
|
45
|
+
}}
|
|
46
|
+
onLogout={() => console.log('logout')}
|
|
47
|
+
/>
|
|
48
|
+
</ThemeProvider>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Components
|
|
54
|
+
|
|
55
|
+
### Header
|
|
56
|
+
|
|
57
|
+
The main header component with customizable sections.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Header } from '@gadagi/ui-header';
|
|
61
|
+
|
|
62
|
+
<Header
|
|
63
|
+
title="Dashboard"
|
|
64
|
+
logo="/logo.svg"
|
|
65
|
+
user={user}
|
|
66
|
+
onLogout={handleLogout}
|
|
67
|
+
onThemeToggle={handleThemeToggle}
|
|
68
|
+
navigationItems={navItems}
|
|
69
|
+
/>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Props:**
|
|
73
|
+
- `title?: string` - Header title text
|
|
74
|
+
- `logo?: string` - Logo image URL
|
|
75
|
+
- `user?: User` - Current user information
|
|
76
|
+
- `onLogout?: () => void` - Logout callback
|
|
77
|
+
- `onThemeToggle?: () => void` - Theme toggle callback
|
|
78
|
+
- `navigationItems?: NavItem[]` - Navigation menu items
|
|
79
|
+
- `showThemeToggle?: boolean` - Show theme switcher (default: true)
|
|
80
|
+
- `showUserMenu?: boolean` - Show user menu (default: true)
|
|
81
|
+
- `className?: string` - Additional CSS classes
|
|
82
|
+
|
|
83
|
+
### UserMenu
|
|
84
|
+
|
|
85
|
+
Dropdown menu for user actions.
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { UserMenu } from '@gadagi/ui-header';
|
|
89
|
+
|
|
90
|
+
<UserMenu
|
|
91
|
+
user={{
|
|
92
|
+
name: "John Doe",
|
|
93
|
+
email: "john@example.com",
|
|
94
|
+
avatar: "/avatar.jpg"
|
|
95
|
+
}}
|
|
96
|
+
onLogout={handleLogout}
|
|
97
|
+
onProfile={() => navigate('/profile')}
|
|
98
|
+
onSettings={() => navigate('/settings')}
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Props:**
|
|
103
|
+
- `user: User` - User information
|
|
104
|
+
- `onLogout: () => void` - Logout callback
|
|
105
|
+
- `onProfile?: () => void` - Profile navigation callback
|
|
106
|
+
- `onSettings?: () => void` - Settings navigation callback
|
|
107
|
+
|
|
108
|
+
### ThemeToggle
|
|
109
|
+
|
|
110
|
+
Theme switching button.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { ThemeToggle } from '@gadagi/ui-header';
|
|
114
|
+
|
|
115
|
+
<ThemeToggle
|
|
116
|
+
theme="light"
|
|
117
|
+
onToggle={handleThemeToggle}
|
|
118
|
+
/>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Props:**
|
|
122
|
+
- `theme: 'light' | 'dark'` - Current theme
|
|
123
|
+
- `onToggle: () => void` - Theme toggle callback
|
|
124
|
+
|
|
125
|
+
## Usage Examples
|
|
126
|
+
|
|
127
|
+
### Basic Header
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { Header } from '@gadagi/ui-header';
|
|
131
|
+
|
|
132
|
+
function BasicHeader() {
|
|
133
|
+
return (
|
|
134
|
+
<Header
|
|
135
|
+
title="My App"
|
|
136
|
+
logo="/logo.svg"
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Header with User Menu
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
function HeaderWithUser() {
|
|
146
|
+
const [user] = useState({
|
|
147
|
+
name: "John Doe",
|
|
148
|
+
email: "john@example.com",
|
|
149
|
+
avatar: "/avatar.jpg"
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const handleLogout = () => {
|
|
153
|
+
// Logout logic
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<Header
|
|
158
|
+
title="Dashboard"
|
|
159
|
+
user={user}
|
|
160
|
+
onLogout={handleLogout}
|
|
161
|
+
/>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Header with Navigation
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
function HeaderWithNavigation() {
|
|
170
|
+
const navigationItems = [
|
|
171
|
+
{ id: 'dashboard', label: 'Dashboard', path: '/dashboard' },
|
|
172
|
+
{ id: 'users', label: 'Users', path: '/users' },
|
|
173
|
+
{ id: 'reports', label: 'Reports', path: '/reports' }
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<Header
|
|
178
|
+
title="Admin Panel"
|
|
179
|
+
navigationItems={navigationItems}
|
|
180
|
+
onThemeToggle={() => setTheme(theme === 'light' ? 'dark' : 'light')}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Custom Styling
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
function CustomHeader() {
|
|
190
|
+
return (
|
|
191
|
+
<Header
|
|
192
|
+
title="Custom App"
|
|
193
|
+
className="custom-header"
|
|
194
|
+
showThemeToggle={false}
|
|
195
|
+
showUserMenu={false}
|
|
196
|
+
/>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```css
|
|
202
|
+
.custom-header {
|
|
203
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
204
|
+
color: white;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Integration with Design System
|
|
209
|
+
|
|
210
|
+
The header component integrates seamlessly with the Gadagi design system:
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import { Header } from '@gadagi/ui-header';
|
|
214
|
+
import { ThemeProvider, useTheme } from '@gadagi/design-system';
|
|
215
|
+
|
|
216
|
+
function App() {
|
|
217
|
+
const { theme, setTheme } = useTheme();
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<ThemeProvider>
|
|
221
|
+
<Header
|
|
222
|
+
title="Gadagi Platform"
|
|
223
|
+
onThemeToggle={() => setTheme(theme === 'light' ? 'dark' : 'light')}
|
|
224
|
+
/>
|
|
225
|
+
</ThemeProvider>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Responsive Design
|
|
231
|
+
|
|
232
|
+
The header automatically adapts to different screen sizes:
|
|
233
|
+
|
|
234
|
+
- **Desktop**: Full header with all sections
|
|
235
|
+
- **Tablet**: Compact navigation
|
|
236
|
+
- **Mobile**: Hamburger menu with slide-out navigation
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// Mobile navigation is handled automatically
|
|
240
|
+
<Header
|
|
241
|
+
title="Mobile App"
|
|
242
|
+
navigationItems={navItems}
|
|
243
|
+
// Navigation becomes a hamburger menu on small screens
|
|
244
|
+
/>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Accessibility Features
|
|
248
|
+
|
|
249
|
+
- **Keyboard Navigation**: Full tab support
|
|
250
|
+
- **Screen Readers**: Proper ARIA labels
|
|
251
|
+
- **Focus Management**: Logical focus flow
|
|
252
|
+
- **Color Contrast**: WCAG compliant colors
|
|
253
|
+
|
|
254
|
+
## TypeScript Support
|
|
255
|
+
|
|
256
|
+
Full TypeScript support with proper interfaces:
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
import { HeaderProps, User } from '@gadagi/ui-header';
|
|
260
|
+
import { NavItem } from '@gadagi/types';
|
|
261
|
+
|
|
262
|
+
const user: User = {
|
|
263
|
+
name: 'John Doe',
|
|
264
|
+
email: 'john@example.com',
|
|
265
|
+
avatar: '/avatar.jpg'
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const navItems: NavItem[] = [
|
|
269
|
+
{ id: 'home', label: 'Home', path: '/' }
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
const headerProps: HeaderProps = {
|
|
273
|
+
title: 'App',
|
|
274
|
+
user,
|
|
275
|
+
navigationItems: navItems
|
|
276
|
+
};
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Customization
|
|
280
|
+
|
|
281
|
+
### Custom Branding
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
<Header
|
|
285
|
+
title="My Brand"
|
|
286
|
+
logo="/custom-logo.svg"
|
|
287
|
+
className="brand-header"
|
|
288
|
+
/>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Custom Actions
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
function CustomActions() {
|
|
295
|
+
return (
|
|
296
|
+
<div className="header-actions">
|
|
297
|
+
<button onClick={handleNotification}>
|
|
298
|
+
<BellIcon />
|
|
299
|
+
</button>
|
|
300
|
+
<button onClick={handleSearch}>
|
|
301
|
+
<SearchIcon />
|
|
302
|
+
</button>
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
<Header
|
|
308
|
+
title="App"
|
|
309
|
+
rightActions={<CustomActions />}
|
|
310
|
+
/>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Development
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
# Install dependencies
|
|
317
|
+
npm install
|
|
318
|
+
|
|
319
|
+
# Start development
|
|
320
|
+
npm run dev
|
|
321
|
+
|
|
322
|
+
# Build for production
|
|
323
|
+
npm run build
|
|
324
|
+
|
|
325
|
+
# Run tests
|
|
326
|
+
npm test
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Contributing
|
|
330
|
+
|
|
331
|
+
1. Fork the repository
|
|
332
|
+
2. Create a feature branch
|
|
333
|
+
3. Make your changes
|
|
334
|
+
4. Add tests for new functionality
|
|
335
|
+
5. Submit a pull request
|
|
336
|
+
|
|
337
|
+
## License
|
|
338
|
+
|
|
339
|
+
MIT © Gadagi Team
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gadagi/ui-header",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Top header component for gadagi micro-frontends",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"module": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"default": "./src/index.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["src"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "webpack --mode production && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
17
|
+
"dev": "webpack --mode development --watch"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": "^19.0.0",
|
|
24
|
+
"react-dom": "^19.0.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@gadagi/types": "^1.0.1",
|
|
28
|
+
"@gadagi/design-system": "^1.0.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/react": "^19.0.0",
|
|
32
|
+
"@types/react-dom": "^19.0.0",
|
|
33
|
+
"css-loader": "^7.0.0",
|
|
34
|
+
"react": "^19.0.0",
|
|
35
|
+
"react-dom": "^19.0.0",
|
|
36
|
+
"style-loader": "^4.0.0",
|
|
37
|
+
"ts-loader": "^9.0.0",
|
|
38
|
+
"typescript": "^5.0.0",
|
|
39
|
+
"webpack": "^5.0.0",
|
|
40
|
+
"webpack-cli": "^5.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/Header.tsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { User } from '@gadagi/types';
|
|
3
|
+
import { colors, typography } from '@gadagi/design-system';
|
|
4
|
+
import { UserMenu } from './UserMenu';
|
|
5
|
+
|
|
6
|
+
interface HeaderProps {
|
|
7
|
+
appName?: string;
|
|
8
|
+
user?: User | null;
|
|
9
|
+
onLogout?: () => void;
|
|
10
|
+
logo?: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const Header: React.FC<HeaderProps> = ({
|
|
14
|
+
appName = 'gadagi Platform',
|
|
15
|
+
user,
|
|
16
|
+
onLogout = () => {},
|
|
17
|
+
logo,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<header
|
|
21
|
+
style={{
|
|
22
|
+
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
|
23
|
+
padding: '0 1.5rem', height: '56px',
|
|
24
|
+
background: colors.neutral[800],
|
|
25
|
+
borderBottom: `1px solid ${colors.neutral[900]}`,
|
|
26
|
+
position: 'sticky', top: 0, zIndex: 50,
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
|
30
|
+
{logo}
|
|
31
|
+
<span
|
|
32
|
+
style={{
|
|
33
|
+
fontSize: typography.fontSize.lg,
|
|
34
|
+
fontWeight: typography.fontWeight.semibold,
|
|
35
|
+
color: '#fff',
|
|
36
|
+
letterSpacing: '-0.01em',
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
{appName}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
|
44
|
+
{user && <UserMenu user={user} onLogout={onLogout} />}
|
|
45
|
+
</div>
|
|
46
|
+
</header>
|
|
47
|
+
);
|
|
48
|
+
};
|
package/src/UserMenu.tsx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { User } from '@gadagi/types';
|
|
3
|
+
import { Button, colors, typography } from '@gadagi/design-system';
|
|
4
|
+
|
|
5
|
+
interface UserMenuProps {
|
|
6
|
+
user: User;
|
|
7
|
+
onLogout: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const UserMenu: React.FC<UserMenuProps> = ({ user, onLogout }) => {
|
|
11
|
+
const [open, setOpen] = useState(false);
|
|
12
|
+
const initials = `${user.firstName[0]}${user.lastName[0]}`.toUpperCase();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div style={{ position: 'relative' }}>
|
|
16
|
+
<button
|
|
17
|
+
onClick={() => setOpen(o => !o)}
|
|
18
|
+
style={{
|
|
19
|
+
display: 'flex', alignItems: 'center', gap: '8px',
|
|
20
|
+
background: 'transparent', border: 'none', cursor: 'pointer', color: '#fff',
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
style={{
|
|
25
|
+
width: '32px', height: '32px', borderRadius: '50%',
|
|
26
|
+
background: colors.primary[500],
|
|
27
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
28
|
+
fontSize: typography.fontSize.sm, fontWeight: typography.fontWeight.semibold,
|
|
29
|
+
color: '#fff',
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
{initials}
|
|
33
|
+
</div>
|
|
34
|
+
<span style={{ fontSize: typography.fontSize.sm }}>{user.firstName}</span>
|
|
35
|
+
</button>
|
|
36
|
+
|
|
37
|
+
{open && (
|
|
38
|
+
<div
|
|
39
|
+
style={{
|
|
40
|
+
position: 'absolute', right: 0, top: '100%', marginTop: '8px',
|
|
41
|
+
background: '#fff', border: `1px solid ${colors.neutral[200]}`,
|
|
42
|
+
borderRadius: '8px', padding: '8px', minWidth: '160px',
|
|
43
|
+
boxShadow: '0 4px 12px rgba(0,0,0,0.1)', zIndex: 100,
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<div style={{ padding: '8px 12px', borderBottom: `1px solid ${colors.neutral[100]}`, marginBottom: '4px' }}>
|
|
47
|
+
<p style={{ fontSize: typography.fontSize.sm, fontWeight: typography.fontWeight.medium, color: colors.neutral[800], margin: 0 }}>
|
|
48
|
+
{user.firstName} {user.lastName}
|
|
49
|
+
</p>
|
|
50
|
+
<p style={{ fontSize: typography.fontSize.xs, color: colors.neutral[400], margin: 0 }}>{user.email}</p>
|
|
51
|
+
</div>
|
|
52
|
+
<Button variant="ghost" size="sm" fullWidth onClick={() => { setOpen(false); onLogout(); }}>
|
|
53
|
+
Sign out
|
|
54
|
+
</Button>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
};
|
package/src/index.ts
ADDED