mjpic 1.0.21 → 1.0.23

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.
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <meta name="description" content="敏捷图片(mjpic)是一个轻量级网页版图片处理工具,设计灵感来源于光影魔术手。" />
8
8
  <title>敏捷图片 (mjpic) - 轻量级网页版图片处理工具</title>
9
- <script type="module" crossorigin src="/assets/index-DORSlWYO.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-Cy470xj2.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="/assets/index-C6nMBMvY.css">
11
11
  </head>
12
12
  <body>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mjpic",
3
3
  "description": "敏捷图片(mjpic)是一个轻量级网页版图片处理工具,设计灵感来源于光影魔术手。",
4
- "version": "1.0.21",
4
+ "version": "1.0.23",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mjpic": "dist/cli/cli.js"
package/src/App.tsx CHANGED
@@ -1,9 +1,10 @@
1
1
  import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
2
2
  import Home from "@/pages/Home";
3
+ import { getRouterBasename } from "@/lib/runtime";
3
4
 
4
5
  export default function App() {
5
6
  return (
6
- <Router>
7
+ <Router basename={getRouterBasename()}>
7
8
  <Routes>
8
9
  <Route path="/" element={<Home />} />
9
10
  <Route path="/other" element={<div className="text-center text-xl">Other Page - Coming Soon</div>} />
@@ -4,6 +4,7 @@ import { FolderOpen, Save, Undo, Redo, Languages } from 'lucide-react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import Konva from 'konva';
6
6
  import { SaveDialog } from '@/components/dialogs/SaveDialog';
7
+ import { apiUrl } from '@/lib/runtime';
7
8
 
8
9
  interface HeaderProps {
9
10
  stageRef: React.MutableRefObject<Konva.Stage | null>;
@@ -146,7 +147,7 @@ export const Header = ({ stageRef }: HeaderProps) => {
146
147
 
147
148
  // Try to get current image path for CLI mode
148
149
  try {
149
- const response = await fetch('/api/current-image');
150
+ const response = await fetch(apiUrl('api/current-image'));
150
151
  const imageData = response.ok ? await response.json() : null;
151
152
  if (imageData && imageData.path) {
152
153
  setCurrentPath(imageData.path);
@@ -272,7 +273,7 @@ export const Header = ({ stageRef }: HeaderProps) => {
272
273
  // If savePath is provided (from dialog), use it
273
274
  if (savePath) {
274
275
  // CLI Mode: Save to specific path
275
- const saveRes = await fetch('/api/image/save', {
276
+ const saveRes = await fetch(apiUrl('api/image/save'), {
276
277
  method: 'POST',
277
278
  headers: { 'Content-Type': 'application/json' },
278
279
  body: JSON.stringify({ data: dataUrl, filePath: savePath })
@@ -0,0 +1,31 @@
1
+ const ABSOLUTE_URL_RE = /^[a-z]+:/i;
2
+
3
+ export const normalizeBasePath = (value?: string): string => {
4
+ const raw = (value || '/').trim();
5
+ if (!raw || raw === '/') return '/';
6
+
7
+ const stripped = raw.replace(/^\/+|\/+$/g, '');
8
+ return stripped ? `/${stripped}/` : '/';
9
+ };
10
+
11
+ export const getRouterBasename = (): string | undefined => {
12
+ const base = normalizeBasePath(import.meta.env.BASE_URL);
13
+ return base === '/' ? undefined : base.replace(/\/$/, '');
14
+ };
15
+
16
+ export const withBasePath = (path: string, base = import.meta.env.BASE_URL): string => {
17
+ if (!path) return normalizeBasePath(base);
18
+ if (ABSOLUTE_URL_RE.test(path) || path.startsWith('//') || path.startsWith('data:')) {
19
+ return path;
20
+ }
21
+
22
+ const normalizedBase = normalizeBasePath(base);
23
+ const normalizedPath = path.replace(/^\/+/, '');
24
+
25
+ return normalizedBase === '/' ? `/${normalizedPath}` : `${normalizedBase}${normalizedPath}`;
26
+ };
27
+
28
+ export const apiUrl = (path: string): string => {
29
+ const apiBase = import.meta.env.VITE_API_BASE || import.meta.env.BASE_URL;
30
+ return withBasePath(path, apiBase);
31
+ };
@@ -5,6 +5,7 @@ import { Sidebar } from '@/components/layout/Sidebar';
5
5
  import { CanvasArea } from '@/components/layout/CanvasArea';
6
6
  import { RightPanel } from '@/components/layout/RightPanel';
7
7
  import { StatusBar } from '@/components/layout/StatusBar';
8
+ import { apiUrl } from '@/lib/runtime';
8
9
  import Konva from 'konva';
9
10
 
10
11
  export default function Home() {
@@ -36,7 +37,7 @@ export default function Home() {
36
37
  };
37
38
 
38
39
  useEffect(() => {
39
- fetch('/api/current-image')
40
+ fetch(apiUrl('api/current-image'))
40
41
  .then(res => {
41
42
  if (res.ok) return res.json();
42
43
  throw new Error('No image');
@@ -46,7 +47,7 @@ export default function Home() {
46
47
  // Extract filename from path
47
48
  // Handle both Windows (\) and Unix (/) paths
48
49
  const name = data.path.split(/[/\\]/).pop();
49
- loadImage('/api/image-content', name, data.path);
50
+ loadImage(apiUrl('api/image-content'), name, data.path);
50
51
  }
51
52
  })
52
53
  .catch(() => {
package/vite.config.ts CHANGED
@@ -2,8 +2,17 @@ import { defineConfig } from 'vite'
2
2
  import react from '@vitejs/plugin-react'
3
3
  import tsconfigPaths from "vite-tsconfig-paths";
4
4
 
5
+ const normalizeBasePath = (value?: string) => {
6
+ const raw = (value || '/').trim();
7
+ if (!raw || raw === '/') return '/';
8
+
9
+ const stripped = raw.replace(/^\/+|\/+$/g, '');
10
+ return stripped ? `/${stripped}/` : '/';
11
+ };
12
+
5
13
  // https://vite.dev/config/
6
14
  export default defineConfig({
15
+ base: normalizeBasePath(process.env.VITE_BASE_PATH),
7
16
  plugins: [
8
17
  react({
9
18
  babel: {