@lokvis/ui-react 0.1.1-beta.0 → 0.2.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/LICENSE +21 -0
- package/dist/components/AssetPanel.d.ts +2 -2
- package/dist/components/AssetPanel.d.ts.map +1 -1
- package/dist/components/AssetPanel.js +79 -7
- package/dist/components/AssetPanel.js.map +1 -1
- package/dist/components/Canvas.d.ts +9 -1
- package/dist/components/Canvas.d.ts.map +1 -1
- package/dist/components/Canvas.js +39 -2
- package/dist/components/Canvas.js.map +1 -1
- package/dist/components/CommandPalette.d.ts +48 -0
- package/dist/components/CommandPalette.d.ts.map +1 -0
- package/dist/components/CommandPalette.js +154 -0
- package/dist/components/CommandPalette.js.map +1 -0
- package/dist/components/CompareSlider.d.ts +25 -0
- package/dist/components/CompareSlider.d.ts.map +1 -0
- package/dist/components/CompareSlider.js +106 -0
- package/dist/components/CompareSlider.js.map +1 -0
- package/dist/components/DownloadPanel.d.ts +20 -0
- package/dist/components/DownloadPanel.d.ts.map +1 -0
- package/dist/components/DownloadPanel.js +169 -0
- package/dist/components/DownloadPanel.js.map +1 -0
- package/dist/components/ErrorBanner.d.ts +22 -0
- package/dist/components/ErrorBanner.d.ts.map +1 -0
- package/dist/components/ErrorBanner.js +47 -0
- package/dist/components/ErrorBanner.js.map +1 -0
- package/dist/components/ExifPanel.d.ts +26 -0
- package/dist/components/ExifPanel.d.ts.map +1 -0
- package/dist/components/ExifPanel.js +104 -0
- package/dist/components/ExifPanel.js.map +1 -0
- package/dist/components/GlobalDropzone.d.ts +37 -0
- package/dist/components/GlobalDropzone.d.ts.map +1 -0
- package/dist/components/GlobalDropzone.js +154 -0
- package/dist/components/GlobalDropzone.js.map +1 -0
- package/dist/components/HistoryPanel.d.ts +17 -7
- package/dist/components/HistoryPanel.d.ts.map +1 -1
- package/dist/components/HistoryPanel.js +74 -62
- package/dist/components/HistoryPanel.js.map +1 -1
- package/dist/components/Inspector.d.ts.map +1 -1
- package/dist/components/Inspector.js +2 -1
- package/dist/components/Inspector.js.map +1 -1
- package/dist/components/ProgressBar.d.ts +18 -0
- package/dist/components/ProgressBar.d.ts.map +1 -0
- package/dist/components/ProgressBar.js +35 -0
- package/dist/components/ProgressBar.js.map +1 -0
- package/dist/components/StatusBar.d.ts +8 -2
- package/dist/components/StatusBar.d.ts.map +1 -1
- package/dist/components/StatusBar.js +59 -4
- package/dist/components/StatusBar.js.map +1 -1
- package/dist/components/ThemeToggle.d.ts +20 -0
- package/dist/components/ThemeToggle.d.ts.map +1 -0
- package/dist/components/ThemeToggle.js +60 -0
- package/dist/components/ThemeToggle.js.map +1 -0
- package/dist/components/WorkflowEditor.d.ts +24 -0
- package/dist/components/WorkflowEditor.d.ts.map +1 -0
- package/dist/components/WorkflowEditor.js +160 -0
- package/dist/components/WorkflowEditor.js.map +1 -0
- package/dist/components/WorkflowTemplates.d.ts +23 -0
- package/dist/components/WorkflowTemplates.d.ts.map +1 -0
- package/dist/components/WorkflowTemplates.js +32 -0
- package/dist/components/WorkflowTemplates.js.map +1 -0
- package/dist/components/Workspace.d.ts +48 -2
- package/dist/components/Workspace.d.ts.map +1 -1
- package/dist/components/Workspace.js +78 -4
- package/dist/components/Workspace.js.map +1 -1
- package/dist/data/workflow-templates.d.ts +42 -0
- package/dist/data/workflow-templates.d.ts.map +1 -0
- package/dist/data/workflow-templates.js +112 -0
- package/dist/data/workflow-templates.js.map +1 -0
- package/dist/hooks/useDebouncedRun.d.ts +49 -0
- package/dist/hooks/useDebouncedRun.d.ts.map +1 -0
- package/dist/hooks/useDebouncedRun.js +117 -0
- package/dist/hooks/useDebouncedRun.js.map +1 -0
- package/dist/hooks/useLokvis.js +1 -1
- package/dist/hooks/useMediaQuery.d.ts +27 -0
- package/dist/hooks/useMediaQuery.d.ts.map +1 -0
- package/dist/hooks/useMediaQuery.js +41 -0
- package/dist/hooks/useMediaQuery.js.map +1 -0
- package/dist/hooks/useShareLink.d.ts +58 -0
- package/dist/hooks/useShareLink.d.ts.map +1 -0
- package/dist/hooks/useShareLink.js +120 -0
- package/dist/hooks/useShareLink.js.map +1 -0
- package/dist/hooks/useTheme.d.ts +30 -0
- package/dist/hooks/useTheme.d.ts.map +1 -0
- package/dist/hooks/useTheme.js +105 -0
- package/dist/hooks/useTheme.js.map +1 -0
- package/dist/hooks/useWorkflowProgress.d.ts +28 -0
- package/dist/hooks/useWorkflowProgress.d.ts.map +1 -0
- package/dist/hooks/useWorkflowProgress.js +25 -0
- package/dist/hooks/useWorkflowProgress.js.map +1 -0
- package/dist/hooks/useWorkflows.d.ts +86 -0
- package/dist/hooks/useWorkflows.d.ts.map +1 -0
- package/dist/hooks/useWorkflows.js +247 -0
- package/dist/hooks/useWorkflows.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/dist/store/assets-slice.d.ts.map +1 -1
- package/dist/store/assets-slice.js +2 -0
- package/dist/store/assets-slice.js.map +1 -1
- package/dist/store/history-slice.d.ts +18 -0
- package/dist/store/history-slice.d.ts.map +1 -0
- package/dist/store/history-slice.js +42 -0
- package/dist/store/history-slice.js.map +1 -0
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +3 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/runtime-slice.d.ts +10 -2
- package/dist/store/runtime-slice.d.ts.map +1 -1
- package/dist/store/runtime-slice.js +77 -28
- package/dist/store/runtime-slice.js.map +1 -1
- package/dist/store/types.d.ts +70 -1
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/types.js +10 -0
- package/dist/store/types.js.map +1 -1
- package/dist/store/workflow-slice.d.ts +1 -1
- package/dist/store/workflow-slice.d.ts.map +1 -1
- package/dist/store/workflow-slice.js +128 -9
- package/dist/store/workflow-slice.js.map +1 -1
- package/package.json +9 -6
- package/src/components/AssetPanel.tsx +149 -8
- package/src/components/Canvas.tsx +79 -2
- package/src/components/CommandPalette.tsx +300 -0
- package/src/components/CompareSlider.tsx +186 -0
- package/src/components/DownloadPanel.tsx +252 -0
- package/src/components/ErrorBanner.tsx +95 -0
- package/src/components/ExifPanel.tsx +187 -0
- package/src/components/GlobalDropzone.tsx +220 -0
- package/src/components/HistoryPanel.tsx +231 -104
- package/src/components/Inspector.tsx +4 -0
- package/src/components/ProgressBar.tsx +104 -0
- package/src/components/StatusBar.tsx +124 -5
- package/src/components/ThemeToggle.tsx +122 -0
- package/src/components/WorkflowEditor.tsx +382 -0
- package/src/components/WorkflowTemplates.tsx +101 -0
- package/src/components/Workspace.tsx +205 -8
- package/src/data/workflow-templates.ts +137 -0
- package/src/hooks/useDebouncedRun.ts +151 -0
- package/src/hooks/useLokvis.ts +1 -1
- package/src/hooks/useMediaQuery.ts +53 -0
- package/src/hooks/useShareLink.ts +158 -0
- package/src/hooks/useTheme.ts +116 -0
- package/src/hooks/useWorkflowProgress.ts +41 -0
- package/src/hooks/useWorkflows.ts +326 -0
- package/src/index.ts +32 -0
- package/src/store/assets-slice.ts +2 -0
- package/src/store/history-slice.ts +65 -0
- package/src/store/index.ts +3 -0
- package/src/store/runtime-slice.ts +89 -32
- package/src/store/types.ts +71 -1
- package/src/store/workflow-slice.ts +139 -10
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useShareLink - 分享链接生成与解析(W11.5)
|
|
3
|
+
*
|
|
4
|
+
* 把当前工作流节点序列编码为 base64 URL 参数,生成可分享的链接。
|
|
5
|
+
* 接收方打开链接即可还原工作流(本地 base64,无需 cloud 短链)。
|
|
6
|
+
*
|
|
7
|
+
* 编码格式:
|
|
8
|
+
* `<origin><pathname>?workflow=<base64url-encoded-json>`
|
|
9
|
+
*
|
|
10
|
+
* 其中 JSON 结构为 `{ v: 1, nodes: [{c, p}] }`(v=版本号,向前兼容)。
|
|
11
|
+
* 使用 base64url 编码(URL 安全,无 +/= 字符)。
|
|
12
|
+
*
|
|
13
|
+
* 注意:
|
|
14
|
+
* - base64 编码会膨胀约 33%,长工作流可能超过 URL 长度限制(浏览器 ~2KB 安全,~8KB 极限)
|
|
15
|
+
* - 5 步工作流通常远小于限制
|
|
16
|
+
* - 不包含 asset 引用(asset 是本地文件,无法跨设备分享)
|
|
17
|
+
*
|
|
18
|
+
* @module useShareLink
|
|
19
|
+
*/
|
|
20
|
+
import { useCallback } from 'react';
|
|
21
|
+
import { useWorkspaceStore } from '../store/index.js';
|
|
22
|
+
/** 标准 base64 → base64url(URL 安全: + → -, / → _, 去除 = 填充) */
|
|
23
|
+
function toBase64Url(b64) {
|
|
24
|
+
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
25
|
+
}
|
|
26
|
+
/** base64url → 标准 base64 */
|
|
27
|
+
function fromBase64Url(b64url) {
|
|
28
|
+
let b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
|
|
29
|
+
// 补齐 padding
|
|
30
|
+
const pad = b64.length % 4;
|
|
31
|
+
if (pad)
|
|
32
|
+
b64 += '='.repeat(4 - pad);
|
|
33
|
+
return b64;
|
|
34
|
+
}
|
|
35
|
+
/** UTF-8 安全的 base64 编码(处理非 ASCII 字符如中文水印) */
|
|
36
|
+
function encodeUtf8Base64Url(str) {
|
|
37
|
+
const bytes = new TextEncoder().encode(str);
|
|
38
|
+
let binary = '';
|
|
39
|
+
for (const byte of bytes) {
|
|
40
|
+
binary += String.fromCharCode(byte);
|
|
41
|
+
}
|
|
42
|
+
return toBase64Url(btoa(binary));
|
|
43
|
+
}
|
|
44
|
+
/** UTF-8 安全的 base64url 解码 */
|
|
45
|
+
function decodeUtf8Base64Url(b64url) {
|
|
46
|
+
const b64 = fromBase64Url(b64url);
|
|
47
|
+
const binary = atob(b64);
|
|
48
|
+
const bytes = new Uint8Array(binary.length);
|
|
49
|
+
for (let i = 0; i < binary.length; i++) {
|
|
50
|
+
bytes[i] = binary.charCodeAt(i);
|
|
51
|
+
}
|
|
52
|
+
return new TextDecoder().decode(bytes);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 编码工作流节点为 base64url 字符串(用于分享链接)。
|
|
56
|
+
* 导出供测试与外部直接使用。
|
|
57
|
+
*/
|
|
58
|
+
export function encodeWorkflowForShare(nodes) {
|
|
59
|
+
const data = {
|
|
60
|
+
v: 1,
|
|
61
|
+
nodes: nodes.map((n) => ({ c: n.capability, p: n.params })),
|
|
62
|
+
};
|
|
63
|
+
return encodeUtf8Base64Url(JSON.stringify(data));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 解码 base64url 字符串为工作流节点。
|
|
67
|
+
* @returns 节点数组;解析失败返回 null。
|
|
68
|
+
*/
|
|
69
|
+
export function decodeWorkflowFromShare(encoded) {
|
|
70
|
+
try {
|
|
71
|
+
const json = decodeUtf8Base64Url(encoded);
|
|
72
|
+
const data = JSON.parse(json);
|
|
73
|
+
if (!data || typeof data !== 'object' || data.v !== 1 || !Array.isArray(data.nodes)) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
return data.nodes.map((n) => ({
|
|
77
|
+
capability: String(n.c),
|
|
78
|
+
params: (n.p && typeof n.p === 'object' ? n.p : {}),
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function useShareLink() {
|
|
86
|
+
const nodes = useWorkspaceStore((s) => s.nodes);
|
|
87
|
+
const loadWorkflowTemplate = useWorkspaceStore((s) => s.loadWorkflowTemplate);
|
|
88
|
+
const generateShareUrl = useCallback(() => {
|
|
89
|
+
if (nodes.length === 0)
|
|
90
|
+
return null;
|
|
91
|
+
const encoded = encodeWorkflowForShare(nodes);
|
|
92
|
+
if (typeof window === 'undefined')
|
|
93
|
+
return null;
|
|
94
|
+
const { origin, pathname } = window.location;
|
|
95
|
+
return `${origin}${pathname}?workflow=${encoded}`;
|
|
96
|
+
}, [nodes]);
|
|
97
|
+
const parseShareUrl = useCallback((url) => {
|
|
98
|
+
const searchPart = url.includes('?') ? url.slice(url.indexOf('?') + 1) : '';
|
|
99
|
+
const params = new URLSearchParams(searchPart);
|
|
100
|
+
const encoded = params.get('workflow');
|
|
101
|
+
if (!encoded)
|
|
102
|
+
return null;
|
|
103
|
+
return decodeWorkflowFromShare(encoded);
|
|
104
|
+
}, []);
|
|
105
|
+
const loadFromCurrentUrl = useCallback(() => {
|
|
106
|
+
if (typeof window === 'undefined')
|
|
107
|
+
return false;
|
|
108
|
+
const parsed = parseShareUrl(window.location.href);
|
|
109
|
+
if (!parsed || parsed.length === 0)
|
|
110
|
+
return false;
|
|
111
|
+
loadWorkflowTemplate(parsed);
|
|
112
|
+
return true;
|
|
113
|
+
}, [parseShareUrl, loadWorkflowTemplate]);
|
|
114
|
+
return {
|
|
115
|
+
generateShareUrl,
|
|
116
|
+
parseShareUrl,
|
|
117
|
+
loadFromCurrentUrl,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=useShareLink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShareLink.js","sourceRoot":"","sources":["../../src/hooks/useShareLink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTheme - 暗色模式切换 + 持久化(W9.7)
|
|
3
|
+
*
|
|
4
|
+
* 监听并切换 `<html>` 的 `.dark` / `.light` 类,与 `tokens.css` 双触发机制对齐:
|
|
5
|
+
* - 显式设置:`document.documentElement.classList` 添加 `dark` 或 `light`
|
|
6
|
+
* - 系统兜底:未显式设置时,`@media prefers-color-scheme` 自动生效
|
|
7
|
+
*
|
|
8
|
+
* 持久化:`localStorage.theme = 'dark' | 'light'`,刷新后恢复。
|
|
9
|
+
* 跨 tab 同步:监听 `storage` 事件,一个 tab 切换,其他 tab 同步生效。
|
|
10
|
+
*
|
|
11
|
+
* 系统偏好变化:未显式设置主题时,跟随 `matchMedia('(prefers-color-scheme: dark)')`。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* const { theme, resolvedTheme, toggleTheme, setTheme } = useTheme();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export type ThemeMode = 'light' | 'dark';
|
|
19
|
+
export interface UseThemeResult {
|
|
20
|
+
/** 用户显式选择的主题(未设置时为 null,跟随系统) */
|
|
21
|
+
theme: ThemeMode | null;
|
|
22
|
+
/** 实际生效的主题(显式选择或系统偏好) */
|
|
23
|
+
resolvedTheme: ThemeMode;
|
|
24
|
+
/** 设置指定主题(传 null 表示跟随系统) */
|
|
25
|
+
setTheme(theme: ThemeMode | null): void;
|
|
26
|
+
/** 在 light / dark 之间切换(无显式主题时基于 resolvedTheme 决定下一态) */
|
|
27
|
+
toggleTheme(): void;
|
|
28
|
+
}
|
|
29
|
+
export declare function useTheme(): UseThemeResult;
|
|
30
|
+
//# sourceMappingURL=useTheme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTheme.d.ts","sourceRoot":"","sources":["../../src/hooks/useTheme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AA8BzC,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,yBAAyB;IACzB,aAAa,EAAE,SAAS,CAAC;IACzB,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;IACxC,wDAAwD;IACxD,WAAW,IAAI,IAAI,CAAC;CACrB;AAED,wBAAgB,QAAQ,IAAI,cAAc,CAsDzC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTheme - 暗色模式切换 + 持久化(W9.7)
|
|
3
|
+
*
|
|
4
|
+
* 监听并切换 `<html>` 的 `.dark` / `.light` 类,与 `tokens.css` 双触发机制对齐:
|
|
5
|
+
* - 显式设置:`document.documentElement.classList` 添加 `dark` 或 `light`
|
|
6
|
+
* - 系统兜底:未显式设置时,`@media prefers-color-scheme` 自动生效
|
|
7
|
+
*
|
|
8
|
+
* 持久化:`localStorage.theme = 'dark' | 'light'`,刷新后恢复。
|
|
9
|
+
* 跨 tab 同步:监听 `storage` 事件,一个 tab 切换,其他 tab 同步生效。
|
|
10
|
+
*
|
|
11
|
+
* 系统偏好变化:未显式设置主题时,跟随 `matchMedia('(prefers-color-scheme: dark)')`。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* const { theme, resolvedTheme, toggleTheme, setTheme } = useTheme();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
19
|
+
const STORAGE_KEY = 'lokvis-theme';
|
|
20
|
+
function readStoredTheme() {
|
|
21
|
+
if (typeof window === 'undefined')
|
|
22
|
+
return null;
|
|
23
|
+
try {
|
|
24
|
+
const v = window.localStorage.getItem(STORAGE_KEY);
|
|
25
|
+
if (v === 'light' || v === 'dark')
|
|
26
|
+
return v;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// localStorage 不可用(隐私模式 / iframe 沙箱)— 退回系统偏好
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function readSystemTheme() {
|
|
34
|
+
if (typeof window === 'undefined' || !window.matchMedia)
|
|
35
|
+
return 'light';
|
|
36
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
37
|
+
}
|
|
38
|
+
/** 把显式主题应用到 <html>(null 表示清空,回退到系统偏好) */
|
|
39
|
+
function applyTheme(theme) {
|
|
40
|
+
if (typeof document === 'undefined')
|
|
41
|
+
return;
|
|
42
|
+
const root = document.documentElement;
|
|
43
|
+
root.classList.remove('dark', 'light');
|
|
44
|
+
if (theme === 'dark')
|
|
45
|
+
root.classList.add('dark');
|
|
46
|
+
else if (theme === 'light')
|
|
47
|
+
root.classList.add('light');
|
|
48
|
+
// theme === null: 两个类都不加 → 由 @media prefers-color-scheme 接管
|
|
49
|
+
}
|
|
50
|
+
export function useTheme() {
|
|
51
|
+
const [theme, setThemeState] = useState(() => readStoredTheme());
|
|
52
|
+
const [systemTheme, setSystemTheme] = useState(() => readSystemTheme());
|
|
53
|
+
// 监听系统偏好变化(仅在用户未显式选择时影响 resolvedTheme)
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (typeof window === 'undefined' || !window.matchMedia)
|
|
56
|
+
return;
|
|
57
|
+
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
|
58
|
+
const onChange = () => setSystemTheme(mq.matches ? 'dark' : 'light');
|
|
59
|
+
mq.addEventListener('change', onChange);
|
|
60
|
+
return () => mq.removeEventListener('change', onChange);
|
|
61
|
+
}, []);
|
|
62
|
+
// 应用主题到 <html>
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
applyTheme(theme);
|
|
65
|
+
}, [theme]);
|
|
66
|
+
// 跨 tab 同步:监听 storage 事件
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (typeof window === 'undefined')
|
|
69
|
+
return;
|
|
70
|
+
const onStorage = (e) => {
|
|
71
|
+
if (e.key !== STORAGE_KEY)
|
|
72
|
+
return;
|
|
73
|
+
setThemeState(readStoredTheme());
|
|
74
|
+
};
|
|
75
|
+
window.addEventListener('storage', onStorage);
|
|
76
|
+
return () => window.removeEventListener('storage', onStorage);
|
|
77
|
+
}, []);
|
|
78
|
+
const setTheme = useCallback((next) => {
|
|
79
|
+
setThemeState(next);
|
|
80
|
+
try {
|
|
81
|
+
if (typeof window === 'undefined')
|
|
82
|
+
return;
|
|
83
|
+
if (next === null) {
|
|
84
|
+
window.localStorage.removeItem(STORAGE_KEY);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
window.localStorage.setItem(STORAGE_KEY, next);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// 写入失败(隐私模式 / quota)— 不影响运行时切换,只是无法持久化
|
|
92
|
+
}
|
|
93
|
+
}, []);
|
|
94
|
+
const toggleTheme = useCallback(() => {
|
|
95
|
+
const resolved = theme ?? systemTheme;
|
|
96
|
+
setTheme(resolved === 'dark' ? 'light' : 'dark');
|
|
97
|
+
}, [theme, systemTheme, setTheme]);
|
|
98
|
+
return {
|
|
99
|
+
theme,
|
|
100
|
+
resolvedTheme: theme ?? systemTheme,
|
|
101
|
+
setTheme,
|
|
102
|
+
toggleTheme,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=useTheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTheme.js","sourceRoot":"","sources":["../../src/hooks/useTheme.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useWorkflowProgress - 工作流执行进度(W11.6,review 抽取)
|
|
3
|
+
*
|
|
4
|
+
* 单一来源计算节点执行进度,供 ProgressBar / StatusBar 共用,
|
|
5
|
+
* 避免两组件各自从 nodes 重复计算 done/total/pct。
|
|
6
|
+
*
|
|
7
|
+
* 计算口径:
|
|
8
|
+
* - done: 已结束节点(success + failed + cancelled)
|
|
9
|
+
* - failedCount: 失败节点数(用于红色高亮)
|
|
10
|
+
* - pct: 完成百分比(0-100),total=0 时为 0
|
|
11
|
+
*
|
|
12
|
+
* @module useWorkflowProgress
|
|
13
|
+
*/
|
|
14
|
+
export interface WorkflowProgress {
|
|
15
|
+
/** 节点总数 */
|
|
16
|
+
total: number;
|
|
17
|
+
/** 已结束节点数(success + failed + cancelled) */
|
|
18
|
+
done: number;
|
|
19
|
+
/** 失败节点数 */
|
|
20
|
+
failedCount: number;
|
|
21
|
+
/** 完成百分比(0-100) */
|
|
22
|
+
pct: number;
|
|
23
|
+
/** 是否有失败节点 */
|
|
24
|
+
hasFailure: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** 计算工作流执行进度(单一来源,供 ProgressBar / StatusBar 共用) */
|
|
27
|
+
export declare function useWorkflowProgress(): WorkflowProgress;
|
|
28
|
+
//# sourceMappingURL=useWorkflowProgress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWorkflowProgress.d.ts","sourceRoot":"","sources":["../../src/hooks/useWorkflowProgress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,WAAW;IACX,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,mDAAmD;AACnD,wBAAgB,mBAAmB,IAAI,gBAAgB,CAUtD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useWorkflowProgress - 工作流执行进度(W11.6,review 抽取)
|
|
3
|
+
*
|
|
4
|
+
* 单一来源计算节点执行进度,供 ProgressBar / StatusBar 共用,
|
|
5
|
+
* 避免两组件各自从 nodes 重复计算 done/total/pct。
|
|
6
|
+
*
|
|
7
|
+
* 计算口径:
|
|
8
|
+
* - done: 已结束节点(success + failed + cancelled)
|
|
9
|
+
* - failedCount: 失败节点数(用于红色高亮)
|
|
10
|
+
* - pct: 完成百分比(0-100),total=0 时为 0
|
|
11
|
+
*
|
|
12
|
+
* @module useWorkflowProgress
|
|
13
|
+
*/
|
|
14
|
+
import { useWorkspaceStore } from '../store/index.js';
|
|
15
|
+
/** 计算工作流执行进度(单一来源,供 ProgressBar / StatusBar 共用) */
|
|
16
|
+
export function useWorkflowProgress() {
|
|
17
|
+
const nodes = useWorkspaceStore((s) => s.nodes);
|
|
18
|
+
const total = nodes.length;
|
|
19
|
+
const done = nodes.filter((n) => n.status === 'success' || n.status === 'failed' || n.status === 'cancelled').length;
|
|
20
|
+
const failedCount = nodes.filter((n) => n.status === 'failed').length;
|
|
21
|
+
const pct = total > 0 ? Math.round((done / total) * 100) : 0;
|
|
22
|
+
const hasFailure = failedCount > 0;
|
|
23
|
+
return { total, done, failedCount, pct, hasFailure };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=useWorkflowProgress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWorkflowProgress.js","sourceRoot":"","sources":["../../src/hooks/useWorkflowProgress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAetD,mDAAmD;AACnD,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CACvB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,CACnF,CAAC,MAAM,CAAC;IACT,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACtE,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,WAAW,GAAG,CAAC,CAAC;IACnC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useWorkflows - 工作流槽位持久化 hook(W10.6 + W10.7)
|
|
3
|
+
*
|
|
4
|
+
* 提供 5 个工作流槽位的本地保存能力(免费 5 / Pro 无限),以及 JSON 导入/导出。
|
|
5
|
+
* 数据存储在 localStorage 的 `lokvis.workflows` key,JSON 数组形式。
|
|
6
|
+
*
|
|
7
|
+
* 与 useCustomPresets 的区别:
|
|
8
|
+
* - 自定义预设是尺寸配置(width/height/fit)
|
|
9
|
+
* - 工作流槽位是完整 Workflow 定义(含 nodes/edges/inputs/outputs)
|
|
10
|
+
*
|
|
11
|
+
* 序列化策略:
|
|
12
|
+
* - 保存时用 workflowSchema.safeParse() 防御损坏数据(数据完整性)
|
|
13
|
+
* - 加载时用 workflowSchema.safeParse() 过滤无效条目(向前兼容)
|
|
14
|
+
* - JSON 导出:Workflow JSON + $schema 字段
|
|
15
|
+
* - JSON 导入:validateWorkflow() 完整校验(含 capability 兼容性若提供回调)
|
|
16
|
+
*
|
|
17
|
+
* 多 tab / 多实例同步:
|
|
18
|
+
* - 原生 storage 事件:跨 tab 同步
|
|
19
|
+
* - 自定义 SYNC_EVENT:同 tab 多实例同步
|
|
20
|
+
*
|
|
21
|
+
* @module useWorkflows
|
|
22
|
+
*/
|
|
23
|
+
import type { Workflow } from '@lokvis/schema';
|
|
24
|
+
import { type ValidateWorkflowOptions } from '@lokvis/schema';
|
|
25
|
+
/** 免费用户工作流槽位上限 */
|
|
26
|
+
export declare const FREE_WORKFLOW_LIMIT = 5;
|
|
27
|
+
/** Pro 用户无上限 */
|
|
28
|
+
export declare const PRO_WORKFLOW_LIMIT: number;
|
|
29
|
+
/** 工作流槽位存储格式 */
|
|
30
|
+
export interface WorkflowSlot {
|
|
31
|
+
/** 唯一 ID */
|
|
32
|
+
id: string;
|
|
33
|
+
/** 用户自定义名称(默认取 workflow.name) */
|
|
34
|
+
name: string;
|
|
35
|
+
/** 完整 Workflow 定义 */
|
|
36
|
+
workflow: Workflow;
|
|
37
|
+
/** 创建时间戳 */
|
|
38
|
+
createdAt: number;
|
|
39
|
+
/** 最后更新时间戳 */
|
|
40
|
+
updatedAt: number;
|
|
41
|
+
}
|
|
42
|
+
/** 保存工作流时的输入 */
|
|
43
|
+
export interface SaveWorkflowInput {
|
|
44
|
+
/** 工作流名称(可选,默认取 workflow.name) */
|
|
45
|
+
name?: string;
|
|
46
|
+
/** 完整 Workflow 定义 */
|
|
47
|
+
workflow: Workflow;
|
|
48
|
+
/** 若指定则更新该 id 的槽位,否则新增 */
|
|
49
|
+
id?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface UseWorkflowsResult {
|
|
52
|
+
/** 当前所有工作流槽位(按 updatedAt 降序) */
|
|
53
|
+
slots: WorkflowSlot[];
|
|
54
|
+
/** 保存或更新工作流;超限时抛 Error */
|
|
55
|
+
save(input: SaveWorkflowInput): WorkflowSlot;
|
|
56
|
+
/** 按 id 删除槽位 */
|
|
57
|
+
remove(id: string): void;
|
|
58
|
+
/** 按 id 加载工作流到 store(返回 Workflow) */
|
|
59
|
+
load(id: string): Workflow | null;
|
|
60
|
+
/** 当前上限(免费 5 / Pro 无限) */
|
|
61
|
+
limit: number;
|
|
62
|
+
/** 是否还能再保存 */
|
|
63
|
+
canSaveMore: boolean;
|
|
64
|
+
/** 还能再保存多少个 */
|
|
65
|
+
remaining: number;
|
|
66
|
+
/** 导出工作流为 JSON 字符串(可直接下载) */
|
|
67
|
+
exportToJson(id: string): string | null;
|
|
68
|
+
/** 导出所有工作流为 JSON 数组字符串 */
|
|
69
|
+
exportAllToJson(): string;
|
|
70
|
+
/** 从 JSON 字符导入工作流(单个或数组);返回导入结果(含跳过原因) */
|
|
71
|
+
importFromJson(json: string, options?: {
|
|
72
|
+
resolveCapability?: ValidateWorkflowOptions['resolveCapability'];
|
|
73
|
+
maxSteps?: number;
|
|
74
|
+
}): {
|
|
75
|
+
imported: number;
|
|
76
|
+
skipped: Array<{
|
|
77
|
+
reason: string;
|
|
78
|
+
}>;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @param isPro 是否为 Pro 模式。父组件从 runtime.isPro 传入。
|
|
83
|
+
* 影响 limit:免费 5 / Pro 无上限。
|
|
84
|
+
*/
|
|
85
|
+
export declare function useWorkflows(isPro?: boolean): UseWorkflowsResult;
|
|
86
|
+
//# sourceMappingURL=useWorkflows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWorkflows.d.ts","sourceRoot":"","sources":["../../src/hooks/useWorkflows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAoC,KAAK,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAMhG,kBAAkB;AAClB,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,gBAAgB;AAChB,eAAO,MAAM,kBAAkB,QAAW,CAAC;AAE3C,gBAAgB;AAChB,MAAM,WAAW,YAAY;IAC3B,YAAY;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gBAAgB;AAChB,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,0BAA0B;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,0BAA0B;IAC1B,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAAC;IAC7C,gBAAgB;IAChB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,qCAAqC;IACrC,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAClC,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACxC,0BAA0B;IAC1B,eAAe,IAAI,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,cAAc,CACZ,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAChG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CAC7D;AA4DD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,UAAQ,GAAG,kBAAkB,CAiL9D"}
|