@lokvis/ui-react 0.1.1-beta.0 → 0.2.1

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.
Files changed (152) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/AssetPanel.d.ts +2 -2
  3. package/dist/components/AssetPanel.d.ts.map +1 -1
  4. package/dist/components/AssetPanel.js +79 -7
  5. package/dist/components/AssetPanel.js.map +1 -1
  6. package/dist/components/Canvas.d.ts +9 -1
  7. package/dist/components/Canvas.d.ts.map +1 -1
  8. package/dist/components/Canvas.js +39 -2
  9. package/dist/components/Canvas.js.map +1 -1
  10. package/dist/components/CommandPalette.d.ts +48 -0
  11. package/dist/components/CommandPalette.d.ts.map +1 -0
  12. package/dist/components/CommandPalette.js +154 -0
  13. package/dist/components/CommandPalette.js.map +1 -0
  14. package/dist/components/CompareSlider.d.ts +25 -0
  15. package/dist/components/CompareSlider.d.ts.map +1 -0
  16. package/dist/components/CompareSlider.js +106 -0
  17. package/dist/components/CompareSlider.js.map +1 -0
  18. package/dist/components/DownloadPanel.d.ts +20 -0
  19. package/dist/components/DownloadPanel.d.ts.map +1 -0
  20. package/dist/components/DownloadPanel.js +169 -0
  21. package/dist/components/DownloadPanel.js.map +1 -0
  22. package/dist/components/ErrorBanner.d.ts +22 -0
  23. package/dist/components/ErrorBanner.d.ts.map +1 -0
  24. package/dist/components/ErrorBanner.js +47 -0
  25. package/dist/components/ErrorBanner.js.map +1 -0
  26. package/dist/components/ExifPanel.d.ts +26 -0
  27. package/dist/components/ExifPanel.d.ts.map +1 -0
  28. package/dist/components/ExifPanel.js +104 -0
  29. package/dist/components/ExifPanel.js.map +1 -0
  30. package/dist/components/GlobalDropzone.d.ts +37 -0
  31. package/dist/components/GlobalDropzone.d.ts.map +1 -0
  32. package/dist/components/GlobalDropzone.js +154 -0
  33. package/dist/components/GlobalDropzone.js.map +1 -0
  34. package/dist/components/HistoryPanel.d.ts +17 -7
  35. package/dist/components/HistoryPanel.d.ts.map +1 -1
  36. package/dist/components/HistoryPanel.js +74 -62
  37. package/dist/components/HistoryPanel.js.map +1 -1
  38. package/dist/components/Inspector.d.ts.map +1 -1
  39. package/dist/components/Inspector.js +2 -1
  40. package/dist/components/Inspector.js.map +1 -1
  41. package/dist/components/ProgressBar.d.ts +18 -0
  42. package/dist/components/ProgressBar.d.ts.map +1 -0
  43. package/dist/components/ProgressBar.js +35 -0
  44. package/dist/components/ProgressBar.js.map +1 -0
  45. package/dist/components/StatusBar.d.ts +8 -2
  46. package/dist/components/StatusBar.d.ts.map +1 -1
  47. package/dist/components/StatusBar.js +59 -4
  48. package/dist/components/StatusBar.js.map +1 -1
  49. package/dist/components/ThemeToggle.d.ts +20 -0
  50. package/dist/components/ThemeToggle.d.ts.map +1 -0
  51. package/dist/components/ThemeToggle.js +60 -0
  52. package/dist/components/ThemeToggle.js.map +1 -0
  53. package/dist/components/WorkflowEditor.d.ts +24 -0
  54. package/dist/components/WorkflowEditor.d.ts.map +1 -0
  55. package/dist/components/WorkflowEditor.js +160 -0
  56. package/dist/components/WorkflowEditor.js.map +1 -0
  57. package/dist/components/WorkflowTemplates.d.ts +23 -0
  58. package/dist/components/WorkflowTemplates.d.ts.map +1 -0
  59. package/dist/components/WorkflowTemplates.js +32 -0
  60. package/dist/components/WorkflowTemplates.js.map +1 -0
  61. package/dist/components/Workspace.d.ts +48 -2
  62. package/dist/components/Workspace.d.ts.map +1 -1
  63. package/dist/components/Workspace.js +78 -4
  64. package/dist/components/Workspace.js.map +1 -1
  65. package/dist/data/workflow-templates.d.ts +42 -0
  66. package/dist/data/workflow-templates.d.ts.map +1 -0
  67. package/dist/data/workflow-templates.js +112 -0
  68. package/dist/data/workflow-templates.js.map +1 -0
  69. package/dist/hooks/useDebouncedRun.d.ts +49 -0
  70. package/dist/hooks/useDebouncedRun.d.ts.map +1 -0
  71. package/dist/hooks/useDebouncedRun.js +117 -0
  72. package/dist/hooks/useDebouncedRun.js.map +1 -0
  73. package/dist/hooks/useLokvis.js +1 -1
  74. package/dist/hooks/useMediaQuery.d.ts +27 -0
  75. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  76. package/dist/hooks/useMediaQuery.js +41 -0
  77. package/dist/hooks/useMediaQuery.js.map +1 -0
  78. package/dist/hooks/useShareLink.d.ts +58 -0
  79. package/dist/hooks/useShareLink.d.ts.map +1 -0
  80. package/dist/hooks/useShareLink.js +120 -0
  81. package/dist/hooks/useShareLink.js.map +1 -0
  82. package/dist/hooks/useTheme.d.ts +30 -0
  83. package/dist/hooks/useTheme.d.ts.map +1 -0
  84. package/dist/hooks/useTheme.js +105 -0
  85. package/dist/hooks/useTheme.js.map +1 -0
  86. package/dist/hooks/useWorkflowProgress.d.ts +28 -0
  87. package/dist/hooks/useWorkflowProgress.d.ts.map +1 -0
  88. package/dist/hooks/useWorkflowProgress.js +25 -0
  89. package/dist/hooks/useWorkflowProgress.js.map +1 -0
  90. package/dist/hooks/useWorkflows.d.ts +86 -0
  91. package/dist/hooks/useWorkflows.d.ts.map +1 -0
  92. package/dist/hooks/useWorkflows.js +247 -0
  93. package/dist/hooks/useWorkflows.js.map +1 -0
  94. package/dist/index.d.ts +26 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +26 -0
  97. package/dist/index.js.map +1 -1
  98. package/dist/store/assets-slice.d.ts.map +1 -1
  99. package/dist/store/assets-slice.js +2 -0
  100. package/dist/store/assets-slice.js.map +1 -1
  101. package/dist/store/history-slice.d.ts +18 -0
  102. package/dist/store/history-slice.d.ts.map +1 -0
  103. package/dist/store/history-slice.js +42 -0
  104. package/dist/store/history-slice.js.map +1 -0
  105. package/dist/store/index.d.ts +1 -0
  106. package/dist/store/index.d.ts.map +1 -1
  107. package/dist/store/index.js +3 -0
  108. package/dist/store/index.js.map +1 -1
  109. package/dist/store/runtime-slice.d.ts +10 -2
  110. package/dist/store/runtime-slice.d.ts.map +1 -1
  111. package/dist/store/runtime-slice.js +77 -28
  112. package/dist/store/runtime-slice.js.map +1 -1
  113. package/dist/store/types.d.ts +70 -1
  114. package/dist/store/types.d.ts.map +1 -1
  115. package/dist/store/types.js +10 -0
  116. package/dist/store/types.js.map +1 -1
  117. package/dist/store/workflow-slice.d.ts +1 -1
  118. package/dist/store/workflow-slice.d.ts.map +1 -1
  119. package/dist/store/workflow-slice.js +128 -9
  120. package/dist/store/workflow-slice.js.map +1 -1
  121. package/package.json +9 -6
  122. package/src/components/AssetPanel.tsx +149 -8
  123. package/src/components/Canvas.tsx +79 -2
  124. package/src/components/CommandPalette.tsx +300 -0
  125. package/src/components/CompareSlider.tsx +186 -0
  126. package/src/components/DownloadPanel.tsx +252 -0
  127. package/src/components/ErrorBanner.tsx +95 -0
  128. package/src/components/ExifPanel.tsx +187 -0
  129. package/src/components/GlobalDropzone.tsx +220 -0
  130. package/src/components/HistoryPanel.tsx +231 -104
  131. package/src/components/Inspector.tsx +4 -0
  132. package/src/components/ProgressBar.tsx +104 -0
  133. package/src/components/StatusBar.tsx +124 -5
  134. package/src/components/ThemeToggle.tsx +122 -0
  135. package/src/components/WorkflowEditor.tsx +382 -0
  136. package/src/components/WorkflowTemplates.tsx +101 -0
  137. package/src/components/Workspace.tsx +205 -8
  138. package/src/data/workflow-templates.ts +137 -0
  139. package/src/hooks/useDebouncedRun.ts +151 -0
  140. package/src/hooks/useLokvis.ts +1 -1
  141. package/src/hooks/useMediaQuery.ts +53 -0
  142. package/src/hooks/useShareLink.ts +158 -0
  143. package/src/hooks/useTheme.ts +116 -0
  144. package/src/hooks/useWorkflowProgress.ts +41 -0
  145. package/src/hooks/useWorkflows.ts +326 -0
  146. package/src/index.ts +32 -0
  147. package/src/store/assets-slice.ts +2 -0
  148. package/src/store/history-slice.ts +65 -0
  149. package/src/store/index.ts +3 -0
  150. package/src/store/runtime-slice.ts +89 -32
  151. package/src/store/types.ts +71 -1
  152. package/src/store/workflow-slice.ts +139 -10
@@ -1,8 +1,33 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /**
3
3
  * Workspace - 完整工作台组件
4
4
  *
5
- * 标准三栏布局:Toolbar → [AssetPanel | Canvas | Inspector] → PipelineBar → StatusBar
5
+ * W9 布局:
6
+ * ┌──────────────────────────────────────────────┐
7
+ * │ Toolbar │
8
+ * ├──────┬──────────────┬───────────────────────┤
9
+ * │Asset │ Canvas │ Inspector │
10
+ * │Panel │ (center) │ (right) │
11
+ * ├──────┴──────────────┴───────────────────────┤
12
+ * │ PipelineBar │
13
+ * ├──────────────────────────────────────────────┤
14
+ * │ HistoryPanel (horizontal, W9.1) │
15
+ * ├──────────────────────────────────────────────┤
16
+ * │ DownloadPanel (W9.5,条件渲染) │
17
+ * ├──────────────────────────────────────────────┤
18
+ * │ StatusBar │
19
+ * └──────────────────────────────────────────────┘
20
+ *
21
+ * W9 集成:
22
+ * - 9.1 HistoryPanel 移到底部(horizontal variant)
23
+ * - 9.2 CommandPalette(⌘K)挂载在 Workspace 内
24
+ * - 9.3 GlobalDropzone 全屏拖拽 + MIME 校验
25
+ * - 9.4 Canvas 内置 CompareSlider(before/after)
26
+ * - 9.5 DownloadPanel 在 HistoryPanel 下方,有 outputs 时显示
27
+ * - 9.6 StatusBar 已增强(当前工具/进度/在线)
28
+ * - 9.7 ThemeToggle 通过 Toolbar rightExtra 挂载
29
+ * - 9.8 响应式:移动端折叠为 drawer 模式
30
+ *
6
31
  * 通过 useLokvis 自动初始化 Runtime 与插件。
7
32
  *
8
33
  * @example
@@ -13,22 +38,71 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
38
  * <Workspace plugins={[imageToolsPlugin()]} />
14
39
  * ```
15
40
  */
41
+ import * as React from 'react';
16
42
  import { Icon } from '@lokvis/ui-core';
17
43
  import { useLokvis } from '../hooks/useLokvis.js';
44
+ import { useBreakpoints } from '../hooks/useMediaQuery.js';
18
45
  import { Toolbar } from './Toolbar.js';
19
46
  import { AssetPanel } from './AssetPanel.js';
47
+ import { HistoryPanel } from './HistoryPanel.js';
20
48
  import { Canvas } from './Canvas.js';
21
49
  import { Inspector } from './Inspector.js';
22
50
  import { PipelineBar } from './PipelineBar.js';
51
+ import { WorkflowEditor } from './WorkflowEditor.js';
52
+ import { ProgressBar } from './ProgressBar.js';
53
+ import { ErrorBanner } from './ErrorBanner.js';
23
54
  import { StatusBar } from './StatusBar.js';
24
- export function Workspace({ title, showStatusBar = true, className = '', ...lokvisOptions }) {
55
+ import { DownloadPanel } from './DownloadPanel.js';
56
+ import { CommandPalette, useCommandPalette } from './CommandPalette.js';
57
+ import { GlobalDropzone } from './GlobalDropzone.js';
58
+ import { ThemeToggle } from './ThemeToggle.js';
59
+ import { useShareLink } from '../hooks/useShareLink.js';
60
+ import { useWorkspaceStore } from '../store/index.js';
61
+ export function Workspace({ title, showStatusBar = true, showHistoryPanel = true, enableGlobalDropzone = true, enableCommandPalette = true, enableThemeToggle = true, enableCompare = true, enableDownloadPanel = true, enableWorkflowEditor = false, enableProgressBar = true, enableErrorBanner = true, enableShareLink = true, className = '', ...lokvisOptions }) {
25
62
  const { status, error } = useLokvis(lokvisOptions);
63
+ const { isMobile } = useBreakpoints();
64
+ const [paletteOpen, setPaletteOpen] = useCommandPalette({ enabled: enableCommandPalette });
65
+ // W9.8 移动端抽屉:Asset / Inspector 切换显示
66
+ const [mobilePanel, setMobilePanel] = React.useState(null);
67
+ // W11.5: 从 URL ?workflow= 参数加载分享工作流(runtime 就绪后执行一次)
68
+ // 保护:若用户已通过其它路径(如 localStorage 恢复或手动添加)有 nodes,
69
+ // 不静默替换 —— 用 confirm 让用户显式选择,避免丢失未保存工作。
70
+ // 注:不用 useWorkspaceStore 订阅 nodes.length 做 effect 依赖
71
+ // (review 反馈:那样 nodesLength 变化会触发 effect 重跑,而 ref 已 true
72
+ // 时重跑无意义,且语义上 effect 只应在 status 切换时跑一次)。
73
+ // 改用 getState() 在体内读取最新值,既不订阅也不进 deps。
74
+ const { loadFromCurrentUrl } = useShareLink();
75
+ const shareLoadedRef = React.useRef(false);
76
+ React.useEffect(() => {
77
+ if (enableShareLink && !shareLoadedRef.current && status !== 'initializing' && status !== 'error') {
78
+ shareLoadedRef.current = true;
79
+ // 仅在 URL 含 ?workflow= 参数时才提示(避免无谓 confirm 弹窗)
80
+ const hasShareParam = typeof window !== 'undefined'
81
+ && new URLSearchParams(window.location.search).has('workflow');
82
+ if (!hasShareParam)
83
+ return;
84
+ // 读取当前 nodes 长度(最新值,非订阅快照)
85
+ const currentNodesLength = useWorkspaceStore.getState().nodes.length;
86
+ if (currentNodesLength > 0) {
87
+ const ok = window.confirm(`检测到分享工作流链接,但当前已有 ${currentNodesLength} 个节点。是否替换为分享的工作流?`);
88
+ if (!ok)
89
+ return;
90
+ }
91
+ loadFromCurrentUrl();
92
+ }
93
+ }, [enableShareLink, status, loadFromCurrentUrl]);
26
94
  if (status === 'initializing') {
27
95
  return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [_jsxs("div", { className: "relative flex h-12 w-12 items-center justify-center", children: [_jsx("div", { className: "absolute inset-0 rounded-full border-2 border-indigo-200 dark:border-indigo-800" }), _jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-2 border-transparent border-t-indigo-500" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Initializing Runtime" }), _jsx("p", { className: "mt-1 text-xs text-zinc-400", children: "Loading plugins and capabilities..." })] })] }) }));
28
96
  }
29
97
  if (status === 'error') {
30
98
  return (_jsx("div", { className: "flex h-full items-center justify-center px-6", children: _jsxs("div", { className: "max-w-md rounded-xl border border-red-200 bg-red-50 p-6 text-center dark:border-red-800/50 dark:bg-red-950/20", children: [_jsx("div", { className: "mb-3 flex h-10 w-10 mx-auto items-center justify-center rounded-full bg-red-100 dark:bg-red-900/40", children: _jsxs(Icon, { size: 20, className: "text-red-500", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }) }), _jsx("p", { className: "font-semibold text-red-700 dark:text-red-400", children: "Failed to initialize" }), _jsx("p", { className: "mt-1.5 text-sm text-red-600/80 dark:text-red-400/70", children: error })] }) }));
31
99
  }
32
- return (_jsxs("div", { className: `flex h-full flex-col bg-white dark:bg-zinc-900 ${className}`, children: [_jsx(Toolbar, { title: title }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsx(AssetPanel, {}), _jsx(Canvas, {}), _jsx(Inspector, {})] }), _jsx(PipelineBar, {}), showStatusBar && _jsx(StatusBar, {})] }));
100
+ // W9.7 Toolbar rightExtra: ThemeToggle + ⌘K hint
101
+ const toolbarRight = (_jsxs(_Fragment, { children: [enableCommandPalette && (_jsxs("button", { type: "button", onClick: () => setPaletteOpen(true), "aria-label": "Open command palette", title: "Command palette (\u2318K)", className: "flex h-7 items-center gap-1 rounded-md border border-zinc-200 px-1.5 text-[10px] text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-700 dark:border-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200", children: [_jsxs(Icon, { size: 11, children: [_jsx("circle", { cx: "11", cy: "11", r: "8" }), _jsx("path", { d: "m21 21-4.3-4.3" })] }), _jsx("kbd", { className: "font-sans", children: "\u2318K" })] })), enableThemeToggle && _jsx(ThemeToggle, {}), isMobile && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => setMobilePanel(mobilePanel === 'asset' ? null : 'asset'), "aria-label": "Toggle asset panel", "aria-pressed": mobilePanel === 'asset', className: "flex h-7 w-7 items-center justify-center rounded-md text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200", children: _jsxs(Icon, { size: 14, children: [_jsx("rect", { x: "3", y: "3", width: "7", height: "18", rx: "1" }), _jsx("path", { d: "M14 3h7v18h-7z", opacity: "0.3" })] }) }), _jsx("button", { type: "button", onClick: () => setMobilePanel(mobilePanel === 'inspector' ? null : 'inspector'), "aria-label": "Toggle inspector panel", "aria-pressed": mobilePanel === 'inspector', className: "flex h-7 w-7 items-center justify-center rounded-md text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200", children: _jsxs(Icon, { size: 14, children: [_jsx("path", { d: "M3 3h7v18H3z", opacity: "0.3" }), _jsx("rect", { x: "14", y: "3", width: "7", height: "18", rx: "1" })] }) })] }))] }));
102
+ return (_jsxs("div", { className: `flex h-full flex-col bg-white dark:bg-zinc-900 ${className}`, children: [_jsx(Toolbar, { title: title, rightExtra: toolbarRight }), enableErrorBanner && _jsx(ErrorBanner, {}), enableGlobalDropzone && _jsx(GlobalDropzone, {}), enableCommandPalette && (_jsx(CommandPalette, { open: paletteOpen, onClose: () => setPaletteOpen(false) })), _jsxs("div", { className: "flex flex-1 overflow-hidden relative", children: [_jsx("div", { className: `${isMobile
103
+ ? `absolute inset-y-0 left-0 z-20 w-64 max-w-[80vw] transition-transform duration-200 ${mobilePanel === 'asset' ? 'translate-x-0' : '-translate-x-full'}`
104
+ : 'relative'}`, children: _jsx(AssetPanel, { className: "h-full" }) }), _jsx(Canvas, { enableCompare: enableCompare }), _jsx("div", { className: `${isMobile
105
+ ? `absolute inset-y-0 right-0 z-20 w-72 max-w-[80vw] transition-transform duration-200 ${mobilePanel === 'inspector' ? 'translate-x-0' : 'translate-x-full'}`
106
+ : 'relative'}`, children: _jsx(Inspector, { className: "h-full" }) }), isMobile && mobilePanel !== null && (_jsx("button", { type: "button", "aria-label": "Close panel", onClick: () => setMobilePanel(null), className: "absolute inset-0 z-10 bg-black/30" }))] }), enableWorkflowEditor ? _jsx(WorkflowEditor, {}) : _jsx(PipelineBar, {}), enableProgressBar && _jsx(ProgressBar, {}), showHistoryPanel && _jsx(HistoryPanel, { variant: "horizontal" }), enableDownloadPanel && _jsx(DownloadPanel, {}), showStatusBar && _jsx(StatusBar, {})] }));
33
107
  }
34
108
  //# sourceMappingURL=Workspace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Workspace.js","sourceRoot":"","sources":["../../src/components/Workspace.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAyB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAU3C,MAAM,UAAU,SAAS,CAAC,EACxB,KAAK,EACL,aAAa,GAAG,IAAI,EACpB,SAAS,GAAG,EAAE,EACd,GAAG,aAAa,EACD;IACf,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;IAEnD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,OAAO,CACL,cAAK,SAAS,EAAC,yCAAyC,YACtD,eAAK,SAAS,EAAC,kCAAkC,aAC/C,eAAK,SAAS,EAAC,qDAAqD,aAClE,cAAK,SAAS,EAAC,iFAAiF,GAAG,EACnG,cAAK,SAAS,EAAC,mFAAmF,GAAG,IACjG,EACN,eAAK,SAAS,EAAC,aAAa,aAC1B,YAAG,SAAS,EAAC,sDAAsD,qCAAyB,EAC5F,YAAG,SAAS,EAAC,4BAA4B,oDAAwC,IAC7E,IACF,GACF,CACP,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,CACL,cAAK,SAAS,EAAC,8CAA8C,YAC3D,eAAK,SAAS,EAAC,+GAA+G,aAC5H,cAAK,SAAS,EAAC,oGAAoG,YACjH,MAAC,IAAI,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,cAAc,aAAC,iBAAQ,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,GAAG,EAAA,eAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,GAAG,EAAA,eAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,OAAO,EAAC,EAAE,EAAC,IAAI,GAAG,IAAO,GAC/J,EACN,YAAG,SAAS,EAAC,8CAA8C,qCAAyB,EACpF,YAAG,SAAS,EAAC,qDAAqD,YAAE,KAAK,GAAK,IAC1E,GACF,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAE,kDAAkD,SAAS,EAAE,aAE3E,KAAC,OAAO,IAAC,KAAK,EAAE,KAAK,GAAI,EAGzB,eAAK,SAAS,EAAC,6BAA6B,aAC1C,KAAC,UAAU,KAAG,EACd,KAAC,MAAM,KAAG,EACV,KAAC,SAAS,KAAG,IACT,EAGN,KAAC,WAAW,KAAG,EAGd,aAAa,IAAI,KAAC,SAAS,KAAG,IAC3B,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Workspace.js","sourceRoot":"","sources":["../../src/components/Workspace.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 工作流模板数据(W11.4)
3
+ *
4
+ * 5 个内置模板,覆盖常见图片处理场景:
5
+ * 1. Web 优化 - resize + compress(webp),适用于网页素材
6
+ * 2. 社媒批量 - resize(1080) + watermark,适用于 Instagram/Twitter
7
+ * 3. 电商主图 - resize(800) + compress(jpeg) + watermark(店铺名)
8
+ * 4. 打印预处理 - resize(高分辨率) + convert(png),无损打印
9
+ * 5. 截图压缩 - resize(1280) + compress(png, 低质量),减小体积
10
+ *
11
+ * 每个模板仅含 capability + 默认 params,由 loadWorkflowTemplate() 应用到 store。
12
+ * 用户应用模板后仍可在 Inspector 调整参数。
13
+ *
14
+ * @module workflow-templates
15
+ */
16
+ /** 单个模板节点定义 */
17
+ export interface WorkflowTemplateNode {
18
+ /** 能力名,如 `image.resize` */
19
+ capability: string;
20
+ /** 默认参数(用户可修改) */
21
+ params: Record<string, unknown>;
22
+ }
23
+ /** 工作流模板 */
24
+ export interface WorkflowTemplate {
25
+ /** 模板 ID(唯一) */
26
+ id: string;
27
+ /** 模板名称(中文) */
28
+ name: string;
29
+ /** 模板描述 */
30
+ description: string;
31
+ /** 图标 emoji(用于 UI 展示) */
32
+ icon: string;
33
+ /** 模板分类 */
34
+ category: 'web' | 'social' | 'ecommerce' | 'print' | 'utility';
35
+ /** 节点序列 */
36
+ nodes: WorkflowTemplateNode[];
37
+ }
38
+ /** 5 个内置工作流模板 */
39
+ export declare const WORKFLOW_TEMPLATES: WorkflowTemplate[];
40
+ /** 按 ID 查找模板 */
41
+ export declare function findTemplate(id: string): WorkflowTemplate | undefined;
42
+ //# sourceMappingURL=workflow-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-templates.d.ts","sourceRoot":"","sources":["../../src/data/workflow-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAe;AACf,MAAM,WAAW,oBAAoB;IACnC,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,YAAY;AACZ,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;IAC/D,WAAW;IACX,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B;AAED,iBAAiB;AACjB,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EA0FhD,CAAC;AAEF,gBAAgB;AAChB,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAErE"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * 工作流模板数据(W11.4)
3
+ *
4
+ * 5 个内置模板,覆盖常见图片处理场景:
5
+ * 1. Web 优化 - resize + compress(webp),适用于网页素材
6
+ * 2. 社媒批量 - resize(1080) + watermark,适用于 Instagram/Twitter
7
+ * 3. 电商主图 - resize(800) + compress(jpeg) + watermark(店铺名)
8
+ * 4. 打印预处理 - resize(高分辨率) + convert(png),无损打印
9
+ * 5. 截图压缩 - resize(1280) + compress(png, 低质量),减小体积
10
+ *
11
+ * 每个模板仅含 capability + 默认 params,由 loadWorkflowTemplate() 应用到 store。
12
+ * 用户应用模板后仍可在 Inspector 调整参数。
13
+ *
14
+ * @module workflow-templates
15
+ */
16
+ /** 5 个内置工作流模板 */
17
+ export const WORKFLOW_TEMPLATES = [
18
+ {
19
+ id: 'tpl-web-optimize',
20
+ name: 'Web 优化',
21
+ description: '调整尺寸并压缩为 WebP,适用于网页素材',
22
+ icon: '🌐',
23
+ category: 'web',
24
+ nodes: [
25
+ {
26
+ capability: 'image.resize',
27
+ params: { width: 1920, height: 1080, fit: 'inside' },
28
+ },
29
+ {
30
+ capability: 'image.compress',
31
+ params: { format: 'webp', quality: 80 },
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ id: 'tpl-social-batch',
37
+ name: '社媒批量',
38
+ description: '统一为 1080px 并添加水印,适用于 Instagram/Twitter',
39
+ icon: '📱',
40
+ category: 'social',
41
+ nodes: [
42
+ {
43
+ capability: 'image.resize',
44
+ params: { width: 1080, height: 1080, fit: 'cover' },
45
+ },
46
+ {
47
+ capability: 'image.watermark',
48
+ params: { text: '@username', position: 'bottom-right', opacity: 0.7 },
49
+ },
50
+ ],
51
+ },
52
+ {
53
+ id: 'tpl-ecommerce-main',
54
+ name: '电商主图',
55
+ description: '800px 主图 + JPEG 压缩 + 店铺水印',
56
+ icon: '🛒',
57
+ category: 'ecommerce',
58
+ nodes: [
59
+ {
60
+ capability: 'image.resize',
61
+ params: { width: 800, height: 800, fit: 'contain' },
62
+ },
63
+ {
64
+ capability: 'image.compress',
65
+ params: { format: 'jpeg', quality: 90 },
66
+ },
67
+ {
68
+ capability: 'image.watermark',
69
+ params: { text: '店铺名', position: 'center', opacity: 0.3 },
70
+ },
71
+ ],
72
+ },
73
+ {
74
+ id: 'tpl-print-prep',
75
+ name: '打印预处理',
76
+ description: '高分辨率 resize + PNG 无损转换,适用于打印',
77
+ icon: '🖨️',
78
+ category: 'print',
79
+ nodes: [
80
+ {
81
+ capability: 'image.resize',
82
+ params: { width: 3508, height: 2480, fit: 'inside', dpi: 300 },
83
+ },
84
+ {
85
+ capability: 'image.convert',
86
+ params: { format: 'png' },
87
+ },
88
+ ],
89
+ },
90
+ {
91
+ id: 'tpl-screenshot-compress',
92
+ name: '截图压缩',
93
+ description: '缩小到 1280px 并压缩为低质量 PNG,减小体积',
94
+ icon: '📸',
95
+ category: 'utility',
96
+ nodes: [
97
+ {
98
+ capability: 'image.resize',
99
+ params: { width: 1280, height: 720, fit: 'inside' },
100
+ },
101
+ {
102
+ capability: 'image.compress',
103
+ params: { format: 'png', quality: 60 },
104
+ },
105
+ ],
106
+ },
107
+ ];
108
+ /** 按 ID 查找模板 */
109
+ export function findTemplate(id) {
110
+ return WORKFLOW_TEMPLATES.find((t) => t.id === id);
111
+ }
112
+ //# sourceMappingURL=workflow-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-templates.js","sourceRoot":"","sources":["../../src/data/workflow-templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * useDebouncedRun - 修改参数后 debounced 自动重跑(W11.2)
3
+ *
4
+ * 监听当前工作流节点序列(含 params),变化后延迟 delay 毫秒自动调用
5
+ * store.run(),实现"修改参数即时预览"。
6
+ *
7
+ * 设计要点:
8
+ * - 仅在 enabled=true 且 nodes.length>0 且 selectedAssetId 存在时触发
9
+ * - debounce 避免连续修改(如拖滑块)触发过多执行
10
+ * - 组件卸载时清除 timer,避免卸载后仍调用 store action
11
+ * - running 期间不触发新的 run(避免并发执行同一工作流;run() 也有并发保护)
12
+ * - 用户可手动触发 runNow() 立即执行(取消 pending debounce)
13
+ *
14
+ * 实现说明:
15
+ * - 主 effect 依赖 [nodesKey, enabled, selectedAssetId, delay](用户输入)
16
+ * - run / running / nodes.length 通过 ref 读取最新值,避免加入 deps:
17
+ * - run / running:store action 引用每次 store 变化都变,加入 deps 触发循环重订阅
18
+ * - nodes.length:节点数量变化必然使 nodesKey(JSON 序列化)变化,
19
+ * 加入 deps 是冗余触发源(节点增减会触发两次 effect 重新计时)
20
+ * - 这是 React 社区标准模式(避免 effect 与 store action 循环 + 消除冗余触发),非 workaround
21
+ *
22
+ * 典型用法:
23
+ * ```tsx
24
+ * const { enabled, setEnabled, runNow } = useDebouncedRun({ delay: 400 });
25
+ * <Toggle checked={enabled} onChange={setEnabled} label="实时预览" />
26
+ * ```
27
+ *
28
+ * @module useDebouncedRun
29
+ */
30
+ export interface UseDebouncedRunOptions {
31
+ /** 防抖延迟毫秒(默认 400ms,平衡响应性与性能) */
32
+ delay?: number;
33
+ /** 初始是否启用(默认 false,需用户显式开启避免意外执行) */
34
+ initialEnabled?: boolean;
35
+ }
36
+ export interface UseDebouncedRunResult {
37
+ /** 当前是否启用自动运行 */
38
+ enabled: boolean;
39
+ /** 切换启用状态 */
40
+ setEnabled: (v: boolean) => void;
41
+ /** 立即触发运行(取消 pending debounce) */
42
+ runNow: () => void;
43
+ /** 取消 pending debounce(不取消正在运行的) */
44
+ cancelPending: () => void;
45
+ /** 是否有 pending 的执行(等待 debounce 触发) */
46
+ isPending: boolean;
47
+ }
48
+ export declare function useDebouncedRun(options?: UseDebouncedRunOptions): UseDebouncedRunResult;
49
+ //# sourceMappingURL=useDebouncedRun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebouncedRun.d.ts","sourceRoot":"","sources":["../../src/hooks/useDebouncedRun.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,MAAM,WAAW,sBAAsB;IACrC,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,iBAAiB;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa;IACb,UAAU,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,kCAAkC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,oCAAoC;IACpC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,sCAAsC;IACtC,SAAS,EAAE,OAAO,CAAC;CACpB;AAWD,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,qBAAqB,CAsFvB"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * useDebouncedRun - 修改参数后 debounced 自动重跑(W11.2)
3
+ *
4
+ * 监听当前工作流节点序列(含 params),变化后延迟 delay 毫秒自动调用
5
+ * store.run(),实现"修改参数即时预览"。
6
+ *
7
+ * 设计要点:
8
+ * - 仅在 enabled=true 且 nodes.length>0 且 selectedAssetId 存在时触发
9
+ * - debounce 避免连续修改(如拖滑块)触发过多执行
10
+ * - 组件卸载时清除 timer,避免卸载后仍调用 store action
11
+ * - running 期间不触发新的 run(避免并发执行同一工作流;run() 也有并发保护)
12
+ * - 用户可手动触发 runNow() 立即执行(取消 pending debounce)
13
+ *
14
+ * 实现说明:
15
+ * - 主 effect 依赖 [nodesKey, enabled, selectedAssetId, delay](用户输入)
16
+ * - run / running / nodes.length 通过 ref 读取最新值,避免加入 deps:
17
+ * - run / running:store action 引用每次 store 变化都变,加入 deps 触发循环重订阅
18
+ * - nodes.length:节点数量变化必然使 nodesKey(JSON 序列化)变化,
19
+ * 加入 deps 是冗余触发源(节点增减会触发两次 effect 重新计时)
20
+ * - 这是 React 社区标准模式(避免 effect 与 store action 循环 + 消除冗余触发),非 workaround
21
+ *
22
+ * 典型用法:
23
+ * ```tsx
24
+ * const { enabled, setEnabled, runNow } = useDebouncedRun({ delay: 400 });
25
+ * <Toggle checked={enabled} onChange={setEnabled} label="实时预览" />
26
+ * ```
27
+ *
28
+ * @module useDebouncedRun
29
+ */
30
+ import { useCallback, useEffect, useRef, useState } from 'react';
31
+ import { useWorkspaceStore } from '../store/index.js';
32
+ /** 序列化节点序列用于变化检测(params 嵌套对象需稳定序列化) */
33
+ function serializeNodes(nodes) {
34
+ return JSON.stringify(nodes.map((n) => ({ c: n.capability, p: n.params })));
35
+ }
36
+ export function useDebouncedRun(options = {}) {
37
+ const { delay = 400, initialEnabled = false } = options;
38
+ const [enabled, setEnabled] = useState(initialEnabled);
39
+ const [isPending, setIsPending] = useState(false);
40
+ const timerRef = useRef(null);
41
+ const nodes = useWorkspaceStore((s) => s.nodes);
42
+ const selectedAssetId = useWorkspaceStore((s) => s.selectedAssetId);
43
+ const running = useWorkspaceStore((s) => s.running);
44
+ const run = useWorkspaceStore((s) => s.run);
45
+ // 用 ref 持有最新的 run / running / nodes.length 引用:
46
+ // 主 effect 依赖数组只跟踪用户输入(nodesKey / enabled / selectedAssetId / delay),
47
+ // 不包含 store action 引用(每次 store 变化都生成新函数引用,加入 deps 会
48
+ // 触发 effect 重订阅 → debounce timer 重置 → 无法稳定等待 delay)。
49
+ // nodes.length 同样用 ref 读取:节点数量变化必然导致 nodesKey(JSON 序列化)
50
+ // 变化,nodes.length 在主 effect deps 中是冗余触发源,改用 ref 在 body 中读取
51
+ // 最新值即可(与 run / running 同模式,非 workaround)。
52
+ const runRef = useRef(run);
53
+ const runningRef = useRef(running);
54
+ const nodesLengthRef = useRef(nodes.length);
55
+ useEffect(() => {
56
+ runRef.current = run;
57
+ runningRef.current = running;
58
+ nodesLengthRef.current = nodes.length;
59
+ }, [run, running, nodes.length]);
60
+ // 序列化节点,作为 debounce 触发依赖
61
+ const nodesKey = serializeNodes(nodes);
62
+ const clearTimer = useCallback(() => {
63
+ if (timerRef.current !== null) {
64
+ clearTimeout(timerRef.current);
65
+ timerRef.current = null;
66
+ }
67
+ setIsPending(false);
68
+ }, []);
69
+ const runNow = useCallback(() => {
70
+ clearTimer();
71
+ if (!selectedAssetId || nodesLengthRef.current === 0 || runningRef.current)
72
+ return;
73
+ void runRef.current();
74
+ }, [clearTimer, selectedAssetId]);
75
+ // 监听节点序列变化。依赖数组为用户输入:
76
+ // nodesKey(序列化节点) / enabled / selectedAssetId / delay
77
+ // run / running / nodes.length 通过 ref 读取最新值(见上):
78
+ // - run / running:action 引用每次 store 变化都变,加入 deps 触发循环重订阅
79
+ // - nodes.length:节点数量变化必然使 nodesKey 变化,加入 deps 是冗余触发源
80
+ useEffect(() => {
81
+ if (!enabled)
82
+ return;
83
+ if (!selectedAssetId || nodesLengthRef.current === 0 || runningRef.current)
84
+ return;
85
+ // 清除上一次 pending,重新计时
86
+ if (timerRef.current !== null) {
87
+ clearTimeout(timerRef.current);
88
+ }
89
+ setIsPending(true);
90
+ timerRef.current = setTimeout(() => {
91
+ timerRef.current = null;
92
+ setIsPending(false);
93
+ // 再次检查 running + 节点非空,避免 timer 排队期间状态已变化
94
+ // (用户手动触发 run / 清空节点)
95
+ if (!runningRef.current && nodesLengthRef.current > 0) {
96
+ void runRef.current();
97
+ }
98
+ }, delay);
99
+ return () => {
100
+ // cleanup:清 timer + 重置 isPending。React 18 卸载后调用 setState 不再 warn,
101
+ // 但 cleanup 仍是正确做法(避免卸载后 timer 触发仍调用 store action)。
102
+ if (timerRef.current !== null) {
103
+ clearTimeout(timerRef.current);
104
+ timerRef.current = null;
105
+ }
106
+ setIsPending(false);
107
+ };
108
+ }, [nodesKey, enabled, selectedAssetId, delay]);
109
+ return {
110
+ enabled,
111
+ setEnabled,
112
+ runNow,
113
+ cancelPending: clearTimer,
114
+ isPending,
115
+ };
116
+ }
117
+ //# sourceMappingURL=useDebouncedRun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebouncedRun.js","sourceRoot":"","sources":["../../src/hooks/useDebouncedRun.ts"],"names":[],"mappings":"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"}
@@ -55,7 +55,7 @@ export function useLokvis(options = {}) {
55
55
  return () => {
56
56
  cancelled = true;
57
57
  };
58
- // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
59
59
  }, []);
60
60
  return { runtime, status, error };
61
61
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * useMediaQuery - 响应式断点 hook(W9.8)
3
+ *
4
+ * 在 React 中订阅 `matchMedia` 查询,断点变化时触发组件重渲染。
5
+ * SSR 安全:`window` 不存在时返回初始值 `false`。
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const isMobile = useMediaQuery('(max-width: 768px)');
10
+ * const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
11
+ * ```
12
+ *
13
+ * 内置断点常量(与 Tailwind v4 默认对齐):
14
+ * - sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px
15
+ */
16
+ export declare function useMediaQuery(query: string): boolean;
17
+ /** W9.8 三档断点 helper */
18
+ export interface Breakpoints {
19
+ /** 移动端 (< 768px) */
20
+ isMobile: boolean;
21
+ /** 平板 (768px - 1023px) */
22
+ isTablet: boolean;
23
+ /** 桌面 (>= 1024px) */
24
+ isDesktop: boolean;
25
+ }
26
+ export declare function useBreakpoints(): Breakpoints;
27
+ //# sourceMappingURL=useMediaQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaQuery.d.ts","sourceRoot":"","sources":["../../src/hooks/useMediaQuery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAiBpD;AAED,uBAAuB;AACvB,MAAM,WAAW,WAAW;IAC1B,oBAAoB;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,qBAAqB;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,cAAc,IAAI,WAAW,CAK5C"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * useMediaQuery - 响应式断点 hook(W9.8)
3
+ *
4
+ * 在 React 中订阅 `matchMedia` 查询,断点变化时触发组件重渲染。
5
+ * SSR 安全:`window` 不存在时返回初始值 `false`。
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const isMobile = useMediaQuery('(max-width: 768px)');
10
+ * const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
11
+ * ```
12
+ *
13
+ * 内置断点常量(与 Tailwind v4 默认对齐):
14
+ * - sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px
15
+ */
16
+ import { useEffect, useState } from 'react';
17
+ export function useMediaQuery(query) {
18
+ const [matches, setMatches] = useState(() => {
19
+ if (typeof window === 'undefined' || !window.matchMedia)
20
+ return false;
21
+ return window.matchMedia(query).matches;
22
+ });
23
+ useEffect(() => {
24
+ if (typeof window === 'undefined' || !window.matchMedia)
25
+ return;
26
+ const mq = window.matchMedia(query);
27
+ const onChange = () => setMatches(mq.matches);
28
+ // 初始同步(matchMedia 可能在 effect 跑前已变化)
29
+ setMatches(mq.matches);
30
+ mq.addEventListener('change', onChange);
31
+ return () => mq.removeEventListener('change', onChange);
32
+ }, [query]);
33
+ return matches;
34
+ }
35
+ export function useBreakpoints() {
36
+ const isMobile = useMediaQuery('(max-width: 767px)');
37
+ const isTablet = useMediaQuery('(min-width: 768px) and (max-width: 1023px)');
38
+ const isDesktop = useMediaQuery('(min-width: 1024px)');
39
+ return { isMobile, isTablet, isDesktop };
40
+ }
41
+ //# sourceMappingURL=useMediaQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaQuery.js","sourceRoot":"","sources":["../../src/hooks/useMediaQuery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAU,GAAG,EAAE;QACnD,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QACtE,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,OAAO;QAChE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAC9C,oCAAoC;QACpC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QACvB,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,OAAO,CAAC;AACjB,CAAC;AAYD,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,aAAa,CAAC,4CAA4C,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACvD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,58 @@
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
+ /**
21
+ * 编码工作流节点为 base64url 字符串(用于分享链接)。
22
+ * 导出供测试与外部直接使用。
23
+ */
24
+ export declare function encodeWorkflowForShare(nodes: ReadonlyArray<{
25
+ capability: string;
26
+ params: Record<string, unknown>;
27
+ }>): string;
28
+ /**
29
+ * 解码 base64url 字符串为工作流节点。
30
+ * @returns 节点数组;解析失败返回 null。
31
+ */
32
+ export declare function decodeWorkflowFromShare(encoded: string): Array<{
33
+ capability: string;
34
+ params: Record<string, unknown>;
35
+ }> | null;
36
+ export interface UseShareLinkResult {
37
+ /**
38
+ * 生成分享链接(基于当前 store 中的 nodes)。
39
+ * 返回完整 URL;若 nodes 为空返回 null。
40
+ */
41
+ generateShareUrl(): string | null;
42
+ /**
43
+ * 从 URL 解析工作流节点。
44
+ * @param url 完整 URL 或仅 search 部分
45
+ * @returns 节点数组;无 workflow 参数或解析失败返回 null
46
+ */
47
+ parseShareUrl(url: string): Array<{
48
+ capability: string;
49
+ params: Record<string, unknown>;
50
+ }> | null;
51
+ /**
52
+ * 从当前页面 URL 加载工作流(若有 ?workflow=)。
53
+ * @returns true 表示成功加载并应用到 store
54
+ */
55
+ loadFromCurrentUrl(): boolean;
56
+ }
57
+ export declare function useShareLink(): UseShareLinkResult;
58
+ //# sourceMappingURL=useShareLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShareLink.d.ts","sourceRoot":"","sources":["../../src/hooks/useShareLink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAgDH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAC5E,MAAM,CAMR;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,GACd,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAAG,IAAI,CAcvE;AAED,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAClG;;;OAGG;IACH,kBAAkB,IAAI,OAAO,CAAC;CAC/B;AAED,wBAAgB,YAAY,IAAI,kBAAkB,CAoCjD"}