@delightui/components 0.1.105 → 0.1.107
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 +104 -1
- package/dist/cjs/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/cjs/components/molecules/Modal/index.d.ts +2 -0
- package/dist/cjs/components/molecules/index.d.ts +2 -0
- package/dist/cjs/library.css +19 -6
- package/dist/cjs/library.js +3 -3
- package/dist/cjs/library.js.map +1 -1
- package/dist/esm/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/esm/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/esm/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/esm/components/molecules/Modal/index.d.ts +2 -0
- package/dist/esm/components/molecules/index.d.ts +2 -0
- package/dist/esm/library.css +19 -6
- package/dist/esm/library.js +3 -3
- package/dist/esm/library.js.map +1 -1
- package/dist/index.d.ts +108 -2
- package/docs/README.md +264 -0
- package/docs/components/atoms/ActionImage.md +119 -0
- package/docs/components/atoms/Button.md +197 -0
- package/docs/components/atoms/Checkbox.md +299 -0
- package/docs/components/atoms/CheckboxItem.md +314 -0
- package/docs/components/atoms/Chip.md +380 -0
- package/docs/components/atoms/CustomToggle.md +270 -0
- package/docs/components/atoms/Icon.md +365 -0
- package/docs/components/atoms/IconButton.md +407 -0
- package/docs/components/atoms/Image.md +448 -0
- package/docs/components/atoms/Input.md +430 -0
- package/docs/components/atoms/ListItem.md +502 -0
- package/docs/components/atoms/Password.md +472 -0
- package/docs/components/atoms/RadioButton.md +614 -0
- package/docs/components/atoms/RadioButtonItem.md +588 -0
- package/docs/components/atoms/ResponsiveComponent.md +612 -0
- package/docs/components/atoms/SelectListItem.md +609 -0
- package/docs/components/atoms/Slider.md +605 -0
- package/docs/components/atoms/Spinner.md +605 -0
- package/docs/components/atoms/Text.md +463 -0
- package/docs/components/atoms/TextArea.md +670 -0
- package/docs/components/atoms/ToastNotification.md +668 -0
- package/docs/components/atoms/Toggle.md +737 -0
- package/docs/components/atoms/ToggleButton.md +751 -0
- package/docs/components/atoms/Tooltip.md +391 -0
- package/docs/components/molecules/Accordion.md +440 -0
- package/docs/components/molecules/AccordionGroup.md +547 -0
- package/docs/components/molecules/ActionCard.md +546 -0
- package/docs/components/molecules/Breadcrumb.md +403 -0
- package/docs/components/molecules/Breadcrumbs.md +485 -0
- package/docs/components/molecules/ButtonGroup.md +383 -0
- package/docs/components/molecules/Card.md +298 -0
- package/docs/components/molecules/ChipInput.md +646 -0
- package/docs/components/molecules/ContextMenu.md +768 -0
- package/docs/components/molecules/CustomTimeSelector.md +116 -0
- package/docs/components/molecules/DatePicker.md +516 -0
- package/docs/components/molecules/DateTimeSelector.md +166 -0
- package/docs/components/molecules/FormField.md +312 -0
- package/docs/components/molecules/Grid.md +577 -0
- package/docs/components/molecules/GridItem.md +834 -0
- package/docs/components/molecules/GridList.md +244 -0
- package/docs/components/molecules/List.md +485 -0
- package/docs/components/molecules/Modal.md +470 -0
- package/docs/components/molecules/ModalFooter.md +702 -0
- package/docs/components/molecules/ModalHeader.md +756 -0
- package/docs/components/molecules/ModalProvider.md +205 -0
- package/docs/components/molecules/Nav.md +530 -0
- package/docs/components/molecules/NavItem.md +572 -0
- package/docs/components/molecules/NavLink.md +499 -0
- package/docs/components/molecules/Option.md +521 -0
- package/docs/components/molecules/Pagination.md +592 -0
- package/docs/components/molecules/PaginationNumberField.md +722 -0
- package/docs/components/molecules/Popover.md +516 -0
- package/docs/components/molecules/ProgressBar.md +624 -0
- package/docs/components/molecules/RadioGroup.md +831 -0
- package/docs/components/molecules/RepeaterList.md +185 -0
- package/docs/components/molecules/Select.md +402 -0
- package/docs/components/molecules/SortableTrigger.md +82 -0
- package/docs/components/molecules/useModal.md +379 -0
- package/docs/components/organisms/Dropzone.md +346 -0
- package/docs/components/organisms/DropzoneClear.md +135 -0
- package/docs/components/organisms/DropzoneContent.md +216 -0
- package/docs/components/organisms/DropzoneFilename.md +191 -0
- package/docs/components/organisms/DropzoneSupportedFormats.md +184 -0
- package/docs/components/organisms/DropzoneTrigger.md +209 -0
- package/docs/components/organisms/Form.md +533 -0
- package/docs/components/organisms/SlideOutPanel.md +662 -0
- package/docs/components/organisms/TabContent.md +902 -0
- package/docs/components/organisms/TabItem.md +1091 -0
- package/docs/components/organisms/Table.md +611 -0
- package/docs/components/organisms/TableBody.md +679 -0
- package/docs/components/organisms/TableCell.md +482 -0
- package/docs/components/organisms/TableHeader.md +513 -0
- package/docs/components/organisms/TableHeaderCell.md +661 -0
- package/docs/components/organisms/TableRow.md +715 -0
- package/docs/components/organisms/Tabs.md +1330 -0
- package/docs/components/utils/ConditionalView.md +568 -0
- package/docs/components/utils/RenderStateView.md +726 -0
- package/docs/components/utils/WrapTextNodes.md +614 -0
- package/package.json +3 -2
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
# NavLink
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
A navigation link component that handles both internal routing and external links with automatic detection. Extends Button component functionality with router integration, supporting various styles, icons, and accessibility features for seamless navigation experiences.
|
|
6
|
+
|
|
7
|
+
## Aliases
|
|
8
|
+
|
|
9
|
+
- NavLink
|
|
10
|
+
- NavigationLink
|
|
11
|
+
- RouterLink
|
|
12
|
+
- MenuLink
|
|
13
|
+
- ActionLink
|
|
14
|
+
|
|
15
|
+
## Props Breakdown
|
|
16
|
+
|
|
17
|
+
**Extends:** `Omit<RouteLinkProps, 'to'>` + `Pick<ButtonProps, 'appearance' | 'size' | 'style' | 'leadingIcon' | 'trailingIcon'>`
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default | Required | Description |
|
|
20
|
+
|------|------|---------|----------|-------------|
|
|
21
|
+
| `to` | `string \| -1` | - | Yes | Destination URL/path. External URLs (starting with "https") render as `<a>` tags, internal paths as RouterNavLink |
|
|
22
|
+
| `type` | `NavLinkTypeEnum \| ButtonTypeEnum` | `'Fill'` | No | Visual style type (Fill, Underline, etc.) |
|
|
23
|
+
| `appearance` | `string` | - | No | Visual appearance variant |
|
|
24
|
+
| `size` | `string` | - | No | Size variant of the link |
|
|
25
|
+
| `style` | `string` | - | No | Style variant for different contexts |
|
|
26
|
+
| `leadingIcon` | `ReactNode` | - | No | Icon displayed before the link text |
|
|
27
|
+
| `trailingIcon` | `ReactNode` | - | No | Icon displayed after the link text |
|
|
28
|
+
| `component-variant` | `string` | - | No | Override styling variant |
|
|
29
|
+
| `children` | `ReactNode` | - | Yes | Link content (text, icons, etc.) |
|
|
30
|
+
|
|
31
|
+
Plus all React Router Link props and Button styling props.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
```tsx
|
|
37
|
+
import { NavLink, Icon } from '@delightui/components';
|
|
38
|
+
|
|
39
|
+
function BasicExample() {
|
|
40
|
+
return (
|
|
41
|
+
<div className="basic-nav-links">
|
|
42
|
+
<NavLink to="/home">Home</NavLink>
|
|
43
|
+
<NavLink to="/about">About Us</NavLink>
|
|
44
|
+
<NavLink to="/contact">Contact</NavLink>
|
|
45
|
+
<NavLink to="https://external-site.com">External Link</NavLink>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Navigation Links with Icons
|
|
52
|
+
```tsx
|
|
53
|
+
function IconNavLinksExample() {
|
|
54
|
+
return (
|
|
55
|
+
<div className="icon-nav-links">
|
|
56
|
+
<NavLink
|
|
57
|
+
to="/dashboard"
|
|
58
|
+
leadingIcon={<Icon icon="Dashboard" />}
|
|
59
|
+
>
|
|
60
|
+
Dashboard
|
|
61
|
+
</NavLink>
|
|
62
|
+
|
|
63
|
+
<NavLink
|
|
64
|
+
to="/projects"
|
|
65
|
+
leadingIcon={<Icon icon="Folder" />}
|
|
66
|
+
trailingIcon={<Icon icon="ChevronRight" />}
|
|
67
|
+
>
|
|
68
|
+
Projects
|
|
69
|
+
</NavLink>
|
|
70
|
+
|
|
71
|
+
<NavLink
|
|
72
|
+
to="/settings"
|
|
73
|
+
leadingIcon={<Icon icon="Settings" />}
|
|
74
|
+
>
|
|
75
|
+
Settings
|
|
76
|
+
</NavLink>
|
|
77
|
+
|
|
78
|
+
<NavLink
|
|
79
|
+
to="https://help.example.com"
|
|
80
|
+
leadingIcon={<Icon icon="Help" />}
|
|
81
|
+
trailingIcon={<Icon icon="ExternalLink" />}
|
|
82
|
+
>
|
|
83
|
+
Help Center
|
|
84
|
+
</NavLink>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Different Link Types
|
|
91
|
+
```tsx
|
|
92
|
+
function LinkTypesExample() {
|
|
93
|
+
return (
|
|
94
|
+
<div className="link-types">
|
|
95
|
+
<NavLink to="/home" type="Fill">
|
|
96
|
+
Fill Link
|
|
97
|
+
</NavLink>
|
|
98
|
+
|
|
99
|
+
<NavLink to="/about" type="Underline">
|
|
100
|
+
Underline Link
|
|
101
|
+
</NavLink>
|
|
102
|
+
|
|
103
|
+
<NavLink to="/contact" type="Ghost">
|
|
104
|
+
Ghost Link
|
|
105
|
+
</NavLink>
|
|
106
|
+
|
|
107
|
+
<NavLink to="/services" type="Outlined">
|
|
108
|
+
Outlined Link
|
|
109
|
+
</NavLink>
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Active State Navigation
|
|
116
|
+
```tsx
|
|
117
|
+
function ActiveStateExample() {
|
|
118
|
+
const [currentPath, setCurrentPath] = useState('/dashboard');
|
|
119
|
+
|
|
120
|
+
const navigationItems = [
|
|
121
|
+
{ path: '/dashboard', label: 'Dashboard', icon: 'Dashboard' },
|
|
122
|
+
{ path: '/projects', label: 'Projects', icon: 'Folder' },
|
|
123
|
+
{ path: '/team', label: 'Team', icon: 'People' },
|
|
124
|
+
{ path: '/reports', label: 'Reports', icon: 'Description' }
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div className="active-nav">
|
|
129
|
+
{navigationItems.map(item => (
|
|
130
|
+
<NavLink
|
|
131
|
+
key={item.path}
|
|
132
|
+
to={item.path}
|
|
133
|
+
className={currentPath === item.path ? 'active' : ''}
|
|
134
|
+
onClick={() => setCurrentPath(item.path)}
|
|
135
|
+
leadingIcon={<Icon icon={item.icon} />}
|
|
136
|
+
style={currentPath === item.path ? 'Primary' : 'Default'}
|
|
137
|
+
>
|
|
138
|
+
{item.label}
|
|
139
|
+
</NavLink>
|
|
140
|
+
))}
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Styled Navigation Links
|
|
147
|
+
```tsx
|
|
148
|
+
function StyledNavLinksExample() {
|
|
149
|
+
return (
|
|
150
|
+
<div className="styled-nav-links">
|
|
151
|
+
<NavLink
|
|
152
|
+
to="/important"
|
|
153
|
+
style="Primary"
|
|
154
|
+
leadingIcon={<Icon icon="Star" />}
|
|
155
|
+
>
|
|
156
|
+
Important Section
|
|
157
|
+
</NavLink>
|
|
158
|
+
|
|
159
|
+
<NavLink
|
|
160
|
+
to="/warning"
|
|
161
|
+
style="Warning"
|
|
162
|
+
leadingIcon={<Icon icon="Warning" />}
|
|
163
|
+
>
|
|
164
|
+
Warning Area
|
|
165
|
+
</NavLink>
|
|
166
|
+
|
|
167
|
+
<NavLink
|
|
168
|
+
to="/danger"
|
|
169
|
+
style="Destructive"
|
|
170
|
+
leadingIcon={<Icon icon="Error" />}
|
|
171
|
+
>
|
|
172
|
+
Danger Zone
|
|
173
|
+
</NavLink>
|
|
174
|
+
|
|
175
|
+
<NavLink
|
|
176
|
+
to="/success"
|
|
177
|
+
style="Success"
|
|
178
|
+
leadingIcon={<Icon icon="CheckCircle" />}
|
|
179
|
+
>
|
|
180
|
+
Success Page
|
|
181
|
+
</NavLink>
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Breadcrumb Navigation Links
|
|
188
|
+
```tsx
|
|
189
|
+
function BreadcrumbLinksExample() {
|
|
190
|
+
const breadcrumbs = [
|
|
191
|
+
{ label: 'Home', path: '/' },
|
|
192
|
+
{ label: 'Products', path: '/products' },
|
|
193
|
+
{ label: 'Electronics', path: '/products/electronics' },
|
|
194
|
+
{ label: 'Smartphones', path: '/products/electronics/smartphones' }
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div className="breadcrumb-links">
|
|
199
|
+
{breadcrumbs.map((crumb, index) => (
|
|
200
|
+
<div key={crumb.path} className="breadcrumb-item">
|
|
201
|
+
<NavLink
|
|
202
|
+
to={crumb.path}
|
|
203
|
+
type="Underline"
|
|
204
|
+
size="Small"
|
|
205
|
+
>
|
|
206
|
+
{crumb.label}
|
|
207
|
+
</NavLink>
|
|
208
|
+
|
|
209
|
+
{index < breadcrumbs.length - 1 && (
|
|
210
|
+
<Icon icon="ChevronRight" className="breadcrumb-separator" />
|
|
211
|
+
)}
|
|
212
|
+
</div>
|
|
213
|
+
))}
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Mobile Navigation Links
|
|
220
|
+
```tsx
|
|
221
|
+
function MobileNavLinksExample() {
|
|
222
|
+
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
223
|
+
|
|
224
|
+
const navigationItems = [
|
|
225
|
+
{ to: '/home', label: 'Home', icon: 'Home' },
|
|
226
|
+
{ to: '/products', label: 'Products', icon: 'ShoppingCart' },
|
|
227
|
+
{ to: '/services', label: 'Services', icon: 'Build' },
|
|
228
|
+
{ to: '/about', label: 'About', icon: 'Info' },
|
|
229
|
+
{ to: '/contact', label: 'Contact', icon: 'Phone' }
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<div className="mobile-nav">
|
|
234
|
+
<Button
|
|
235
|
+
className="mobile-toggle"
|
|
236
|
+
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
|
237
|
+
leadingIcon={<Icon icon={isMobileMenuOpen ? 'Close' : 'Menu'} />}
|
|
238
|
+
>
|
|
239
|
+
Menu
|
|
240
|
+
</Button>
|
|
241
|
+
|
|
242
|
+
<div className={`mobile-nav-links ${isMobileMenuOpen ? 'open' : ''}`}>
|
|
243
|
+
{navigationItems.map(item => (
|
|
244
|
+
<NavLink
|
|
245
|
+
key={item.to}
|
|
246
|
+
to={item.to}
|
|
247
|
+
leadingIcon={<Icon icon={item.icon} />}
|
|
248
|
+
onClick={() => setIsMobileMenuOpen(false)}
|
|
249
|
+
className="mobile-nav-link"
|
|
250
|
+
>
|
|
251
|
+
{item.label}
|
|
252
|
+
</NavLink>
|
|
253
|
+
))}
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Tab Navigation Links
|
|
261
|
+
```tsx
|
|
262
|
+
function TabNavigationExample() {
|
|
263
|
+
const [activeTab, setActiveTab] = useState('overview');
|
|
264
|
+
|
|
265
|
+
const tabs = [
|
|
266
|
+
{ id: 'overview', label: 'Overview', icon: 'Dashboard' },
|
|
267
|
+
{ id: 'details', label: 'Details', icon: 'Description' },
|
|
268
|
+
{ id: 'analytics', label: 'Analytics', icon: 'BarChart' },
|
|
269
|
+
{ id: 'settings', label: 'Settings', icon: 'Settings' }
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<div className="tab-navigation">
|
|
274
|
+
<div className="tab-links">
|
|
275
|
+
{tabs.map(tab => (
|
|
276
|
+
<NavLink
|
|
277
|
+
key={tab.id}
|
|
278
|
+
to={`/project/${tab.id}`}
|
|
279
|
+
className={activeTab === tab.id ? 'active-tab' : 'inactive-tab'}
|
|
280
|
+
onClick={() => setActiveTab(tab.id)}
|
|
281
|
+
leadingIcon={<Icon icon={tab.icon} />}
|
|
282
|
+
type="Underline"
|
|
283
|
+
>
|
|
284
|
+
{tab.label}
|
|
285
|
+
</NavLink>
|
|
286
|
+
))}
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div className="tab-content">
|
|
290
|
+
{activeTab === 'overview' && (
|
|
291
|
+
<div>Overview content...</div>
|
|
292
|
+
)}
|
|
293
|
+
{activeTab === 'details' && (
|
|
294
|
+
<div>Project details...</div>
|
|
295
|
+
)}
|
|
296
|
+
{activeTab === 'analytics' && (
|
|
297
|
+
<div>Analytics dashboard...</div>
|
|
298
|
+
)}
|
|
299
|
+
{activeTab === 'settings' && (
|
|
300
|
+
<div>Project settings...</div>
|
|
301
|
+
)}
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### External Links with Indicators
|
|
309
|
+
```tsx
|
|
310
|
+
function ExternalLinksExample() {
|
|
311
|
+
const externalLinks = [
|
|
312
|
+
{
|
|
313
|
+
url: 'https://github.com/company/repo',
|
|
314
|
+
label: 'GitHub Repository',
|
|
315
|
+
icon: 'Code'
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
url: 'https://docs.example.com',
|
|
319
|
+
label: 'Documentation',
|
|
320
|
+
icon: 'Book'
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
url: 'https://support.example.com',
|
|
324
|
+
label: 'Support Center',
|
|
325
|
+
icon: 'Support'
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
url: 'https://blog.example.com',
|
|
329
|
+
label: 'Company Blog',
|
|
330
|
+
icon: 'Article'
|
|
331
|
+
}
|
|
332
|
+
];
|
|
333
|
+
|
|
334
|
+
return (
|
|
335
|
+
<div className="external-links">
|
|
336
|
+
<Text type="Heading5">External Resources</Text>
|
|
337
|
+
|
|
338
|
+
{externalLinks.map(link => (
|
|
339
|
+
<NavLink
|
|
340
|
+
key={link.url}
|
|
341
|
+
to={link.url}
|
|
342
|
+
leadingIcon={<Icon icon={link.icon} />}
|
|
343
|
+
trailingIcon={<Icon icon="ExternalLink" />}
|
|
344
|
+
className="external-link"
|
|
345
|
+
target="_blank"
|
|
346
|
+
rel="noopener noreferrer"
|
|
347
|
+
>
|
|
348
|
+
{link.label}
|
|
349
|
+
</NavLink>
|
|
350
|
+
))}
|
|
351
|
+
</div>
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Conditional Navigation Links
|
|
357
|
+
```tsx
|
|
358
|
+
function ConditionalLinksExample() {
|
|
359
|
+
const [user, setUser] = useState({
|
|
360
|
+
isAuthenticated: true,
|
|
361
|
+
role: 'admin',
|
|
362
|
+
permissions: ['read', 'write', 'admin']
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const hasPermission = (permission) => {
|
|
366
|
+
return user.permissions.includes(permission);
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return (
|
|
370
|
+
<div className="conditional-nav">
|
|
371
|
+
{/* Always visible */}
|
|
372
|
+
<NavLink to="/dashboard" leadingIcon={<Icon icon="Dashboard" />}>
|
|
373
|
+
Dashboard
|
|
374
|
+
</NavLink>
|
|
375
|
+
|
|
376
|
+
{/* Authenticated users only */}
|
|
377
|
+
{user.isAuthenticated && (
|
|
378
|
+
<>
|
|
379
|
+
<NavLink to="/profile" leadingIcon={<Icon icon="Person" />}>
|
|
380
|
+
Profile
|
|
381
|
+
</NavLink>
|
|
382
|
+
|
|
383
|
+
<NavLink to="/projects" leadingIcon={<Icon icon="Folder" />}>
|
|
384
|
+
My Projects
|
|
385
|
+
</NavLink>
|
|
386
|
+
</>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
{/* Permission-based navigation */}
|
|
390
|
+
{hasPermission('admin') && (
|
|
391
|
+
<>
|
|
392
|
+
<NavLink
|
|
393
|
+
to="/admin/users"
|
|
394
|
+
leadingIcon={<Icon icon="People" />}
|
|
395
|
+
style="Warning"
|
|
396
|
+
>
|
|
397
|
+
User Management
|
|
398
|
+
</NavLink>
|
|
399
|
+
|
|
400
|
+
<NavLink
|
|
401
|
+
to="/admin/settings"
|
|
402
|
+
leadingIcon={<Icon icon="Settings" />}
|
|
403
|
+
style="Warning"
|
|
404
|
+
>
|
|
405
|
+
System Settings
|
|
406
|
+
</NavLink>
|
|
407
|
+
</>
|
|
408
|
+
)}
|
|
409
|
+
|
|
410
|
+
{/* Role-based navigation */}
|
|
411
|
+
{user.role === 'admin' && (
|
|
412
|
+
<NavLink
|
|
413
|
+
to="/admin/logs"
|
|
414
|
+
leadingIcon={<Icon icon="Description" />}
|
|
415
|
+
style="Destructive"
|
|
416
|
+
>
|
|
417
|
+
System Logs
|
|
418
|
+
</NavLink>
|
|
419
|
+
)}
|
|
420
|
+
|
|
421
|
+
{/* Unauthenticated users */}
|
|
422
|
+
{!user.isAuthenticated && (
|
|
423
|
+
<>
|
|
424
|
+
<NavLink to="/login" style="Primary">
|
|
425
|
+
Sign In
|
|
426
|
+
</NavLink>
|
|
427
|
+
|
|
428
|
+
<NavLink to="/register" type="Outlined">
|
|
429
|
+
Sign Up
|
|
430
|
+
</NavLink>
|
|
431
|
+
</>
|
|
432
|
+
)}
|
|
433
|
+
</div>
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Navigation Links with Loading States
|
|
439
|
+
```tsx
|
|
440
|
+
function LoadingStateLinksExample() {
|
|
441
|
+
const [loadingStates, setLoadingStates] = useState({});
|
|
442
|
+
|
|
443
|
+
const handleNavClick = async (path) => {
|
|
444
|
+
setLoadingStates(prev => ({ ...prev, [path]: true }));
|
|
445
|
+
|
|
446
|
+
// Simulate navigation delay
|
|
447
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
448
|
+
|
|
449
|
+
setLoadingStates(prev => ({ ...prev, [path]: false }));
|
|
450
|
+
// Navigate to the path
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
return (
|
|
454
|
+
<div className="loading-nav-links">
|
|
455
|
+
<NavLink
|
|
456
|
+
to="/dashboard"
|
|
457
|
+
leadingIcon={
|
|
458
|
+
loadingStates['/dashboard'] ? (
|
|
459
|
+
<Spinner size="Small" />
|
|
460
|
+
) : (
|
|
461
|
+
<Icon icon="Dashboard" />
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
onClick={(e) => {
|
|
465
|
+
e.preventDefault();
|
|
466
|
+
handleNavClick('/dashboard');
|
|
467
|
+
}}
|
|
468
|
+
disabled={loadingStates['/dashboard']}
|
|
469
|
+
>
|
|
470
|
+
Dashboard
|
|
471
|
+
{loadingStates['/dashboard'] && (
|
|
472
|
+
<Text type="BodySmall">Loading...</Text>
|
|
473
|
+
)}
|
|
474
|
+
</NavLink>
|
|
475
|
+
|
|
476
|
+
<NavLink
|
|
477
|
+
to="/reports"
|
|
478
|
+
leadingIcon={
|
|
479
|
+
loadingStates['/reports'] ? (
|
|
480
|
+
<Spinner size="Small" />
|
|
481
|
+
) : (
|
|
482
|
+
<Icon icon="Description" />
|
|
483
|
+
)
|
|
484
|
+
}
|
|
485
|
+
onClick={(e) => {
|
|
486
|
+
e.preventDefault();
|
|
487
|
+
handleNavClick('/reports');
|
|
488
|
+
}}
|
|
489
|
+
disabled={loadingStates['/reports']}
|
|
490
|
+
>
|
|
491
|
+
Reports
|
|
492
|
+
{loadingStates['/reports'] && (
|
|
493
|
+
<Text type="BodySmall">Loading...</Text>
|
|
494
|
+
)}
|
|
495
|
+
</NavLink>
|
|
496
|
+
</div>
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
```
|