@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 @@
|
|
|
1
|
+
export { GET, POST, DELETE } from '../../../../src/handlers'
|
package/app/layout.tsx
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Metadata } from 'next'
|
|
2
|
+
|
|
3
|
+
export const metadata: Metadata = {
|
|
4
|
+
title: 'Studio - Media Manager',
|
|
5
|
+
description: 'Manage images and media files for your project',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function RootLayout({
|
|
9
|
+
children,
|
|
10
|
+
}: {
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<html lang="en">
|
|
15
|
+
<body style={{ margin: 0, padding: 0 }}>
|
|
16
|
+
{children}
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
19
|
+
)
|
|
20
|
+
}
|
package/app/page.tsx
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import dynamic from 'next/dynamic'
|
|
4
|
+
import { css } from '@emotion/react'
|
|
5
|
+
import { colors, fontStack } from '../src/components/tokens'
|
|
6
|
+
|
|
7
|
+
// Dynamically import StudioUI to avoid SSR issues with Emotion
|
|
8
|
+
const StudioUI = dynamic(() => import('../src/components/StudioUI'), {
|
|
9
|
+
ssr: false,
|
|
10
|
+
loading: () => <LoadingState />,
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const styles = {
|
|
14
|
+
container: css`
|
|
15
|
+
position: fixed;
|
|
16
|
+
top: 0;
|
|
17
|
+
left: 0;
|
|
18
|
+
right: 0;
|
|
19
|
+
bottom: 0;
|
|
20
|
+
background: ${colors.background};
|
|
21
|
+
font-family: ${fontStack};
|
|
22
|
+
`,
|
|
23
|
+
loading: css`
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
height: 100vh;
|
|
28
|
+
background: ${colors.background};
|
|
29
|
+
font-family: ${fontStack};
|
|
30
|
+
`,
|
|
31
|
+
loadingContent: css`
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: 16px;
|
|
36
|
+
`,
|
|
37
|
+
spinner: css`
|
|
38
|
+
width: 36px;
|
|
39
|
+
height: 36px;
|
|
40
|
+
border-radius: 50%;
|
|
41
|
+
border: 3px solid ${colors.border};
|
|
42
|
+
border-top-color: ${colors.primary};
|
|
43
|
+
animation: spin 0.8s linear infinite;
|
|
44
|
+
|
|
45
|
+
@keyframes spin {
|
|
46
|
+
to {
|
|
47
|
+
transform: rotate(360deg);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`,
|
|
51
|
+
loadingText: css`
|
|
52
|
+
color: ${colors.textSecondary};
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
margin: 0;
|
|
56
|
+
`,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function LoadingState() {
|
|
60
|
+
return (
|
|
61
|
+
<div css={styles.loading}>
|
|
62
|
+
<div css={styles.loadingContent}>
|
|
63
|
+
<div css={styles.spinner} />
|
|
64
|
+
<p css={styles.loadingText}>Loading Studio...</p>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default function StudioPage() {
|
|
71
|
+
const workspace = process.env.NEXT_PUBLIC_STUDIO_WORKSPACE || 'Unknown'
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div css={styles.container}>
|
|
75
|
+
<StudioUI
|
|
76
|
+
isVisible={true}
|
|
77
|
+
standaloneMode={true}
|
|
78
|
+
workspacePath={workspace}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
package/bin/studio.mjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'child_process'
|
|
4
|
+
import { resolve, dirname } from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import { existsSync } from 'fs'
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = dirname(__filename)
|
|
10
|
+
|
|
11
|
+
// Parse command line arguments
|
|
12
|
+
const args = process.argv.slice(2)
|
|
13
|
+
let workspace = process.cwd()
|
|
14
|
+
let shouldOpen = false
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < args.length; i++) {
|
|
17
|
+
if (args[i] === '--workspace' && args[i + 1]) {
|
|
18
|
+
workspace = resolve(args[i + 1])
|
|
19
|
+
i++
|
|
20
|
+
} else if (args[i] === '--open' || args[i] === '-o') {
|
|
21
|
+
shouldOpen = true
|
|
22
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
23
|
+
console.log(`
|
|
24
|
+
Studio - Media Manager
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
studio [options]
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--workspace <path> Path to the project workspace (default: current directory)
|
|
31
|
+
--open, -o Open browser automatically
|
|
32
|
+
--help, -h Show this help message
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
studio # Run in current directory
|
|
36
|
+
studio --workspace ~/my-project # Run for specific project
|
|
37
|
+
studio --workspace . --open # Open browser automatically
|
|
38
|
+
`)
|
|
39
|
+
process.exit(0)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Validate workspace exists
|
|
44
|
+
if (!existsSync(workspace)) {
|
|
45
|
+
console.error(`Error: Workspace path does not exist: ${workspace}`)
|
|
46
|
+
process.exit(1)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check for public folder
|
|
50
|
+
const publicPath = resolve(workspace, 'public')
|
|
51
|
+
if (!existsSync(publicPath)) {
|
|
52
|
+
console.error(`Error: No 'public' folder found in workspace: ${workspace}`)
|
|
53
|
+
console.error('Studio requires a public folder to manage media files.')
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(`
|
|
58
|
+
┌─────────────────────────────────────┐
|
|
59
|
+
│ Studio - Media Manager │
|
|
60
|
+
├─────────────────────────────────────┤
|
|
61
|
+
│ Workspace: ${workspace.length > 24 ? '...' + workspace.slice(-21) : workspace.padEnd(24)}│
|
|
62
|
+
│ URL: http://localhost:3001 │
|
|
63
|
+
└─────────────────────────────────────┘
|
|
64
|
+
`)
|
|
65
|
+
|
|
66
|
+
// Find the next binary
|
|
67
|
+
const studioRoot = resolve(__dirname, '..')
|
|
68
|
+
const nextBin = resolve(studioRoot, 'node_modules', '.bin', 'next')
|
|
69
|
+
|
|
70
|
+
if (!existsSync(nextBin)) {
|
|
71
|
+
console.error('Error: Next.js not found. Please run: npm install')
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Set up environment
|
|
76
|
+
const env = {
|
|
77
|
+
...process.env,
|
|
78
|
+
STUDIO_WORKSPACE: workspace,
|
|
79
|
+
NODE_ENV: 'development',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Start Next.js dev server
|
|
83
|
+
const child = spawn(nextBin, ['dev', '-p', '3001'], {
|
|
84
|
+
stdio: 'inherit',
|
|
85
|
+
cwd: studioRoot,
|
|
86
|
+
env,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// Open browser if requested
|
|
90
|
+
if (shouldOpen) {
|
|
91
|
+
setTimeout(async () => {
|
|
92
|
+
const open = (await import('open')).default
|
|
93
|
+
open('http://localhost:3001')
|
|
94
|
+
}, 2000)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Handle process termination
|
|
98
|
+
process.on('SIGINT', () => {
|
|
99
|
+
child.kill('SIGINT')
|
|
100
|
+
process.exit(0)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
process.on('SIGTERM', () => {
|
|
104
|
+
child.kill('SIGTERM')
|
|
105
|
+
process.exit(0)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
child.on('close', (code) => {
|
|
109
|
+
process.exit(code || 0)
|
|
110
|
+
})
|