@shohojdhara/atomix 0.2.7 → 0.2.9
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/CHANGELOG.md +58 -0
- package/README.md +40 -1
- package/dist/atomix.css +412 -77
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +913 -12
- package/dist/index.esm.js +1739 -209
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1763 -208
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/applemix.css +412 -77
- package/dist/themes/applemix.min.css +3 -3
- package/dist/themes/boomdevs.css +411 -76
- package/dist/themes/boomdevs.min.css +3 -3
- package/dist/themes/esrar.css +412 -77
- package/dist/themes/esrar.min.css +3 -3
- package/dist/themes/flashtrade.css +1803 -622
- package/dist/themes/flashtrade.min.css +113 -7
- package/dist/themes/mashroom.css +411 -76
- package/dist/themes/mashroom.min.css +4 -4
- package/dist/themes/shaj-default.css +411 -76
- package/dist/themes/shaj-default.min.css +3 -3
- package/package.json +13 -2
- package/src/components/Button/Button.stories.tsx +174 -0
- package/src/components/Button/Button.tsx +238 -78
- package/src/components/Card/Card.stories.tsx +202 -0
- package/src/components/Card/Card.tsx +253 -77
- package/src/components/Form/Input.stories.tsx +228 -2
- package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +301 -13
- package/src/components/Navigation/SideMenu/SideMenu.tsx +236 -9
- package/src/components/Tooltip/Tooltip.tsx +68 -66
- package/src/lib/composables/useButton.ts +37 -5
- package/src/lib/composables/useInput.ts +39 -1
- package/src/lib/composables/useSideMenu.ts +89 -30
- package/src/lib/constants/components.ts +53 -0
- package/src/lib/index.ts +5 -0
- package/src/lib/theme/ThemeContext.tsx +17 -0
- package/src/lib/theme/ThemeManager.stories.tsx +472 -0
- package/src/lib/theme/ThemeManager.test.ts +186 -0
- package/src/lib/theme/ThemeManager.ts +501 -0
- package/src/lib/theme/ThemeProvider.tsx +227 -0
- package/src/lib/theme/index.ts +56 -0
- package/src/lib/theme/types.ts +247 -0
- package/src/lib/theme/useTheme.test.tsx +66 -0
- package/src/lib/theme/useTheme.ts +80 -0
- package/src/lib/theme/utils.test.ts +140 -0
- package/src/lib/theme/utils.ts +398 -0
- package/src/lib/types/components.ts +304 -4
- package/src/styles/01-settings/_settings.tooltip.scss +2 -2
- package/src/styles/06-components/_components.button.scss +100 -0
- package/src/styles/06-components/_components.card.scss +235 -2
- package/src/styles/06-components/_components.side-menu.scss +79 -18
- package/src/styles/06-components/_components.tooltip.scss +89 -66
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
3
|
import { Input } from './Input';
|
|
4
|
+
import { MagnifyingGlass, Envelope, Lock, User, Phone, Calendar } from '@phosphor-icons/react';
|
|
3
5
|
|
|
4
6
|
const meta = {
|
|
5
7
|
title: 'Components/Form/Input',
|
|
@@ -20,7 +22,7 @@ const meta = {
|
|
|
20
22
|
},
|
|
21
23
|
variant: {
|
|
22
24
|
control: { type: 'select' },
|
|
23
|
-
options: ['primary', 'success', '
|
|
25
|
+
options: ['primary', 'success', 'error', 'warning', 'info'],
|
|
24
26
|
description: 'Color variant of the input',
|
|
25
27
|
},
|
|
26
28
|
disabled: {
|
|
@@ -43,6 +45,22 @@ const meta = {
|
|
|
43
45
|
control: 'boolean',
|
|
44
46
|
description: 'Enable glass morphism effect',
|
|
45
47
|
},
|
|
48
|
+
clearable: {
|
|
49
|
+
control: 'boolean',
|
|
50
|
+
description: 'Show clear button when input has value',
|
|
51
|
+
},
|
|
52
|
+
showCounter: {
|
|
53
|
+
control: 'boolean',
|
|
54
|
+
description: 'Show character counter',
|
|
55
|
+
},
|
|
56
|
+
showPasswordToggle: {
|
|
57
|
+
control: 'boolean',
|
|
58
|
+
description: 'Show password visibility toggle (for password inputs)',
|
|
59
|
+
},
|
|
60
|
+
fullWidth: {
|
|
61
|
+
control: 'boolean',
|
|
62
|
+
description: 'Input takes full width',
|
|
63
|
+
},
|
|
46
64
|
},
|
|
47
65
|
} satisfies Meta<typeof Input>;
|
|
48
66
|
|
|
@@ -88,7 +106,6 @@ export const Variants: Story = {
|
|
|
88
106
|
render: () => (
|
|
89
107
|
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '300px' }}>
|
|
90
108
|
<Input variant="primary" placeholder="Primary input" />
|
|
91
|
-
<Input variant="secondary" placeholder="Secondary input" />
|
|
92
109
|
<Input variant="success" placeholder="Success input" />
|
|
93
110
|
<Input variant="error" placeholder="Error input" />
|
|
94
111
|
<Input variant="warning" placeholder="Warning input" />
|
|
@@ -109,6 +126,215 @@ export const States: Story = {
|
|
|
109
126
|
),
|
|
110
127
|
};
|
|
111
128
|
|
|
129
|
+
// Prefix and Suffix Icons
|
|
130
|
+
export const WithIcons: Story = {
|
|
131
|
+
render: () => (
|
|
132
|
+
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '300px' }}>
|
|
133
|
+
<Input
|
|
134
|
+
placeholder="Search..."
|
|
135
|
+
prefixIcon={<MagnifyingGlass size={18} />}
|
|
136
|
+
/>
|
|
137
|
+
<Input
|
|
138
|
+
placeholder="Email address"
|
|
139
|
+
type="email"
|
|
140
|
+
prefixIcon={<Envelope size={18} />}
|
|
141
|
+
/>
|
|
142
|
+
<Input
|
|
143
|
+
placeholder="Username"
|
|
144
|
+
prefixIcon={<User size={18} />}
|
|
145
|
+
suffixIcon={<span style={{ color: 'green' }}>✓</span>}
|
|
146
|
+
/>
|
|
147
|
+
<Input
|
|
148
|
+
placeholder="Phone number"
|
|
149
|
+
type="tel"
|
|
150
|
+
prefixIcon={<Phone size={18} />}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
),
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Clearable Input
|
|
157
|
+
export const Clearable: Story = {
|
|
158
|
+
render: () => {
|
|
159
|
+
const [value, setValue] = React.useState('');
|
|
160
|
+
return (
|
|
161
|
+
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '300px' }}>
|
|
162
|
+
<Input
|
|
163
|
+
placeholder="Type to see clear button"
|
|
164
|
+
value={value}
|
|
165
|
+
onChange={(e) => setValue(e.target.value)}
|
|
166
|
+
clearable
|
|
167
|
+
/>
|
|
168
|
+
<Input
|
|
169
|
+
placeholder="With prefix icon"
|
|
170
|
+
prefixIcon={<MagnifyingGlass size={18} />}
|
|
171
|
+
value={value}
|
|
172
|
+
onChange={(e) => setValue(e.target.value)}
|
|
173
|
+
clearable
|
|
174
|
+
/>
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Character Counter
|
|
181
|
+
export const WithCounter: Story = {
|
|
182
|
+
render: () => {
|
|
183
|
+
const [value, setValue] = React.useState('');
|
|
184
|
+
return (
|
|
185
|
+
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '300px' }}>
|
|
186
|
+
<Input
|
|
187
|
+
placeholder="Type here (max 50 characters)"
|
|
188
|
+
value={value}
|
|
189
|
+
onChange={(e) => setValue(e.target.value)}
|
|
190
|
+
maxLength={50}
|
|
191
|
+
showCounter
|
|
192
|
+
/>
|
|
193
|
+
<Input
|
|
194
|
+
placeholder="With custom max count"
|
|
195
|
+
value={value}
|
|
196
|
+
onChange={(e) => setValue(e.target.value)}
|
|
197
|
+
maxCount={100}
|
|
198
|
+
showCounter
|
|
199
|
+
/>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Password Toggle
|
|
206
|
+
export const PasswordToggle: Story = {
|
|
207
|
+
render: () => {
|
|
208
|
+
const [password, setPassword] = React.useState('');
|
|
209
|
+
return (
|
|
210
|
+
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '300px' }}>
|
|
211
|
+
<Input
|
|
212
|
+
type="password"
|
|
213
|
+
placeholder="Enter password"
|
|
214
|
+
value={password}
|
|
215
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
216
|
+
showPasswordToggle
|
|
217
|
+
/>
|
|
218
|
+
<Input
|
|
219
|
+
type="password"
|
|
220
|
+
placeholder="Password with prefix icon"
|
|
221
|
+
prefixIcon={<Lock size={18} />}
|
|
222
|
+
value={password}
|
|
223
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
224
|
+
showPasswordToggle
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// Error Messages and Helper Text
|
|
232
|
+
export const WithMessages: Story = {
|
|
233
|
+
render: () => {
|
|
234
|
+
const [email, setEmail] = React.useState('');
|
|
235
|
+
const [username, setUsername] = React.useState('');
|
|
236
|
+
const isValidEmail = email.includes('@') && email.includes('.');
|
|
237
|
+
const isInvalidEmail = email.length > 0 && !isValidEmail;
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '300px' }}>
|
|
241
|
+
<Input
|
|
242
|
+
type="email"
|
|
243
|
+
placeholder="Email address"
|
|
244
|
+
value={email}
|
|
245
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
246
|
+
invalid={isInvalidEmail}
|
|
247
|
+
errorMessage={isInvalidEmail ? 'Please enter a valid email address' : undefined}
|
|
248
|
+
helperText={!isInvalidEmail ? 'We\'ll never share your email' : undefined}
|
|
249
|
+
/>
|
|
250
|
+
<Input
|
|
251
|
+
placeholder="Username"
|
|
252
|
+
value={username}
|
|
253
|
+
onChange={(e) => setUsername(e.target.value)}
|
|
254
|
+
helperText="Choose a unique username"
|
|
255
|
+
/>
|
|
256
|
+
<Input
|
|
257
|
+
placeholder="Required field"
|
|
258
|
+
required
|
|
259
|
+
helperText="This field is required"
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
);
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// Full Width
|
|
267
|
+
export const FullWidth: Story = {
|
|
268
|
+
render: () => (
|
|
269
|
+
<div className="u-d-flex u-flex-column u-gap-3" style={{ width: '100%', maxWidth: '500px' }}>
|
|
270
|
+
<Input placeholder="Full width input" fullWidth />
|
|
271
|
+
<Input
|
|
272
|
+
placeholder="Full width with icon"
|
|
273
|
+
prefixIcon={<MagnifyingGlass size={18} />}
|
|
274
|
+
fullWidth
|
|
275
|
+
/>
|
|
276
|
+
</div>
|
|
277
|
+
),
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Comprehensive Example
|
|
281
|
+
export const Comprehensive: Story = {
|
|
282
|
+
render: () => {
|
|
283
|
+
const [search, setSearch] = React.useState('');
|
|
284
|
+
const [password, setPassword] = React.useState('');
|
|
285
|
+
const [bio, setBio] = React.useState('');
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<div className="u-d-flex u-flex-column u-gap-4" style={{ width: '400px' }}>
|
|
289
|
+
<div>
|
|
290
|
+
<label style={{ display: 'block', marginBottom: '0.5rem', color: 'white' }}>
|
|
291
|
+
Search
|
|
292
|
+
</label>
|
|
293
|
+
<Input
|
|
294
|
+
placeholder="Search products..."
|
|
295
|
+
value={search}
|
|
296
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
297
|
+
prefixIcon={<MagnifyingGlass size={18} />}
|
|
298
|
+
clearable
|
|
299
|
+
fullWidth
|
|
300
|
+
/>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<div>
|
|
304
|
+
<label style={{ display: 'block', marginBottom: '0.5rem', color: 'white' }}>
|
|
305
|
+
Password
|
|
306
|
+
</label>
|
|
307
|
+
<Input
|
|
308
|
+
type="password"
|
|
309
|
+
placeholder="Enter your password"
|
|
310
|
+
value={password}
|
|
311
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
312
|
+
prefixIcon={<Lock size={18} />}
|
|
313
|
+
showPasswordToggle
|
|
314
|
+
fullWidth
|
|
315
|
+
helperText="Must be at least 8 characters"
|
|
316
|
+
/>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<div>
|
|
320
|
+
<label style={{ display: 'block', marginBottom: '0.5rem', color: 'white' }}>
|
|
321
|
+
Bio
|
|
322
|
+
</label>
|
|
323
|
+
<Input
|
|
324
|
+
placeholder="Tell us about yourself"
|
|
325
|
+
value={bio}
|
|
326
|
+
onChange={(e) => setBio(e.target.value)}
|
|
327
|
+
maxLength={200}
|
|
328
|
+
showCounter
|
|
329
|
+
fullWidth
|
|
330
|
+
helperText="Maximum 200 characters"
|
|
331
|
+
/>
|
|
332
|
+
</div>
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
|
|
112
338
|
// Glass Effect
|
|
113
339
|
export const Glass: Story = {
|
|
114
340
|
args: {
|
|
@@ -20,6 +20,7 @@ The SideMenu component provides a collapsible navigation menu with title and men
|
|
|
20
20
|
|
|
21
21
|
- **Responsive Design**: Automatically collapses on mobile devices
|
|
22
22
|
- **Collapsible**: Can be toggled open/closed with smooth animations
|
|
23
|
+
- **Nested Menu Items**: Support for collapsible nested sections with independent toggle functionality
|
|
23
24
|
- **Accessibility**: Full keyboard navigation and screen reader support
|
|
24
25
|
- **Active States**: Support for active menu items
|
|
25
26
|
- **Icon Support**: Menu items can include Phosphor icons
|
|
@@ -52,6 +53,26 @@ The SideMenu component provides a collapsible navigation menu with title and men
|
|
|
52
53
|
</SideMenu>
|
|
53
54
|
\`\`\`
|
|
54
55
|
|
|
56
|
+
### With Nested Menu Items
|
|
57
|
+
\`\`\`tsx
|
|
58
|
+
<SideMenu title="Navigation" menuItems={[
|
|
59
|
+
{
|
|
60
|
+
title: 'Dashboard',
|
|
61
|
+
items: [
|
|
62
|
+
{ title: 'Overview', href: '/dashboard', icon: <Icon name="ChartBar" />, active: true },
|
|
63
|
+
{ title: 'Analytics', href: '/dashboard/analytics', icon: <Icon name="TrendUp" /> },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
title: 'Users',
|
|
68
|
+
items: [
|
|
69
|
+
{ title: 'All Users', href: '/users', icon: <Icon name="Users" /> },
|
|
70
|
+
{ title: 'Roles', href: '/users/roles', icon: <Icon name="Shield" /> },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
]} />
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
55
76
|
### Vanilla JavaScript
|
|
56
77
|
\`\`\`html
|
|
57
78
|
<div class="c-side-menu" data-side-menu data-collapsible="true">
|
|
@@ -369,7 +390,6 @@ export const DisabledMenu: Story = {
|
|
|
369
390
|
// Complex Navigation
|
|
370
391
|
export const ComplexNavigation: Story = {
|
|
371
392
|
args: {
|
|
372
|
-
title: 'Admin Panel',
|
|
373
393
|
children: (
|
|
374
394
|
<>
|
|
375
395
|
<SideMenuList>
|
|
@@ -435,8 +455,8 @@ export const ComplexNavigation: Story = {
|
|
|
435
455
|
// Responsive Demo
|
|
436
456
|
export const ResponsiveDemo: Story = {
|
|
437
457
|
render: args => (
|
|
438
|
-
<div style={{ maxWidth: '300px' }}>
|
|
439
|
-
<p style={{ marginBottom: '1rem', fontSize: '0.875rem', color: '#666' }}>
|
|
458
|
+
<div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
459
|
+
<p style={{ marginBottom: '1rem', fontSize: '0.875rem', color: 'var(--atomix-secondary-text-emphasis, #666)' }}>
|
|
440
460
|
Resize your browser window to see the responsive behavior. On mobile (less than 768px), the
|
|
441
461
|
menu becomes collapsible.
|
|
442
462
|
</p>
|
|
@@ -521,6 +541,273 @@ export const EcommerceNavigation: Story = {
|
|
|
521
541
|
},
|
|
522
542
|
};
|
|
523
543
|
|
|
544
|
+
// Desktop Collapsible SideMenu (Vertical Collapse)
|
|
545
|
+
export const DesktopCollapsible: Story = {
|
|
546
|
+
render: args => {
|
|
547
|
+
const [isOpen, setIsOpen] = React.useState(true);
|
|
548
|
+
|
|
549
|
+
return (
|
|
550
|
+
<div style={{ maxWidth: '300px', padding: '2rem', margin: '0 auto' }}>
|
|
551
|
+
<p style={{ marginBottom: '1rem', fontSize: '0.875rem', color: 'var(--atomix-secondary-text-emphasis, #666)' }}>
|
|
552
|
+
Desktop vertical collapse - click the toggle button to expand/collapse the menu vertically.
|
|
553
|
+
Each section can also be toggled independently.
|
|
554
|
+
</p>
|
|
555
|
+
<SideMenu
|
|
556
|
+
{...args}
|
|
557
|
+
title="Navigation"
|
|
558
|
+
collapsibleDesktop
|
|
559
|
+
defaultCollapsedDesktop={false}
|
|
560
|
+
isOpen={isOpen}
|
|
561
|
+
onToggle={setIsOpen}
|
|
562
|
+
menuItems={[
|
|
563
|
+
{
|
|
564
|
+
title: 'Navigation',
|
|
565
|
+
items: [
|
|
566
|
+
{ title: 'Home', href: '/', icon: <Icon name="House" size="sm" />, active: true },
|
|
567
|
+
{ title: 'Dashboard', href: '/dashboard', icon: <Icon name="ChartBar" size="sm" /> },
|
|
568
|
+
{ title: 'Analytics', href: '/analytics', icon: <Icon name="TrendUp" size="sm" /> },
|
|
569
|
+
{ title: 'Users', href: '/users', icon: <Icon name="Users" size="sm" /> },
|
|
570
|
+
{ title: 'Settings', href: '/settings', icon: <Icon name="Gear" size="sm" /> },
|
|
571
|
+
],
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
title: 'Products',
|
|
575
|
+
items: [
|
|
576
|
+
{ title: 'All Products', href: '/products', icon: <Icon name="Package" size="sm" /> },
|
|
577
|
+
{ title: 'Categories', href: '/products/categories', icon: <Icon name="Tag" size="sm" /> },
|
|
578
|
+
{ title: 'Inventory', href: '/products/inventory', icon: <Icon name="Warehouse" size="sm" /> },
|
|
579
|
+
],
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
title: 'Services',
|
|
583
|
+
items: [
|
|
584
|
+
{ title: 'Service List', href: '/services', icon: <Icon name="Gear" size="sm" /> },
|
|
585
|
+
{ title: 'Service Requests', href: '/services/requests', icon: <Icon name="Clipboard" size="sm" /> },
|
|
586
|
+
],
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
title: 'About Us',
|
|
590
|
+
items: [
|
|
591
|
+
{ title: 'About Us', href: '/about-us', icon: <Icon name="Info" size="sm" /> },
|
|
592
|
+
{ title: 'Contact', href: '/contact', icon: <Icon name="Envelope" size="sm" /> },
|
|
593
|
+
],
|
|
594
|
+
},
|
|
595
|
+
]}
|
|
596
|
+
/>
|
|
597
|
+
<div style={{ marginTop: '1rem', padding: '0.75rem', backgroundColor: 'var(--atomix-secondary-bg-subtle, rgba(0,0,0,0.05))', borderRadius: '6px', fontSize: '0.875rem' }}>
|
|
598
|
+
<strong>Current state:</strong> {isOpen ? 'Expanded' : 'Collapsed'}
|
|
599
|
+
</div>
|
|
600
|
+
</div>
|
|
601
|
+
);
|
|
602
|
+
},
|
|
603
|
+
args: {
|
|
604
|
+
onToggle: fn(),
|
|
605
|
+
},
|
|
606
|
+
parameters: {
|
|
607
|
+
layout: 'centered',
|
|
608
|
+
docs: {
|
|
609
|
+
description: {
|
|
610
|
+
story:
|
|
611
|
+
'Desktop collapsible sidebar with vertical collapse. The menu collapses vertically (height-based) on desktop, similar to mobile behavior. Each nested section can be toggled independently. Use EdgePanel for horizontal slide-in panels.',
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
// Nested Menu Items with Toggle
|
|
618
|
+
export const NestedMenuItems: Story = {
|
|
619
|
+
args: {
|
|
620
|
+
menuItems: [
|
|
621
|
+
{
|
|
622
|
+
title: 'Dashboard',
|
|
623
|
+
items: [
|
|
624
|
+
{ title: 'Overview', href: '/dashboard', icon: <Icon name="ChartBar" size="sm" />, active: true },
|
|
625
|
+
{ title: 'Analytics', href: '/dashboard/analytics', icon: <Icon name="TrendUp" size="sm" /> },
|
|
626
|
+
{ title: 'Reports', href: '/dashboard/reports', icon: <Icon name="FileText" size="sm" /> },
|
|
627
|
+
],
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
title: 'User Management',
|
|
631
|
+
items: [
|
|
632
|
+
{ title: 'Users', href: '/users', icon: <Icon name="Users" size="sm" /> },
|
|
633
|
+
{ title: 'Roles', href: '/users/roles', icon: <Icon name="Shield" size="sm" /> },
|
|
634
|
+
{ title: 'Permissions', href: '/users/permissions', icon: <Icon name="Lock" size="sm" /> },
|
|
635
|
+
],
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
title: 'Content',
|
|
639
|
+
items: [
|
|
640
|
+
{ title: 'Pages', href: '/content/pages', icon: <Icon name="Article" size="sm" /> },
|
|
641
|
+
{ title: 'Media', href: '/content/media', icon: <Icon name="Image" size="sm" /> },
|
|
642
|
+
{ title: 'Blog', href: '/content/blog', icon: <Icon name="Pencil" size="sm" /> },
|
|
643
|
+
],
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
title: 'Settings',
|
|
647
|
+
items: [
|
|
648
|
+
{ title: 'General', href: '/settings/general', icon: <Icon name="Gear" size="sm" /> },
|
|
649
|
+
{ title: 'Notifications', href: '/settings/notifications', icon: <Icon name="Bell" size="sm" /> },
|
|
650
|
+
{ title: 'Security', href: '/settings/security', icon: <Icon name="Lock" size="sm" />, disabled: true },
|
|
651
|
+
],
|
|
652
|
+
},
|
|
653
|
+
],
|
|
654
|
+
collapsible: true,
|
|
655
|
+
onToggle: fn(),
|
|
656
|
+
},
|
|
657
|
+
parameters: {
|
|
658
|
+
layout: 'centered',
|
|
659
|
+
docs: {
|
|
660
|
+
description: {
|
|
661
|
+
story:
|
|
662
|
+
'SideMenu with nested menu items. Each section can be collapsed/expanded independently by clicking on the section title. The toggle icon rotates when sections are open.',
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
},
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
// Nested Menu Items with Children
|
|
669
|
+
export const NestedMenuItemsWithChildren: Story = {
|
|
670
|
+
args: {
|
|
671
|
+
title: 'Navigation',
|
|
672
|
+
children: (
|
|
673
|
+
<SideMenuList>
|
|
674
|
+
<SideMenuItem href="/" icon={<Icon name="House" size="sm" />} active>
|
|
675
|
+
Home
|
|
676
|
+
</SideMenuItem>
|
|
677
|
+
<SideMenuItem href="/about" icon={<Icon name="Info" size="sm" />}>
|
|
678
|
+
About
|
|
679
|
+
</SideMenuItem>
|
|
680
|
+
</SideMenuList>
|
|
681
|
+
),
|
|
682
|
+
menuItems: [
|
|
683
|
+
{
|
|
684
|
+
title: 'Products',
|
|
685
|
+
items: [
|
|
686
|
+
{ title: 'All Products', href: '/products', icon: <Icon name="Package" size="sm" /> },
|
|
687
|
+
{ title: 'Categories', href: '/products/categories', icon: <Icon name="Tag" size="sm" /> },
|
|
688
|
+
{ title: 'Inventory', href: '/products/inventory', icon: <Icon name="Warehouse" size="sm" /> },
|
|
689
|
+
],
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
title: 'Services',
|
|
693
|
+
items: [
|
|
694
|
+
{ title: 'Service List', href: '/services', icon: <Icon name="Gear" size="sm" /> },
|
|
695
|
+
{ title: 'Service Requests', href: '/services/requests', icon: <Icon name="Clipboard" size="sm" /> },
|
|
696
|
+
],
|
|
697
|
+
},
|
|
698
|
+
],
|
|
699
|
+
collapsible: true,
|
|
700
|
+
onToggle: fn(),
|
|
701
|
+
},
|
|
702
|
+
parameters: {
|
|
703
|
+
layout: 'centered',
|
|
704
|
+
docs: {
|
|
705
|
+
description: {
|
|
706
|
+
story:
|
|
707
|
+
'SideMenu combining both children (static items) and menuItems (collapsible sections). The children appear first, followed by the collapsible menu item sections.',
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
},
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// Nested Menu Items with Custom Toggle Icons
|
|
714
|
+
export const NestedMenuItemsCustomIcons: Story = {
|
|
715
|
+
args: {
|
|
716
|
+
title: 'Settings',
|
|
717
|
+
menuItems: [
|
|
718
|
+
{
|
|
719
|
+
title: 'Account Settings',
|
|
720
|
+
toggleIcon: <Icon name="CaretDown" size="xs" />,
|
|
721
|
+
items: [
|
|
722
|
+
{ title: 'Profile', href: '/settings/profile', icon: <Icon name="User" size="sm" /> },
|
|
723
|
+
{ title: 'Security', href: '/settings/security', icon: <Icon name="Lock" size="sm" /> },
|
|
724
|
+
{ title: 'Privacy', href: '/settings/privacy', icon: <Icon name="Eye" size="sm" /> },
|
|
725
|
+
],
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
title: 'Preferences',
|
|
729
|
+
toggleIcon: <Icon name="CaretDown" size="xs" />,
|
|
730
|
+
items: [
|
|
731
|
+
{ title: 'Notifications', href: '/settings/notifications', icon: <Icon name="Bell" size="sm" /> },
|
|
732
|
+
{ title: 'Appearance', href: '/settings/appearance', icon: <Icon name="PaintBrush" size="sm" /> },
|
|
733
|
+
{ title: 'Language', href: '/settings/language', icon: <Icon name="Globe" size="sm" /> },
|
|
734
|
+
],
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
title: 'Billing',
|
|
738
|
+
toggleIcon: <Icon name="CaretDown" size="xs" />,
|
|
739
|
+
items: [
|
|
740
|
+
{ title: 'Subscription', href: '/settings/billing', icon: <Icon name="CreditCard" size="sm" /> },
|
|
741
|
+
{ title: 'Invoices', href: '/settings/invoices', icon: <Icon name="Receipt" size="sm" /> },
|
|
742
|
+
],
|
|
743
|
+
},
|
|
744
|
+
],
|
|
745
|
+
collapsible: true,
|
|
746
|
+
onToggle: fn(),
|
|
747
|
+
},
|
|
748
|
+
parameters: {
|
|
749
|
+
layout: 'centered',
|
|
750
|
+
docs: {
|
|
751
|
+
description: {
|
|
752
|
+
story:
|
|
753
|
+
'Nested menu items with custom toggle icons. Each section can have its own toggle icon, which rotates when the section is expanded.',
|
|
754
|
+
},
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
// Desktop Collapsible - Starting Collapsed
|
|
760
|
+
export const DesktopCollapsibleStartCollapsed: Story = {
|
|
761
|
+
render: args => {
|
|
762
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
763
|
+
|
|
764
|
+
return (
|
|
765
|
+
<div style={{ maxWidth: '300px', padding: '2rem', margin: '0 auto' }}>
|
|
766
|
+
<p style={{ marginBottom: '1rem', fontSize: '0.875rem', color: 'var(--atomix-secondary-text-emphasis, #666)' }}>
|
|
767
|
+
Sidebar starts collapsed on desktop.
|
|
768
|
+
</p>
|
|
769
|
+
<SideMenu
|
|
770
|
+
{...args}
|
|
771
|
+
title="Navigation"
|
|
772
|
+
collapsibleDesktop
|
|
773
|
+
defaultCollapsedDesktop={true}
|
|
774
|
+
isOpen={isOpen}
|
|
775
|
+
onToggle={setIsOpen}
|
|
776
|
+
>
|
|
777
|
+
<SideMenuList>
|
|
778
|
+
<SideMenuItem href="/" icon={<Icon name="House" size="sm" />} active>
|
|
779
|
+
Home
|
|
780
|
+
</SideMenuItem>
|
|
781
|
+
<SideMenuItem href="/dashboard" icon={<Icon name="ChartBar" size="sm" />}>
|
|
782
|
+
Dashboard
|
|
783
|
+
</SideMenuItem>
|
|
784
|
+
<SideMenuItem href="/analytics" icon={<Icon name="TrendUp" size="sm" />}>
|
|
785
|
+
Analytics
|
|
786
|
+
</SideMenuItem>
|
|
787
|
+
<SideMenuItem href="/users" icon={<Icon name="Users" size="sm" />}>
|
|
788
|
+
Users
|
|
789
|
+
</SideMenuItem>
|
|
790
|
+
<SideMenuItem href="/settings" icon={<Icon name="Gear" size="sm" />}>
|
|
791
|
+
Settings
|
|
792
|
+
</SideMenuItem>
|
|
793
|
+
</SideMenuList>
|
|
794
|
+
</SideMenu>
|
|
795
|
+
</div>
|
|
796
|
+
);
|
|
797
|
+
},
|
|
798
|
+
args: {
|
|
799
|
+
onToggle: fn(),
|
|
800
|
+
},
|
|
801
|
+
parameters: {
|
|
802
|
+
layout: 'centered',
|
|
803
|
+
docs: {
|
|
804
|
+
description: {
|
|
805
|
+
story: 'Desktop collapsible sidebar that starts in a collapsed state.',
|
|
806
|
+
},
|
|
807
|
+
},
|
|
808
|
+
},
|
|
809
|
+
};
|
|
810
|
+
|
|
524
811
|
// Interactive Demo with Actions
|
|
525
812
|
export const InteractiveDemo: Story = {
|
|
526
813
|
render: args => {
|
|
@@ -539,13 +826,14 @@ export const InteractiveDemo: Story = {
|
|
|
539
826
|
};
|
|
540
827
|
|
|
541
828
|
return (
|
|
542
|
-
<div>
|
|
829
|
+
<div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
543
830
|
<div
|
|
544
831
|
style={{
|
|
545
832
|
marginBottom: '1rem',
|
|
546
|
-
padding: '0.
|
|
547
|
-
backgroundColor: '
|
|
548
|
-
borderRadius: '
|
|
833
|
+
padding: '0.75rem',
|
|
834
|
+
backgroundColor: 'var(--atomix-secondary-bg-subtle, rgba(0,0,0,0.05))',
|
|
835
|
+
borderRadius: '6px',
|
|
836
|
+
fontSize: '0.875rem',
|
|
549
837
|
}}
|
|
550
838
|
>
|
|
551
839
|
<strong>Current Page:</strong> {activeItem} | <strong>Menu:</strong>{' '}
|
|
@@ -697,7 +985,7 @@ export const Glass: Story = {
|
|
|
697
985
|
</SideMenuList>
|
|
698
986
|
</SideMenu>
|
|
699
987
|
</div>
|
|
700
|
-
<div style={{ position: 'relative',
|
|
988
|
+
<div style={{ position: 'relative', flex: 1, maxWidth: '600px' }}>
|
|
701
989
|
<h2
|
|
702
990
|
style={{
|
|
703
991
|
color: 'white',
|
|
@@ -746,7 +1034,7 @@ export const GlassCustom: Story = {
|
|
|
746
1034
|
backgroundImage="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?q=80&w=2940&auto=format&fit=crop"
|
|
747
1035
|
overlay
|
|
748
1036
|
>
|
|
749
|
-
<div style={{ position: 'relative', width: '320px'
|
|
1037
|
+
<div style={{ position: 'relative', width: '320px',}}>
|
|
750
1038
|
<SideMenu
|
|
751
1039
|
title="Nature Explorer"
|
|
752
1040
|
glass={{
|
|
@@ -831,7 +1119,7 @@ export const GlassThemeShowcase: Story = {
|
|
|
831
1119
|
backgroundImage="https://images.unsplash.com/photo-1505142468610-359e7d316be0?q=80&w=2940&auto=format&fit=crop"
|
|
832
1120
|
height="70vh"
|
|
833
1121
|
>
|
|
834
|
-
<div style={{ position: 'relative', width: '300px'
|
|
1122
|
+
<div style={{ position: 'relative', width: '300px',}}>
|
|
835
1123
|
<SideMenu title="Ocean Explorer" glass>
|
|
836
1124
|
<SideMenuList>
|
|
837
1125
|
<SideMenuItem href="/" icon={<Icon name="House" size="sm" />} active>
|
|
@@ -865,8 +1153,8 @@ export const GlassThemeShowcase: Story = {
|
|
|
865
1153
|
backgroundImage="https://images.unsplash.com/photo-1514565131-fce0801e5785?q=80&w=2940&auto=format&fit=crop"
|
|
866
1154
|
height="70vh"
|
|
867
1155
|
>
|
|
868
|
-
<div style={{ position: 'relative', width: '300px'
|
|
869
|
-
<SideMenu
|
|
1156
|
+
<div style={{ position: 'relative', width: '300px',}}>
|
|
1157
|
+
<SideMenu glass>
|
|
870
1158
|
<SideMenuList>
|
|
871
1159
|
<SideMenuItem href="/dashboard" icon={<Icon name="ChartBar" size="sm" />} active>
|
|
872
1160
|
Dashboard
|
|
@@ -899,7 +1187,7 @@ export const GlassThemeShowcase: Story = {
|
|
|
899
1187
|
backgroundImage="https://images.unsplash.com/photo-1495616811223-4d98c6e9c869?q=80&w=2940&auto=format&fit=crop"
|
|
900
1188
|
height="70vh"
|
|
901
1189
|
>
|
|
902
|
-
<div style={{ position: 'relative', width: '320px'
|
|
1190
|
+
<div style={{ position: 'relative', width: '320px',}}>
|
|
903
1191
|
<SideMenu
|
|
904
1192
|
title="Travel Hub"
|
|
905
1193
|
glass={{
|