@arronqzy/vue-view 0.1.0 → 0.1.3

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 (48) hide show
  1. package/package.json +10 -7
  2. package/src/panel/VueViewOnlinePreview.vue +15 -7
  3. package/src/panel/VueViewPanel.vue +81 -55
  4. package/src/panel/components/ConfigHintIcon.vue +4 -2
  5. package/src/panel/components/ElementsLayer.vue +15 -0
  6. package/src/panel/components/MaterialPreview.vue +19 -1
  7. package/src/panel/components/MaterialSidebar.vue +35 -31
  8. package/src/panel/components/MaterialSidebarTreeNode.vue +27 -26
  9. package/src/panel/components/MoveableLayer.vue +7 -4
  10. package/src/panel/components/PanelConfigSidebar.vue +57 -39
  11. package/src/panel/components/ViewElementScopePanel.vue +6 -4
  12. package/src/panel/components/WorkspaceConfigSidebar.vue +7 -1
  13. package/src/panel/components/WorkspaceProjectNav.vue +23 -16
  14. package/src/panel/components/WorkspaceStageSplit.vue +10 -7
  15. package/src/panel/components/config/ConfigColorField.vue +3 -1
  16. package/src/panel/components/config/PanelConfigAudioSection.vue +44 -43
  17. package/src/panel/components/config/PanelConfigChartSection.vue +79 -76
  18. package/src/panel/components/config/PanelConfigGeometrySection.vue +21 -19
  19. package/src/panel/components/config/PanelConfigGridChildSpan.vue +7 -5
  20. package/src/panel/components/config/PanelConfigGridSection.vue +10 -8
  21. package/src/panel/components/config/PanelConfigImageSection.vue +22 -21
  22. package/src/panel/components/config/PanelConfigMultiSelect.vue +42 -40
  23. package/src/panel/components/config/PanelConfigNodeInfo.vue +19 -16
  24. package/src/panel/components/config/PanelConfigReferenceSection.vue +11 -9
  25. package/src/panel/components/config/PanelConfigStyleSections.vue +27 -26
  26. package/src/panel/components/config/PanelConfigTextSection.vue +20 -17
  27. package/src/panel/components/config/PanelConfigVideoSection.vue +15 -14
  28. package/src/panel/components/config/shared.ts +0 -3
  29. package/src/panel/components/elementsLayerNodes.ts +37 -18
  30. package/src/panel/components/materialSidebarData.ts +73 -54
  31. package/src/panel/components/scope-config/ScopeTemplatePreviewHost.vue +7 -2
  32. package/src/panel/components/scope-config/ScopeTemplatePreviewPanel.vue +6 -3
  33. package/src/panel/components/scope-config/ScopeTemplateUsageHint.vue +7 -16
  34. package/src/panel/components/scope-config/ScopeTemplateWarningsPanel.vue +4 -2
  35. package/src/panel/components/table/ConditionEditor.vue +181 -0
  36. package/src/panel/components/table/JsonCodeEditor.vue +148 -0
  37. package/src/panel/components/table/PanelConfigTableSection.vue +2033 -0
  38. package/src/panel/components/table/TableNodeContent.vue +557 -0
  39. package/src/panel/constants/messages.ts +76 -34
  40. package/src/panel/hooks/usePanelElements.ts +54 -41
  41. package/src/panel/hooks/useWorkspaceProjects.ts +8 -5
  42. package/src/panel/types.ts +4 -0
  43. package/src/panel/utils/panelElementDefaults.ts +73 -39
  44. package/src/panel/utils/scope-field-labels.ts +53 -39
  45. package/src/panel/utils/scope-template-spread.ts +57 -24
  46. package/src/panel/utils/scope-template-warnings.ts +23 -22
  47. package/src/panel/utils/scope-template.ts +80 -0
  48. package/src/tailwind.css +18 -10
@@ -0,0 +1,557 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineComponent, h, ref, type PropType, type VNode } from "vue";
3
+ import { useVirtualizer } from "@tanstack/vue-virtual";
4
+ import { Tooltip } from "ant-design-vue";
5
+ import { useI18n } from "@arronqzy/i18n/vue";
6
+ import {
7
+ transformToTableCached,
8
+ resolveCellDisplay,
9
+ resolveRowDisplay,
10
+ stylePropsToCss,
11
+ resolveRawTableInput,
12
+ resolveProgressDisplay,
13
+ type PanelTableConfig,
14
+ type NormalizedColumn,
15
+ type NormalizedRow,
16
+ type CellDisplay,
17
+ type TableCellActionPayload,
18
+ } from "@arronqzy/view-table";
19
+ import type { PanelElement } from "../../types";
20
+
21
+ export type TableCellActionHandler = (payload: TableCellActionPayload) => void;
22
+
23
+ function wrapCellTooltip(cell: CellDisplay, node: VNode): VNode {
24
+ if (!cell.tooltip?.enabled || !cell.tooltip.text) return node;
25
+ return h(
26
+ Tooltip,
27
+ {
28
+ title: cell.tooltip.text,
29
+ placement: cell.tooltip.placement ?? "top",
30
+ },
31
+ { default: () => node }
32
+ );
33
+ }
34
+
35
+ const props = withDefaults(
36
+ defineProps<{
37
+ element: PanelElement;
38
+ interactive?: boolean;
39
+ onCellAction?: TableCellActionHandler;
40
+ }>(),
41
+ { interactive: false }
42
+ );
43
+
44
+ const { t } = useI18n();
45
+ const parentRef = ref<HTMLDivElement | null>(null);
46
+
47
+ const config = computed(
48
+ () => (props.element.table ?? {}) as PanelTableConfig
49
+ );
50
+
51
+ const model = computed(() => {
52
+ try {
53
+ const raw = resolveRawTableInput(config.value);
54
+ return transformToTableCached(raw, config.value);
55
+ } catch {
56
+ return { columns: [], rows: [] };
57
+ }
58
+ });
59
+
60
+ const columns = computed(() => model.value.columns);
61
+ const rowHeight = computed(() => Math.max(24, config.value.rowHeight ?? 36));
62
+ const showHeader = computed(() => config.value.showHeader !== false);
63
+ const emptyText = computed(
64
+ () => config.value.emptyText || t("panel.config.tableEmpty")
65
+ );
66
+
67
+ const gridTemplate = computed(() =>
68
+ columns.value
69
+ .map((c) => {
70
+ if (c.width) return `${c.width}px`;
71
+ if (c.minWidth) return `minmax(${c.minWidth}px, 1fr)`;
72
+ return "minmax(96px, 1fr)";
73
+ })
74
+ .join(" ")
75
+ );
76
+
77
+ const virtualizerOptions = computed(() => ({
78
+ count: model.value.rows.length,
79
+ getScrollElement: () => parentRef.value,
80
+ estimateSize: () => rowHeight.value,
81
+ overscan: 8,
82
+ }));
83
+
84
+ const virtualizer = useVirtualizer(virtualizerOptions);
85
+ const virtualItems = computed(() => virtualizer.value.getVirtualItems());
86
+ const totalSize = computed(() => virtualizer.value.getTotalSize());
87
+
88
+ const tableStyle = computed(() => stylePropsToCss(config.value.tableStyle ?? {}));
89
+ const headerStyle = computed(() => stylePropsToCss(config.value.headerStyle ?? {}));
90
+
91
+ const tableTextColor = computed(
92
+ () =>
93
+ (typeof tableStyle.value.color === "string" && tableStyle.value.color.trim()) ||
94
+ (typeof config.value.tableStyle?.color === "string" && config.value.tableStyle.color.trim()) ||
95
+ "#111827"
96
+ );
97
+ const headerTextColor = computed(
98
+ () =>
99
+ (typeof headerStyle.value.color === "string" && headerStyle.value.color.trim()) ||
100
+ (typeof config.value.headerStyle?.color === "string" && config.value.headerStyle.color.trim()) ||
101
+ tableTextColor.value
102
+ );
103
+
104
+ const rootStyle = computed(() => ({
105
+ background: (config.value.tableStyle?.backgroundColor as string) || "#fff",
106
+ border:
107
+ config.value.tableStyle?.borderWidth != null
108
+ ? `${config.value.tableStyle.borderWidth}px solid ${config.value.tableStyle.borderColor ?? "rgba(0,0,0,0.12)"}`
109
+ : "1px solid rgba(0,0,0,0.08)",
110
+ borderRadius: config.value.tableStyle?.borderRadius ?? 6,
111
+ fontSize: config.value.tableStyle?.fontSize ?? 12,
112
+ ...tableStyle.value,
113
+ color: tableTextColor.value,
114
+ display: "flex" as const,
115
+ flexDirection: "column" as const,
116
+ }));
117
+
118
+ const headerRowStyle = computed(() => ({
119
+ display: "grid" as const,
120
+ gridTemplateColumns: gridTemplate.value,
121
+ height: `${rowHeight.value}px`,
122
+ flex: "0 0 auto",
123
+ position:
124
+ config.value.tableStyle?.stickyHeader === false
125
+ ? ("relative" as const)
126
+ : ("sticky" as const),
127
+ top: 0,
128
+ zIndex: 2,
129
+ background: (config.value.headerStyle?.backgroundColor as string) || "rgba(0,0,0,0.04)",
130
+ borderBottom: "1px solid rgba(0,0,0,0.1)",
131
+ ...headerStyle.value,
132
+ color: headerTextColor.value,
133
+ }));
134
+
135
+ function headerLabelOf(col: NormalizedColumn) {
136
+ return (col.title ?? "").trim() || col.field || col.id;
137
+ }
138
+
139
+ function headerJustify(align: NormalizedColumn["align"]) {
140
+ if (align === "center") return "center";
141
+ if (align === "right") return "flex-end";
142
+ return "flex-start";
143
+ }
144
+
145
+ function cellCommonStyle(cell: CellDisplay): Record<string, string | number> {
146
+ const style = stylePropsToCss(cell.style);
147
+ const textOverflow = cell.widgetProps?.textStyle?.overflow ?? "ellipsis";
148
+ const isWrap = cell.widget === "text" && textOverflow === "wrap";
149
+ return {
150
+ ...style,
151
+ overflow: "hidden",
152
+ ...(isWrap
153
+ ? { whiteSpace: "normal", wordBreak: "break-word" }
154
+ : { textOverflow: "ellipsis", whiteSpace: "nowrap" }),
155
+ width: "100%",
156
+ height: "100%",
157
+ display: "flex",
158
+ alignItems: isWrap ? "flex-start" : "center",
159
+ boxSizing: "border-box",
160
+ padding: (style.padding as string | number | undefined) ?? "0 8px",
161
+ };
162
+ }
163
+
164
+ const TableCellView = defineComponent({
165
+ name: "TableCellView",
166
+ props: {
167
+ cell: { type: Object as PropType<CellDisplay>, required: true },
168
+ row: { type: Object as PropType<NormalizedRow>, required: true },
169
+ column: { type: Object as PropType<NormalizedColumn>, required: true },
170
+ elementId: { type: String, required: true },
171
+ interactive: { type: Boolean, default: false },
172
+ onCellAction: { type: Function as PropType<TableCellActionHandler | undefined>, default: undefined },
173
+ },
174
+ setup(p) {
175
+ const emit = (kind: TableCellActionPayload["kind"], blueprintNodeId?: string) => {
176
+ const id = blueprintNodeId?.trim();
177
+ if (!id || !p.onCellAction) return;
178
+ p.onCellAction({
179
+ kind,
180
+ blueprintNodeId: id,
181
+ elementId: p.elementId,
182
+ columnField: p.column.field,
183
+ rowId: p.row.id,
184
+ row: p.row.values,
185
+ value: p.cell.raw,
186
+ });
187
+ };
188
+
189
+ return (): VNode => {
190
+ const cell = p.cell;
191
+ const common = cellCommonStyle(cell);
192
+ let node: VNode;
193
+
194
+ if (cell.widget === "tag" || cell.widget === "badge") {
195
+ const bg = cell.color ?? "#3b82f6";
196
+ node = h("div", { style: common }, [
197
+ h(
198
+ "span",
199
+ {
200
+ style: {
201
+ display: "inline-flex",
202
+ alignItems: "center",
203
+ gap: 6,
204
+ maxWidth: "100%",
205
+ borderRadius: cell.widget === "badge" ? 999 : 4,
206
+ padding: cell.widget === "badge" ? "0 8px" : "1px 8px",
207
+ fontSize: 12,
208
+ lineHeight: "20px",
209
+ color: "#fff",
210
+ background: bg,
211
+ },
212
+ },
213
+ [
214
+ cell.widget === "badge"
215
+ ? h("span", {
216
+ style: {
217
+ width: 6,
218
+ height: 6,
219
+ borderRadius: 99,
220
+ background: "rgba(255,255,255,0.9)",
221
+ flex: "0 0 auto",
222
+ },
223
+ })
224
+ : null,
225
+ h("span", { style: { overflow: "hidden", textOverflow: "ellipsis" } }, cell.text),
226
+ ]
227
+ ),
228
+ ]);
229
+ } else if (cell.widget === "link") {
230
+ node = h("div", { style: common }, [
231
+ h(
232
+ "a",
233
+ {
234
+ href: cell.href || "#",
235
+ target: cell.widgetProps?.openInNewTab === false ? undefined : "_blank",
236
+ rel: "noreferrer",
237
+ onClick: (e: Event) => {
238
+ e.stopPropagation();
239
+ emit("click", cell.widgetProps?.actions?.onClickBlueprintNodeId);
240
+ },
241
+ style: {
242
+ color: "#2563eb",
243
+ textDecoration: "underline",
244
+ overflow: "hidden",
245
+ textOverflow: "ellipsis",
246
+ },
247
+ },
248
+ cell.text || cell.href
249
+ ),
250
+ ]);
251
+ } else if (cell.widget === "progress") {
252
+ const pct = cell.progress ?? 0;
253
+ const display = resolveProgressDisplay(cell.widgetProps);
254
+ const trackColor = cell.color ?? "#3b82f6";
255
+ const label = h(
256
+ "span",
257
+ { style: { fontSize: 11, color: "rgba(0,0,0,0.55)", flex: "0 0 auto" } },
258
+ cell.text
259
+ );
260
+
261
+ if (display === "label") {
262
+ node = h("div", { style: common }, [label]);
263
+ } else if (display === "circle") {
264
+ const size = Math.max(16, cell.widgetProps?.progressSize ?? 28);
265
+ const stroke = Math.max(2, cell.widgetProps?.progressStrokeWidth ?? 3);
266
+ const r = (size - stroke) / 2;
267
+ const c = 2 * Math.PI * r;
268
+ const offset = c * (1 - Math.max(0, Math.min(100, pct)) / 100);
269
+ node = h("div", { style: { ...common, gap: 6, justifyContent: "center" } }, [
270
+ h("svg", { width: size, height: size, style: { flex: "0 0 auto" } }, [
271
+ h("circle", {
272
+ cx: size / 2,
273
+ cy: size / 2,
274
+ r,
275
+ fill: "none",
276
+ stroke: "rgba(0,0,0,0.08)",
277
+ "stroke-width": stroke,
278
+ }),
279
+ h("circle", {
280
+ cx: size / 2,
281
+ cy: size / 2,
282
+ r,
283
+ fill: "none",
284
+ stroke: trackColor,
285
+ "stroke-width": stroke,
286
+ "stroke-linecap": "round",
287
+ "stroke-dasharray": c,
288
+ "stroke-dashoffset": offset,
289
+ transform: `rotate(-90 ${size / 2} ${size / 2})`,
290
+ }),
291
+ h(
292
+ "text",
293
+ {
294
+ x: "50%",
295
+ y: "50%",
296
+ "dominant-baseline": "central",
297
+ "text-anchor": "middle",
298
+ "font-size": Math.max(8, Math.round(size * 0.32)),
299
+ fill: "rgba(0,0,0,0.65)",
300
+ },
301
+ String(Math.round(pct))
302
+ ),
303
+ ]),
304
+ ]);
305
+ } else {
306
+ const bar = h(
307
+ "div",
308
+ {
309
+ style: {
310
+ flex: 1,
311
+ height: 8,
312
+ borderRadius: 99,
313
+ background: "rgba(0,0,0,0.08)",
314
+ overflow: "hidden",
315
+ minWidth: 24,
316
+ },
317
+ },
318
+ [
319
+ h("div", {
320
+ style: { width: `${pct}%`, height: "100%", background: trackColor },
321
+ }),
322
+ ]
323
+ );
324
+
325
+ node = h("div", { style: { ...common, gap: 8 } }, [
326
+ bar,
327
+ display === "barLabel" ? label : null,
328
+ ]);
329
+ }
330
+ } else if (cell.widget === "image") {
331
+ const w = cell.widgetProps?.imageWidth ?? 28;
332
+ const hImg = cell.widgetProps?.imageHeight ?? 28;
333
+ node = h("div", { style: common }, [
334
+ cell.imageUrl
335
+ ? h("img", {
336
+ src: cell.imageUrl,
337
+ alt: "",
338
+ style: {
339
+ width: w,
340
+ height: hImg,
341
+ objectFit: (cell.widgetProps?.imageObjectFit as string) || "cover",
342
+ borderRadius: 4,
343
+ },
344
+ draggable: false,
345
+ })
346
+ : h("span", { style: { fontSize: 11, opacity: 0.5 } }, "—"),
347
+ ]);
348
+ } else if (cell.widget === "boolean") {
349
+ const on = Boolean(cell.booleanValue);
350
+ const canToggle = Boolean(p.interactive && p.onCellAction);
351
+ node = h("div", { style: common }, [
352
+ h(
353
+ "button",
354
+ {
355
+ type: "button",
356
+ disabled: !canToggle,
357
+ onMousedown: (e: Event) => e.stopPropagation(),
358
+ onClick: (e: Event) => {
359
+ e.stopPropagation();
360
+ if (!canToggle) return;
361
+ if (on) {
362
+ emit("toggleOff", cell.widgetProps?.actions?.onFalseBlueprintNodeId);
363
+ } else {
364
+ emit("toggleOn", cell.widgetProps?.actions?.onTrueBlueprintNodeId);
365
+ }
366
+ },
367
+ style: {
368
+ width: 28,
369
+ height: 16,
370
+ borderRadius: 99,
371
+ background: on ? "#16a34a" : "rgba(0,0,0,0.2)",
372
+ position: "relative",
373
+ display: "inline-block",
374
+ flex: "0 0 auto",
375
+ border: "none",
376
+ padding: 0,
377
+ cursor: canToggle ? "pointer" : "default",
378
+ },
379
+ "aria-pressed": on,
380
+ },
381
+ [
382
+ h("span", {
383
+ style: {
384
+ position: "absolute",
385
+ top: 2,
386
+ left: on ? 14 : 2,
387
+ width: 12,
388
+ height: 12,
389
+ borderRadius: 99,
390
+ background: "#fff",
391
+ },
392
+ }),
393
+ ]
394
+ ),
395
+ h("span", { style: { marginLeft: 6, fontSize: 12 } }, cell.text),
396
+ ]);
397
+ } else {
398
+ const textStyle = cell.widgetProps?.textStyle;
399
+ const canClickText = Boolean(cell.widgetProps?.actions?.onClickBlueprintNodeId);
400
+ node = h(
401
+ "div",
402
+ {
403
+ style: {
404
+ ...common,
405
+ fontFamily: textStyle?.fontFamily,
406
+ fontStyle: textStyle?.fontStyle,
407
+ textDecoration:
408
+ textStyle?.textDecoration === "none" ? undefined : textStyle?.textDecoration,
409
+ cursor: canClickText ? "pointer" : undefined,
410
+ color: canClickText && !(common as { color?: string }).color ? "#2563eb" : common.color,
411
+ },
412
+ onClick: (e: Event) => {
413
+ if (!canClickText) return;
414
+ e.stopPropagation();
415
+ emit("click", cell.widgetProps?.actions?.onClickBlueprintNodeId);
416
+ },
417
+ },
418
+ cell.text
419
+ );
420
+ }
421
+
422
+ return wrapCellTooltip(cell, node);
423
+ };
424
+ },
425
+ });
426
+
427
+ const TableRowView = defineComponent({
428
+ name: "TableRowView",
429
+ props: {
430
+ row: { type: Object as PropType<NormalizedRow>, required: true },
431
+ columns: { type: Array as PropType<NormalizedColumn[]>, required: true },
432
+ config: { type: Object as PropType<PanelTableConfig>, required: true },
433
+ rowHeight: { type: Number, required: true },
434
+ gridTemplate: { type: String, required: true },
435
+ elementId: { type: String, required: true },
436
+ interactive: { type: Boolean, default: false },
437
+ onCellAction: { type: Function as PropType<TableCellActionHandler | undefined>, default: undefined },
438
+ },
439
+ setup(p) {
440
+ return (): VNode => {
441
+ const rowDisplay = resolveRowDisplay(p.row, p.config);
442
+ return h(
443
+ "div",
444
+ {
445
+ role: "row",
446
+ style: {
447
+ display: "grid",
448
+ gridTemplateColumns: p.gridTemplate,
449
+ height: p.rowHeight,
450
+ boxSizing: "border-box",
451
+ borderBottom: "1px solid rgba(0,0,0,0.06)",
452
+ ...stylePropsToCss(rowDisplay.style),
453
+ },
454
+ },
455
+ p.columns.map((col) => {
456
+ const cell = resolveCellDisplay(p.row, col, p.config);
457
+ return h(
458
+ "div",
459
+ {
460
+ key: col.id,
461
+ role: "cell",
462
+ style: { minWidth: 0, borderRight: "1px solid rgba(0,0,0,0.04)" },
463
+ },
464
+ [
465
+ h(TableCellView, {
466
+ cell,
467
+ row: p.row,
468
+ column: col,
469
+ elementId: p.elementId,
470
+ interactive: p.interactive,
471
+ onCellAction: p.onCellAction,
472
+ }),
473
+ ]
474
+ );
475
+ })
476
+ );
477
+ };
478
+ },
479
+ });
480
+ </script>
481
+
482
+ <template>
483
+ <div class="rv-table-node h-full w-full overflow-hidden" :style="rootStyle">
484
+ <div v-if="showHeader" role="row" :style="headerRowStyle">
485
+ <div
486
+ v-for="col in columns"
487
+ :key="col.id"
488
+ role="columnheader"
489
+ :title="headerLabelOf(col)"
490
+ :style="{
491
+ padding: '0 8px',
492
+ display: 'flex',
493
+ alignItems: 'center',
494
+ fontWeight: config.headerStyle?.fontWeight ?? 600,
495
+ overflow: 'hidden',
496
+ textOverflow: 'ellipsis',
497
+ whiteSpace: 'nowrap',
498
+ borderRight: '1px solid rgba(0,0,0,0.04)',
499
+ textAlign: col.align,
500
+ justifyContent: headerJustify(col.align),
501
+ }"
502
+ >
503
+ {{ headerLabelOf(col) }}
504
+ </div>
505
+ </div>
506
+
507
+ <div ref="parentRef" class="min-h-0 flex-1 overflow-auto">
508
+ <div
509
+ v-if="model.rows.length === 0"
510
+ class="flex h-full flex-col items-center justify-center gap-2 px-3 text-center text-xs text-gray-400"
511
+ >
512
+ <svg
513
+ viewBox="0 0 48 48"
514
+ class="h-10 w-10 opacity-45"
515
+ fill="none"
516
+ stroke="currentColor"
517
+ stroke-width="1.6"
518
+ aria-hidden="true"
519
+ >
520
+ <rect x="8" y="12" width="32" height="24" rx="3" />
521
+ <path d="M8 20h32M20 12v24M28 12v24" stroke-opacity="0.55" />
522
+ <circle cx="24" cy="30" r="1.2" fill="currentColor" stroke="none" />
523
+ </svg>
524
+ <div>{{ emptyText }}</div>
525
+ </div>
526
+ <div
527
+ v-else
528
+ :style="{ height: `${totalSize}px`, position: 'relative', width: '100%' }"
529
+ >
530
+ <div
531
+ v-for="item in virtualItems"
532
+ :key="model.rows[item.index]?.id ?? item.key"
533
+ :style="{
534
+ position: 'absolute',
535
+ top: 0,
536
+ left: 0,
537
+ width: '100%',
538
+ height: `${item.size}px`,
539
+ transform: `translateY(${item.start}px)`,
540
+ }"
541
+ >
542
+ <TableRowView
543
+ v-if="model.rows[item.index]"
544
+ :row="model.rows[item.index]!"
545
+ :columns="columns"
546
+ :config="config"
547
+ :row-height="rowHeight"
548
+ :grid-template="gridTemplate"
549
+ :element-id="element.id"
550
+ :interactive="interactive"
551
+ :on-cell-action="onCellAction"
552
+ />
553
+ </div>
554
+ </div>
555
+ </div>
556
+ </div>
557
+ </template>
@@ -1,34 +1,76 @@
1
- export const PANEL_MESSAGES = {
2
- nodeNotFound: "未找到节点,可能已被删除",
3
- sourceNodeNotFound: "未找到源节点,可能已被删除",
4
- targetLayerNotFound: "目标图层不存在",
5
- nodeMoveSameLayer: "已在当前图层",
6
- nodeDeleteLocked: "锁定节点不可删除,请在右侧【节点信息】中取消锁定后重试",
7
- nodeDeleteLayerLocked: "当前节点所在图层已锁定,无法删除。请先在图层栏取消锁定",
8
- nodeBatchDeleteContainsLocked:
9
- "选中节点包含锁定节点,无法批量删除。请先在右侧【节点信息】中取消锁定",
10
- nodeMoveLocked: "锁定节点不允许更换图层,请先在右侧【节点信息】中取消锁定",
11
- nodeMoveSourceLayerLocked: "节点所在图层已锁定,无法更换图层。请先在图层栏取消锁定",
12
- nodeMoveTargetLayerLocked: "目标图层已锁定,无法移入。请先在图层栏取消锁定",
13
- activeLayerLockedCannotAdd: "当前图层已锁定,无法新增节点",
14
- nodeLayerLockedCannotCopy: "当前节点所在图层已锁定,无法复制",
15
- selectionContainsLockedLayerNode: "选中节点包含锁定图层内容,无法批量删除",
16
- sourceLayerLockedCannotPaste: "复制源节点所在图层已锁定,无法粘贴",
17
- nodeConfigLocked: "当前节点已锁定,配置项不可编辑。",
18
- nodeConfigLayerLocked: "当前节点所在图层已锁定,配置项不可编辑。",
19
- readImageFailed: "读取图片失败",
20
- readAudioFailed: "读取音频失败",
21
- readVideoFailed: "读取视频失败",
22
- readRecordAudioFailed: "录音读取失败",
23
- audioLocalSaved: "已写入本地音频(base64)",
24
- audioRemoteUploaded: "已上传服务器并更新远程链接",
25
- audioServerUploadFailed: "服务器上传失败,仅保留本地音频",
26
- audioPosterSet: "已设置音频占位图",
27
- audioRecordUnsupported: "当前环境不支持录音",
28
- audioRecordSaved: "录音已保存,可直接播放",
29
- audioRecording: "录音中...",
30
- audioRecordStartFailed: "无法开始录音,请检查麦克风权限",
31
- videoLocalSaved: "已写入本地视频(base64)",
32
- videoRemoteUploaded: "已上传服务器并更新远程链接",
33
- videoServerUploadFailed: "服务器上传失败,仅保留本地视频",
34
- } as const;
1
+ import type { TranslateFn } from "@arronqzy/i18n";
2
+
3
+ export function getPanelMessages(t: TranslateFn) {
4
+ return {
5
+ nodeNotFound: t("panel.messages.nodeNotFound"),
6
+ sourceNodeNotFound: t("panel.messages.sourceNodeNotFound"),
7
+ targetLayerNotFound: t("panel.messages.targetLayerNotFound"),
8
+ nodeMoveSameLayer: t("panel.messages.nodeMoveSameLayer"),
9
+ nodeDeleteLocked: t("panel.messages.nodeDeleteLocked"),
10
+ nodeDeleteLayerLocked: t("panel.messages.nodeDeleteLayerLocked"),
11
+ nodeBatchDeleteContainsLocked: t("panel.messages.nodeBatchDeleteContainsLocked"),
12
+ nodeMoveLocked: t("panel.messages.nodeMoveLocked"),
13
+ nodeMoveSourceLayerLocked: t("panel.messages.nodeMoveSourceLayerLocked"),
14
+ nodeMoveTargetLayerLocked: t("panel.messages.nodeMoveTargetLayerLocked"),
15
+ activeLayerLockedCannotAdd: t("panel.messages.activeLayerLockedCannotAdd"),
16
+ nodeLayerLockedCannotCopy: t("panel.messages.nodeLayerLockedCannotCopy"),
17
+ selectionContainsLockedLayerNode: t("panel.messages.selectionContainsLockedLayerNode"),
18
+ sourceLayerLockedCannotPaste: t("panel.messages.sourceLayerLockedCannotPaste"),
19
+ nodeConfigLocked: t("panel.messages.nodeConfigLocked"),
20
+ nodeConfigLayerLocked: t("panel.messages.nodeConfigLayerLocked"),
21
+ readImageFailed: t("panel.messages.readImageFailed"),
22
+ readAudioFailed: t("panel.messages.readAudioFailed"),
23
+ readVideoFailed: t("panel.messages.readVideoFailed"),
24
+ readRecordAudioFailed: t("panel.messages.readRecordAudioFailed"),
25
+ audioLocalSaved: t("panel.messages.audioLocalSaved"),
26
+ audioRemoteUploaded: t("panel.messages.audioRemoteUploaded"),
27
+ audioServerUploadFailed: t("panel.messages.audioServerUploadFailed"),
28
+ audioPosterSet: t("panel.messages.audioPosterSet"),
29
+ audioRecordUnsupported: t("panel.messages.audioRecordUnsupported"),
30
+ audioRecordSaved: t("panel.messages.audioRecordSaved"),
31
+ audioRecording: t("panel.messages.audioRecording"),
32
+ audioRecordStartFailed: t("panel.messages.audioRecordStartFailed"),
33
+ videoLocalSaved: t("panel.messages.videoLocalSaved"),
34
+ videoRemoteUploaded: t("panel.messages.videoRemoteUploaded"),
35
+ videoServerUploadFailed: t("panel.messages.videoServerUploadFailed"),
36
+ operationRestricted: t("panel.messages.operationRestricted"),
37
+ importInvalidFormat: t("panel.messages.importInvalidFormat"),
38
+ importJsonParseError: t("panel.messages.importJsonParseError"),
39
+ blueprintImportInvalid: t("panel.messages.blueprintImportInvalid"),
40
+ iconReadFailed: t("panel.messages.iconReadFailed"),
41
+ blueprintNotFound: t("panel.messages.blueprintNotFound"),
42
+ blueprintSynced: (name: string) => t("panel.messages.blueprintSynced", { name }),
43
+ blueprintSavedLocal: t("panel.messages.blueprintSavedLocal"),
44
+ blueprintSavedToLibrary: t("panel.messages.blueprintSavedToLibrary"),
45
+ blueprintSyncedToLibrary: t("panel.messages.blueprintSyncedToLibrary"),
46
+ blueprintExported: t("panel.messages.blueprintExported"),
47
+ blueprintRenamed: t("panel.messages.blueprintRenamed"),
48
+ renameFailed: t("panel.messages.renameFailed"),
49
+ blueprintDeletedFromLibrary: t("panel.messages.blueprintDeletedFromLibrary"),
50
+ blueprintImported: t("panel.messages.blueprintImported"),
51
+ workspaceCreated: (name: string) => t("panel.messages.workspaceCreated", { name }),
52
+ workspaceLoaded: t("panel.messages.workspaceLoaded"),
53
+ workspaceLoadedDesc: t("panel.messages.workspaceLoadedDesc"),
54
+ openWorkspaceFailed: t("panel.messages.openWorkspaceFailed"),
55
+ syncFailed: t("panel.messages.syncFailed"),
56
+ workspaceDeleted: t("panel.messages.workspaceDeleted"),
57
+ openPreviewFailed: t("panel.messages.openPreviewFailed"),
58
+ clearedBlueprintLogs: (removed: number) =>
59
+ t("panel.messages.clearedBlueprintLogs", { removed }),
60
+ noSavedBlueprintLogs: t("panel.messages.noSavedBlueprintLogs"),
61
+ mergeNeedTwoLayers: t("panel.messages.mergeNeedTwoLayers"),
62
+ layerNotFound: t("panel.messages.layerNotFound"),
63
+ defaultLayerCannotDelete: t("panel.messages.defaultLayerCannotDelete"),
64
+ lockedLayerCannotDelete: t("panel.messages.lockedLayerCannotDelete"),
65
+ selectTargetLayer: t("panel.messages.selectTargetLayer"),
66
+ shallowRefBlockingDelete: t("panel.messages.shallowRefBlockingDelete"),
67
+ noNodesSelected: t("panel.messages.noNodesSelected"),
68
+ noMigratableNodes: t("panel.messages.noMigratableNodes"),
69
+ lockedCannotOpenMapping: t("panel.messages.lockedCannotOpenMapping"),
70
+ saveWorkspaceFirst: t("panel.messages.saveWorkspaceFirst"),
71
+ workspaceNotFound: t("panel.messages.workspaceNotFound"),
72
+ workspaceDataInvalid: t("panel.messages.workspaceDataInvalid"),
73
+ };
74
+ }
75
+
76
+ export type PanelMessages = ReturnType<typeof getPanelMessages>;