@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.
- package/package.json +10 -7
- package/src/panel/VueViewOnlinePreview.vue +15 -7
- package/src/panel/VueViewPanel.vue +81 -55
- package/src/panel/components/ConfigHintIcon.vue +4 -2
- package/src/panel/components/ElementsLayer.vue +15 -0
- package/src/panel/components/MaterialPreview.vue +19 -1
- package/src/panel/components/MaterialSidebar.vue +35 -31
- package/src/panel/components/MaterialSidebarTreeNode.vue +27 -26
- package/src/panel/components/MoveableLayer.vue +7 -4
- package/src/panel/components/PanelConfigSidebar.vue +57 -39
- package/src/panel/components/ViewElementScopePanel.vue +6 -4
- package/src/panel/components/WorkspaceConfigSidebar.vue +7 -1
- package/src/panel/components/WorkspaceProjectNav.vue +23 -16
- package/src/panel/components/WorkspaceStageSplit.vue +10 -7
- package/src/panel/components/config/ConfigColorField.vue +3 -1
- package/src/panel/components/config/PanelConfigAudioSection.vue +44 -43
- package/src/panel/components/config/PanelConfigChartSection.vue +79 -76
- package/src/panel/components/config/PanelConfigGeometrySection.vue +21 -19
- package/src/panel/components/config/PanelConfigGridChildSpan.vue +7 -5
- package/src/panel/components/config/PanelConfigGridSection.vue +10 -8
- package/src/panel/components/config/PanelConfigImageSection.vue +22 -21
- package/src/panel/components/config/PanelConfigMultiSelect.vue +42 -40
- package/src/panel/components/config/PanelConfigNodeInfo.vue +19 -16
- package/src/panel/components/config/PanelConfigReferenceSection.vue +11 -9
- package/src/panel/components/config/PanelConfigStyleSections.vue +27 -26
- package/src/panel/components/config/PanelConfigTextSection.vue +20 -17
- package/src/panel/components/config/PanelConfigVideoSection.vue +15 -14
- package/src/panel/components/config/shared.ts +0 -3
- package/src/panel/components/elementsLayerNodes.ts +37 -18
- package/src/panel/components/materialSidebarData.ts +73 -54
- package/src/panel/components/scope-config/ScopeTemplatePreviewHost.vue +7 -2
- package/src/panel/components/scope-config/ScopeTemplatePreviewPanel.vue +6 -3
- package/src/panel/components/scope-config/ScopeTemplateUsageHint.vue +7 -16
- package/src/panel/components/scope-config/ScopeTemplateWarningsPanel.vue +4 -2
- package/src/panel/components/table/ConditionEditor.vue +181 -0
- package/src/panel/components/table/JsonCodeEditor.vue +148 -0
- package/src/panel/components/table/PanelConfigTableSection.vue +2033 -0
- package/src/panel/components/table/TableNodeContent.vue +557 -0
- package/src/panel/constants/messages.ts +76 -34
- package/src/panel/hooks/usePanelElements.ts +54 -41
- package/src/panel/hooks/useWorkspaceProjects.ts +8 -5
- package/src/panel/types.ts +4 -0
- package/src/panel/utils/panelElementDefaults.ts +73 -39
- package/src/panel/utils/scope-field-labels.ts +53 -39
- package/src/panel/utils/scope-template-spread.ts +57 -24
- package/src/panel/utils/scope-template-warnings.ts +23 -22
- package/src/panel/utils/scope-template.ts +80 -0
- package/src/tailwind.css +18 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arronqzy/vue-view",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Vue 3 visual view editor for Abuilder (Ant Design Vue)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
".": "./src/index.ts"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
+
"@tanstack/vue-virtual": "^3.13.2",
|
|
15
16
|
"ant-design-vue": "^4.2.6",
|
|
16
17
|
"dayjs": "^1.11.13",
|
|
17
18
|
"echarts": "^6.0.0",
|
|
@@ -22,10 +23,12 @@
|
|
|
22
23
|
"selecto": "^1.26.3",
|
|
23
24
|
"uuid": "^13.0.0",
|
|
24
25
|
"vue": "^3.5.13",
|
|
25
|
-
"@arronqzy/blueprint-dsl": "1.0.
|
|
26
|
-
"@arronqzy/
|
|
27
|
-
"@arronqzy/vue-blueprint": "0.1.
|
|
28
|
-
"@arronqzy/
|
|
26
|
+
"@arronqzy/blueprint-dsl": "1.0.4",
|
|
27
|
+
"@arronqzy/rx-store": "1.0.3",
|
|
28
|
+
"@arronqzy/vue-blueprint": "0.1.2",
|
|
29
|
+
"@arronqzy/i18n": "0.1.2",
|
|
30
|
+
"@arronqzy/vue-rx-store": "0.1.1",
|
|
31
|
+
"@arronqzy/view-table": "0.1.2"
|
|
29
32
|
},
|
|
30
33
|
"peerDependencies": {
|
|
31
34
|
"vue": "^3.4.0"
|
|
@@ -35,8 +38,8 @@
|
|
|
35
38
|
"eslint": "^8.57.0",
|
|
36
39
|
"typescript": "^5.5.4",
|
|
37
40
|
"vue-tsc": "^2.2.0",
|
|
38
|
-
"@arronqzy/
|
|
39
|
-
"@arronqzy/
|
|
41
|
+
"@arronqzy/typescript-config": "1.0.0",
|
|
42
|
+
"@arronqzy/eslint-config": "0.0.0"
|
|
40
43
|
},
|
|
41
44
|
"publishConfig": {
|
|
42
45
|
"access": "public"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useI18n } from "@arronqzy/i18n/vue";
|
|
2
3
|
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
|
3
4
|
import {
|
|
4
5
|
BlueprintGraph,
|
|
@@ -31,6 +32,8 @@ import {
|
|
|
31
32
|
resolvePreviewLayerElements,
|
|
32
33
|
} from "./utils/panelStateIO";
|
|
33
34
|
|
|
35
|
+
const { t, locale } = useI18n();
|
|
36
|
+
|
|
34
37
|
const PREVIEW_BOOT_PHASES: PageLifecyclePhase[] = ["mounted"];
|
|
35
38
|
|
|
36
39
|
const props = defineProps<{
|
|
@@ -76,13 +79,13 @@ function applyTitleIcon(titleIconDataUrl?: string) {
|
|
|
76
79
|
async function loadProject() {
|
|
77
80
|
const record = await loadWorkspaceRecord(props.projectId);
|
|
78
81
|
if (!record) {
|
|
79
|
-
loadError.value = "
|
|
82
|
+
loadError.value = t("panel.messages.workspaceNotFound");
|
|
80
83
|
panelState.value = null;
|
|
81
84
|
return;
|
|
82
85
|
}
|
|
83
86
|
const normalized = normalizeImportedPanelState(record.panelState);
|
|
84
87
|
if (!normalized) {
|
|
85
|
-
loadError.value = "
|
|
88
|
+
loadError.value = t("panel.messages.workspaceDataInvalid");
|
|
86
89
|
panelState.value = null;
|
|
87
90
|
return;
|
|
88
91
|
}
|
|
@@ -90,7 +93,7 @@ async function loadProject() {
|
|
|
90
93
|
clearViewElementScopes();
|
|
91
94
|
panelState.value = normalized;
|
|
92
95
|
blueprintGraph.value = BlueprintGraph.fromDocument(record.blueprintDocument);
|
|
93
|
-
document.title = record.productName.trim() || record.name || "
|
|
96
|
+
document.title = record.productName.trim() || record.name || t("panel.workspace.previewDocTitle");
|
|
94
97
|
applyTitleIcon(record.titleIconDataUrl);
|
|
95
98
|
projectRevision.value += 1;
|
|
96
99
|
}
|
|
@@ -192,7 +195,7 @@ const lifecycleReady = computed(
|
|
|
192
195
|
() => Boolean(panelState.value && layerElements.value.length > 0 && layoutReady.value)
|
|
193
196
|
);
|
|
194
197
|
|
|
195
|
-
useBlueprintPageLifecycle({
|
|
198
|
+
const { triggerBlueprintNode } = useBlueprintPageLifecycle({
|
|
196
199
|
graph: blueprintGraph,
|
|
197
200
|
active: ref(true),
|
|
198
201
|
enabled: lifecycleReady,
|
|
@@ -230,15 +233,15 @@ function noopSelect() {}
|
|
|
230
233
|
v-else-if="!panelState"
|
|
231
234
|
class="flex min-h-screen w-full items-center justify-center bg-white text-sm text-gray-600"
|
|
232
235
|
>
|
|
233
|
-
|
|
236
|
+
{{ t("panel.workspace.previewLoading") }}
|
|
234
237
|
</div>
|
|
235
238
|
|
|
236
239
|
<div
|
|
237
240
|
v-else-if="layerElements.length === 0"
|
|
238
241
|
class="flex min-h-screen w-full flex-col items-center justify-center gap-2 bg-white px-6 text-center text-sm text-gray-600"
|
|
239
242
|
>
|
|
240
|
-
<div
|
|
241
|
-
<div class="text-xs text-gray-400"
|
|
243
|
+
<div>{{ t("panel.workspace.previewNoNodes") }}</div>
|
|
244
|
+
<div class="text-xs text-gray-400">{{ t("panel.workspace.previewHint") }}</div>
|
|
242
245
|
</div>
|
|
243
246
|
|
|
244
247
|
<div
|
|
@@ -268,6 +271,11 @@ function noopSelect() {}
|
|
|
268
271
|
:layer-locked="true"
|
|
269
272
|
:preview-mode="true"
|
|
270
273
|
:preview-layout-key="layoutRevision"
|
|
274
|
+
:on-table-cell-action="
|
|
275
|
+
(payload) => {
|
|
276
|
+
void triggerBlueprintNode(payload.blueprintNodeId, payload);
|
|
277
|
+
}
|
|
278
|
+
"
|
|
271
279
|
@select-ids="noopSelect"
|
|
272
280
|
/>
|
|
273
281
|
</div>
|
|
@@ -63,8 +63,13 @@ import {
|
|
|
63
63
|
useViewElementScope,
|
|
64
64
|
} from "./scope/view-scope-store";
|
|
65
65
|
import { useRafThrottledScroll } from "./hooks/useRafThrottledScroll";
|
|
66
|
+
import { useI18n } from "@arronqzy/i18n/vue";
|
|
67
|
+
import { getPanelMessages } from "./constants/messages";
|
|
66
68
|
import "../tailwind.css";
|
|
67
69
|
|
|
70
|
+
const { t, locale, setLocale } = useI18n();
|
|
71
|
+
const panelMessages = () => getPanelMessages(t);
|
|
72
|
+
|
|
68
73
|
const props = withDefaults(
|
|
69
74
|
defineProps<{
|
|
70
75
|
class?: string;
|
|
@@ -107,7 +112,7 @@ const {
|
|
|
107
112
|
const selectedIds = ref<string[]>([]);
|
|
108
113
|
const zoom = ref<ViewportZoom>({ x: props.initialZoom, y: props.initialZoom });
|
|
109
114
|
const blueprintGraph = ref(BlueprintGraph.empty());
|
|
110
|
-
const blueprintMeta = ref<BlueprintMetaDraft>({ name: "
|
|
115
|
+
const blueprintMeta = ref<BlueprintMetaDraft>({ name: t("panel.defaults.unnamedBlueprint"), remark: "" });
|
|
111
116
|
const blueprintOpen = ref(false);
|
|
112
117
|
const selectedBlueprintNodeId = ref<string | null>(null);
|
|
113
118
|
const blueprintLibraryItems = ref<BlueprintLibraryListItem[]>([]);
|
|
@@ -118,7 +123,7 @@ const workspaceBlueprintRef = shallowRef<{
|
|
|
118
123
|
meta: BlueprintMetaDraft;
|
|
119
124
|
} | null>(null);
|
|
120
125
|
const configFocus = ref<WorkspaceConfigFocus>("view");
|
|
121
|
-
const productName = ref("
|
|
126
|
+
const productName = ref(t("panel.defaults.unnamedProduct"));
|
|
122
127
|
const titleIconDataUrl = ref("");
|
|
123
128
|
const editingLayerId = ref<string | null>(null);
|
|
124
129
|
const editingLayerName = ref("");
|
|
@@ -305,7 +310,7 @@ function handleViewScopeUpdate(viewElementIds: string[], scope: unknown) {
|
|
|
305
310
|
const blueprintDebugSession = useBlueprintDebugSession({
|
|
306
311
|
graph: blueprintGraph,
|
|
307
312
|
blueprintId: activeBlueprintLibraryId,
|
|
308
|
-
blueprintName: computed(() => blueprintMeta.value.name || "
|
|
313
|
+
blueprintName: computed(() => { void locale.value; return blueprintMeta.value.name || t("panel.defaults.unnamedBlueprint"); }),
|
|
309
314
|
resolveLibraryBlueprint,
|
|
310
315
|
libraryNameById: blueprintLibraryNameById,
|
|
311
316
|
onExecutionBlocked: handleBlueprintExecutionBlocked,
|
|
@@ -361,7 +366,7 @@ function handleWorkspaceProjectApplied(record: WorkspaceProjectRecord) {
|
|
|
361
366
|
workspaceBlueprintRef.value = {
|
|
362
367
|
document: record.blueprintDocument,
|
|
363
368
|
meta: {
|
|
364
|
-
name: record.blueprintMeta?.name ?? "
|
|
369
|
+
name: record.blueprintMeta?.name ?? t("panel.defaults.unnamedBlueprint"),
|
|
365
370
|
remark: record.blueprintMeta?.remark ?? "",
|
|
366
371
|
},
|
|
367
372
|
};
|
|
@@ -395,7 +400,7 @@ const workspaceProjects = useWorkspaceProjects({
|
|
|
395
400
|
onProjectApplied: handleWorkspaceProjectApplied,
|
|
396
401
|
});
|
|
397
402
|
|
|
398
|
-
useBlueprintPageLifecycle({
|
|
403
|
+
const { triggerBlueprintNode } = useBlueprintPageLifecycle({
|
|
399
404
|
graph: blueprintGraph,
|
|
400
405
|
active: blueprintOpen,
|
|
401
406
|
bootKey: computed(() => workspaceProjects.activeProjectId.value ?? undefined),
|
|
@@ -407,10 +412,16 @@ useBlueprintPageLifecycle({
|
|
|
407
412
|
onViewScopeUpdate: handleViewScopeUpdate,
|
|
408
413
|
});
|
|
409
414
|
|
|
415
|
+
const blueprintNodeOptions = computed(() =>
|
|
416
|
+
blueprintGraph.value.document.nodes.map((node) => ({
|
|
417
|
+
id: node.id,
|
|
418
|
+
label: `${node.label || node.id}${node.nodeType ? ` (${node.nodeType})` : ""}`,
|
|
419
|
+
}))
|
|
420
|
+
);
|
|
410
421
|
async function loadBlueprintFromLibrary(id: string) {
|
|
411
422
|
const record = await getBlueprintLibraryRecord(id);
|
|
412
423
|
if (!record) {
|
|
413
|
-
message.error(
|
|
424
|
+
message.error(panelMessages().blueprintNotFound);
|
|
414
425
|
void refreshBlueprintLibrary();
|
|
415
426
|
return;
|
|
416
427
|
}
|
|
@@ -461,7 +472,7 @@ async function syncBlueprintToLibrary() {
|
|
|
461
472
|
remark: blueprintMeta.value.remark,
|
|
462
473
|
});
|
|
463
474
|
blueprintSyncedDocument.value = blueprintGraph.value.document;
|
|
464
|
-
message.success(
|
|
475
|
+
message.success(panelMessages().blueprintSyncedToLibrary);
|
|
465
476
|
await refreshBlueprintLibrary();
|
|
466
477
|
}
|
|
467
478
|
|
|
@@ -478,7 +489,7 @@ async function saveBlueprintToLibrary(meta: BlueprintMetaDraft) {
|
|
|
478
489
|
blueprintSyncedDocument.value = blueprintGraph.value.document;
|
|
479
490
|
blueprintMeta.value = meta;
|
|
480
491
|
await refreshBlueprintLibrary();
|
|
481
|
-
message.success(
|
|
492
|
+
message.success(panelMessages().blueprintSavedToLibrary);
|
|
482
493
|
}
|
|
483
494
|
|
|
484
495
|
function handleExport() {
|
|
@@ -499,7 +510,7 @@ async function handleImportFile(file: File) {
|
|
|
499
510
|
const text = await file.text();
|
|
500
511
|
const parsed = JSON.parse(text) as State;
|
|
501
512
|
const ok = importPanelData(parsed);
|
|
502
|
-
if (!ok) window.alert(
|
|
513
|
+
if (!ok) window.alert(panelMessages().importInvalidFormat);
|
|
503
514
|
else selectedIds.value = [];
|
|
504
515
|
}
|
|
505
516
|
|
|
@@ -507,7 +518,7 @@ function openBlueprintExport() {
|
|
|
507
518
|
downloadBlueprintExport(
|
|
508
519
|
buildBlueprintExportPayload(blueprintGraph.value.document, blueprintMeta.value)
|
|
509
520
|
);
|
|
510
|
-
message.success(
|
|
521
|
+
message.success(panelMessages().blueprintExported);
|
|
511
522
|
}
|
|
512
523
|
|
|
513
524
|
async function handleBlueprintImportFile(file: File) {
|
|
@@ -518,12 +529,12 @@ async function handleBlueprintImportFile(file: File) {
|
|
|
518
529
|
await refreshBlueprintLibrary();
|
|
519
530
|
if (!activeBlueprintLibraryId.value) snapshotWorkspaceBlueprint();
|
|
520
531
|
await loadBlueprintFromLibrary(record.id);
|
|
521
|
-
message.success(
|
|
532
|
+
message.success(panelMessages().blueprintImported);
|
|
522
533
|
}
|
|
523
534
|
|
|
524
535
|
async function handleWorkspaceCreateProject() {
|
|
525
536
|
const result = await workspaceProjects.handleCreateProject();
|
|
526
|
-
if (result?.name) message.success(
|
|
537
|
+
if (result?.name) message.success(panelMessages().workspaceCreated(result.name));
|
|
527
538
|
}
|
|
528
539
|
|
|
529
540
|
async function handleWorkspaceOpenProject(id: string) {
|
|
@@ -531,24 +542,24 @@ async function handleWorkspaceOpenProject(id: string) {
|
|
|
531
542
|
clearViewElementScopes();
|
|
532
543
|
await workspaceProjects.handleOpenProject(id);
|
|
533
544
|
selectedIds.value = [];
|
|
534
|
-
message.success(
|
|
545
|
+
message.success(panelMessages().workspaceLoaded);
|
|
535
546
|
} catch (error) {
|
|
536
|
-
message.error(error instanceof Error ? error.message :
|
|
547
|
+
message.error(error instanceof Error ? error.message : panelMessages().openWorkspaceFailed);
|
|
537
548
|
}
|
|
538
549
|
}
|
|
539
550
|
|
|
540
551
|
async function handleWorkspaceSyncProject() {
|
|
541
552
|
try {
|
|
542
553
|
const name = await workspaceProjects.handleSyncProject();
|
|
543
|
-
if (name) message.success(
|
|
554
|
+
if (name) message.success(panelMessages().blueprintSynced(name));
|
|
544
555
|
} catch (error) {
|
|
545
|
-
message.error(error instanceof Error ? error.message :
|
|
556
|
+
message.error(error instanceof Error ? error.message : panelMessages().syncFailed);
|
|
546
557
|
}
|
|
547
558
|
}
|
|
548
559
|
|
|
549
560
|
async function handleWorkspaceDeleteProject(id: string) {
|
|
550
561
|
await workspaceProjects.handleDeleteProject(id);
|
|
551
|
-
message.success(
|
|
562
|
+
message.success(panelMessages().workspaceDeleted);
|
|
552
563
|
}
|
|
553
564
|
|
|
554
565
|
async function openOnlinePreviewForProject(
|
|
@@ -572,7 +583,7 @@ function commitRenameLayer() {
|
|
|
572
583
|
|
|
573
584
|
function handleMergeLayers() {
|
|
574
585
|
if (!canMergeLayers.value) {
|
|
575
|
-
message.warning(
|
|
586
|
+
message.warning(panelMessages().mergeNeedTwoLayers);
|
|
576
587
|
return;
|
|
577
588
|
}
|
|
578
589
|
mergeSelectedLayers(mergeLayerName.value.trim() || undefined);
|
|
@@ -610,39 +621,39 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
610
621
|
</script>
|
|
611
622
|
|
|
612
623
|
<template>
|
|
613
|
-
<Layout class="vue-view-panel h-screen overflow-hidden" :class="props.class">
|
|
624
|
+
<Layout class="vue-view-panel h-screen overflow-hidden" :class="props.class" :key="locale">
|
|
614
625
|
<Layout.Header class="flex h-auto flex-wrap items-center gap-2 bg-[#001529] px-3 py-2">
|
|
615
626
|
<Dropdown :trigger="['click']">
|
|
616
|
-
<Button type="text" class="!text-white"
|
|
627
|
+
<Button type="text" class="!text-white">{{ t("panel.menubar.file") }}</Button>
|
|
617
628
|
<template #overlay>
|
|
618
629
|
<Menu>
|
|
619
|
-
<Menu.Item @click="handleExport"
|
|
620
|
-
<Menu.Item @click="importInputRef?.click()"
|
|
630
|
+
<Menu.Item @click="handleExport">{{ t("panel.menubar.exportPanelJson") }}</Menu.Item>
|
|
631
|
+
<Menu.Item @click="importInputRef?.click()">{{ t("panel.menubar.importPanelJson") }}</Menu.Item>
|
|
621
632
|
</Menu>
|
|
622
633
|
</template>
|
|
623
634
|
</Dropdown>
|
|
624
635
|
<Dropdown :trigger="['click']">
|
|
625
|
-
<Button type="text" class="!text-white"
|
|
636
|
+
<Button type="text" class="!text-white">{{ t("panel.menubar.edit") }}</Button>
|
|
626
637
|
<template #overlay>
|
|
627
638
|
<Menu>
|
|
628
|
-
<Menu.Item :disabled="!canUndo" @click="undo"
|
|
629
|
-
<Menu.Item :disabled="!canRedo" @click="redo"
|
|
639
|
+
<Menu.Item :disabled="!canUndo" @click="undo">{{ t("panel.menubar.undo") }}</Menu.Item>
|
|
640
|
+
<Menu.Item :disabled="!canRedo" @click="redo">{{ t("panel.menubar.redo") }}</Menu.Item>
|
|
630
641
|
<Menu.Divider />
|
|
631
|
-
<Menu.Item :disabled="!hasUnlockedSelection" @click="bringElementsForward(selectedIds)"
|
|
632
|
-
<Menu.Item :disabled="!hasUnlockedSelection" @click="sendElementsBackward(selectedIds)"
|
|
633
|
-
<Menu.Item :disabled="!hasUnlockedSelection" @click="bringElementsToFront(selectedIds)"
|
|
634
|
-
<Menu.Item :disabled="!hasUnlockedSelection" @click="sendElementsToBack(selectedIds)"
|
|
642
|
+
<Menu.Item :disabled="!hasUnlockedSelection" @click="bringElementsForward(selectedIds)">{{ t("panel.menubar.bringForward") }}</Menu.Item>
|
|
643
|
+
<Menu.Item :disabled="!hasUnlockedSelection" @click="sendElementsBackward(selectedIds)">{{ t("panel.menubar.sendBackward") }}</Menu.Item>
|
|
644
|
+
<Menu.Item :disabled="!hasUnlockedSelection" @click="bringElementsToFront(selectedIds)">{{ t("panel.menubar.bringToFront") }}</Menu.Item>
|
|
645
|
+
<Menu.Item :disabled="!hasUnlockedSelection" @click="sendElementsToBack(selectedIds)">{{ t("panel.menubar.sendToBack") }}</Menu.Item>
|
|
635
646
|
<Menu.Divider />
|
|
636
|
-
<Menu.Item :disabled="!hasUnlockedSelection" @click="handleDeleteSelected"
|
|
647
|
+
<Menu.Item :disabled="!hasUnlockedSelection" @click="handleDeleteSelected">{{ t("panel.menubar.deleteSelected") }}</Menu.Item>
|
|
637
648
|
</Menu>
|
|
638
649
|
</template>
|
|
639
650
|
</Dropdown>
|
|
640
651
|
<Dropdown :trigger="['click']">
|
|
641
|
-
<Button type="text" class="!text-white"
|
|
652
|
+
<Button type="text" class="!text-white">{{ t("panel.menubar.blueprint") }}</Button>
|
|
642
653
|
<template #overlay>
|
|
643
654
|
<Menu>
|
|
644
|
-
<Menu.Item @click="openBlueprintExport"
|
|
645
|
-
<Menu.Item @click="blueprintImportInputRef?.click()"
|
|
655
|
+
<Menu.Item @click="openBlueprintExport">{{ t("panel.menubar.exportBlueprint") }}</Menu.Item>
|
|
656
|
+
<Menu.Item @click="blueprintImportInputRef?.click()">{{ t("panel.menubar.importBlueprint") }}</Menu.Item>
|
|
646
657
|
</Menu>
|
|
647
658
|
</template>
|
|
648
659
|
</Dropdown>
|
|
@@ -657,17 +668,26 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
657
668
|
@delete-project="handleWorkspaceDeleteProject"
|
|
658
669
|
@preview-project="openOnlinePreviewForProject"
|
|
659
670
|
/>
|
|
671
|
+
<Dropdown :trigger="['click']">
|
|
672
|
+
<Button type="text" class="!text-white">{{ t("panel.theme.language") }}</Button>
|
|
673
|
+
<template #overlay>
|
|
674
|
+
<Menu>
|
|
675
|
+
<Menu.Item :class="{ 'ant-menu-item-selected': locale === 'zh-CN' }" @click="setLocale('zh-CN')">{{ t("panel.theme.zhCN") }}</Menu.Item>
|
|
676
|
+
<Menu.Item :class="{ 'ant-menu-item-selected': locale === 'en-US' }" @click="setLocale('en-US')">{{ t("panel.theme.enUS") }}</Menu.Item>
|
|
677
|
+
</Menu>
|
|
678
|
+
</template>
|
|
679
|
+
</Dropdown>
|
|
660
680
|
<div class="flex-1" />
|
|
661
681
|
<Space>
|
|
662
|
-
<Button size="small" :disabled="!canUndo" @click="undo"
|
|
663
|
-
<Button size="small" :disabled="!canRedo" @click="redo"
|
|
682
|
+
<Button size="small" :disabled="!canUndo" @click="undo">{{ t("panel.menubar.undo") }}</Button>
|
|
683
|
+
<Button size="small" :disabled="!canRedo" @click="redo">{{ t("panel.menubar.redo") }}</Button>
|
|
664
684
|
<Button
|
|
665
685
|
size="small"
|
|
666
686
|
type="primary"
|
|
667
687
|
:disabled="!workspaceProjects.activeProjectId.value"
|
|
668
688
|
@click="workspaceProjects.activeProjectId.value && openOnlinePreviewForProject(workspaceProjects.activeProjectId.value, { syncFirst: workspaceProjects.dirty.value })"
|
|
669
689
|
>
|
|
670
|
-
|
|
690
|
+
{{ t("common.preview") }}
|
|
671
691
|
</Button>
|
|
672
692
|
</Space>
|
|
673
693
|
</Layout.Header>
|
|
@@ -689,9 +709,9 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
689
709
|
v-model:value="productName"
|
|
690
710
|
size="small"
|
|
691
711
|
class="w-[200px]"
|
|
692
|
-
placeholder="
|
|
712
|
+
:placeholder="t('panel.menubar.productName')"
|
|
693
713
|
/>
|
|
694
|
-
<span class="text-xs text-gray-500"
|
|
714
|
+
<span class="text-xs text-gray-500">{{ t("panel.menubar.zoom") }}</span>
|
|
695
715
|
<Slider
|
|
696
716
|
:min="0.25"
|
|
697
717
|
:max="4"
|
|
@@ -701,9 +721,9 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
701
721
|
@change="(v: number | [number, number]) => setUniformZoom(Array.isArray(v) ? v[0] : v)"
|
|
702
722
|
/>
|
|
703
723
|
<Tag v-if="activeLayer">{{ activeLayer.name }}</Tag>
|
|
704
|
-
<Tag color="blue"
|
|
724
|
+
<Tag color="blue">{{ t("panel.menubar.selectedCount", { count: selectedIds.length }) }}</Tag>
|
|
705
725
|
<div data-blueprint-toggle class="ml-auto flex items-center gap-2">
|
|
706
|
-
<span class="text-xs text-gray-500"
|
|
726
|
+
<span class="text-xs text-gray-500">{{ t("panel.menubar.blueprint") }}</span>
|
|
707
727
|
<Switch v-model:checked="blueprintOpen" size="small" />
|
|
708
728
|
</div>
|
|
709
729
|
</div>
|
|
@@ -738,6 +758,11 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
738
758
|
:selected-ids="selectedIds"
|
|
739
759
|
:update-element="updateElement"
|
|
740
760
|
:layer-locked="Boolean(activeLayer?.locked)"
|
|
761
|
+
:on-table-cell-action="
|
|
762
|
+
(payload) => {
|
|
763
|
+
void triggerBlueprintNode(payload.blueprintNodeId, payload);
|
|
764
|
+
}
|
|
765
|
+
"
|
|
741
766
|
@select-ids="selectIds"
|
|
742
767
|
/>
|
|
743
768
|
<SelectLayer
|
|
@@ -765,9 +790,9 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
765
790
|
|
|
766
791
|
<div class="border-t bg-white px-2 py-2">
|
|
767
792
|
<div class="mb-2 flex flex-wrap items-center gap-2">
|
|
768
|
-
<span class="text-xs font-semibold text-gray-500"
|
|
769
|
-
<Button size="small" @click="addLayer()"
|
|
770
|
-
<Button size="small" :disabled="!canMergeLayers" @click="isMergingLayers = true"
|
|
793
|
+
<span class="text-xs font-semibold text-gray-500">{{ t("panel.layers.title") }}</span>
|
|
794
|
+
<Button size="small" @click="addLayer()">{{ t("panel.layers.addShort") }}</Button>
|
|
795
|
+
<Button size="small" :disabled="!canMergeLayers" @click="isMergingLayers = true">{{ t("panel.layers.mergeShort") }}</Button>
|
|
771
796
|
</div>
|
|
772
797
|
<Tabs
|
|
773
798
|
size="small"
|
|
@@ -779,8 +804,8 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
779
804
|
<template #tab>
|
|
780
805
|
<span class="inline-flex items-center gap-1">
|
|
781
806
|
{{ layer.name }}
|
|
782
|
-
<Tag v-if="layer.isMapping" color="blue" class="!m-0"
|
|
783
|
-
<Tag v-if="layer.isPrimary" color="green" class="!m-0"
|
|
807
|
+
<Tag v-if="layer.isMapping" color="blue" class="!m-0">{{ t("panel.layers.mapping") }}</Tag>
|
|
808
|
+
<Tag v-if="layer.isPrimary" color="green" class="!m-0">{{ t("panel.layers.primary") }}</Tag>
|
|
784
809
|
</span>
|
|
785
810
|
</template>
|
|
786
811
|
</Tabs.TabPane>
|
|
@@ -794,23 +819,23 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
794
819
|
class="w-40"
|
|
795
820
|
@press-enter="commitRenameLayer"
|
|
796
821
|
/>
|
|
797
|
-
<Button size="small" type="primary" @click="commitRenameLayer"
|
|
822
|
+
<Button size="small" type="primary" @click="commitRenameLayer">{{ t("common.ok") }}</Button>
|
|
798
823
|
</template>
|
|
799
824
|
<template v-else>
|
|
800
825
|
<span class="font-medium">{{ activeLayer.name }}</span>
|
|
801
|
-
<Button size="small" type="link" @click="startRenameLayer(activeLayer.id, activeLayer.name)"
|
|
826
|
+
<Button size="small" type="link" @click="startRenameLayer(activeLayer.id, activeLayer.name)">{{ t("panel.layers.renameShort") }}</Button>
|
|
802
827
|
</template>
|
|
803
828
|
<Button size="small" @click="toggleLayerLock(activeLayer.id)">
|
|
804
|
-
{{ activeLayer.locked ? "
|
|
829
|
+
{{ activeLayer.locked ? t("panel.layers.unlockShort") : t("panel.layers.lockShort") }}
|
|
805
830
|
</Button>
|
|
806
831
|
<Checkbox
|
|
807
832
|
:checked="Boolean(activeLayer.mergeSelected)"
|
|
808
833
|
@change="() => toggleLayerMergeSelected(activeLayer!.id)"
|
|
809
834
|
>
|
|
810
|
-
|
|
835
|
+
{{ t("panel.layers.joinMerge") }}
|
|
811
836
|
</Checkbox>
|
|
812
837
|
<Button size="small" :disabled="activeLayer.isPrimary" @click="setPrimaryLayer(activeLayer.id)">
|
|
813
|
-
|
|
838
|
+
{{ t("panel.layers.setPrimary") }}
|
|
814
839
|
</Button>
|
|
815
840
|
<Button
|
|
816
841
|
size="small"
|
|
@@ -818,7 +843,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
818
843
|
:disabled="!activeLayer.editable"
|
|
819
844
|
@click="deleteLayer(activeLayer.id)"
|
|
820
845
|
>
|
|
821
|
-
|
|
846
|
+
{{ t("panel.layers.delete") }}
|
|
822
847
|
</Button>
|
|
823
848
|
</div>
|
|
824
849
|
</div>
|
|
@@ -840,6 +865,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
840
865
|
:selected-blueprint-node="selectedBlueprintNode"
|
|
841
866
|
:allow-false-signal-propagation="blueprintGraph.document.allowFalseSignalPropagation"
|
|
842
867
|
:blueprint-library-options="blueprintLibraryOptions"
|
|
868
|
+
:blueprint-node-options="blueprintNodeOptions"
|
|
843
869
|
:all-view-elements="allElements"
|
|
844
870
|
:on-update-blueprint-node="handleUpdateBlueprintNode"
|
|
845
871
|
:on-update-allow-false-signal-propagation="handleUpdateAllowFalseSignalPropagation"
|
|
@@ -852,12 +878,12 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
|
|
|
852
878
|
|
|
853
879
|
<Modal
|
|
854
880
|
v-model:open="isMergingLayers"
|
|
855
|
-
title="
|
|
856
|
-
ok-text="
|
|
881
|
+
:title="t('panel.layers.mergeDialogTitle')"
|
|
882
|
+
:ok-text="t('panel.layers.mergeOk')"
|
|
857
883
|
@ok="handleMergeLayers"
|
|
858
884
|
>
|
|
859
|
-
<Input v-model:value="mergeLayerName" placeholder="
|
|
860
|
-
<div class="mt-2 text-xs text-gray-500"
|
|
885
|
+
<Input v-model:value="mergeLayerName" :placeholder="t('panel.layers.mergedNamePlaceholderOptional')" />
|
|
886
|
+
<div class="mt-2 text-xs text-gray-500">{{ t("panel.layers.mergeSelectedCount", { count: mergeSelectedCount }) }}</div>
|
|
861
887
|
</Modal>
|
|
862
888
|
</Layout>
|
|
863
889
|
</template>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useI18n } from "@arronqzy/i18n/vue";
|
|
2
3
|
import { Tooltip } from "ant-design-vue";
|
|
3
4
|
|
|
5
|
+
const { t, locale } = useI18n();
|
|
4
6
|
withDefaults(
|
|
5
7
|
defineProps<{
|
|
6
8
|
label?: string;
|
|
7
9
|
contentClass?: string;
|
|
8
10
|
buttonClass?: string;
|
|
9
11
|
}>(),
|
|
10
|
-
{ label: "
|
|
12
|
+
{ label: t("common.hint") }
|
|
11
13
|
);
|
|
12
14
|
</script>
|
|
13
15
|
|
|
@@ -26,7 +28,7 @@ withDefaults(
|
|
|
26
28
|
buttonClass ??
|
|
27
29
|
'inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-border text-[10px] leading-none text-muted-foreground hover:bg-accent/50'
|
|
28
30
|
"
|
|
29
|
-
:aria-label="
|
|
31
|
+
:aria-label="t('common.hintAria', { label })"
|
|
30
32
|
>
|
|
31
33
|
?
|
|
32
34
|
</button>
|
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
TextNodeContent,
|
|
15
15
|
VideoNodeContent,
|
|
16
16
|
} from "./elementsLayerNodes";
|
|
17
|
+
import TableNodeContent from "./table/TableNodeContent.vue";
|
|
18
|
+
import type { TableCellActionHandler } from "./table/TableNodeContent.vue";
|
|
17
19
|
|
|
18
20
|
const props = withDefaults(
|
|
19
21
|
defineProps<{
|
|
@@ -28,6 +30,7 @@ const props = withDefaults(
|
|
|
28
30
|
layerLocked?: boolean;
|
|
29
31
|
previewMode?: boolean;
|
|
30
32
|
previewLayoutKey?: number;
|
|
33
|
+
onTableCellAction?: TableCellActionHandler;
|
|
31
34
|
}>(),
|
|
32
35
|
{ layerLocked: false, previewMode: false }
|
|
33
36
|
);
|
|
@@ -45,6 +48,10 @@ const NodeContent = defineComponent({
|
|
|
45
48
|
layerLocked: { type: Boolean, default: false },
|
|
46
49
|
previewMode: { type: Boolean, default: false },
|
|
47
50
|
previewLayoutKey: { type: Number, default: undefined },
|
|
51
|
+
onTableCellAction: {
|
|
52
|
+
type: Function as PropType<TableCellActionHandler | undefined>,
|
|
53
|
+
default: undefined,
|
|
54
|
+
},
|
|
48
55
|
updateElement: {
|
|
49
56
|
type: Function as PropType<
|
|
50
57
|
(
|
|
@@ -100,6 +107,13 @@ const NodeContent = defineComponent({
|
|
|
100
107
|
if (el.materialType === "image") {
|
|
101
108
|
return h(ImageNodeContent, { element: el });
|
|
102
109
|
}
|
|
110
|
+
if (el.materialType === "table") {
|
|
111
|
+
return h(TableNodeContent, {
|
|
112
|
+
element: el,
|
|
113
|
+
interactive: p.previewMode || Boolean(p.onTableCellAction),
|
|
114
|
+
onCellAction: p.onTableCellAction,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
103
117
|
return h(EmptyNodePlaceholder, { element: el });
|
|
104
118
|
};
|
|
105
119
|
},
|
|
@@ -160,6 +174,7 @@ function onSelect(id: string, event: MouseEvent) {
|
|
|
160
174
|
:preview-mode="previewMode"
|
|
161
175
|
:preview-layout-key="previewLayoutKey"
|
|
162
176
|
:update-element="updateElement"
|
|
177
|
+
:on-table-cell-action="onTableCellAction"
|
|
163
178
|
/>
|
|
164
179
|
</div>
|
|
165
180
|
</template>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useI18n } from "@arronqzy/i18n/vue";
|
|
3
|
+
const { t, locale } = useI18n();
|
|
2
4
|
defineProps<{ id: string }>();
|
|
3
5
|
|
|
4
6
|
const common =
|
|
@@ -76,6 +78,22 @@ const common =
|
|
|
76
78
|
<div class="h-1.5 w-8/12 rounded bg-muted-foreground/45" />
|
|
77
79
|
</div>
|
|
78
80
|
</div>
|
|
81
|
+
<div v-else-if="id === 'table'" :class="common">
|
|
82
|
+
<div class="absolute inset-0 flex flex-col gap-1 p-2">
|
|
83
|
+
<div class="grid h-3 flex-none grid-cols-3 gap-1">
|
|
84
|
+
<div class="rounded-sm bg-primary/75" />
|
|
85
|
+
<div class="rounded-sm bg-primary/65" />
|
|
86
|
+
<div class="rounded-sm bg-primary/70" />
|
|
87
|
+
</div>
|
|
88
|
+
<div class="grid min-h-0 flex-1 grid-cols-3 gap-1">
|
|
89
|
+
<div
|
|
90
|
+
v-for="idx in 6"
|
|
91
|
+
:key="idx"
|
|
92
|
+
class="rounded-sm border border-primary/25 bg-primary/10"
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
79
97
|
<div v-else-if="id === 'rect'" :class="common">
|
|
80
98
|
<div class="absolute inset-2 rounded-md border-2 border-primary/80 bg-primary/15" />
|
|
81
99
|
</div>
|
|
@@ -91,7 +109,7 @@ const common =
|
|
|
91
109
|
<div v-else-if="id === 'reference'" :class="common">
|
|
92
110
|
<div class="absolute inset-2 rounded-md border border-dashed border-primary/70 bg-primary/10" />
|
|
93
111
|
<div class="absolute inset-0 flex items-center justify-center text-[10px] text-primary/80">
|
|
94
|
-
|
|
112
|
+
{{ t("panel.material.reference") }}
|
|
95
113
|
</div>
|
|
96
114
|
</div>
|
|
97
115
|
<div v-else-if="id === 'image'" :class="common">
|