@arronqzy/react-view 1.0.39 → 1.0.40
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/styles.css +316 -241
- package/package.json +7 -7
- package/src/panel/ReactViewPanel.tsx +80 -71
- package/src/panel/components/ElementsLayer.tsx +1 -1
- package/src/panel/components/MaterialSidebar.tsx +304 -264
- package/src/panel/components/MoveableLayer.tsx +11 -2
- package/src/panel/components/PanelCanvas.tsx +1 -0
- package/src/panel/components/PanelConfigSidebar.tsx +49 -65
- package/src/panel/components/PanelLayerDock.tsx +397 -316
- package/src/panel/components/PanelRulers.tsx +169 -42
- package/src/panel/components/SelectLayer.tsx +2 -2
- package/src/panel/components/WorkspaceProjectNav.tsx +1 -1
- package/src/panel/icons.tsx +117 -0
- package/src/tailwind.css +66 -5
|
@@ -1,26 +1,63 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from "react";
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import Ruler from "@scena/react-ruler";
|
|
3
3
|
import { PANEL_Z_INDEX } from "../constants/zIndex";
|
|
4
4
|
|
|
5
|
-
const RULER_WORLD_UNIT = 100;
|
|
6
5
|
const RULER_SEGMENT = 10;
|
|
6
|
+
/** 主刻度标签在屏幕上的目标间距(px),过密/过疏时动态调 unit */
|
|
7
|
+
const RULER_TARGET_MAJOR_PX = 78;
|
|
8
|
+
/** @scena/react-ruler 内部把刻度文字原点写死为 17px,厚度必须大于该值才看得见数字 */
|
|
9
|
+
const SCENA_TEXT_ORIGIN = 17;
|
|
7
10
|
|
|
8
11
|
export type PanelRulersProps = {
|
|
9
12
|
zoomX: number;
|
|
10
13
|
zoomY: number;
|
|
11
14
|
scrollLeft: number;
|
|
12
15
|
scrollTop: number;
|
|
16
|
+
/** 固定厚度;省略时按编辑区尺寸动态计算 */
|
|
13
17
|
size?: number;
|
|
14
18
|
};
|
|
15
19
|
|
|
20
|
+
function clamp(n: number, min: number, max: number) {
|
|
21
|
+
return Math.min(max, Math.max(min, n));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 1/2/5 × 10^n 好看步长 */
|
|
25
|
+
function niceNumber(raw: number): number {
|
|
26
|
+
if (!Number.isFinite(raw) || raw <= 0) return 1;
|
|
27
|
+
const exp = Math.floor(Math.log10(raw));
|
|
28
|
+
const frac = raw / 10 ** exp;
|
|
29
|
+
const niceFrac = frac <= 1 ? 1 : frac <= 2 ? 2 : frac <= 5 ? 5 : 10;
|
|
30
|
+
return niceFrac * 10 ** exp;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 按缩放动态主刻度单位:屏幕上主刻度间距 roughly 恒定,
|
|
35
|
+
* 缩小 → unit 变大(标签变少),放大 → unit 变小(标签变密)。
|
|
36
|
+
*/
|
|
37
|
+
export function resolveRulerUnit(zoom: number): number {
|
|
38
|
+
const z = Math.max(zoom, 0.0001);
|
|
39
|
+
return Math.max(1, niceNumber(RULER_TARGET_MAJOR_PX / z));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** 按画布可视区域动态计算刻度尺厚度(保证刻度数字可读) */
|
|
43
|
+
export function resolveRulerSize(width: number, height: number): number {
|
|
44
|
+
const edge = Math.min(width || 0, height || 0);
|
|
45
|
+
if (edge <= 0) return 22;
|
|
46
|
+
// 下限 24:文字带与刻度带分离,避免数字压住刻度线
|
|
47
|
+
return Math.round(clamp(edge * 0.032, 24, 30));
|
|
48
|
+
}
|
|
49
|
+
|
|
16
50
|
export function PanelRulers({
|
|
17
51
|
zoomX,
|
|
18
52
|
zoomY,
|
|
19
53
|
scrollLeft,
|
|
20
54
|
scrollTop,
|
|
21
|
-
size
|
|
55
|
+
size: sizeProp,
|
|
22
56
|
}: PanelRulersProps) {
|
|
57
|
+
const rootRef = useRef<HTMLDivElement | null>(null);
|
|
58
|
+
const [autoSize, setAutoSize] = useState(22);
|
|
23
59
|
const [isDark, setIsDark] = useState(false);
|
|
60
|
+
|
|
24
61
|
useEffect(() => {
|
|
25
62
|
const root = document.documentElement;
|
|
26
63
|
const update = () => setIsDark(root.classList.contains("dark"));
|
|
@@ -30,60 +67,150 @@ export function PanelRulers({
|
|
|
30
67
|
return () => observer.disconnect();
|
|
31
68
|
}, []);
|
|
32
69
|
|
|
33
|
-
|
|
34
|
-
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (typeof sizeProp === "number") return;
|
|
72
|
+
const el = rootRef.current;
|
|
73
|
+
if (!el) return;
|
|
74
|
+
const update = () => {
|
|
75
|
+
const rect = el.getBoundingClientRect();
|
|
76
|
+
setAutoSize(resolveRulerSize(rect.width, rect.height));
|
|
77
|
+
};
|
|
78
|
+
update();
|
|
79
|
+
const ro = new ResizeObserver(update);
|
|
80
|
+
ro.observe(el);
|
|
81
|
+
return () => ro.disconnect();
|
|
82
|
+
}, [sizeProp]);
|
|
35
83
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
textColor: isDark ? "rgba(248,250,252,0.95)" : "rgba(15,23,42,0.75)",
|
|
44
|
-
font: "10px system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial",
|
|
45
|
-
longLineSize: 8,
|
|
46
|
-
shortLineSize: 4,
|
|
47
|
-
}),
|
|
48
|
-
[isDark, zoomX]
|
|
49
|
-
);
|
|
84
|
+
const size = typeof sizeProp === "number" ? sizeProp : autoSize;
|
|
85
|
+
const s = `${size}px`;
|
|
86
|
+
const fontPx = Math.max(10, Math.min(11, Math.round(size * 0.38)));
|
|
87
|
+
const bg = isDark ? "rgba(15,23,42,0.98)" : "rgba(255,255,255,0.98)";
|
|
88
|
+
const lineColor = isDark ? "rgba(226,232,240,0.85)" : "rgba(15,23,42,0.55)";
|
|
89
|
+
const textColor = isDark ? "#f8fafc" : "#0f172a";
|
|
90
|
+
const seam = isDark ? "rgba(226,232,240,0.45)" : "rgba(15,23,42,0.28)";
|
|
50
91
|
|
|
51
|
-
|
|
92
|
+
// 刻度线只占内侧约 30%,数字在外侧,互不遮挡
|
|
93
|
+
const longLineSize = Math.max(4, Math.min(Math.round(size * 0.3), size - fontPx - 4));
|
|
94
|
+
const shortLineSize = Math.max(2, Math.round(longLineSize * 0.55));
|
|
95
|
+
// @scena 文字原点写死 17px
|
|
96
|
+
// end(顶/左): baseline=bottom,目标底边 ≈ fontPx+1
|
|
97
|
+
// start(底/右): baseline=top,目标顶边 ≈ size-fontPx-2
|
|
98
|
+
// 横向 offset=[沿尺, 厚度];纵向 offset=[厚度, 沿尺]
|
|
99
|
+
const textBandEnd = fontPx + 1 - (size - SCENA_TEXT_ORIGIN);
|
|
100
|
+
const textBandStart = size - fontPx - 2 - SCENA_TEXT_ORIGIN;
|
|
101
|
+
const textOffsetHEnd: [number, number] = [3, textBandEnd];
|
|
102
|
+
const textOffsetHStart: [number, number] = [3, textBandStart];
|
|
103
|
+
const textOffsetVEnd: [number, number] = [textBandEnd, 3];
|
|
104
|
+
const textOffsetVStart: [number, number] = [textBandStart, 3];
|
|
105
|
+
|
|
106
|
+
const rulerScrollLeft = scrollLeft + size * (1 - 1 / Math.max(zoomX, 0.0001));
|
|
107
|
+
const rulerScrollTop = scrollTop + size * (1 - 1 / Math.max(zoomY, 0.0001));
|
|
108
|
+
const unitX = useMemo(() => resolveRulerUnit(zoomX), [zoomX]);
|
|
109
|
+
const unitY = useMemo(() => resolveRulerUnit(zoomY), [zoomY]);
|
|
110
|
+
|
|
111
|
+
const sharedPaint = useMemo(
|
|
52
112
|
() => ({
|
|
53
|
-
zoom: zoomY,
|
|
54
|
-
unit: RULER_WORLD_UNIT,
|
|
55
113
|
segment: RULER_SEGMENT,
|
|
56
|
-
backgroundColor:
|
|
57
|
-
lineColor
|
|
58
|
-
textColor
|
|
59
|
-
font:
|
|
60
|
-
longLineSize
|
|
61
|
-
shortLineSize
|
|
114
|
+
backgroundColor: bg,
|
|
115
|
+
lineColor,
|
|
116
|
+
textColor,
|
|
117
|
+
font: `500 ${fontPx}px system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial`,
|
|
118
|
+
longLineSize,
|
|
119
|
+
shortLineSize,
|
|
120
|
+
mainLineSize: longLineSize + 2,
|
|
62
121
|
}),
|
|
63
|
-
[
|
|
122
|
+
[bg, fontPx, lineColor, longLineSize, shortLineSize, textColor]
|
|
64
123
|
);
|
|
65
124
|
|
|
125
|
+
const clipTop = `polygon(0 0, 100% 0, calc(100% - ${s}) 100%, ${s} 100%)`;
|
|
126
|
+
const clipBottom = `polygon(${s} 0, calc(100% - ${s}) 0, 100% 100%, 0 100%)`;
|
|
127
|
+
const clipLeft = `polygon(0 0, 100% ${s}, 100% calc(100% - ${s}), 0 100%)`;
|
|
128
|
+
const clipRight = `polygon(0 ${s}, 100% 0, 100% 100%, 0 calc(100% - ${s}))`;
|
|
129
|
+
|
|
66
130
|
return (
|
|
67
131
|
<div
|
|
132
|
+
ref={rootRef}
|
|
68
133
|
className="pointer-events-none absolute inset-0 isolate"
|
|
69
|
-
style={{ ["--rv-ruler-size" as string]:
|
|
134
|
+
style={{ ["--rv-ruler-size" as string]: s, zIndex: PANEL_Z_INDEX.ruler }}
|
|
70
135
|
>
|
|
71
|
-
|
|
72
|
-
|
|
136
|
+
{/* 顶:刻度朝下(end),数字在上半区 */}
|
|
137
|
+
<div
|
|
138
|
+
className="absolute inset-x-0 top-0 overflow-hidden"
|
|
139
|
+
style={{ height: s, clipPath: clipTop, backgroundColor: bg }}
|
|
140
|
+
>
|
|
141
|
+
<Ruler
|
|
142
|
+
key={`h-end-${unitX}`}
|
|
143
|
+
type="horizontal"
|
|
144
|
+
{...sharedPaint}
|
|
145
|
+
unit={unitX}
|
|
146
|
+
zoom={zoomX}
|
|
147
|
+
direction="end"
|
|
148
|
+
textOffset={textOffsetHEnd}
|
|
149
|
+
scrollPos={rulerScrollLeft}
|
|
150
|
+
/>
|
|
73
151
|
</div>
|
|
74
|
-
|
|
75
|
-
|
|
152
|
+
{/* 左:刻度朝右(end),数字在左半区 */}
|
|
153
|
+
<div
|
|
154
|
+
className="absolute inset-y-0 left-0 overflow-hidden"
|
|
155
|
+
style={{ width: s, clipPath: clipLeft, backgroundColor: bg }}
|
|
156
|
+
>
|
|
157
|
+
<Ruler
|
|
158
|
+
key={`v-end-${unitY}`}
|
|
159
|
+
type="vertical"
|
|
160
|
+
{...sharedPaint}
|
|
161
|
+
unit={unitY}
|
|
162
|
+
zoom={zoomY}
|
|
163
|
+
direction="end"
|
|
164
|
+
textOffset={textOffsetVEnd}
|
|
165
|
+
scrollPos={rulerScrollTop}
|
|
166
|
+
/>
|
|
76
167
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
168
|
+
{/* 底:刻度朝上(start),数字在下半区 */}
|
|
169
|
+
<div
|
|
170
|
+
className="absolute inset-x-0 bottom-0 overflow-hidden"
|
|
171
|
+
style={{ height: s, clipPath: clipBottom, backgroundColor: bg }}
|
|
172
|
+
>
|
|
173
|
+
<Ruler
|
|
174
|
+
key={`h-start-${unitX}`}
|
|
175
|
+
type="horizontal"
|
|
176
|
+
{...sharedPaint}
|
|
177
|
+
unit={unitX}
|
|
178
|
+
zoom={zoomX}
|
|
179
|
+
direction="start"
|
|
180
|
+
textOffset={textOffsetHStart}
|
|
181
|
+
scrollPos={rulerScrollLeft}
|
|
182
|
+
/>
|
|
79
183
|
</div>
|
|
80
|
-
|
|
81
|
-
|
|
184
|
+
{/* 右:刻度朝左(start),数字在右半区 */}
|
|
185
|
+
<div
|
|
186
|
+
className="absolute inset-y-0 right-0 overflow-hidden"
|
|
187
|
+
style={{ width: s, clipPath: clipRight, backgroundColor: bg }}
|
|
188
|
+
>
|
|
189
|
+
<Ruler
|
|
190
|
+
key={`v-start-${unitY}`}
|
|
191
|
+
type="vertical"
|
|
192
|
+
{...sharedPaint}
|
|
193
|
+
unit={unitY}
|
|
194
|
+
zoom={zoomY}
|
|
195
|
+
direction="start"
|
|
196
|
+
textOffset={textOffsetVStart}
|
|
197
|
+
scrollPos={rulerScrollTop}
|
|
198
|
+
/>
|
|
82
199
|
</div>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<
|
|
86
|
-
|
|
200
|
+
|
|
201
|
+
{/* 四角斜缝:SVG 明确画外角→内角 */}
|
|
202
|
+
<svg aria-hidden className="pointer-events-none absolute left-0 top-0" width={size} height={size} style={{ zIndex: 1 }}>
|
|
203
|
+
<line x1={0} y1={0} x2={size} y2={size} stroke={seam} strokeWidth={1} />
|
|
204
|
+
</svg>
|
|
205
|
+
<svg aria-hidden className="pointer-events-none absolute right-0 top-0" width={size} height={size} style={{ zIndex: 1 }}>
|
|
206
|
+
<line x1={size} y1={0} x2={0} y2={size} stroke={seam} strokeWidth={1} />
|
|
207
|
+
</svg>
|
|
208
|
+
<svg aria-hidden className="pointer-events-none absolute bottom-0 left-0" width={size} height={size} style={{ zIndex: 1 }}>
|
|
209
|
+
<line x1={0} y1={size} x2={size} y2={0} stroke={seam} strokeWidth={1} />
|
|
210
|
+
</svg>
|
|
211
|
+
<svg aria-hidden className="pointer-events-none absolute bottom-0 right-0" width={size} height={size} style={{ zIndex: 1 }}>
|
|
212
|
+
<line x1={size} y1={size} x2={0} y2={0} stroke={seam} strokeWidth={1} />
|
|
213
|
+
</svg>
|
|
87
214
|
</div>
|
|
88
215
|
);
|
|
89
216
|
}
|
|
@@ -44,8 +44,8 @@ export function SelectLayer({
|
|
|
44
44
|
|
|
45
45
|
return (
|
|
46
46
|
<Selecto
|
|
47
|
-
//
|
|
48
|
-
container={
|
|
47
|
+
// 框选层挂在未 scale 的视口上,避免选区宽高被画布 transform 放大、线宽视觉变粗
|
|
48
|
+
container={dragRoot}
|
|
49
49
|
rootContainer={dragRoot}
|
|
50
50
|
// 选择框渲染到 body,避免受滚动/缩放影响产生偏移
|
|
51
51
|
portalContainer={overlayContainer}
|
|
@@ -74,7 +74,7 @@ export function WorkspaceProjectNav({
|
|
|
74
74
|
|
|
75
75
|
return (
|
|
76
76
|
<>
|
|
77
|
-
<div className="flex items-center gap-1.5 border-l border-border pl-2">
|
|
77
|
+
<div className="flex items-center gap-1.5 border-l border-border/60 pl-2.5">
|
|
78
78
|
<TooltipProvider delayDuration={150}>
|
|
79
79
|
<Tooltip>
|
|
80
80
|
<TooltipTrigger asChild>
|
package/src/panel/icons.tsx
CHANGED
|
@@ -158,3 +158,120 @@ export function IconImage() {
|
|
|
158
158
|
</svg>
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
export function IconFolder() {
|
|
163
|
+
return (
|
|
164
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
165
|
+
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Z" />
|
|
166
|
+
</svg>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function IconGrid() {
|
|
171
|
+
return (
|
|
172
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
173
|
+
<rect x="3" y="3" width="7" height="7" rx="1" />
|
|
174
|
+
<rect x="14" y="3" width="7" height="7" rx="1" />
|
|
175
|
+
<rect x="3" y="14" width="7" height="7" rx="1" />
|
|
176
|
+
<rect x="14" y="14" width="7" height="7" rx="1" />
|
|
177
|
+
</svg>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function IconTree() {
|
|
182
|
+
return (
|
|
183
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
184
|
+
<path d="M12 4v8" />
|
|
185
|
+
<path d="M6 20v-4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v4" />
|
|
186
|
+
<circle cx="12" cy="4" r="2" />
|
|
187
|
+
<circle cx="6" cy="20" r="2" />
|
|
188
|
+
<circle cx="18" cy="20" r="2" />
|
|
189
|
+
</svg>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function IconSearch() {
|
|
194
|
+
return (
|
|
195
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
196
|
+
<circle cx="11" cy="11" r="7" />
|
|
197
|
+
<path d="m20 20-3.5-3.5" />
|
|
198
|
+
</svg>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function IconStar({ filled }: { filled?: boolean }) {
|
|
203
|
+
return (
|
|
204
|
+
<svg
|
|
205
|
+
viewBox="0 0 24 24"
|
|
206
|
+
className="h-3.5 w-3.5"
|
|
207
|
+
fill={filled ? "currentColor" : "none"}
|
|
208
|
+
stroke="currentColor"
|
|
209
|
+
strokeWidth="2"
|
|
210
|
+
>
|
|
211
|
+
<path d="m12 3 2.7 5.5 6 .9-4.4 4.3 1 6L12 16.8 6.7 19.7l1-6L3.3 9.4l6-.9L12 3Z" />
|
|
212
|
+
</svg>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function IconEyeOff() {
|
|
217
|
+
return (
|
|
218
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
219
|
+
<path d="M3 3l18 18" />
|
|
220
|
+
<path d="M10.6 10.6a2 2 0 0 0 2.8 2.8" />
|
|
221
|
+
<path d="M9.9 5.1A10.6 10.6 0 0 1 12 5c5 0 9.3 3.1 11 7-.5 1.2-1.2 2.3-2.1 3.2" />
|
|
222
|
+
<path d="M6.1 6.1C4.2 7.3 2.7 9 1.9 11c1.7 3.9 6 7 10.1 7 1.4 0 2.7-.3 3.9-.7" />
|
|
223
|
+
</svg>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** 仅看引用子树 */
|
|
228
|
+
export function IconRefFilter({ active }: { active?: boolean }) {
|
|
229
|
+
return (
|
|
230
|
+
<svg
|
|
231
|
+
viewBox="0 0 24 24"
|
|
232
|
+
className="h-3.5 w-3.5"
|
|
233
|
+
fill="none"
|
|
234
|
+
stroke="currentColor"
|
|
235
|
+
strokeWidth={active ? 2.2 : 2}
|
|
236
|
+
>
|
|
237
|
+
<path d="M4 5h16l-5.5 6.5V18l-5 2.5v-9L4 5Z" fill={active ? "currentColor" : "none"} fillOpacity={active ? 0.2 : 0} />
|
|
238
|
+
<circle cx="16.5" cy="16.5" r="2.2" />
|
|
239
|
+
<path d="M14.8 15.2 12 12.5" />
|
|
240
|
+
</svg>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function IconBlueprint({ active }: { active?: boolean }) {
|
|
245
|
+
return (
|
|
246
|
+
<svg
|
|
247
|
+
viewBox="0 0 24 24"
|
|
248
|
+
className="h-3.5 w-3.5"
|
|
249
|
+
fill="none"
|
|
250
|
+
stroke="currentColor"
|
|
251
|
+
strokeWidth={active ? 2.2 : 2}
|
|
252
|
+
>
|
|
253
|
+
<rect x="3" y="4" width="18" height="16" rx="2" />
|
|
254
|
+
<circle cx="8" cy="10" r="1.5" fill={active ? "currentColor" : "none"} />
|
|
255
|
+
<circle cx="16" cy="10" r="1.5" fill={active ? "currentColor" : "none"} />
|
|
256
|
+
<circle cx="12" cy="16" r="1.5" fill={active ? "currentColor" : "none"} />
|
|
257
|
+
<path d="M9.2 10.8 10.8 14.2M14.8 10.8 13.2 14.2" />
|
|
258
|
+
</svg>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function IconSun() {
|
|
263
|
+
return (
|
|
264
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
265
|
+
<circle cx="12" cy="12" r="4" />
|
|
266
|
+
<path d="M12 2v2.5M12 19.5V22M4.93 4.93l1.77 1.77M17.3 17.3l1.77 1.77M2 12h2.5M19.5 12H22M4.93 19.07 6.7 17.3M17.3 6.7l1.77-1.77" />
|
|
267
|
+
</svg>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function IconMoon() {
|
|
272
|
+
return (
|
|
273
|
+
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
|
|
274
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3c0 .66.08 1.3.22 1.92A7 7 0 0 0 19.08 12c.62.14 1.26.22 1.92.22Z" />
|
|
275
|
+
</svg>
|
|
276
|
+
);
|
|
277
|
+
}
|
package/src/tailwind.css
CHANGED
|
@@ -26,6 +26,70 @@
|
|
|
26
26
|
background: hsl(var(--foreground) / 0.45);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/*
|
|
30
|
+
* 物料侧栏:容器查询写在源 CSS 里(JIT 的 @[Npx] 经常未进 dist)
|
|
31
|
+
* 窄:单列、卡片最多 112px;宽:auto-fill 换行,单卡约 88–104px
|
|
32
|
+
*/
|
|
33
|
+
.rv-material-sidebar {
|
|
34
|
+
container-type: inline-size;
|
|
35
|
+
container-name: rv-material;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.rv-material-grid {
|
|
39
|
+
display: grid;
|
|
40
|
+
grid-template-columns: minmax(0, 1fr);
|
|
41
|
+
justify-items: stretch;
|
|
42
|
+
gap: 0.375rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.rv-material-card {
|
|
46
|
+
width: 100%;
|
|
47
|
+
max-width: 112px;
|
|
48
|
+
justify-self: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@container rv-material (min-width: 200px) {
|
|
52
|
+
.rv-material-grid {
|
|
53
|
+
grid-template-columns: repeat(auto-fill, minmax(88px, 104px));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.rv-material-card {
|
|
57
|
+
max-width: none;
|
|
58
|
+
justify-self: stretch;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
* 配置侧栏:窄时多列表单改单列,避免挤成一团
|
|
64
|
+
*/
|
|
65
|
+
.scope-config-sidebar {
|
|
66
|
+
container-type: inline-size;
|
|
67
|
+
container-name: rv-config;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@container rv-config (max-width: 260px) {
|
|
71
|
+
.scope-config-sidebar .grid {
|
|
72
|
+
grid-template-columns: minmax(0, 1fr) !important;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.scope-config-sidebar .grid > * {
|
|
76
|
+
min-width: 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* 节点选中描边:用倒数抵消画布 scale,屏幕上始终约 2px(勿用 ring/border,会随缩放变粗)
|
|
82
|
+
*/
|
|
83
|
+
.rv-node-selected {
|
|
84
|
+
box-shadow: 0 0 0 calc(2px / var(--rv-canvas-scale, 1)) rgb(59 130 246 / 0.9);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Selecto 框选:渲染在 body,线宽保持屏幕 1px */
|
|
88
|
+
.selecto-selection {
|
|
89
|
+
border-width: 1px !important;
|
|
90
|
+
box-sizing: border-box !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
29
93
|
/*
|
|
30
94
|
* Moveable 控制框:
|
|
31
95
|
* - 根节点必须高于画布元素 zIndex(节点默认 ≥1),否则多选组框线会被节点盖住,只剩锚点可见
|
|
@@ -65,14 +129,11 @@
|
|
|
65
129
|
background: transparent !important;
|
|
66
130
|
}
|
|
67
131
|
|
|
132
|
+
/* 锚点尺寸交给 Moveable 的 scale(zoom) 补偿,勿写死 px 覆盖,否则放大后会偏粗 */
|
|
68
133
|
.rv-moveable-layer .moveable-control {
|
|
69
|
-
width: 14px !important;
|
|
70
|
-
height: 14px !important;
|
|
71
|
-
margin-top: -7px !important;
|
|
72
|
-
margin-left: -7px !important;
|
|
73
134
|
border-radius: 50% !important;
|
|
74
135
|
box-sizing: border-box !important;
|
|
75
|
-
border:
|
|
136
|
+
border-color: hsl(var(--background)) !important;
|
|
76
137
|
background: #1990ff !important;
|
|
77
138
|
background: var(--moveable-color) !important;
|
|
78
139
|
z-index: 10 !important;
|