mjpic 1.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/.trae/documents/mjpic-prd.md +111 -0
- package/.trae/documents/mjpic-technical-architecture.md +234 -0
- package/README.md +57 -0
- package/api/app.ts +60 -0
- package/api/cli.ts +61 -0
- package/api/index.ts +19 -0
- package/api/routes/auth.ts +33 -0
- package/api/routes/image.ts +27 -0
- package/api/server.ts +45 -0
- package/dist/cli/app.js +43 -0
- package/dist/cli/cli.js +49 -0
- package/dist/cli/index.js +13 -0
- package/dist/cli/routes/auth.js +28 -0
- package/dist/cli/routes/image.js +21 -0
- package/dist/cli/server.js +38 -0
- package/dist/client/assets/index-BUIYLOn-.js +197 -0
- package/dist/client/assets/index-BoiS81Ei.css +1 -0
- package/dist/client/favicon.svg +4 -0
- package/dist/client/index.html +354 -0
- package/eslint.config.js +28 -0
- package/index.html +24 -0
- package/nodemon.json +10 -0
- package/package.json +68 -0
- package/postcss.config.js +10 -0
- package/public/favicon.svg +4 -0
- package/src/App.tsx +13 -0
- package/src/assets/react.svg +1 -0
- package/src/components/Empty.tsx +8 -0
- package/src/components/dialogs/AspectRatioDialog.tsx +218 -0
- package/src/components/dialogs/SaveDialog.tsx +150 -0
- package/src/components/layout/CanvasArea.tsx +874 -0
- package/src/components/layout/Header.tsx +156 -0
- package/src/components/layout/RightPanel.tsx +886 -0
- package/src/components/layout/Sidebar.tsx +36 -0
- package/src/components/layout/StatusBar.tsx +44 -0
- package/src/hooks/useDebounce.ts +17 -0
- package/src/hooks/useTheme.ts +29 -0
- package/src/i18n/index.ts +26 -0
- package/src/i18n/locales/en.json +56 -0
- package/src/i18n/locales/zh.json +59 -0
- package/src/index.css +14 -0
- package/src/lib/utils.ts +73 -0
- package/src/main.tsx +11 -0
- package/src/pages/Home.tsx +72 -0
- package/src/store/useImageStore.ts +316 -0
- package/src/store/usePresetStore.ts +65 -0
- package/src/store/useUIStore.ts +17 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.js +13 -0
- package/tmp/guangxi.jpg +0 -0
- package/tsconfig.json +40 -0
- package/tsconfig.server.json +15 -0
- package/vercel.json +12 -0
- package/vite.config.ts +50 -0
- package//345/217/202/350/200/203/345/233/276/347/211/207//346/210/252/345/261/2172026-02-18 16.47.45_/345/233/276/347/211/207/345/260/272/345/257/270/350/260/203/350/212/202_/351/242/204/350/256/276/345/260/272/345/257/270.jpg +0 -0
- package//345/217/202/350/200/203/345/233/276/347/211/207//346/210/252/345/261/2172026-02-18 16.47.51_/345/233/276/347/211/207/345/260/272/345/257/270/350/260/203/350/212/202_/346/211/213/345/267/245/350/276/223/345/205/245/345/260/272/345/257/270.jpg +0 -0
- package//345/217/202/350/200/203/345/233/276/347/211/207//346/210/252/345/261/2172026-02-18 16.54.56_/345/233/276/347/211/207/345/260/272/345/257/270/350/260/203/350/212/202_/346/267/273/345/212/240/345/270/270/347/224/250/345/260/272/345/257/270.jpg +0 -0
- package//345/217/202/350/200/203/345/233/276/347/211/207//346/210/252/345/261/2172026-02-18 16.55.11_/345/233/276/347/211/207/345/260/272/345/257/270/350/260/203/350/212/202_/345/210/240/351/231/244/345/270/270/347/224/250/345/260/272/345/257/270.jpg +0 -0
package/dist/cli/cli.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import open from 'open';
|
|
7
|
+
import app from './app.js';
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const program = new Command();
|
|
11
|
+
program
|
|
12
|
+
.name('mjpic')
|
|
13
|
+
.description('Agile Image Processing Tool')
|
|
14
|
+
.version('1.0.0')
|
|
15
|
+
.option('-p, --port <number>', 'server port', '3000')
|
|
16
|
+
.option('--host <string>', 'server host', 'localhost')
|
|
17
|
+
.argument('[file]', 'image file to open')
|
|
18
|
+
.action(async (file, options) => {
|
|
19
|
+
const port = parseInt(options.port, 10);
|
|
20
|
+
const host = options.host;
|
|
21
|
+
if (file) {
|
|
22
|
+
const absPath = path.resolve(file);
|
|
23
|
+
console.log(`Opening file: ${absPath}`);
|
|
24
|
+
app.get('/api/current-image', (req, res) => {
|
|
25
|
+
res.json({ path: absPath });
|
|
26
|
+
});
|
|
27
|
+
app.get('/api/image-content', (req, res) => {
|
|
28
|
+
res.sendFile(absPath);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// Serve static files
|
|
32
|
+
// In production (dist), client is in ../client
|
|
33
|
+
const clientPath = path.join(__dirname, '../client');
|
|
34
|
+
app.use(express.static(clientPath));
|
|
35
|
+
// API 404 handler - Ensure API requests don't fall through to index.html
|
|
36
|
+
app.use('/api/*', (req, res) => {
|
|
37
|
+
res.status(404).json({ success: false, error: 'API not found' });
|
|
38
|
+
});
|
|
39
|
+
// SPA fallback
|
|
40
|
+
app.get('*', (req, res) => {
|
|
41
|
+
res.sendFile(path.join(clientPath, 'index.html'));
|
|
42
|
+
});
|
|
43
|
+
app.listen(port, host, () => {
|
|
44
|
+
const url = `http://${host}:${port}`;
|
|
45
|
+
console.log(`mjpic is running at ${url}`);
|
|
46
|
+
open(url);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
program.parse();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a user authentication API route demo.
|
|
3
|
+
* Handle user registration, login, token management, etc.
|
|
4
|
+
*/
|
|
5
|
+
import { Router } from 'express';
|
|
6
|
+
const router = Router();
|
|
7
|
+
/**
|
|
8
|
+
* User Login
|
|
9
|
+
* POST /api/auth/register
|
|
10
|
+
*/
|
|
11
|
+
router.post('/register', async (req, res) => {
|
|
12
|
+
// TODO: Implement register logic
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* User Login
|
|
16
|
+
* POST /api/auth/login
|
|
17
|
+
*/
|
|
18
|
+
router.post('/login', async (req, res) => {
|
|
19
|
+
// TODO: Implement login logic
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* User Logout
|
|
23
|
+
* POST /api/auth/logout
|
|
24
|
+
*/
|
|
25
|
+
router.post('/logout', async (req, res) => {
|
|
26
|
+
// TODO: Implement logout logic
|
|
27
|
+
});
|
|
28
|
+
export default router;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
const router = Router();
|
|
4
|
+
router.post('/save', async (req, res) => {
|
|
5
|
+
try {
|
|
6
|
+
const { filePath, data } = req.body;
|
|
7
|
+
if (!filePath || !data) {
|
|
8
|
+
return res.status(400).json({ success: false, error: 'Missing filePath or data' });
|
|
9
|
+
}
|
|
10
|
+
// data is data:image/png;base64,....
|
|
11
|
+
const base64Data = data.replace(/^data:image\/\w+;base64,/, "");
|
|
12
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
13
|
+
await fs.writeFile(filePath, buffer);
|
|
14
|
+
res.json({ success: true });
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error('Save error:', error);
|
|
18
|
+
res.status(500).json({ success: false, error: 'Failed to save file' });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
export default router;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* local server entry file, for local development
|
|
3
|
+
*/
|
|
4
|
+
import app from './app.js';
|
|
5
|
+
/**
|
|
6
|
+
* 404 handler
|
|
7
|
+
*/
|
|
8
|
+
app.use((req, res) => {
|
|
9
|
+
res.status(404).json({
|
|
10
|
+
success: false,
|
|
11
|
+
error: 'API not found',
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* start server with port
|
|
16
|
+
*/
|
|
17
|
+
const PORT = process.env.PORT || 3002;
|
|
18
|
+
const server = app.listen(PORT, () => {
|
|
19
|
+
console.log(`Server ready on port ${PORT}`);
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* close server
|
|
23
|
+
*/
|
|
24
|
+
process.on('SIGTERM', () => {
|
|
25
|
+
console.log('SIGTERM signal received');
|
|
26
|
+
server.close(() => {
|
|
27
|
+
console.log('Server closed');
|
|
28
|
+
process.exit(0);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
process.on('SIGINT', () => {
|
|
32
|
+
console.log('SIGINT signal received');
|
|
33
|
+
server.close(() => {
|
|
34
|
+
console.log('Server closed');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
export default app;
|