@arronqzy/vue-view 0.1.19 → 0.1.20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arronqzy/vue-view",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Vue 3 visual view editor for Abuilder (Ant Design Vue)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,13 +23,13 @@
23
23
  "selecto": "^1.26.3",
24
24
  "uuid": "^13.0.0",
25
25
  "vue": "^3.5.13",
26
- "@arronqzy/i18n": "0.1.13",
27
26
  "@arronqzy/blueprint-dsl": "1.0.15",
28
- "@arronqzy/view-scene3d": "0.1.5",
27
+ "@arronqzy/i18n": "0.1.14",
29
28
  "@arronqzy/view-table": "0.1.8",
30
- "@arronqzy/rx-store": "1.0.8",
29
+ "@arronqzy/view-scene3d": "0.1.5",
31
30
  "@arronqzy/vue-blueprint": "0.1.14",
32
- "@arronqzy/vue-rx-store": "0.1.6"
31
+ "@arronqzy/vue-rx-store": "0.1.6",
32
+ "@arronqzy/rx-store": "1.0.8"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "vue": "^3.4.0"
@@ -83,10 +83,26 @@ const props = withDefaults(
83
83
  initialZoom?: number;
84
84
  nameSpace?: string | null;
85
85
  initialWorkspace?: WorkspaceProjectRecord | null;
86
+ /** 顶栏「设置 → 关于」展示的 npm 包名 */
87
+ packageName?: string | null;
88
+ /** 顶栏「设置 → 关于」展示的包版本号 */
89
+ packageVersion?: string | null;
86
90
  }>(),
87
- { initialZoom: 1, nameSpace: null, initialWorkspace: null }
91
+ {
92
+ initialZoom: 1,
93
+ nameSpace: null,
94
+ initialWorkspace: null,
95
+ packageName: null,
96
+ packageVersion: null,
97
+ }
88
98
  );
89
99
 
100
+ const packageVersionText = computed(() => {
101
+ const version = (props.packageVersion ?? "").trim();
102
+ if (!version) return t("panel.menubar.versionUnavailable");
103
+ return t("panel.menubar.versionValue", { version });
104
+ });
105
+
90
106
  const {
91
107
  elements,
92
108
  allElements,
@@ -756,7 +772,29 @@ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
756
772
  @delete-project="handleWorkspaceDeleteProject"
757
773
  @preview-project="openOnlinePreviewForProject"
758
774
  />
759
- <Dropdown :trigger="['click']">
775
+ <Dropdown :trigger="['click']">
776
+ <Button type="text" class="!text-white">{{ t("panel.menubar.settings") }}</Button>
777
+ <template #overlay>
778
+ <Menu>
779
+ <Menu.ItemGroup :title="t('panel.theme.language')">
780
+ <Menu.Item :class="{ 'ant-menu-item-selected': locale === 'zh-CN' }" @click="setLocale('zh-CN')">{{ t("panel.theme.zhCN") }}</Menu.Item>
781
+ <Menu.Item :class="{ 'ant-menu-item-selected': locale === 'en-US' }" @click="setLocale('en-US')">{{ t("panel.theme.enUS") }}</Menu.Item>
782
+ </Menu.ItemGroup>
783
+ <Menu.Divider />
784
+ <Menu.SubMenu :title="t('panel.menubar.about')" key="about">
785
+ <Menu.Item
786
+ key="version"
787
+ disabled
788
+ class="!cursor-default !opacity-100"
789
+ :data-abuilder-version="props.packageVersion || undefined"
790
+ >
791
+ {{ packageVersionText }}
792
+ </Menu.Item>
793
+ </Menu.SubMenu>
794
+ </Menu>
795
+ </template>
796
+ </Dropdown>
797
+ <Dropdown :trigger="['click']">
760
798
  <Button type="text" class="!text-white">{{ t("panel.theme.language") }}</Button>
761
799
  <template #overlay>
762
800
  <Menu>
@@ -62,8 +62,10 @@ const isSearchCollapsed = ref(false);
62
62
  const sidebarScrollRef = ref<HTMLElement | null>(null);
63
63
  const configScrollPosById = new Map<string, number>();
64
64
  const activeConfigScrollKey = ref<string | null>(null);
65
+ const expandedSectionsById = new Map<string, Record<string, boolean>>();
66
+ const activeExpandedKey = ref<string | null>(null);
65
67
 
66
- const expandedSections = ref<Record<string, boolean>>({
68
+ const DEFAULT_EXPANDED_SECTIONS: Record<string, boolean> = {
67
69
  nodeInfo: true,
68
70
  styleBackground: false,
69
71
  styleBorder: false,
@@ -78,6 +80,10 @@ const expandedSections = ref<Record<string, boolean>>({
78
80
  reference: true,
79
81
  imageConfig: true,
80
82
  tableConfig: true,
83
+ };
84
+
85
+ const expandedSections = ref<Record<string, boolean>>({
86
+ ...DEFAULT_EXPANDED_SECTIONS,
81
87
  });
82
88
 
83
89
  const normalizedSearch = computed(() => configSearch.value.trim().toLowerCase());
@@ -118,12 +124,39 @@ watch(
118
124
  }
119
125
  activeConfigScrollKey.value = nextKey;
120
126
  void nextTick(() => restoreConfigScroll(nextKey));
127
+
128
+ if (prevKey && prevKey !== nextKey) {
129
+ expandedSectionsById.set(prevKey, { ...expandedSections.value });
130
+ }
131
+ activeExpandedKey.value = nextKey;
132
+ if (!nextKey) {
133
+ expandedSections.value = { ...DEFAULT_EXPANDED_SECTIONS };
134
+ return;
135
+ }
136
+ const saved = expandedSectionsById.get(nextKey);
137
+ if (saved) {
138
+ expandedSections.value = { ...saved };
139
+ return;
140
+ }
141
+ const initial = { ...DEFAULT_EXPANDED_SECTIONS };
142
+ expandedSectionsById.set(nextKey, initial);
143
+ expandedSections.value = initial;
121
144
  },
122
145
  { flush: "post" }
123
146
  );
124
147
 
125
148
  onMounted(() => {
126
149
  activeConfigScrollKey.value = configScrollKey.value;
150
+ activeExpandedKey.value = configScrollKey.value;
151
+ if (configScrollKey.value) {
152
+ const saved = expandedSectionsById.get(configScrollKey.value);
153
+ if (saved) expandedSections.value = { ...saved };
154
+ else {
155
+ const initial = { ...DEFAULT_EXPANDED_SECTIONS };
156
+ expandedSectionsById.set(configScrollKey.value, initial);
157
+ expandedSections.value = initial;
158
+ }
159
+ }
127
160
  const el = sidebarScrollRef.value;
128
161
  el?.addEventListener("scroll", onConfigSidebarScroll, { passive: true });
129
162
  restoreConfigScroll(configScrollKey.value);
@@ -171,13 +204,23 @@ const materialType = computed(() => props.selectedElement?.materialType ?? "");
171
204
 
172
205
  const forceOpenSections = computed(() => hasSearch.value);
173
206
  provide("configHasSearch", hasSearch);
207
+ provide("configExpandState", {
208
+ isExpanded: (key: string, defaultValue = true) =>
209
+ expandedSections.value[key] ?? defaultValue,
210
+ setExpanded: (key: string, next: boolean) => {
211
+ setSectionExpanded(key, next);
212
+ },
213
+ });
174
214
 
175
215
  function isSectionExpanded(key: string, defaultValue = true) {
176
216
  return expandedSections.value[key] ?? defaultValue;
177
217
  }
178
218
 
179
219
  function setSectionExpanded(key: string, next: boolean) {
180
- expandedSections.value = { ...expandedSections.value, [key]: next };
220
+ const updated = { ...expandedSections.value, [key]: next };
221
+ expandedSections.value = updated;
222
+ const id = activeExpandedKey.value;
223
+ if (id) expandedSectionsById.set(id, updated);
181
224
  }
182
225
 
183
226
  function shouldShowSection(key: string, title: string, searchTerms: string[] = []) {
@@ -223,15 +266,6 @@ onMounted(() => {
223
266
  watch(isSearchCollapsed, (next) => {
224
267
  window.localStorage.setItem(SEARCH_COLLAPSE_STORAGE_KEY, next ? "1" : "0");
225
268
  });
226
-
227
- watch(
228
- () => [props.selectedElement?.id, props.selectedElement?.materialType],
229
- () => {
230
- if (isChartElement.value) {
231
- setSectionExpanded("chartBasic", true);
232
- }
233
- }
234
- );
235
269
  </script>
236
270
 
237
271
  <template>
@@ -2,12 +2,19 @@
2
2
  import { computed, inject, ref, type ComputedRef } from "vue";
3
3
  import ConfigHintIcon from "../ConfigHintIcon.vue";
4
4
 
5
+ export type ConfigExpandState = {
6
+ isExpanded: (key: string, defaultValue?: boolean) => boolean;
7
+ setExpanded: (key: string, next: boolean) => void;
8
+ };
9
+
5
10
  const props = withDefaults(
6
11
  defineProps<{
7
12
  title: string;
8
13
  hint?: boolean;
9
14
  collapsible?: boolean;
10
15
  defaultOpen?: boolean;
16
+ /** Stable key for remembering expand state per view node */
17
+ groupKey?: string;
11
18
  }>(),
12
19
  { defaultOpen: true, collapsible: false }
13
20
  );
@@ -16,13 +23,30 @@ const hasSearch = inject<ComputedRef<boolean>>(
16
23
  "configHasSearch",
17
24
  computed(() => false)
18
25
  );
26
+ const expandState = inject<ConfigExpandState | null>("configExpandState", null);
27
+
28
+ const localOpen = ref(props.defaultOpen);
29
+ const storageKey = computed(
30
+ () => props.groupKey?.trim() || `fg:${props.title}`
31
+ );
19
32
 
20
- const open = ref(props.defaultOpen);
21
- const isOpen = computed(() => !props.collapsible || hasSearch.value || open.value);
33
+ const isOpen = computed(() => {
34
+ if (!props.collapsible) return true;
35
+ if (hasSearch.value) return true;
36
+ if (expandState) {
37
+ return expandState.isExpanded(storageKey.value, props.defaultOpen);
38
+ }
39
+ return localOpen.value;
40
+ });
22
41
 
23
42
  function toggle() {
24
43
  if (!props.collapsible || hasSearch.value) return;
25
- open.value = !open.value;
44
+ const next = !isOpen.value;
45
+ if (expandState) {
46
+ expandState.setExpanded(storageKey.value, next);
47
+ return;
48
+ }
49
+ localOpen.value = next;
26
50
  }
27
51
  </script>
28
52
 
@@ -186,6 +186,7 @@ function onPosterFileChange(e: Event) {
186
186
  </ConfigFieldGroup>
187
187
  <ConfigFieldGroup
188
188
  :title="t('panel.config.groupDisplayStyle')"
189
+ group-key="audioDisplayStyle"
189
190
  collapsible
190
191
  :default-open="false"
191
192
  >
@@ -238,6 +238,7 @@ function onOptionJsonChange(v: string) {
238
238
  </ConfigFieldGroup>
239
239
  <ConfigFieldGroup
240
240
  :title="t('panel.config.groupChartDisplayMore')"
241
+ group-key="chartDisplayMore"
241
242
  collapsible
242
243
  :default-open="false"
243
244
  >
@@ -308,6 +309,7 @@ function onOptionJsonChange(v: string) {
308
309
 
309
310
  <ConfigFieldGroup
310
311
  :title="t('panel.config.groupTooltip')"
312
+ group-key="chartTooltip"
311
313
  collapsible
312
314
  :default-open="false"
313
315
  >
@@ -369,6 +371,7 @@ function onOptionJsonChange(v: string) {
369
371
  <ConfigFieldGroup
370
372
  v-if="['bar', 'line', 'area', 'scatter'].includes(selectedChartType)"
371
373
  :title="t('panel.config.groupAxes')"
374
+ group-key="chartAxes"
372
375
  collapsible
373
376
  :default-open="false"
374
377
  >
@@ -140,6 +140,7 @@ function clearSketch() {
140
140
  </ConfigFieldGroup>
141
141
  <ConfigFieldGroup
142
142
  :title="t('panel.config.groupCanvasScript')"
143
+ group-key="geometryCanvasScript"
143
144
  collapsible
144
145
  :default-open="false"
145
146
  >
@@ -158,6 +159,7 @@ function clearSketch() {
158
159
  </ConfigFieldGroup>
159
160
  <ConfigFieldGroup
160
161
  :title="t('panel.config.groupSketchOverlay')"
162
+ group-key="geometrySketch"
161
163
  collapsible
162
164
  :default-open="false"
163
165
  >
@@ -100,6 +100,7 @@ function onFileChange(e: Event) {
100
100
  </ConfigFieldGroup>
101
101
  <ConfigFieldGroup
102
102
  :title="t('panel.config.groupDisplayMode')"
103
+ group-key="imageDisplayMode"
103
104
  collapsible
104
105
  :default-open="false"
105
106
  >
@@ -101,6 +101,7 @@ function patch(patch: Partial<PanelElement>) {
101
101
  </div>
102
102
  <ConfigFieldGroup
103
103
  :title="t('panel.config.groupNodeMore')"
104
+ group-key="nodeMore"
104
105
  collapsible
105
106
  :default-open="false"
106
107
  >
@@ -59,6 +59,7 @@ function patch(patch: Partial<PanelElement>) {
59
59
  </ConfigFieldGroup>
60
60
  <ConfigFieldGroup
61
61
  :title="t('panel.config.groupCopyStrategy')"
62
+ group-key="referenceCopyStrategy"
62
63
  collapsible
63
64
  :default-open="false"
64
65
  >
@@ -84,6 +84,7 @@ function onFileChange(e: Event) {
84
84
  </ConfigFieldGroup>
85
85
  <ConfigFieldGroup
86
86
  :title="t('panel.config.groupBgLayout')"
87
+ group-key="styleBgLayout"
87
88
  collapsible
88
89
  :default-open="false"
89
90
  >
@@ -215,6 +215,7 @@ watch(() => [props.element.id, props.element.textHtml], syncEditorHtml);
215
215
  </ConfigFieldGroup>
216
216
  <ConfigFieldGroup
217
217
  :title="t('panel.config.groupInputAbility')"
218
+ group-key="textInputAbility"
218
219
  collapsible
219
220
  :default-open="false"
220
221
  >
@@ -74,6 +74,7 @@ function patch(next: Partial<PanelElement>) {
74
74
  </ConfigFieldGroup>
75
75
  <ConfigFieldGroup
76
76
  :title="t('panel.config.groupCopyStrategy')"
77
+ group-key="viewportCopyStrategy"
77
78
  collapsible
78
79
  :default-open="false"
79
80
  >