@shohojdhara/atomix 0.5.0 → 0.5.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.
- package/dist/atomix.css +95 -69
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +1 -0
- package/dist/charts.js +231 -332
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +1 -0
- package/dist/core.js +232 -333
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +1 -0
- package/dist/forms.js +231 -332
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +11 -2
- package/dist/heavy.js +233 -334
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.esm.js +228 -327
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +227 -326
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +11 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +62 -90
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
- package/src/components/AtomixGlass/glass-utils.ts +50 -0
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +52 -46
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +88 -41
- package/src/components/AtomixGlass/stories/argTypes.ts +19 -19
- package/src/components/AtomixGlass/stories/shared-components.tsx +7 -12
- package/src/components/AtomixGlass/stories/types.ts +3 -3
- package/src/lib/composables/useAtomixGlass.ts +108 -71
- package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
- package/src/lib/constants/components.ts +1 -0
- package/src/lib/types/components.ts +1 -0
- package/src/lib/utils/displacement-generator.ts +1 -1
- package/src/styles/06-components/_components.atomix-glass.scss +158 -97
- package/scripts/cli/__tests__/README.md +0 -81
- package/scripts/cli/__tests__/basic.test.js +0 -116
- package/scripts/cli/__tests__/clean.test.js +0 -278
- package/scripts/cli/__tests__/component-generator.test.js +0 -332
- package/scripts/cli/__tests__/component-validator.test.js +0 -433
- package/scripts/cli/__tests__/generator.test.js +0 -613
- package/scripts/cli/__tests__/glass-motion.test.js +0 -256
- package/scripts/cli/__tests__/integration.test.js +0 -938
- package/scripts/cli/__tests__/migrate.test.js +0 -74
- package/scripts/cli/__tests__/security.test.js +0 -206
- package/scripts/cli/__tests__/test-setup.js +0 -135
- package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
- package/scripts/cli/__tests__/token-manager.test.js +0 -251
- package/scripts/cli/__tests__/token-provider.test.js +0 -361
- package/scripts/cli/__tests__/utils.test.js +0 -165
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +0 -216
- package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +0 -95
- package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +0 -212
- package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
- package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +0 -348
- package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +0 -410
- package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +0 -436
- package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +0 -264
- package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +0 -247
- package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +0 -418
- package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +0 -402
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
- package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
- package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +0 -335
- package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
- package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +0 -441
- package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
- package/src/components/TypedButton/TypedButton.tsx +0 -39
- package/src/components/TypedButton/index.ts +0 -2
- package/src/lib/composables/useTypedButton.ts +0 -66
|
@@ -1,441 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WidgetExamples.stories.tsx
|
|
3
|
-
*
|
|
4
|
-
* Interactive widget examples for AtomixGlass including music players,
|
|
5
|
-
* chat interfaces, notifications, and utility widgets.
|
|
6
|
-
*
|
|
7
|
-
* @package Atomix
|
|
8
|
-
* @component AtomixGlass
|
|
9
|
-
*/
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import { useState } from 'react';
|
|
12
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
13
|
-
import AtomixGlass from '../AtomixGlass';
|
|
14
|
-
import { BackgroundWrapper, backgroundImages, StoryErrorBoundary } from './shared-components';
|
|
15
|
-
import { baseArgTypes } from './argTypes';
|
|
16
|
-
|
|
17
|
-
import { Button } from '../../Button';
|
|
18
|
-
import { Badge } from '../../Badge';
|
|
19
|
-
import { Input } from '../../../Form/Input';
|
|
20
|
-
|
|
21
|
-
const meta: Meta<typeof AtomixGlass> = {
|
|
22
|
-
title: 'Components/AtomixGlass/Examples/Widget Examples',
|
|
23
|
-
component: AtomixGlass,
|
|
24
|
-
parameters: {
|
|
25
|
-
layout: 'centered',
|
|
26
|
-
docs: {
|
|
27
|
-
description: {
|
|
28
|
-
component:
|
|
29
|
-
'Interactive widget examples demonstrating AtomixGlass for media players, chat interfaces, and utility components.',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
tags: ['!autodocs'],
|
|
34
|
-
argTypes: {
|
|
35
|
-
...baseArgTypes,
|
|
36
|
-
children: { control: false },
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export default meta;
|
|
41
|
-
type Story = StoryObj<typeof AtomixGlass>;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Music Player Widget
|
|
45
|
-
*
|
|
46
|
-
* Premium music player interface with playback controls, progress tracking, and volume control.
|
|
47
|
-
*/
|
|
48
|
-
export const MusicPlayer: Story = {
|
|
49
|
-
render: () => {
|
|
50
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
51
|
-
const [currentTime, setCurrentTime] = useState(125);
|
|
52
|
-
const [volume, setVolume] = useState(70);
|
|
53
|
-
|
|
54
|
-
const totalDuration = 248;
|
|
55
|
-
|
|
56
|
-
const formatTime = (seconds: number) => {
|
|
57
|
-
const mins = Math.floor(seconds / 60);
|
|
58
|
-
const secs = seconds % 60;
|
|
59
|
-
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<StoryErrorBoundary>
|
|
64
|
-
<BackgroundWrapper backgroundImage={backgroundImages[3]} overlay overlayOpacity={0.3}>
|
|
65
|
-
<div style={{ maxWidth: '380px' }} className="u-mx-auto">
|
|
66
|
-
<AtomixGlass
|
|
67
|
-
displacementScale={55}
|
|
68
|
-
blurAmount={3}
|
|
69
|
-
borderRadius={28}
|
|
70
|
-
mode="standard"
|
|
71
|
-
padding="24px"
|
|
72
|
-
>
|
|
73
|
-
<div className="u-text-white">
|
|
74
|
-
{/* Album Art */}
|
|
75
|
-
<div
|
|
76
|
-
style={{
|
|
77
|
-
aspectRatio: '1:1',
|
|
78
|
-
borderRadius: '20px',
|
|
79
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
80
|
-
marginBottom: '24px',
|
|
81
|
-
display: 'flex',
|
|
82
|
-
alignItems: 'center',
|
|
83
|
-
justifyContent: 'center',
|
|
84
|
-
fontSize: '80px',
|
|
85
|
-
boxShadow: '0 20px 40px rgba(102, 126, 234, 0.4)',
|
|
86
|
-
}}
|
|
87
|
-
aria-label="Album art"
|
|
88
|
-
>
|
|
89
|
-
🎵
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
{/* Track Info */}
|
|
93
|
-
<div className="u-text-center u-mb-4">
|
|
94
|
-
<h2 className="u-m-0 u-mb-2 u-text-2xl u-font-bold">Summer Vibes</h2>
|
|
95
|
-
<p className="u-m-0 u-opacity-80 u-text-sm">The Atomix Band</p>
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
{/* Progress Bar */}
|
|
99
|
-
<div className="u-mb-4">
|
|
100
|
-
<div
|
|
101
|
-
style={{
|
|
102
|
-
height: '6px',
|
|
103
|
-
background: 'rgba(255,255,255,0.1)',
|
|
104
|
-
borderRadius: '3px',
|
|
105
|
-
overflow: 'hidden',
|
|
106
|
-
cursor: 'pointer',
|
|
107
|
-
}}
|
|
108
|
-
onClick={(e) => {
|
|
109
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
110
|
-
const x = e.clientX - rect.left;
|
|
111
|
-
const percentage = x / rect.width;
|
|
112
|
-
setCurrentTime(Math.floor(totalDuration * percentage));
|
|
113
|
-
}}
|
|
114
|
-
role="slider"
|
|
115
|
-
aria-valuenow={currentTime}
|
|
116
|
-
aria-valuemin={0}
|
|
117
|
-
aria-valuemax={totalDuration}
|
|
118
|
-
tabIndex={0}
|
|
119
|
-
>
|
|
120
|
-
<div
|
|
121
|
-
style={{
|
|
122
|
-
height: '100%',
|
|
123
|
-
width: `${(currentTime / totalDuration) * 100}%`,
|
|
124
|
-
background: 'linear-gradient(90deg, #667eea 0%, #764ba2 100%)',
|
|
125
|
-
}}
|
|
126
|
-
/>
|
|
127
|
-
</div>
|
|
128
|
-
<div
|
|
129
|
-
style={{
|
|
130
|
-
display: 'flex',
|
|
131
|
-
justifyContent: 'space-between',
|
|
132
|
-
marginTop: '8px',
|
|
133
|
-
fontSize: '13px',
|
|
134
|
-
opacity: 0.7,
|
|
135
|
-
}}
|
|
136
|
-
>
|
|
137
|
-
<span>{formatTime(currentTime)}</span>
|
|
138
|
-
<span>{formatTime(totalDuration)}</span>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
{/* Playback Controls */}
|
|
143
|
-
<div
|
|
144
|
-
style={{
|
|
145
|
-
display: 'flex',
|
|
146
|
-
alignItems: 'center',
|
|
147
|
-
justifyContent: 'center',
|
|
148
|
-
gap: '16px',
|
|
149
|
-
marginBottom: '20px',
|
|
150
|
-
}}
|
|
151
|
-
>
|
|
152
|
-
<button
|
|
153
|
-
onClick={() => setIsPlaying(!isPlaying)}
|
|
154
|
-
style={{
|
|
155
|
-
width: '64px',
|
|
156
|
-
height: '64px',
|
|
157
|
-
borderRadius: '50%',
|
|
158
|
-
border: 'none',
|
|
159
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
160
|
-
color: 'white',
|
|
161
|
-
cursor: 'pointer',
|
|
162
|
-
fontSize: '28px',
|
|
163
|
-
display: 'flex',
|
|
164
|
-
alignItems: 'center',
|
|
165
|
-
justifyContent: 'center',
|
|
166
|
-
boxShadow: '0 8px 20px rgba(102, 126, 234, 0.4)',
|
|
167
|
-
}}
|
|
168
|
-
aria-label={isPlaying ? 'Pause' : 'Play'}
|
|
169
|
-
>
|
|
170
|
-
{isPlaying ? '⏸️' : '▶️'}
|
|
171
|
-
</button>
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
{/* Volume Control */}
|
|
175
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
|
176
|
-
<span style={{ fontSize: '18px', opacity: 0.7 }} aria-hidden="true">
|
|
177
|
-
🔊
|
|
178
|
-
</span>
|
|
179
|
-
<input
|
|
180
|
-
type="range"
|
|
181
|
-
min="0"
|
|
182
|
-
max="100"
|
|
183
|
-
value={volume}
|
|
184
|
-
onChange={(e) => setVolume(Number(e.target.value))}
|
|
185
|
-
style={{
|
|
186
|
-
flex: 1,
|
|
187
|
-
accentColor: '#667eea',
|
|
188
|
-
cursor: 'pointer',
|
|
189
|
-
}}
|
|
190
|
-
aria-label="Volume"
|
|
191
|
-
/>
|
|
192
|
-
<span style={{ fontSize: '14px', opacity: 0.7, minWidth: '35px' }}>
|
|
193
|
-
{volume}%
|
|
194
|
-
</span>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
</AtomixGlass>
|
|
198
|
-
</div>
|
|
199
|
-
</BackgroundWrapper>
|
|
200
|
-
</StoryErrorBoundary>
|
|
201
|
-
);
|
|
202
|
-
},
|
|
203
|
-
parameters: {
|
|
204
|
-
docs: {
|
|
205
|
-
description: {
|
|
206
|
-
story:
|
|
207
|
-
'Music player widget with play/pause controls, progress bar, and volume slider in a premium glass interface.',
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Chat Interface Widget
|
|
215
|
-
*
|
|
216
|
-
* Real-time chat interface with message history and input field.
|
|
217
|
-
*/
|
|
218
|
-
export const ChatInterface: Story = {
|
|
219
|
-
render: () => {
|
|
220
|
-
const [message, setMessage] = useState('');
|
|
221
|
-
const [messages, setMessages] = useState([
|
|
222
|
-
{ id: 1, text: 'Hey! How are you?', sender: 'them', time: '10:30 AM' },
|
|
223
|
-
{ id: 2, text: "I'm doing great! Working on something cool.", sender: 'me', time: '10:32 AM' },
|
|
224
|
-
{ id: 3, text: 'Oh really? What is it?', sender: 'them', time: '10:33 AM' },
|
|
225
|
-
]);
|
|
226
|
-
|
|
227
|
-
const handleSend = () => {
|
|
228
|
-
if (!message.trim()) return;
|
|
229
|
-
setMessages([
|
|
230
|
-
...messages,
|
|
231
|
-
{ id: messages.length + 1, text: message, sender: 'me', time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) },
|
|
232
|
-
]);
|
|
233
|
-
setMessage('');
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
return (
|
|
237
|
-
<StoryErrorBoundary>
|
|
238
|
-
<BackgroundWrapper backgroundImage={backgroundImages[5]} overlay overlayOpacity={0.4}>
|
|
239
|
-
<div style={{ maxWidth: '400px', height: '500px' }}>
|
|
240
|
-
<AtomixGlass
|
|
241
|
-
displacementScale={60}
|
|
242
|
-
blurAmount={0.75}
|
|
243
|
-
saturation={140}
|
|
244
|
-
borderRadius={24}
|
|
245
|
-
mode="standard"
|
|
246
|
-
>
|
|
247
|
-
<div className="u-text-white" style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
|
|
248
|
-
{/* Header */}
|
|
249
|
-
<div
|
|
250
|
-
style={{
|
|
251
|
-
padding: '20px',
|
|
252
|
-
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
|
253
|
-
display: 'flex',
|
|
254
|
-
alignItems: 'center',
|
|
255
|
-
gap: '12px',
|
|
256
|
-
}}
|
|
257
|
-
>
|
|
258
|
-
<div
|
|
259
|
-
style={{
|
|
260
|
-
width: '40px',
|
|
261
|
-
height: '40px',
|
|
262
|
-
borderRadius: '50%',
|
|
263
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
264
|
-
display: 'flex',
|
|
265
|
-
alignItems: 'center',
|
|
266
|
-
justifyContent: 'center',
|
|
267
|
-
fontSize: '20px',
|
|
268
|
-
}}
|
|
269
|
-
aria-hidden="true"
|
|
270
|
-
>
|
|
271
|
-
💬
|
|
272
|
-
</div>
|
|
273
|
-
<div>
|
|
274
|
-
<h3 className="u-m-0 u-font-semibold">Chat</h3>
|
|
275
|
-
<p className="u-m-0 u-text-xs u-opacity-70">3 messages</p>
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
|
|
279
|
-
{/* Messages */}
|
|
280
|
-
<div style={{ flex: 1, padding: '20px', overflowY: 'auto' }}>
|
|
281
|
-
{messages.map((msg) => (
|
|
282
|
-
<div
|
|
283
|
-
key={msg.id}
|
|
284
|
-
style={{
|
|
285
|
-
marginBottom: '16px',
|
|
286
|
-
display: 'flex',
|
|
287
|
-
justifyContent: msg.sender === 'me' ? 'flex-end' : 'flex-start',
|
|
288
|
-
}}
|
|
289
|
-
>
|
|
290
|
-
<div
|
|
291
|
-
style={{
|
|
292
|
-
maxWidth: '75%',
|
|
293
|
-
padding: '12px 16px',
|
|
294
|
-
borderRadius: '16px',
|
|
295
|
-
background: msg.sender === 'me'
|
|
296
|
-
? 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
|
|
297
|
-
: 'rgba(255,255,255,0.1)',
|
|
298
|
-
boxShadow: msg.sender === 'me' ? '0 4px 12px rgba(102, 126, 234, 0.3)' : 'none',
|
|
299
|
-
}}
|
|
300
|
-
>
|
|
301
|
-
<p className="u-m-0 u-text-sm" style={{ lineHeight: 1.5 }}>{msg.text}</p>
|
|
302
|
-
<p className="u-m-0 u-text-xs u-opacity-60 u-mt-1" style={{ textAlign: 'right' }}>
|
|
303
|
-
{msg.time}
|
|
304
|
-
</p>
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
307
|
-
))}
|
|
308
|
-
</div>
|
|
309
|
-
|
|
310
|
-
{/* Input */}
|
|
311
|
-
<div
|
|
312
|
-
style={{
|
|
313
|
-
padding: '16px',
|
|
314
|
-
borderTop: '1px solid rgba(255,255,255,0.1)',
|
|
315
|
-
display: 'flex',
|
|
316
|
-
gap: '12px',
|
|
317
|
-
}}
|
|
318
|
-
>
|
|
319
|
-
<Input
|
|
320
|
-
type="text"
|
|
321
|
-
value={message}
|
|
322
|
-
onChange={(e) => setMessage(e.target.value)}
|
|
323
|
-
placeholder="Type a message..."
|
|
324
|
-
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
|
|
325
|
-
glass={{ elasticity: 0 }}
|
|
326
|
-
className="u-flex-1"
|
|
327
|
-
/>
|
|
328
|
-
<Button
|
|
329
|
-
variant="primary"
|
|
330
|
-
glass={{ elasticity: 0 }}
|
|
331
|
-
onClick={handleSend}
|
|
332
|
-
disabled={!message.trim()}
|
|
333
|
-
>
|
|
334
|
-
Send
|
|
335
|
-
</Button>
|
|
336
|
-
</div>
|
|
337
|
-
</div>
|
|
338
|
-
</AtomixGlass>
|
|
339
|
-
</div>
|
|
340
|
-
</BackgroundWrapper>
|
|
341
|
-
</StoryErrorBoundary>
|
|
342
|
-
);
|
|
343
|
-
},
|
|
344
|
-
parameters: {
|
|
345
|
-
docs: {
|
|
346
|
-
description: {
|
|
347
|
-
story:
|
|
348
|
-
'Real-time chat interface with message history, timestamps, and live input for modern messaging applications.',
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Notification Center Widget
|
|
356
|
-
*
|
|
357
|
-
* Centralized notification panel with multiple notification types.
|
|
358
|
-
*/
|
|
359
|
-
export const NotificationCenter: Story = {
|
|
360
|
-
render: () => {
|
|
361
|
-
const [notifications, setNotifications] = useState([
|
|
362
|
-
{ id: 1, type: 'success', title: 'Payment Received', message: '$250.00 from John Doe', time: '2m ago' },
|
|
363
|
-
{ id: 2, type: 'warning', title: 'Storage Almost Full', message: '85% of your storage is used', time: '1h ago' },
|
|
364
|
-
{ id: 3, type: 'info', title: 'New Feature Available', message: 'Check out the latest updates', time: '3h ago' },
|
|
365
|
-
]);
|
|
366
|
-
|
|
367
|
-
const getTypeIcon = (type: string) => {
|
|
368
|
-
switch (type) {
|
|
369
|
-
case 'success': return '✅';
|
|
370
|
-
case 'warning': return '⚠️';
|
|
371
|
-
case 'info': return 'ℹ️';
|
|
372
|
-
default: return '📢';
|
|
373
|
-
}
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
return (
|
|
377
|
-
<StoryErrorBoundary>
|
|
378
|
-
<BackgroundWrapper backgroundImage={backgroundImages[0]} overlay overlayOpacity={0.4}>
|
|
379
|
-
<div style={{ maxWidth: '420px' }}>
|
|
380
|
-
<AtomixGlass
|
|
381
|
-
displacementScale={65}
|
|
382
|
-
blurAmount={0.75}
|
|
383
|
-
saturation={140}
|
|
384
|
-
borderRadius={24}
|
|
385
|
-
mode="standard"
|
|
386
|
-
>
|
|
387
|
-
<div className="u-text-white" style={{ padding: '24px' }}>
|
|
388
|
-
<div className="u-flex u-items-center u-justify-between u-mb-4">
|
|
389
|
-
<h2 className="u-m-0 u-text-xl u-font-bold">Notifications</h2>
|
|
390
|
-
<Badge variant="primary">{notifications.length}</Badge>
|
|
391
|
-
</div>
|
|
392
|
-
|
|
393
|
-
<div className="u-divide-y" style={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
|
394
|
-
{notifications.map((notification) => (
|
|
395
|
-
<div
|
|
396
|
-
key={notification.id}
|
|
397
|
-
className="u-py-3 u-flex u-gap-3"
|
|
398
|
-
style={{ cursor: 'pointer' }}
|
|
399
|
-
>
|
|
400
|
-
<div
|
|
401
|
-
style={{
|
|
402
|
-
fontSize: '24px',
|
|
403
|
-
flexShrink: 0,
|
|
404
|
-
}}
|
|
405
|
-
aria-hidden="true"
|
|
406
|
-
>
|
|
407
|
-
{getTypeIcon(notification.type)}
|
|
408
|
-
</div>
|
|
409
|
-
<div className="u-flex-1">
|
|
410
|
-
<p className="u-m-0 u-font-semibold u-text-sm">{notification.title}</p>
|
|
411
|
-
<p className="u-m-0 u-text-xs u-opacity-80 u-mt-1">{notification.message}</p>
|
|
412
|
-
</div>
|
|
413
|
-
<span className="u-text-xs u-opacity-60">{notification.time}</span>
|
|
414
|
-
</div>
|
|
415
|
-
))}
|
|
416
|
-
</div>
|
|
417
|
-
|
|
418
|
-
<Button
|
|
419
|
-
variant="outline-light"
|
|
420
|
-
glass={{ elasticity: 0 }}
|
|
421
|
-
size="sm"
|
|
422
|
-
className="u-block u-w-full u-mt-4"
|
|
423
|
-
>
|
|
424
|
-
Mark All as Read
|
|
425
|
-
</Button>
|
|
426
|
-
</div>
|
|
427
|
-
</AtomixGlass>
|
|
428
|
-
</div>
|
|
429
|
-
</BackgroundWrapper>
|
|
430
|
-
</StoryErrorBoundary>
|
|
431
|
-
);
|
|
432
|
-
},
|
|
433
|
-
parameters: {
|
|
434
|
-
docs: {
|
|
435
|
-
description: {
|
|
436
|
-
story:
|
|
437
|
-
'Notification center panel displaying success, warning, and info notifications with timestamps.',
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
},
|
|
441
|
-
};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { TypedButton } from './TypedButton';
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof TypedButton> = {
|
|
5
|
-
title: 'Components/TypedButton',
|
|
6
|
-
component: TypedButton,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: 'centered',
|
|
9
|
-
},
|
|
10
|
-
tags: ['autodocs'],
|
|
11
|
-
argTypes: {
|
|
12
|
-
size: {
|
|
13
|
-
control: 'select',
|
|
14
|
-
options: ['sm', 'md', 'lg'],
|
|
15
|
-
},
|
|
16
|
-
variant: {
|
|
17
|
-
control: 'select',
|
|
18
|
-
options: ['primary', 'secondary', 'success', 'error'],
|
|
19
|
-
},
|
|
20
|
-
disabled: {
|
|
21
|
-
control: 'boolean',
|
|
22
|
-
},
|
|
23
|
-
glass: {
|
|
24
|
-
control: 'boolean',
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default meta;
|
|
30
|
-
type Story = StoryObj<typeof meta>;
|
|
31
|
-
|
|
32
|
-
export const Default: Story = {
|
|
33
|
-
args: {
|
|
34
|
-
children: 'TypedButton Component',
|
|
35
|
-
size: 'md',
|
|
36
|
-
variant: 'primary',
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const Small: Story = {
|
|
41
|
-
args: {
|
|
42
|
-
...Default.args,
|
|
43
|
-
size: 'sm',
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const Large: Story = {
|
|
48
|
-
args: {
|
|
49
|
-
...Default.args,
|
|
50
|
-
size: 'lg',
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const Glass: Story = {
|
|
55
|
-
args: {
|
|
56
|
-
...Default.args,
|
|
57
|
-
glass: true,
|
|
58
|
-
},
|
|
59
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef, useId, memo } from 'react';
|
|
2
|
-
import { TYPEDBUTTON } from '../../lib/constants/components';
|
|
3
|
-
import { useTypedButton } from '../../lib/composables/useTypedButton';
|
|
4
|
-
import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
5
|
-
import type { TypedButtonProps } from '../../lib/types/components';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* TypedButton - Medium Presentational Component
|
|
9
|
-
*
|
|
10
|
-
* @param {TypedButtonProps} props - Component properties
|
|
11
|
-
* @returns {JSX.Element} The rendered component
|
|
12
|
-
*/
|
|
13
|
-
export const TypedButton = memo(
|
|
14
|
-
forwardRef<HTMLDivElement, TypedButtonProps>(
|
|
15
|
-
({ children, className = '', disabled = false, glass, style, 'aria-label': ariaLabel, ...props }, ref) => {
|
|
16
|
-
const instanceId = useId();
|
|
17
|
-
const { generateClassNames } = useTypedButton({ disabled });
|
|
18
|
-
|
|
19
|
-
const content = (
|
|
20
|
-
<div
|
|
21
|
-
ref={ref}
|
|
22
|
-
className={generateClassNames(className)}
|
|
23
|
-
style={style}
|
|
24
|
-
aria-label={ariaLabel}
|
|
25
|
-
aria-disabled={disabled}
|
|
26
|
-
{...props}
|
|
27
|
-
>
|
|
28
|
-
{children}
|
|
29
|
-
</div>
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
return glass ? <AtomixGlass {...(glass === true ? {} : glass)}>{content}</AtomixGlass> : content;
|
|
33
|
-
}
|
|
34
|
-
)
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
TypedButton.displayName = 'TypedButton';
|
|
38
|
-
|
|
39
|
-
export default TypedButton;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { TypedButtonProps } from '../types/components';
|
|
2
|
-
import { TYPEDBUTTON } from '../constants/components';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* TypedButton state and functionality
|
|
6
|
-
* @param initialProps - Initial typedbutton properties
|
|
7
|
-
* @returns TypedButton state and methods
|
|
8
|
-
*/
|
|
9
|
-
export function useTypedButton(initialProps?: Partial<TypedButtonProps>) {
|
|
10
|
-
// Default typedbutton properties
|
|
11
|
-
const defaultProps: Partial<TypedButtonProps> = {
|
|
12
|
-
variant: 'primary',
|
|
13
|
-
size: 'md',
|
|
14
|
-
disabled: false,
|
|
15
|
-
...initialProps,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Generate typedbutton class based on properties
|
|
20
|
-
* @param props - TypedButton properties
|
|
21
|
-
* @returns Class string
|
|
22
|
-
*/
|
|
23
|
-
const generateClassNames = (props: Partial<TypedButtonProps> = {}): string => {
|
|
24
|
-
const {
|
|
25
|
-
variant = defaultProps.variant,
|
|
26
|
-
size = defaultProps.size,
|
|
27
|
-
disabled = defaultProps.disabled,
|
|
28
|
-
glass = defaultProps.glass,
|
|
29
|
-
className = '',
|
|
30
|
-
} = props;
|
|
31
|
-
|
|
32
|
-
const sizeClass = size === 'md' ? '' : `c-typedbutton--${size}`;
|
|
33
|
-
const disabledClass = disabled ? 'c-typedbutton--disabled' : '';
|
|
34
|
-
const glassClass = glass ? 'c-typedbutton--glass' : '';
|
|
35
|
-
|
|
36
|
-
return [
|
|
37
|
-
TYPEDBUTTON.BASE_CLASS,
|
|
38
|
-
`c-typedbutton--${variant}`,
|
|
39
|
-
sizeClass,
|
|
40
|
-
disabledClass,
|
|
41
|
-
glassClass,
|
|
42
|
-
className,
|
|
43
|
-
]
|
|
44
|
-
.filter(Boolean)
|
|
45
|
-
.join(' ');
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Handle typedbutton click with disabled check
|
|
50
|
-
* @param handler - Click handler function
|
|
51
|
-
* @returns Function that respects disabled state
|
|
52
|
-
*/
|
|
53
|
-
const handleClick = (handler?: (event: React.MouseEvent<HTMLDivElement>) => void) => {
|
|
54
|
-
return (event: React.MouseEvent<HTMLDivElement>) => {
|
|
55
|
-
if (!defaultProps.disabled && handler) {
|
|
56
|
-
handler(event);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
defaultProps,
|
|
63
|
-
generateClassNames,
|
|
64
|
-
handleClick,
|
|
65
|
-
};
|
|
66
|
-
}
|