@lokvis/ui-react 0.2.0 → 0.2.2
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/dist/components/AssetPanel.d.ts.map +1 -1
- package/dist/components/AssetPanel.js +14 -14
- package/dist/components/AssetPanel.js.map +1 -1
- package/dist/components/Canvas.d.ts +4 -4
- package/dist/components/Canvas.d.ts.map +1 -1
- package/dist/components/Canvas.js +8 -8
- package/dist/components/Canvas.js.map +1 -1
- package/dist/components/CommandPalette.d.ts +7 -7
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +10 -10
- package/dist/components/CommandPalette.js.map +1 -1
- package/dist/components/CompareSlider.d.ts +6 -6
- package/dist/components/CompareSlider.d.ts.map +1 -1
- package/dist/components/CompareSlider.js +7 -7
- package/dist/components/CompareSlider.js.map +1 -1
- package/dist/components/DownloadPanel.d.ts +3 -3
- package/dist/components/DownloadPanel.d.ts.map +1 -1
- package/dist/components/DownloadPanel.js +9 -9
- package/dist/components/DownloadPanel.js.map +1 -1
- package/dist/components/ErrorBanner.d.ts +2 -2
- package/dist/components/ErrorBanner.d.ts.map +1 -1
- package/dist/components/ErrorBanner.js +3 -3
- package/dist/components/ErrorBanner.js.map +1 -1
- package/dist/components/ExifPanel.d.ts +1 -1
- package/dist/components/ExifPanel.d.ts.map +1 -1
- package/dist/components/ExifPanel.js +2 -2
- package/dist/components/ExifPanel.js.map +1 -1
- package/dist/components/GlobalDropzone.d.ts +5 -5
- package/dist/components/GlobalDropzone.d.ts.map +1 -1
- package/dist/components/GlobalDropzone.js +6 -6
- package/dist/components/GlobalDropzone.js.map +1 -1
- package/dist/components/HistoryPanel.d.ts +2 -2
- package/dist/components/HistoryPanel.d.ts.map +1 -1
- package/dist/components/HistoryPanel.js +23 -23
- package/dist/components/HistoryPanel.js.map +1 -1
- package/dist/components/Inspector.d.ts.map +1 -1
- package/dist/components/Inspector.js +6 -6
- package/dist/components/Inspector.js.map +1 -1
- package/dist/components/ParamForm.d.ts.map +1 -1
- package/dist/components/ParamForm.js +7 -7
- package/dist/components/ParamForm.js.map +1 -1
- package/dist/components/PipelineBar.d.ts.map +1 -1
- package/dist/components/PipelineBar.js +13 -13
- package/dist/components/PipelineBar.js.map +1 -1
- package/dist/components/ProgressBar.d.ts +4 -4
- package/dist/components/ProgressBar.d.ts.map +1 -1
- package/dist/components/ProgressBar.js +8 -8
- package/dist/components/ProgressBar.js.map +1 -1
- package/dist/components/StatusBar.d.ts +3 -3
- package/dist/components/StatusBar.d.ts.map +1 -1
- package/dist/components/StatusBar.js +11 -11
- package/dist/components/StatusBar.js.map +1 -1
- package/dist/components/ThemeToggle.d.ts +4 -4
- package/dist/components/ThemeToggle.d.ts.map +1 -1
- package/dist/components/ThemeToggle.js +7 -7
- package/dist/components/ThemeToggle.js.map +1 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +2 -2
- package/dist/components/Toolbar.js.map +1 -1
- package/dist/components/WorkflowEditor.d.ts +6 -6
- package/dist/components/WorkflowEditor.d.ts.map +1 -1
- package/dist/components/WorkflowEditor.js +25 -25
- package/dist/components/WorkflowEditor.js.map +1 -1
- package/dist/components/WorkflowTemplates.d.ts +2 -2
- package/dist/components/WorkflowTemplates.d.ts.map +1 -1
- package/dist/components/WorkflowTemplates.js +3 -3
- package/dist/components/WorkflowTemplates.js.map +1 -1
- package/dist/components/Workspace.d.ts +22 -22
- package/dist/components/Workspace.d.ts.map +1 -1
- package/dist/components/Workspace.js +30 -30
- package/dist/components/Workspace.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/components/AssetPanel.tsx +263 -263
- package/src/components/Canvas.tsx +174 -174
- package/src/components/CommandPalette.tsx +242 -242
- package/src/components/CompareSlider.tsx +163 -163
- package/src/components/DownloadPanel.tsx +203 -203
- package/src/components/ErrorBanner.tsx +64 -64
- package/src/components/ExifPanel.tsx +154 -154
- package/src/components/GlobalDropzone.tsx +170 -170
- package/src/components/HistoryPanel.tsx +219 -219
- package/src/components/Inspector.tsx +136 -136
- package/src/components/ParamForm.tsx +136 -136
- package/src/components/PipelineBar.tsx +98 -98
- package/src/components/ProgressBar.tsx +78 -78
- package/src/components/StatusBar.tsx +148 -148
- package/src/components/ThemeToggle.tsx +98 -98
- package/src/components/Toolbar.tsx +65 -65
- package/src/components/WorkflowEditor.tsx +321 -321
- package/src/components/WorkflowTemplates.tsx +77 -77
- package/src/components/Workspace.tsx +223 -223
- package/src/css-modules.d.ts +3 -0
- package/src/index.ts +4 -0
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* before / after 两张图。用于直观展示工作流处理效果。
|
|
6
6
|
*
|
|
7
7
|
* 交互:
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* - 鼠标拖拽分隔条(或点击容器任意位置)调整揭示比例
|
|
9
|
+
* - 触摸:touchmove 同步
|
|
10
|
+
* - 键盘:← → 调整 5% 步长(聚焦分隔条时)
|
|
11
11
|
*
|
|
12
12
|
* 数据来源:
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* - before: `store.selectedAssetId` 对应的 thumbnails(由 AssetPanel 自动生成)
|
|
14
|
+
* - after: `store.selectedOutputId` 对应的 thumbnails
|
|
15
|
+
* - 任一缺失则不渲染(返回 null)
|
|
16
16
|
*
|
|
17
17
|
* 注:本组件只负责"展示对比",不负责生成缩略图。缩略图由 AssetPanel
|
|
18
18
|
* 的 effect 统一生成并存入 store.thumbnails,本组件按 assetId 取用。
|
|
@@ -23,164 +23,164 @@ import { Icon } from '@lokvis/ui-core';
|
|
|
23
23
|
import { useWorkspaceStore } from '../store/index.js';
|
|
24
24
|
|
|
25
25
|
export interface CompareSliderProps {
|
|
26
|
-
|
|
26
|
+
className?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function CompareSlider({ className = '' }: CompareSliderProps) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
30
|
+
const assets = useWorkspaceStore((s) => s.assets);
|
|
31
|
+
const thumbnails = useWorkspaceStore((s) => s.thumbnails);
|
|
32
|
+
const selectedAssetId = useWorkspaceStore((s) => s.selectedAssetId);
|
|
33
|
+
const selectedOutputId = useWorkspaceStore((s) => s.selectedOutputId);
|
|
34
|
+
const lastOutputIds = useWorkspaceStore((s) => s.lastOutputIds);
|
|
35
|
+
|
|
36
|
+
// before:用户选中的输入资产;after:用户选中的输出资产(默认第一个)
|
|
37
|
+
const beforeId = selectedAssetId;
|
|
38
|
+
const afterId = selectedOutputId ?? lastOutputIds[0] ?? null;
|
|
39
|
+
|
|
40
|
+
const beforeAsset = beforeId ? assets.find((a) => a.id === beforeId) : null;
|
|
41
|
+
const afterAsset = afterId ? assets.find((a) => a.id === afterId) : null;
|
|
42
|
+
const beforeUrl = beforeId ? thumbnails[beforeId] : undefined;
|
|
43
|
+
const afterUrl = afterId ? thumbnails[afterId] : undefined;
|
|
44
|
+
|
|
45
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
46
|
+
const [pos, setPos] = React.useState(50); // 0-100,分隔条位置百分比
|
|
47
|
+
const [dragging, setDragging] = React.useState(false);
|
|
48
|
+
|
|
49
|
+
// 切换资产时重置位置到中央
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
setPos(50);
|
|
52
|
+
}, [beforeId, afterId]);
|
|
53
|
+
|
|
54
|
+
const updatePos = React.useCallback((clientX: number) => {
|
|
55
|
+
const el = containerRef.current;
|
|
56
|
+
if (!el) return;
|
|
57
|
+
const rect = el.getBoundingClientRect();
|
|
58
|
+
const ratio = (clientX - rect.left) / rect.width;
|
|
59
|
+
setPos(Math.max(0, Math.min(100, ratio * 100)));
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
// 鼠标拖拽
|
|
63
|
+
const handleMouseDown = (e: React.MouseEvent) => {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
setDragging(true);
|
|
66
|
+
updatePos(e.clientX);
|
|
67
|
+
};
|
|
68
|
+
React.useEffect(() => {
|
|
69
|
+
if (!dragging) return;
|
|
70
|
+
const onMove = (e: MouseEvent) => updatePos(e.clientX);
|
|
71
|
+
const onUp = () => setDragging(false);
|
|
72
|
+
document.addEventListener('mousemove', onMove);
|
|
73
|
+
document.addEventListener('mouseup', onUp);
|
|
74
|
+
return () => {
|
|
75
|
+
document.removeEventListener('mousemove', onMove);
|
|
76
|
+
document.removeEventListener('mouseup', onUp);
|
|
77
|
+
};
|
|
78
|
+
}, [dragging, updatePos]);
|
|
79
|
+
|
|
80
|
+
// 触摸拖拽
|
|
81
|
+
const handleTouchStart = (e: React.TouchEvent) => {
|
|
82
|
+
setDragging(true);
|
|
83
|
+
if (e.touches[0]) updatePos(e.touches[0].clientX);
|
|
84
|
+
};
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
if (!dragging) return;
|
|
87
|
+
const onMove = (e: TouchEvent) => {
|
|
88
|
+
if (e.touches[0]) updatePos(e.touches[0].clientX);
|
|
89
|
+
};
|
|
90
|
+
const onEnd = () => setDragging(false);
|
|
91
|
+
document.addEventListener('touchmove', onMove, { passive: true });
|
|
92
|
+
document.addEventListener('touchend', onEnd);
|
|
93
|
+
return () => {
|
|
94
|
+
document.removeEventListener('touchmove', onMove);
|
|
95
|
+
document.removeEventListener('touchend', onEnd);
|
|
96
|
+
};
|
|
97
|
+
}, [dragging, updatePos]);
|
|
98
|
+
|
|
99
|
+
// 键盘:← → 调整 5%
|
|
100
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
101
|
+
if (e.key === 'ArrowLeft') {
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
setPos((p) => Math.max(0, p - 5));
|
|
104
|
+
} else if (e.key === 'ArrowRight') {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
setPos((p) => Math.min(100, p + 5));
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
if (!beforeUrl || !afterUrl) return null;
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
ref={containerRef}
|
|
115
|
+
className={`relative select-none overflow-hidden rounded-lg ring-1 ring-black/5 ${className}`}
|
|
116
|
+
onMouseDown={handleMouseDown}
|
|
117
|
+
onTouchStart={handleTouchStart}
|
|
118
|
+
>
|
|
119
|
+
{/* after 全图(底层)——决定容器尺寸 */}
|
|
120
|
+
<img
|
|
121
|
+
src={afterUrl}
|
|
122
|
+
alt="After"
|
|
123
|
+
draggable={false}
|
|
124
|
+
className="block max-h-full max-w-full object-contain pointer-events-none"
|
|
125
|
+
/>
|
|
126
|
+
|
|
127
|
+
{/* before 覆盖层:绝对定位同尺寸,用 clip-path 从右侧裁剪到 pos%
|
|
128
|
+
(避免读取 containerRef.current.clientWidth 这种"渲染期读 ref"反模式) */}
|
|
129
|
+
<div
|
|
130
|
+
className="absolute inset-0"
|
|
131
|
+
style={{ clipPath: `inset(0 ${100 - pos}% 0 0)` }}
|
|
132
|
+
>
|
|
133
|
+
<img
|
|
134
|
+
src={beforeUrl}
|
|
135
|
+
alt="Before"
|
|
136
|
+
draggable={false}
|
|
137
|
+
className="block max-h-full max-w-full object-contain pointer-events-none"
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
{/* before/after 标签 */}
|
|
142
|
+
<span className="absolute top-2 left-2 rounded bg-black/60 px-1.5 py-0.5 text-[10px] font-medium text-[var(--lokvis-primary-fg)]">
|
|
143
|
+
Before
|
|
144
|
+
</span>
|
|
145
|
+
<span className="absolute top-2 right-2 rounded bg-black/60 px-1.5 py-0.5 text-[10px] font-medium text-[var(--lokvis-primary-fg)]">
|
|
146
|
+
After
|
|
147
|
+
</span>
|
|
148
|
+
|
|
149
|
+
{/* 分隔条 */}
|
|
150
|
+
<div
|
|
151
|
+
className="absolute top-0 bottom-0 z-10 cursor-ew-resize"
|
|
152
|
+
style={{ left: `${pos}%`, transform: 'translateX(-50%)' }}
|
|
153
|
+
role="separator"
|
|
154
|
+
aria-valuenow={Math.round(pos)}
|
|
155
|
+
aria-valuemin={0}
|
|
156
|
+
aria-valuemax={100}
|
|
157
|
+
aria-label="Comparison slider position"
|
|
158
|
+
tabIndex={0}
|
|
159
|
+
onKeyDown={handleKeyDown}
|
|
160
|
+
>
|
|
161
|
+
<div className="absolute inset-y-0 left-1/2 w-0.5 -translate-x-1/2 bg-[var(--lokvis-surface)] shadow-md" />
|
|
162
|
+
<div className="absolute top-1/2 left-1/2 flex h-8 w-8 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-[var(--lokvis-surface)] shadow-lg ring-1 ring-black/10">
|
|
163
|
+
<Icon size={14} className="text-[var(--lokvis-fg-muted)]">
|
|
164
|
+
<path d="M9 5l-5 7 5 7M15 5l5 7-5 7" />
|
|
165
|
+
</Icon>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
{/* 元数据对比(底部叠加) */}
|
|
170
|
+
{(beforeAsset || afterAsset) && (
|
|
171
|
+
<div className="absolute bottom-2 inset-x-2 flex justify-between text-[10px] text-[var(--lokvis-primary-fg)]">
|
|
172
|
+
{beforeAsset?.metadata.dimensions && (
|
|
173
|
+
<span className="rounded bg-black/60 px-1.5 py-0.5">
|
|
174
|
+
{beforeAsset.metadata.dimensions.width}×{beforeAsset.metadata.dimensions.height}
|
|
175
|
+
</span>
|
|
176
|
+
)}
|
|
177
|
+
{afterAsset?.metadata.dimensions && (
|
|
178
|
+
<span className="rounded bg-black/60 px-1.5 py-0.5">
|
|
179
|
+
{afterAsset.metadata.dimensions.width}×{afterAsset.metadata.dimensions.height}
|
|
180
|
+
</span>
|
|
181
|
+
)}
|
|
182
|
+
</div>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
186
|
}
|