@moises.ai/design-system 4.14.7 → 4.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moises.ai/design-system",
3
- "version": "4.14.7",
3
+ "version": "4.14.9",
4
4
  "description": "Design System package based on @radix-ui/themes with custom defaults",
5
5
  "private": false,
6
6
  "type": "module",
@@ -9,6 +9,7 @@ import {
9
9
  } from '@radix-ui/themes'
10
10
  import classNames from 'classnames'
11
11
  import React from 'react'
12
+ import { SparklesIcon } from '../../icons/SparklesIcon'
12
13
  import { ThumbnailPicker } from '../ThumbnailPicker/ThumbnailPicker'
13
14
  import styles from './ListCards.module.css'
14
15
 
@@ -138,6 +139,9 @@ const CardDetails = ({
138
139
  onAvatarClick,
139
140
  avatarContent,
140
141
  seeDetailsText = 'Details',
142
+ actions,
143
+ loading,
144
+ disabled,
141
145
  children,
142
146
  style,
143
147
  ...props
@@ -154,10 +158,21 @@ const CardDetails = ({
154
158
  : itemAvatar
155
159
 
156
160
  return (
157
- <div className={styles.cardWrapper}>
161
+ <div
162
+ className={classNames(
163
+ styles.cardWrapper,
164
+ loading && styles.cardWrapperLoading,
165
+ (disabled || loading) && styles.cardWrapperDisabled,
166
+ )}
167
+ >
158
168
  <RadioCards.Item
159
169
  value={itemId}
160
- className={classNames(className, styles.listCardsItem)}
170
+ className={classNames(
171
+ className,
172
+ styles.listCardsItem,
173
+ loading && styles.listCardsItemLoading,
174
+ (disabled || loading) && styles.listCardsItemDisabled,
175
+ )}
161
176
  style={{
162
177
  '--color-surface': 'transparent',
163
178
  width: '100%',
@@ -170,14 +185,22 @@ const CardDetails = ({
170
185
  gap="2"
171
186
  width="100%"
172
187
  style={{
173
- paddingRight: onSeeDetails || onAvatarClick ? '90px' : '0',
188
+ paddingRight:
189
+ actions || onSeeDetails || onAvatarClick ? '90px' : '0',
174
190
  paddingLeft: onAvatarClick ? '68px' : '0',
175
191
  overflow: 'hidden',
176
192
  }}
177
193
  >
178
- {!onAvatarClick && (
179
- <Avatar src={avatarUrl} className={styles.listCardsAvatar} />
180
- )}
194
+ {!onAvatarClick &&
195
+ (loading ? (
196
+ <div className={styles.listCardsAvatarIcon}>
197
+ <SparklesIcon className={styles.loadingIcon} />
198
+ </div>
199
+ ) : avatarContent ? (
200
+ <div className={styles.listCardsAvatarIcon}>{avatarContent}</div>
201
+ ) : (
202
+ <Avatar src={avatarUrl} className={styles.listCardsAvatar} />
203
+ ))}
181
204
  <Flex direction="column" justify="center">
182
205
  <Text as="div" size="2" className={styles.listCardsItemText}>
183
206
  {itemName}
@@ -224,45 +247,56 @@ const CardDetails = ({
224
247
  )}
225
248
 
226
249
  <div className={styles.cardActions}>
227
- <Flex
228
- direction="column"
229
- align="end"
230
- gap="2"
231
- height="100%"
232
- justify={onFavorite ? 'between' : 'end'}
233
- >
234
- {onFavorite && (
235
- <div
236
- className={classNames(
237
- styles.favoriteButton,
238
- styles.seeDetailsButton,
239
- )}
240
- onClick={(e) => {
241
- e.stopPropagation()
242
- e.preventDefault()
243
- onFavorite(e)
244
- }}
245
- >
246
- {favorite ? <StarFilledIcon /> : <StarIcon />}
247
- </div>
248
- )}
250
+ {actions ? (
251
+ <Flex
252
+ align="start"
253
+ justify="start"
254
+ height="100%"
255
+ className={styles.customActions}
256
+ >
257
+ {actions}
258
+ </Flex>
259
+ ) : (
260
+ <Flex
261
+ direction="column"
262
+ align="end"
263
+ gap="2"
264
+ height="100%"
265
+ justify={onFavorite ? 'between' : 'end'}
266
+ >
267
+ {onFavorite && (
268
+ <div
269
+ className={classNames(
270
+ styles.favoriteButton,
271
+ !favorite && styles.seeDetailsButton,
272
+ )}
273
+ onClick={(e) => {
274
+ e.stopPropagation()
275
+ e.preventDefault()
276
+ onFavorite(e)
277
+ }}
278
+ >
279
+ {favorite ? <StarFilledIcon /> : <StarIcon />}
280
+ </div>
281
+ )}
249
282
 
250
- {onSeeDetails && (
251
- <div
252
- className={classNames(
253
- styles.buttonGhost,
254
- styles.seeDetailsButton,
255
- )}
256
- onClick={(e) => {
257
- e.stopPropagation()
258
- e.preventDefault()
259
- onSeeDetails(e)
260
- }}
261
- >
262
- {seeDetailsText}
263
- </div>
264
- )}
265
- </Flex>
283
+ {onSeeDetails && (
284
+ <div
285
+ className={classNames(
286
+ styles.buttonGhost,
287
+ styles.seeDetailsButton,
288
+ )}
289
+ onClick={(e) => {
290
+ e.stopPropagation()
291
+ e.preventDefault()
292
+ onSeeDetails(e)
293
+ }}
294
+ >
295
+ {seeDetailsText}
296
+ </div>
297
+ )}
298
+ </Flex>
299
+ )}
266
300
  </div>
267
301
  </div>
268
302
  )
@@ -61,6 +61,7 @@
61
61
  .listCardsAvatarIcon {
62
62
  width: 60px;
63
63
  height: 60px;
64
+ min-width: 60px;
64
65
  border-radius: 6px;
65
66
 
66
67
  background: var(--neutral-alpha-2);
@@ -226,6 +227,119 @@
226
227
  outline: 1px solid var(--neutral-alpha-6);
227
228
  outline-offset: -1px;
228
229
  }
230
+ .listCardsItemDisabled {
231
+ pointer-events: none;
232
+ }
233
+
234
+ .listCardsItemDisabled:hover {
235
+ background-color: transparent !important;
236
+ outline: 1px solid var(--neutral-alpha-4);
237
+ outline-offset: -1px;
238
+ }
239
+
240
+ .cardWrapperDisabled {
241
+ cursor: default;
242
+ }
243
+
244
+ .cardWrapperDisabled:hover .listCardsItem {
245
+ background-color: transparent !important;
246
+ outline: 1px solid var(--neutral-alpha-4) !important;
247
+ outline-offset: -1px;
248
+ }
249
+
250
+ .listCardsItemLoading {
251
+ outline: 1px solid var(--neutral-alpha-4) !important;
252
+ outline-offset: -1px;
253
+ }
254
+
255
+ .cardWrapperLoading:hover .listCardsItem {
256
+ background-color: transparent !important;
257
+ outline: 1px solid var(--neutral-alpha-4) !important;
258
+ outline-offset: -1px;
259
+ }
260
+
261
+ .loadingIcon {
262
+ width: 21px;
263
+ height: 21px;
264
+ color: var(--neutral-alpha-6);
265
+ transform: scale(0.619);
266
+ will-change: transform, color;
267
+ animation: loadingIconPulse 5s ease-in-out infinite;
268
+ }
269
+
270
+ @keyframes loadingIconPulse {
271
+ 0%, 100% {
272
+ transform: scale(0.619);
273
+ color: var(--neutral-alpha-6);
274
+ }
275
+ 50% {
276
+ transform: scale(1);
277
+ color: var(--accent-10);
278
+ }
279
+ }
280
+
281
+ .cardWrapperLoading {
282
+ position: relative;
283
+ }
284
+
285
+ .cardWrapperLoading::before {
286
+ content: '';
287
+ position: absolute;
288
+ inset: 0;
289
+ border-radius: 8px;
290
+ padding: 1px;
291
+ background: radial-gradient(
292
+ circle 200px at var(--loading-x, -50%) 50%,
293
+ rgba(25, 228, 241, 1) 0%,
294
+ rgba(25, 228, 241, 0) 100%
295
+ );
296
+ -webkit-mask:
297
+ linear-gradient(#fff 0 0) content-box,
298
+ linear-gradient(#fff 0 0);
299
+ -webkit-mask-composite: xor;
300
+ mask:
301
+ linear-gradient(#fff 0 0) content-box,
302
+ linear-gradient(#fff 0 0);
303
+ mask-composite: exclude;
304
+ animation: listCardsShimmer 5s linear infinite;
305
+ pointer-events: none;
306
+ z-index: 1;
307
+ }
308
+
309
+ .cardWrapperLoading::after {
310
+ content: '';
311
+ position: absolute;
312
+ inset: 0;
313
+ border-radius: 8px;
314
+ background: radial-gradient(
315
+ circle 200px at var(--loading-x, -50%) 50%,
316
+ rgba(25, 228, 241, 0.15) 0%,
317
+ rgba(25, 228, 241, 0) 100%
318
+ );
319
+ animation: listCardsShimmer 5s linear infinite;
320
+ pointer-events: none;
321
+ z-index: 0;
322
+ }
323
+
324
+ @property --loading-x {
325
+ syntax: "<percentage>";
326
+ initial-value: -50%;
327
+ inherits: false;
328
+ }
329
+
330
+ @keyframes listCardsShimmer {
331
+ 0% {
332
+ --loading-x: -80%;
333
+ }
334
+ 100% {
335
+ --loading-x: 180%;
336
+ }
337
+ }
338
+
339
+ .customActions {
340
+ pointer-events: auto;
341
+ }
342
+
229
343
  .gridContainer {
230
344
  display: grid;
231
345
  gap: 8px;
@@ -1,7 +1,16 @@
1
1
  import React, { useState } from 'react'
2
2
  import { ListCards } from './ListCards'
3
- import { Flex, Avatar } from '@radix-ui/themes'
4
- import { MusicIcon, DrumsIcon, PianoIcon } from '../../icons'
3
+ import { Flex, Avatar, Text } from '@radix-ui/themes'
4
+ import {
5
+ MusicIcon,
6
+ DrumsIcon,
7
+ PianoIcon,
8
+ AlertIcon,
9
+ TrashIcon,
10
+ } from '../../icons'
11
+ import { DropdownMenu } from '../DropdownMenu/DropdownMenu'
12
+ import { IconButton } from '../IconButton/IconButton'
13
+ import { MoreButton } from '../MoreButton/MoreButton'
5
14
 
6
15
  export default {
7
16
  title: 'Components/ListCards',
@@ -309,6 +318,121 @@ const sampleItemsForSizes = [
309
318
  },
310
319
  ]
311
320
 
321
+ const voiceItems = [
322
+ {
323
+ id: '1',
324
+ name: 'Ana',
325
+ description: 'Training: 100 rounds completed...',
326
+ isLoading: true,
327
+ },
328
+ {
329
+ id: '2',
330
+ name: 'Carlos',
331
+ description: 'Training: 50 rounds completed...',
332
+ isLoading: true,
333
+ },
334
+ {
335
+ id: '3',
336
+ name: 'Maria',
337
+ description: 'Ready to use',
338
+ isLoading: false,
339
+ },
340
+ {
341
+ id: '4',
342
+ name: 'Ana',
343
+ description: 'Failed',
344
+ isLoading: false,
345
+ isFailed: true,
346
+ },
347
+ ]
348
+
349
+ const menuOptions = [
350
+ {
351
+ type: 'item',
352
+ key: 'rename',
353
+ label: 'Rename',
354
+ onClick: () => console.log('Rename clicked'),
355
+ },
356
+ {
357
+ type: 'item',
358
+ key: 'duplicate',
359
+ label: 'Duplicate',
360
+ onClick: () => console.log('Duplicate clicked'),
361
+ },
362
+ { type: 'separator', key: 'sep1' },
363
+ {
364
+ type: 'item',
365
+ key: 'delete',
366
+ label: 'Delete',
367
+ onClick: () => console.log('Delete clicked'),
368
+ },
369
+ ]
370
+
371
+ export const WithCustomActions = {
372
+ render: (args) => {
373
+ const [selectedId, setSelectedId] = useState('1')
374
+
375
+ const handleSelect = (id) => {
376
+ setSelectedId(id)
377
+ }
378
+
379
+ return (
380
+ <Flex height="400px" width="328px">
381
+ <ListCards>
382
+ {voiceItems.map((item) => (
383
+ <ListCards.CardDetails
384
+ key={item.id}
385
+ item={item}
386
+ loading={item.isLoading}
387
+ disabled={item.isFailed}
388
+ checked={item.isFailed ? false : item.id === selectedId}
389
+ onClick={item.isFailed ? undefined : () => handleSelect(item.id)}
390
+ avatarContent={
391
+ item.isFailed ? (
392
+ <AlertIcon
393
+ width={18}
394
+ height={18}
395
+ style={{ color: '#FF9592' }}
396
+ />
397
+ ) : undefined
398
+ }
399
+ actions={
400
+ item.isFailed ? (
401
+ <IconButton
402
+ variant="ghost"
403
+ size="1"
404
+ color="neutral"
405
+ onClick={(e) => {
406
+ e.stopPropagation()
407
+ console.log('Delete clicked for', item.name)
408
+ }}
409
+ >
410
+ <TrashIcon width={16} height={16} />
411
+ </IconButton>
412
+ ) : (
413
+ <DropdownMenu
414
+ trigger={<MoreButton />}
415
+ options={menuOptions}
416
+ />
417
+ )
418
+ }
419
+ >
420
+ <Text
421
+ as="div"
422
+ size="1"
423
+ style={item.isFailed ? { color: '#FF9592' } : undefined}
424
+ color={item.isFailed ? undefined : 'gray'}
425
+ >
426
+ {item.description}
427
+ </Text>
428
+ </ListCards.CardDetails>
429
+ ))}
430
+ </ListCards>
431
+ </Flex>
432
+ )
433
+ },
434
+ }
435
+
312
436
  export const WithSizes = {
313
437
  render: (args) => {
314
438
  const [selectedId1, setSelectedId1] = useState(null)
@@ -9,10 +9,8 @@
9
9
  background: transparent;
10
10
  border-radius: 9999px;
11
11
  cursor: pointer;
12
- color: var(--neutral-alpha-7);
13
- transition:
14
- background-color 0.15s ease,
15
- color 0.15s ease;
12
+ color: var(--neutral-11);
13
+ transition: color 0.15s ease;
16
14
  }
17
15
 
18
16
  @media (pointer: coarse) {
@@ -27,8 +25,7 @@
27
25
 
28
26
  .MoreButton:hover,
29
27
  .MoreButton.hovered {
30
- background-color: var(--neutral-alpha-3);
31
- color: var(--neutral-alpha-11);
28
+ color: var(--neutral-12);
32
29
  }
33
30
 
34
31
  .MoreButton:focus-visible {