@moises.ai/design-system 3.7.2 → 3.8.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.
@@ -1,19 +1,9 @@
1
- import { Flex, Text, Separator, Spinner } from '@radix-ui/themes'
2
- import styles from './ProjectsList.module.css'
3
- import { useState, createContext, useContext, useCallback } from 'react'
4
- import { ArrowLeftIcon, NoMusicIcon, ChevronDownIcon, ChevronUpIcon } from '../../icons'
5
- import { getIconFromTrackId } from './utils'
6
- import { Button } from '../Button/Button'
7
- import { ProductsBrandPattern } from '../ProductsBrandPattern/ProductsBrandPattern'
8
-
9
- const ProjectsListContext = createContext({
10
- projects: [],
11
- onClickTrack: null,
12
- onInsertAllTracks: null,
13
- onProjectClick: null,
14
- openedItem: null,
15
- setOpenedItem: () => { },
16
- })
1
+ import { Flex } from '@radix-ui/themes'
2
+ import { useState } from 'react'
3
+ import { ProjectsListContext } from './context'
4
+ import ProjectItem from './ProjectItem/ProjectItem'
5
+ import ProjectTrack from './ProjectTrack/ProjectTrack'
6
+ import ProjectTrackVoice from './ProjectTrackVoice/ProjectTrackVoice'
17
7
 
18
8
  export const ProjectsList = ({
19
9
  children,
@@ -24,8 +14,6 @@ export const ProjectsList = ({
24
14
  }) => {
25
15
  const [openedItem, setOpenedItem] = useState(null)
26
16
 
27
- const content = typeof children === 'function' ? children(projects) : children
28
-
29
17
  return (
30
18
  <ProjectsListContext.Provider
31
19
  value={{
@@ -38,143 +26,15 @@ export const ProjectsList = ({
38
26
  }}
39
27
  >
40
28
  <Flex direction="column" width="100%">
41
- {content}
29
+ {projects.map((project) => (
30
+ <ProjectItem key={project.id} {...project}>
31
+ {children}
32
+ </ProjectItem>
33
+ ))}
42
34
  </Flex>
43
35
  </ProjectsListContext.Provider>
44
36
  )
45
37
  }
46
38
 
47
- const ProjectsListItem = ({
48
- id,
49
- title,
50
- artist,
51
- cover,
52
- type,
53
- tracks = [],
54
- isLoading = false,
55
- ...props
56
- }) => {
57
- const { projects, onClickTrack, onInsertAllTracks, onProjectClick, openedItem, setOpenedItem } = useContext(ProjectsListContext)
58
- const [showAllTracks, setShowAllTracks] = useState(false)
59
-
60
- const handleClickProject = useCallback(() => {
61
- setShowAllTracks(false)
62
- const project = projects.find((p) => p.id === id)
63
-
64
- if (openedItem === id) {
65
- setOpenedItem(null)
66
- onProjectClick?.(project, false)
67
- } else {
68
- setOpenedItem(id)
69
- onProjectClick?.(project, true)
70
- }
71
- }, [id, openedItem, setOpenedItem, onProjectClick, projects])
72
-
73
- const handleClickShowAllTracks = useCallback((e) => {
74
- e.preventDefault()
75
- e.stopPropagation()
76
- setShowAllTracks(!showAllTracks)
77
- }, [showAllTracks])
78
-
79
-
80
- return (
81
- <Flex
82
- direction="column"
83
- gap="2"
84
- p="1"
85
- className={`${styles.item} ${openedItem === id ? styles.opened : ''}`}
86
- onClick={handleClickProject}
87
- {...props}
88
- >
89
- <Flex direction="row" gap="3">
90
- <Flex className={styles.projectCover}>
91
- <ProductsBrandPattern type={type} cover={cover} size="48px" />
92
- </Flex>
93
-
94
- <Flex direction="column" gap="1" align="start" justify="center">
95
- <Text size="2" className={styles.projectTitle}>
96
- {title}
97
- </Text>
98
-
99
- {artist && (
100
- <Text size="1" className={styles.projectArtist}>
101
- {artist}
102
- </Text>
103
- )}
104
- </Flex>
105
- </Flex>
106
-
107
- {openedItem === id && (
108
- <Flex direction="column">
109
- {tracks.length === 0 && !isLoading && (
110
- <Flex direction="row" gap="3" p="5" pt="2" align="center" justify="center">
111
- <NoMusicIcon width={16} height={16} style={{ color: 'var(--neutral-alpha-10)' }} />
112
- <Text size="2" style={{ color: 'var(--neutral-alpha-10)' }}>This file has no tracks</Text>
113
- </Flex>
114
- )}
115
-
116
- {isLoading && (
117
- <Flex direction="row" gap="3" p="5" align="center" justify="center">
118
- <Spinner width={16} height={16} style={{ color: 'var(--neutral-alpha-10)' }} />
119
- <Text size="2" style={{ color: 'var(--neutral-alpha-10)' }}>Loading tracks...</Text>
120
- </Flex>
121
- )}
122
-
123
- {tracks.length > 0 && (
124
- <Flex direction="column" gap="1">
125
- {tracks.slice(0, showAllTracks ? tracks.length : 6).map((track) => (
126
- <Flex
127
- key={track.id}
128
- direction="row"
129
- gap="3"
130
- className={styles.itemTrack}
131
- onClick={(e) => {
132
- e.stopPropagation()
133
- onClickTrack?.(track)
134
- }}
135
- >
136
- <div className={styles.icon}>
137
- <Flex className={styles.iconTrack}>
138
- {getIconFromTrackId(track.id)}
139
- </Flex>
140
- <ArrowLeftIcon width={16} height={16} className={styles.iconArrowLeft} />
141
- </div>
142
-
143
- <Flex direction="column" gap="1" align="start" justify="center">
144
- <Text size="2" className={styles.trackTitle}>
145
- {track.title}
146
- </Text>
147
- </Flex>
148
- </Flex>
149
- ))}
150
-
151
- <Flex direction="row" gap="3" p="2" align="center" justify="center">
152
- <Button variant="ghost" color="neutral" style={{ flex: '1' }}
153
- onClick={(e) => {
154
- e.stopPropagation()
155
- onInsertAllTracks?.(tracks)
156
- }}
157
- >
158
- <ArrowLeftIcon width={16} height={16} /> Insert all
159
- </Button>
160
-
161
- {tracks.length > 6 && (
162
- <>
163
- <Separator orientation="vertical" />
164
-
165
- <Button variant="ghost" color="gray" style={{ flex: '1' }} onClick={handleClickShowAllTracks}>
166
- {showAllTracks ? 'Show less' : 'Show more'}
167
- {showAllTracks ? <ChevronUpIcon width={16} height={16} /> : <ChevronDownIcon width={16} height={16} />}
168
- </Button>
169
- </>
170
- )}
171
- </Flex>
172
- </Flex>
173
- )}
174
- </Flex>
175
- )}
176
- </Flex>
177
- )
178
- }
179
-
180
- ProjectsList.Item = ProjectsListItem
39
+ ProjectsList.Track = ProjectTrack
40
+ ProjectsList.TrackVoice = ProjectTrackVoice
@@ -1,5 +1,6 @@
1
+ import { Flex } from '@radix-ui/themes'
1
2
  import { ProjectsList } from './ProjectsList'
2
- import { projects } from './utils-stories'
3
+ import { projects, projectsVoiceStudio } from './utils-stories'
3
4
 
4
5
  export default {
5
6
  title: 'Components/ProjectsList',
@@ -28,18 +29,20 @@ export const Default = {
28
29
  },
29
30
  render: (args) => {
30
31
  return (
31
- <ProjectsList
32
- projects={args.projects}
33
- onClickTrack={args.onClickTrack}
34
- onInsertAllTracks={args.onInsertAllTracks}
35
- onProjectClick={args.onProjectClick}
36
- >
37
- {(projects) =>
38
- projects.map((project) => (
39
- <ProjectsList.Item key={project.id} {...project} />
40
- ))
41
- }
42
- </ProjectsList>
32
+ <Flex width="300px">
33
+ <ProjectsList
34
+ projects={args.projects}
35
+ onClickTrack={args.onClickTrack}
36
+ onInsertAllTracks={args.onInsertAllTracks}
37
+ onProjectClick={args.onProjectClick}
38
+ >
39
+ {(tracks) =>
40
+ tracks.map((track) => (
41
+ <ProjectsList.Track key={track.id} {...track} />
42
+ ))
43
+ }
44
+ </ProjectsList>
45
+ </Flex>
43
46
  )
44
47
  },
45
48
  }
@@ -74,18 +77,20 @@ export const WithEmptyProjects = {
74
77
  },
75
78
  render: (args) => {
76
79
  return (
77
- <ProjectsList
78
- projects={args.projects}
79
- onClickTrack={args.onClickTrack}
80
- onInsertAllTracks={args.onInsertAllTracks}
81
- onProjectClick={args.onProjectClick}
82
- >
83
- {(projects) =>
84
- projects.map((project) => (
85
- <ProjectsList.Item key={project.id} {...project} />
86
- ))
87
- }
88
- </ProjectsList>
80
+ <Flex width="300px">
81
+ <ProjectsList
82
+ projects={args.projects}
83
+ onClickTrack={args.onClickTrack}
84
+ onInsertAllTracks={args.onInsertAllTracks}
85
+ onProjectClick={args.onProjectClick}
86
+ >
87
+ {(tracks) =>
88
+ tracks.map((track) => (
89
+ <ProjectsList.Track key={track.id} {...track} />
90
+ ))
91
+ }
92
+ </ProjectsList>
93
+ </Flex>
89
94
  )
90
95
  },
91
96
  }
@@ -99,7 +104,7 @@ export const WithProjectLoading = {
99
104
  cover: null,
100
105
  duration: 0,
101
106
  type: 'studio',
102
- isLoading: true,
107
+ loading: true,
103
108
  }, {
104
109
  id: '456',
105
110
  title: 'Empty Project 2',
@@ -121,18 +126,110 @@ export const WithProjectLoading = {
121
126
  },
122
127
  render: (args) => {
123
128
  return (
124
- <ProjectsList
125
- projects={args.projects}
126
- onClickTrack={args.onClickTrack}
127
- onInsertAllTracks={args.onInsertAllTracks}
128
- onProjectClick={args.onProjectClick}
129
- >
130
- {(projects) =>
131
- projects.map((project) => (
132
- <ProjectsList.Item key={project.id} {...project} />
133
- ))
134
- }
135
- </ProjectsList>
129
+ <Flex width="300px">
130
+ <ProjectsList
131
+ projects={args.projects}
132
+ onClickTrack={args.onClickTrack}
133
+ onInsertAllTracks={args.onInsertAllTracks}
134
+ onProjectClick={args.onProjectClick}
135
+ >
136
+ {(tracks) =>
137
+ tracks.map((track) => (
138
+ <ProjectsList.Track key={track.id} {...track} />
139
+ ))
140
+ }
141
+ </ProjectsList>
142
+ </Flex>
143
+ )
144
+ },
145
+ }
146
+
147
+ export const WithProjectFailed = {
148
+ args: {
149
+ projects: [{
150
+ id: '123',
151
+ title: 'Project Failed',
152
+ artist: null,
153
+ cover: null,
154
+ duration: 0,
155
+ type: 'studio',
156
+ failed: true,
157
+ }, {
158
+ id: '456',
159
+ title: 'Empty Project 2',
160
+ artist: null,
161
+ cover: null,
162
+ duration: 0,
163
+ type: 'master',
164
+ }],
165
+ onProjectClick: (project, opened) => {
166
+ console.log('project', project)
167
+ console.log('opened', opened)
168
+ },
169
+ onClickTrack: (track) => {
170
+ console.log('track', track)
171
+ },
172
+ onInsertAllTracks: (tracks) => {
173
+ console.log('insert-all-tracks', tracks)
174
+ },
175
+ },
176
+ render: (args) => {
177
+ return (
178
+ <Flex width="300px">
179
+ <ProjectsList
180
+ projects={args.projects}
181
+ onClickTrack={args.onClickTrack}
182
+ onInsertAllTracks={args.onInsertAllTracks}
183
+ onProjectClick={args.onProjectClick}
184
+ >
185
+ {(tracks) =>
186
+ tracks.map((track) => (
187
+ <ProjectsList.Track key={track.id} {...track} />
188
+ ))
189
+ }
190
+ </ProjectsList>
191
+ </Flex>
192
+ )
193
+ },
194
+ }
195
+
196
+ export const WithTrackVoice = {
197
+ args: {
198
+ projects: projectsVoiceStudio,
199
+ onProjectClick: (project, opened) => {
200
+ console.log('project', project)
201
+ console.log('opened', opened)
202
+ },
203
+ onClickTrack: (track) => {
204
+ console.log('track', track)
205
+ },
206
+ onInsertAllTracks: (tracks) => {
207
+ console.log('insert-all-tracks', tracks)
208
+ },
209
+ onChangeTransfer: (track) => {
210
+ console.log('change-transfer', track)
211
+ },
212
+ },
213
+ render: (args) => {
214
+ return (
215
+ <Flex width="300px">
216
+ <ProjectsList
217
+ projects={args.projects}
218
+ onClickTrack={args.onClickTrack}
219
+ onInsertAllTracks={args.onInsertAllTracks}
220
+ onProjectClick={args.onProjectClick}
221
+ >
222
+ {(tracks) =>
223
+ tracks.map((track) => (
224
+ <ProjectsList.TrackVoice
225
+ key={track.id}
226
+ {...track}
227
+ onChangeTransfer={args.onChangeTransfer}
228
+ />
229
+ ))
230
+ }
231
+ </ProjectsList>
232
+ </Flex>
136
233
  )
137
234
  },
138
235
  }
@@ -0,0 +1,10 @@
1
+ import { createContext } from 'react'
2
+
3
+ export const ProjectsListContext = createContext({
4
+ projects: [],
5
+ onClickTrack: null,
6
+ onInsertAllTracks: null,
7
+ onProjectClick: null,
8
+ openedItem: null,
9
+ setOpenedItem: () => { },
10
+ })
@@ -19,7 +19,7 @@ export const projects = [
19
19
  },
20
20
  {
21
21
  "id": "b9470aco6y4a9dlef0c035",
22
- "title": "blink 182 - adams song.mp3",
22
+ "title": "blink 182 - adams song - very long name.mp3",
23
23
  "audioUrl": "https://storage.googleapis.com/moises-stage--tasks-us-east1/studio-tracks/3842c898-9e0c-41e8-8927-7d9f67c50bc6/15a1072d5d04c507eebf39b464329572b8b400c76d8f11197a5f83147a336de5.audio"
24
24
  }
25
25
  ]
@@ -191,7 +191,7 @@ export const projects = [
191
191
  {
192
192
  "id": "3612a6132234-b86c-408e-b23296-b9f0f22dbeb108",
193
193
  "title": "Project without cover and type",
194
- "artist": null,
194
+ "artist": "Artist Very Long Name With Very Long Name",
195
195
  "cover": null,
196
196
  "duration": 227.0215,
197
197
  "tracks": [
@@ -208,3 +208,94 @@ export const projects = [
208
208
  ]
209
209
  }
210
210
  ]
211
+
212
+ export const projectsVoiceStudio = [
213
+ {
214
+ "id": "3842c898-9e0c-41e8-8927-7d9f67c50bc6",
215
+ "title": "vocals - Billie Bossa Nova",
216
+ "artist": "Billie Bossa Nova",
217
+ "cover": null,
218
+ "duration": 30.72,
219
+ "type": "voice",
220
+ "tracks": [
221
+ {
222
+ "id": "q8pzli0h38ptcx21q09h2al-0",
223
+ "title": "Original",
224
+ "type": "voice",
225
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/0b926e1f-52ce-4581-9f76-09545eed1c61/vocals.m4",
226
+ },
227
+ {
228
+ "id": "q8pzli0h38ptcxq09h2al-0",
229
+ "title": "Ana",
230
+ "type": "voice",
231
+ "cover": "https://picsum.photos/101/101",
232
+ "transfers": [
233
+ {
234
+ "id": "q8pzli0h38ptcxq09h2al",
235
+ "pitchShift": "-12",
236
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/0b926e1f-52ce-4581-9f76-09545eed1c61/vocals.m4"
237
+ },
238
+ {
239
+ "id": "q8pzli0h38ptcxq09h2al2",
240
+ "pitchShift": "-13",
241
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/0a6c2a03-320e-49f2-9ea6-a5ad7bbb6141/vocals.m4a"
242
+ }
243
+ ],
244
+ },
245
+ {
246
+ "id": "j1nvrdhrai85pftttb9bo",
247
+ "title": "Carrie",
248
+ "cover": "https://picsum.photos/110/110",
249
+ "type": "voice",
250
+ "transfers": [
251
+ {
252
+ "id": "j1nvrdhrai85pftttb9bo-0",
253
+ "pitchShift": "3",
254
+ "audioUrl": "https://d2-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/9b8df9e7-b35d-487f-a24c-a33e20597203/vocals.m4a"
255
+ },
256
+ {
257
+ "id": "j1nvrdhrai85pftttb9bo-1",
258
+ "pitchShift": "4",
259
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/f38d1691-d0a5-4904-b6a9-2935881f1e75/vocals.m4a"
260
+ }
261
+ ],
262
+ },
263
+ {
264
+ "id": "b9470aco6y4a9dlef0c035",
265
+ "title": "Amelia",
266
+ "cover": "https://picsum.photos/103/103",
267
+ "type": "voice",
268
+ "transfers": [
269
+ {
270
+ "id": "b9470aco6y4a9dlef0c035-0",
271
+ "pitchShift": "-10",
272
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/0b926e1f-52ce-4581-9f76-09545eed1c61/vocals.m4"
273
+ },
274
+ {
275
+ "id": "b9470aco6y4a9dlef0c035-1",
276
+ "pitchShift": "-11",
277
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/0a6c2a03-320e-49f2-9ea6-a5ad7bbb6141/vocals.m4a"
278
+ }
279
+ ],
280
+ },
281
+ {
282
+ "id": "b9470aco6y4a9dlef0c123035",
283
+ "title": "Lauren Very Long Name",
284
+ "cover": "https://picsum.photos/120/400",
285
+ "type": "voice",
286
+ "transfers": [
287
+ {
288
+ "id": "b9470aco6y4a9dleqqwqf0c035-0",
289
+ "pitchShift": "7",
290
+ "audioUrl": "https://d2-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/9b8df9e7-b35d-487f-a24c-a33e20597203/vocals.m4a"
291
+ },
292
+ {
293
+ "id": "b9470aco6y4a9d1111111lef0c035-1",
294
+ "pitchShift": "8",
295
+ "audioUrl": "https://d3-stage.moises.ai/v3/download/moises-stage--tasks-us-east1/operations/VOICETRANSFER_A/f38d1691-d0a5-4904-b6a9-2935881f1e75/vocals.m4a"
296
+ }
297
+ ],
298
+ }
299
+ ]
300
+ }
301
+ ]