@moises.ai/design-system 3.9.9 → 3.9.10

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": "3.9.9",
3
+ "version": "3.9.10",
4
4
  "description": "Design System package based on @radix-ui/themes with custom defaults",
5
5
  "private": false,
6
6
  "type": "module",
@@ -289,7 +289,7 @@ export const DataTable = ({
289
289
  return (
290
290
  <Flex align="center" gap="3">
291
291
  <ProductsBrandPattern
292
- id={row.id}
292
+ title={row.title}
293
293
  size={48}
294
294
  className={styles.thumb}
295
295
  type={row.type}
@@ -1,37 +1,108 @@
1
+ import { useState } from 'react'
1
2
  import classNames from 'classnames'
2
- import lyrics from './Patterns/thumb-song-lyrics.jpg'
3
- import mastering from './Patterns/thumb-song-master.jpg'
4
- import stems from './Patterns/thumb-song-stems.jpg'
5
- import studio from './Patterns/thumb-song-studio.jpg'
6
- import voice from './Patterns/thumb-song-voice.jpg'
3
+
4
+ const palettes = {
5
+ lyrics: ['#0f2a4f', '#1a3a6b', '#2a5a8b', '#1a4a7b', '#3a6a9b', '#152e55'],
6
+ stems: ['#083a48', '#0a4a5a', '#1a5a6a', '#0f3a4a', '#2a6a7a', '#1a6070'],
7
+ voice: ['#3a1a0a', '#5a2a10', '#7a3a1a', '#4a2010', '#8a4a2a', '#6a3018'],
8
+ studio: ['#083838', '#0a4a4a', '#1a5a5a', '#0a3a3a', '#2a6a6a', '#0f5050'],
9
+ master: ['#1a1030', '#2a1a4a', '#3a2a5a', '#4a3a6a', '#2a1848', '#352060'],
10
+ }
11
+
12
+ function hashSeed(str) {
13
+ let h = 0
14
+ for (let i = 0; i < str.length; i++) {
15
+ h = (Math.imul(31, h) + str.charCodeAt(i)) | 0
16
+ }
17
+ return h >>> 0
18
+ }
19
+
20
+ function createRng(seed) {
21
+ let s = hashSeed(String(seed))
22
+ return () => {
23
+ s = (s + 0x6d2b79f5) | 0
24
+ let t = Math.imul(s ^ (s >>> 15), 1 | s)
25
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
26
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296
27
+ }
28
+ }
29
+
30
+ function generatePattern(type, seed) {
31
+ const rng = createRng(seed)
32
+ const colors = palettes[type] || palettes.lyrics
33
+ const pick = () => colors[Math.floor(rng() * colors.length)]
34
+ const uid = hashSeed(String(seed) + type)
35
+
36
+ const bg = pick()
37
+
38
+ const blobCount = 4 + Math.floor(rng() * 2)
39
+ const blobs = Array.from({ length: blobCount }, () => ({
40
+ cx: -10 + rng() * 120,
41
+ cy: -10 + rng() * 120,
42
+ r: 30 + rng() * 35,
43
+ fill: pick(),
44
+ }))
45
+
46
+ const blur = 18 + rng() * 10
47
+
48
+ return { uid, bg, blobs, blur }
49
+ }
7
50
 
8
51
  export const ProductsBrandPattern = ({
9
52
  className,
10
53
  size = '40px',
11
54
  type = 'lyrics',
12
55
  cover,
56
+ title,
13
57
  ...props
14
58
  }) => {
15
- const patterns = {
16
- 'stems': stems,
17
- 'voice': voice,
18
- 'studio': studio,
19
- 'master': mastering,
20
- 'lyrics': lyrics,
59
+ const [randomSeed] = useState(() => String(Math.random()))
60
+
61
+ if (cover) {
62
+ return (
63
+ <img
64
+ src={cover}
65
+ alt={`${type} pattern`}
66
+ width={size}
67
+ height={size}
68
+ draggable={false}
69
+ className={classNames(className)}
70
+ {...props}
71
+ />
72
+ )
21
73
  }
22
74
 
75
+ const effectiveSeed = title != null ? title : randomSeed
76
+ const { uid, bg, blobs, blur } = generatePattern(type, effectiveSeed)
77
+ const filterId = `bl-${uid}`
23
78
 
24
- const pattern = cover || patterns[type]
25
79
  return (
26
- <img
27
- src={pattern}
28
- alt={`${type} pattern`}
80
+ <svg
81
+ viewBox="0 0 100 100"
29
82
  width={size}
30
83
  height={size}
31
- draggable={false}
32
84
  className={classNames(className)}
85
+ aria-label={`${type} pattern`}
86
+ role="img"
33
87
  {...props}
34
- />
88
+ >
89
+ <defs>
90
+ <filter id={filterId} x="-50%" y="-50%" width="200%" height="200%">
91
+ <feGaussianBlur stdDeviation={blur} />
92
+ </filter>
93
+ <clipPath id={`c-${uid}`}>
94
+ <rect width="100" height="100" />
95
+ </clipPath>
96
+ </defs>
97
+
98
+ <rect width="100" height="100" fill={bg} />
99
+
100
+ <g clipPath={`url(#c-${uid})`} filter={`url(#${filterId})`}>
101
+ {blobs.map((b, i) => (
102
+ <circle key={i} cx={b.cx} cy={b.cy} r={b.r} fill={b.fill} />
103
+ ))}
104
+ </g>
105
+ </svg>
35
106
  )
36
107
  }
37
108
 
@@ -26,6 +26,10 @@ export default {
26
26
  control: 'text',
27
27
  description: 'Width/height of the pattern image. Accepts px, rem, or number.',
28
28
  },
29
+ title: {
30
+ control: 'text',
31
+ description: 'Optional title used as seed for deterministic pattern generation. Random if omitted.',
32
+ },
29
33
  },
30
34
  args: {
31
35
  type: 'lyrics',
@@ -81,7 +85,7 @@ export const AllPatterns = {
81
85
  <div style={{ display: 'flex', gap: 16, alignItems: 'center', flexWrap: 'wrap' }}>
82
86
  {patternTypes.map((type) => (
83
87
  <div key={type} style={{ textAlign: 'center' }}>
84
- <ProductsBrandPattern type={type} {...args} />
88
+ <ProductsBrandPattern type={type} title={type} {...args} />
85
89
  <div style={{ fontSize: 12, marginTop: 4, textTransform: 'capitalize' }}>{type}</div>
86
90
  </div>
87
91
  ))}
@@ -91,3 +95,46 @@ export const AllPatterns = {
91
95
  size: '48px',
92
96
  },
93
97
  }
98
+
99
+ export const TitleVariations = {
100
+ render: ({ type, ...args }) => {
101
+ const titles = ['My First Song', 'Late Night Jam', 'Acoustic Demo', 'Final Mix', 'Live Take', 'Rehearsal']
102
+ return (
103
+ <div style={{ display: 'flex', gap: 16, alignItems: 'center', flexWrap: 'wrap' }}>
104
+ {titles.map((title) => (
105
+ <div key={title} style={{ textAlign: 'center' }}>
106
+ <ProductsBrandPattern type={type} title={title} {...args} />
107
+ <div style={{ fontSize: 11, marginTop: 4, color: '#888' }}>{title}</div>
108
+ </div>
109
+ ))}
110
+ </div>
111
+ )
112
+ },
113
+ args: {
114
+ type: 'lyrics',
115
+ size: '64px',
116
+ },
117
+ }
118
+
119
+ export const AllTypesWithTitles = {
120
+ render: () => {
121
+ const titles = ['Song A', 'Song B', 'Song C']
122
+ return (
123
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
124
+ {patternTypes.map((type) => (
125
+ <div key={type}>
126
+ <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 8, textTransform: 'capitalize' }}>{type}</div>
127
+ <div style={{ display: 'flex', gap: 12 }}>
128
+ {titles.map((title) => (
129
+ <div key={title} style={{ textAlign: 'center' }}>
130
+ <ProductsBrandPattern type={type} title={title} size="56px" />
131
+ <div style={{ fontSize: 10, marginTop: 4, color: '#888' }}>{title}</div>
132
+ </div>
133
+ ))}
134
+ </div>
135
+ </div>
136
+ ))}
137
+ </div>
138
+ )
139
+ },
140
+ }
@@ -66,7 +66,7 @@ const ProjectItem = ({
66
66
  >
67
67
  <Flex direction="row" gap="3">
68
68
  <Flex className={styles.projectCover}>
69
- <ProductsBrandPattern type={type} cover={cover} size="48px" />
69
+ <ProductsBrandPattern type={type} cover={cover} title={title} size="48px" />
70
70
  </Flex>
71
71
 
72
72
  <Flex