@gallop.software/studio 1.5.9 → 2.0.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.
- package/app/api/studio/[...path]/route.ts +1 -0
- package/app/layout.tsx +20 -0
- package/app/page.tsx +82 -0
- package/bin/studio.mjs +110 -0
- package/dist/handlers/index.js +84 -63
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/index.mjs +135 -114
- package/dist/handlers/index.mjs.map +1 -1
- package/dist/index.d.mts +14 -10
- package/dist/index.d.ts +14 -10
- package/dist/index.js +2 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -179
- package/dist/index.mjs.map +1 -1
- package/next.config.mjs +22 -0
- package/package.json +18 -10
- package/src/components/AddNewModal.tsx +402 -0
- package/src/components/ErrorModal.tsx +89 -0
- package/src/components/R2SetupModal.tsx +400 -0
- package/src/components/StudioBreadcrumb.tsx +115 -0
- package/src/components/StudioButton.tsx +200 -0
- package/src/components/StudioContext.tsx +219 -0
- package/src/components/StudioDetailView.tsx +714 -0
- package/src/components/StudioFileGrid.tsx +704 -0
- package/src/components/StudioFileList.tsx +743 -0
- package/src/components/StudioFolderPicker.tsx +342 -0
- package/src/components/StudioModal.tsx +473 -0
- package/src/components/StudioPreview.tsx +399 -0
- package/src/components/StudioSettings.tsx +536 -0
- package/src/components/StudioToolbar.tsx +1448 -0
- package/src/components/StudioUI.tsx +731 -0
- package/src/components/styles/common.ts +236 -0
- package/src/components/tokens.ts +78 -0
- package/src/components/useStudioActions.tsx +497 -0
- package/src/config/index.ts +7 -0
- package/src/config/workspace.ts +52 -0
- package/src/handlers/favicon.ts +152 -0
- package/src/handlers/files.ts +784 -0
- package/src/handlers/images.ts +949 -0
- package/src/handlers/import.ts +190 -0
- package/src/handlers/index.ts +168 -0
- package/src/handlers/list.ts +627 -0
- package/src/handlers/scan.ts +311 -0
- package/src/handlers/utils/cdn.ts +234 -0
- package/src/handlers/utils/files.ts +64 -0
- package/src/handlers/utils/index.ts +4 -0
- package/src/handlers/utils/meta.ts +102 -0
- package/src/handlers/utils/thumbnails.ts +98 -0
- package/src/hooks/useFileList.ts +143 -0
- package/src/index.tsx +36 -0
- package/src/lib/api.ts +176 -0
- package/src/types.ts +119 -0
- package/dist/StudioUI-GJK45R3T.js +0 -6500
- package/dist/StudioUI-GJK45R3T.js.map +0 -1
- package/dist/StudioUI-QZ54STXE.mjs +0 -6500
- package/dist/StudioUI-QZ54STXE.mjs.map +0 -1
- package/dist/chunk-N6JYTJCB.js +0 -68
- package/dist/chunk-N6JYTJCB.js.map +0 -1
- package/dist/chunk-RHI3UROE.mjs +0 -68
- package/dist/chunk-RHI3UROE.mjs.map +0 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { css, keyframes } from '@emotion/react'
|
|
2
|
+
import { colors, fontSize } from '../tokens'
|
|
3
|
+
|
|
4
|
+
// Common keyframes
|
|
5
|
+
export const spin = keyframes`
|
|
6
|
+
to { transform: rotate(360deg); }
|
|
7
|
+
`
|
|
8
|
+
|
|
9
|
+
// Loading states
|
|
10
|
+
export const loadingStyles = {
|
|
11
|
+
container: css`
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
height: 256px;
|
|
16
|
+
`,
|
|
17
|
+
spinner: css`
|
|
18
|
+
width: 32px;
|
|
19
|
+
height: 32px;
|
|
20
|
+
border-radius: 50%;
|
|
21
|
+
border: 3px solid ${colors.border};
|
|
22
|
+
border-top-color: ${colors.primary};
|
|
23
|
+
animation: ${spin} 0.8s linear infinite;
|
|
24
|
+
`,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Empty states
|
|
28
|
+
export const emptyStyles = {
|
|
29
|
+
container: css`
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
height: 256px;
|
|
35
|
+
color: ${colors.textSecondary};
|
|
36
|
+
`,
|
|
37
|
+
icon: css`
|
|
38
|
+
width: 48px;
|
|
39
|
+
height: 48px;
|
|
40
|
+
margin-bottom: 16px;
|
|
41
|
+
opacity: 0.5;
|
|
42
|
+
`,
|
|
43
|
+
text: css`
|
|
44
|
+
font-size: ${fontSize.base};
|
|
45
|
+
margin: 0 0 4px 0;
|
|
46
|
+
|
|
47
|
+
&:last-child {
|
|
48
|
+
color: ${colors.textMuted};
|
|
49
|
+
font-size: ${fontSize.sm};
|
|
50
|
+
}
|
|
51
|
+
`,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Buttons
|
|
55
|
+
export const buttonStyles = {
|
|
56
|
+
base: css`
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: 6px;
|
|
60
|
+
padding: 8px 12px;
|
|
61
|
+
border-radius: 6px;
|
|
62
|
+
font-size: ${fontSize.sm};
|
|
63
|
+
font-weight: 500;
|
|
64
|
+
border: 1px solid ${colors.border};
|
|
65
|
+
background: ${colors.surface};
|
|
66
|
+
color: ${colors.text};
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
transition: all 0.15s ease;
|
|
69
|
+
white-space: nowrap;
|
|
70
|
+
|
|
71
|
+
&:hover:not(:disabled) {
|
|
72
|
+
background: ${colors.surfaceHover};
|
|
73
|
+
border-color: #d0d5dd;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&:disabled {
|
|
77
|
+
opacity: 0.5;
|
|
78
|
+
cursor: not-allowed;
|
|
79
|
+
}
|
|
80
|
+
`,
|
|
81
|
+
primary: css`
|
|
82
|
+
background: ${colors.primary};
|
|
83
|
+
border-color: ${colors.primary};
|
|
84
|
+
color: white;
|
|
85
|
+
|
|
86
|
+
&:hover:not(:disabled) {
|
|
87
|
+
background: ${colors.primaryHover};
|
|
88
|
+
border-color: ${colors.primaryHover};
|
|
89
|
+
}
|
|
90
|
+
`,
|
|
91
|
+
danger: css`
|
|
92
|
+
color: ${colors.danger};
|
|
93
|
+
|
|
94
|
+
&:hover:not(:disabled) {
|
|
95
|
+
background: ${colors.dangerLight};
|
|
96
|
+
border-color: ${colors.dangerLight};
|
|
97
|
+
}
|
|
98
|
+
`,
|
|
99
|
+
icon: css`
|
|
100
|
+
width: 16px;
|
|
101
|
+
height: 16px;
|
|
102
|
+
flex-shrink: 0;
|
|
103
|
+
`,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Checkboxes
|
|
107
|
+
export const checkboxStyles = {
|
|
108
|
+
checkbox: css`
|
|
109
|
+
width: 16px;
|
|
110
|
+
height: 16px;
|
|
111
|
+
accent-color: ${colors.primary};
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
`,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Copy button with tooltip
|
|
117
|
+
export const copyButtonStyles = {
|
|
118
|
+
button: css`
|
|
119
|
+
height: 28px;
|
|
120
|
+
width: 28px;
|
|
121
|
+
color: ${colors.textMuted};
|
|
122
|
+
background: transparent;
|
|
123
|
+
border: none;
|
|
124
|
+
padding: 0;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
border-radius: 4px;
|
|
127
|
+
transition: all 0.15s ease;
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
position: relative;
|
|
132
|
+
|
|
133
|
+
&:hover {
|
|
134
|
+
color: ${colors.text};
|
|
135
|
+
}
|
|
136
|
+
`,
|
|
137
|
+
icon: css`
|
|
138
|
+
width: 18px;
|
|
139
|
+
height: 18px;
|
|
140
|
+
`,
|
|
141
|
+
tooltip: css`
|
|
142
|
+
position: absolute;
|
|
143
|
+
top: 50%;
|
|
144
|
+
right: 100%;
|
|
145
|
+
transform: translateY(-50%);
|
|
146
|
+
background: #1a1f36;
|
|
147
|
+
color: white;
|
|
148
|
+
padding: 4px 8px;
|
|
149
|
+
border-radius: 4px;
|
|
150
|
+
font-size: 12px;
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
margin-right: 6px;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
z-index: 100;
|
|
155
|
+
|
|
156
|
+
&::before {
|
|
157
|
+
content: '';
|
|
158
|
+
position: absolute;
|
|
159
|
+
right: -4px;
|
|
160
|
+
top: 50%;
|
|
161
|
+
transform: translateY(-50%);
|
|
162
|
+
border-left: 4px solid #1a1f36;
|
|
163
|
+
border-top: 4px solid transparent;
|
|
164
|
+
border-bottom: 4px solid transparent;
|
|
165
|
+
}
|
|
166
|
+
`,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// CDN badge
|
|
170
|
+
export const cdnBadgeStyles = {
|
|
171
|
+
badge: css`
|
|
172
|
+
display: inline-flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
gap: 4px;
|
|
175
|
+
padding: 2px 6px;
|
|
176
|
+
border-radius: 4px;
|
|
177
|
+
font-size: ${fontSize.xs};
|
|
178
|
+
font-weight: 500;
|
|
179
|
+
background: ${colors.successLight};
|
|
180
|
+
color: ${colors.success};
|
|
181
|
+
`,
|
|
182
|
+
icon: css`
|
|
183
|
+
width: 12px;
|
|
184
|
+
height: 12px;
|
|
185
|
+
`,
|
|
186
|
+
empty: css`
|
|
187
|
+
color: ${colors.textMuted};
|
|
188
|
+
font-size: ${fontSize.sm};
|
|
189
|
+
`,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Folder icons
|
|
193
|
+
export const folderIconStyles = {
|
|
194
|
+
folder: css`
|
|
195
|
+
width: 48px;
|
|
196
|
+
height: 48px;
|
|
197
|
+
color: ${colors.folder};
|
|
198
|
+
`,
|
|
199
|
+
imagesFolder: css`
|
|
200
|
+
width: 48px;
|
|
201
|
+
height: 48px;
|
|
202
|
+
color: ${colors.imagesFolder};
|
|
203
|
+
`,
|
|
204
|
+
lock: css`
|
|
205
|
+
width: 16px;
|
|
206
|
+
height: 16px;
|
|
207
|
+
position: absolute;
|
|
208
|
+
bottom: 0;
|
|
209
|
+
right: 0;
|
|
210
|
+
color: ${colors.imagesFolder};
|
|
211
|
+
`,
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Select all row
|
|
215
|
+
export const selectAllStyles = {
|
|
216
|
+
row: css`
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
gap: 8px;
|
|
220
|
+
padding: 8px 0;
|
|
221
|
+
margin-bottom: 8px;
|
|
222
|
+
border-bottom: 1px solid ${colors.border};
|
|
223
|
+
`,
|
|
224
|
+
label: css`
|
|
225
|
+
display: flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
gap: 8px;
|
|
228
|
+
font-size: ${fontSize.sm};
|
|
229
|
+
color: ${colors.textSecondary};
|
|
230
|
+
cursor: pointer;
|
|
231
|
+
|
|
232
|
+
&:hover {
|
|
233
|
+
color: ${colors.text};
|
|
234
|
+
}
|
|
235
|
+
`,
|
|
236
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { css } from '@emotion/react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stripe-inspired design tokens for Studio
|
|
5
|
+
* These are self-contained and agnostic of any parent template styling
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Base font stack - system fonts that work everywhere
|
|
9
|
+
export const fontStack = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif`
|
|
10
|
+
|
|
11
|
+
// Color palette
|
|
12
|
+
export const colors = {
|
|
13
|
+
// Primary brand
|
|
14
|
+
primary: '#635bff',
|
|
15
|
+
primaryHover: '#5851e5',
|
|
16
|
+
primaryLight: '#f0f0ff',
|
|
17
|
+
|
|
18
|
+
// Backgrounds
|
|
19
|
+
background: '#f6f9fc',
|
|
20
|
+
surface: '#ffffff',
|
|
21
|
+
surfaceHover: '#f6f9fc',
|
|
22
|
+
|
|
23
|
+
// Borders
|
|
24
|
+
border: '#d8dee4',
|
|
25
|
+
borderLight: '#e3e8ee',
|
|
26
|
+
borderHover: '#c1c9d2',
|
|
27
|
+
|
|
28
|
+
// Text
|
|
29
|
+
text: '#1a1f36',
|
|
30
|
+
textSecondary: '#697386',
|
|
31
|
+
textMuted: '#8792a2',
|
|
32
|
+
|
|
33
|
+
// Status
|
|
34
|
+
success: '#0d7d4d',
|
|
35
|
+
successLight: '#e6f7ef',
|
|
36
|
+
danger: '#df1b41',
|
|
37
|
+
dangerHover: '#c41535',
|
|
38
|
+
dangerLight: '#fff5f7',
|
|
39
|
+
|
|
40
|
+
// Shadows
|
|
41
|
+
shadow: 'rgba(50, 50, 93, 0.1)',
|
|
42
|
+
shadowDark: 'rgba(50, 50, 93, 0.2)',
|
|
43
|
+
|
|
44
|
+
// Special folders
|
|
45
|
+
folder: '#64748b',
|
|
46
|
+
imagesFolder: '#8b5cf6',
|
|
47
|
+
imagesFolderLight: '#f3f0ff',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Font sizes - slightly larger for better readability
|
|
51
|
+
export const fontSize = {
|
|
52
|
+
xs: '13px',
|
|
53
|
+
sm: '14px',
|
|
54
|
+
base: '16px',
|
|
55
|
+
md: '17px',
|
|
56
|
+
lg: '19px',
|
|
57
|
+
xl: '22px',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Base reset styles for Studio container - isolates from parent template
|
|
61
|
+
export const baseReset = css`
|
|
62
|
+
font-family: ${fontStack};
|
|
63
|
+
font-size: ${fontSize.base};
|
|
64
|
+
line-height: 1.5;
|
|
65
|
+
color: ${colors.text};
|
|
66
|
+
-webkit-font-smoothing: antialiased;
|
|
67
|
+
-moz-osx-font-smoothing: grayscale;
|
|
68
|
+
box-sizing: border-box;
|
|
69
|
+
|
|
70
|
+
*, *::before, *::after {
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
button, input, select, textarea {
|
|
75
|
+
font-family: inherit;
|
|
76
|
+
font-size: inherit;
|
|
77
|
+
}
|
|
78
|
+
`
|