@tmagic/editor 1.0.0-beta.9 → 1.0.0-rc.1
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/README.md +1 -0
- package/coverage/clover.xml +1560 -0
- package/coverage/coverage-final.json +36 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +206 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/Editor.vue.html +787 -0
- package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
- package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
- package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
- package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
- package/coverage/lcov-report/src/components/index.html +161 -0
- package/coverage/lcov-report/src/index.html +131 -0
- package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
- package/coverage/lcov-report/src/layouts/Framework.vue.html +304 -0
- package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
- package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +319 -0
- package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
- package/coverage/lcov-report/src/layouts/index.html +176 -0
- package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
- package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
- package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
- package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +226 -0
- package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +289 -0
- package/coverage/lcov-report/src/layouts/sidebar/index.html +176 -0
- package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
- package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +757 -0
- package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
- package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +586 -0
- package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
- package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
- package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
- package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
- package/coverage/lcov-report/src/services/events.ts.html +331 -0
- package/coverage/lcov-report/src/services/history.ts.html +478 -0
- package/coverage/lcov-report/src/services/index.html +206 -0
- package/coverage/lcov-report/src/services/props.ts.html +415 -0
- package/coverage/lcov-report/src/services/ui.ts.html +580 -0
- package/coverage/lcov-report/src/type.ts.html +850 -0
- package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
- package/coverage/lcov-report/src/utils/config.ts.html +172 -0
- package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
- package/coverage/lcov-report/src/utils/index.html +221 -0
- package/coverage/lcov-report/src/utils/index.ts.html +151 -0
- package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
- package/coverage/lcov-report/src/utils/props.ts.html +796 -0
- package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
- package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
- package/coverage/lcov.info +3708 -0
- package/dist/style.css +65 -33
- package/dist/tmagic-editor.es.js +1379 -806
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +1381 -808
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +1 -1
- package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
- package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
- package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
- package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +10 -3
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -7
- package/dist/types/src/services/BaseService.d.ts +4 -1
- package/dist/types/src/services/editor.d.ts +5 -2
- package/dist/types/src/services/history.d.ts +1 -0
- package/dist/types/src/services/props.d.ts +2 -2
- package/dist/types/src/services/ui.d.ts +2 -0
- package/dist/types/src/type.d.ts +15 -9
- package/dist/types/src/utils/editor.d.ts +4 -3
- package/dist/types/src/utils/polyfills.d.ts +0 -0
- package/package.json +36 -12
- package/src/components/ContentMenu.vue +107 -0
- package/src/components/ScrollViewer.vue +1 -1
- package/src/components/ToolButton.vue +69 -30
- package/src/fields/UISelect.vue +14 -6
- package/src/index.ts +2 -0
- package/src/layouts/CodeEditor.vue +20 -10
- package/src/layouts/Framework.vue +6 -6
- package/src/layouts/PropsPanel.vue +4 -3
- package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
- package/src/layouts/sidebar/LayerMenu.vue +91 -96
- package/src/layouts/sidebar/LayerPanel.vue +31 -54
- package/src/layouts/sidebar/Sidebar.vue +13 -52
- package/src/layouts/sidebar/TabPane.vue +68 -0
- package/src/layouts/workspace/PageBar.vue +136 -13
- package/src/layouts/workspace/Stage.vue +50 -75
- package/src/layouts/workspace/ViewerMenu.vue +104 -67
- package/src/layouts/workspace/Workspace.vue +106 -23
- package/src/services/BaseService.ts +70 -22
- package/src/services/editor.ts +148 -39
- package/src/services/history.ts +7 -0
- package/src/services/props.ts +3 -3
- package/src/services/ui.ts +35 -5
- package/src/theme/common/var.scss +1 -0
- package/src/theme/component-list-panel.scss +2 -0
- package/src/theme/content-menu.scss +33 -26
- package/src/theme/layer-panel.scss +2 -1
- package/src/theme/nav-menu.scss +6 -2
- package/src/theme/page-bar.scss +35 -3
- package/src/theme/props-panel.scss +13 -13
- package/src/type.ts +16 -9
- package/src/utils/editor.ts +31 -6
- package/{vite.config.ts → src/utils/polyfills.ts} +4 -12
- package/src/utils/props.ts +20 -1
- package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
- package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -979
- package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -193
- package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
- package/tsconfig.json +0 -9
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
ref="tree"
|
|
15
15
|
node-key="id"
|
|
16
16
|
draggable
|
|
17
|
+
:default-expanded-keys="expandedKeys"
|
|
17
18
|
:load="loadItems"
|
|
18
19
|
:data="values"
|
|
19
20
|
:expand-on-click-node="false"
|
|
@@ -32,8 +33,8 @@
|
|
|
32
33
|
<div
|
|
33
34
|
:id="data.id"
|
|
34
35
|
class="cus-tree-node"
|
|
35
|
-
@mousedown="
|
|
36
|
-
@mouseup="
|
|
36
|
+
@mousedown="toggleClickFlag"
|
|
37
|
+
@mouseup="toggleClickFlag"
|
|
37
38
|
@mouseenter="highlightHandler(data)"
|
|
38
39
|
:class="{ 'cus-tree-node-hover': canHighlight && data.id === highlightNode?.id }"
|
|
39
40
|
>
|
|
@@ -47,18 +48,19 @@
|
|
|
47
48
|
</el-tree>
|
|
48
49
|
|
|
49
50
|
<teleport to="body">
|
|
50
|
-
<layer-menu
|
|
51
|
+
<layer-menu ref="menu"></layer-menu>
|
|
51
52
|
</teleport>
|
|
52
53
|
</el-scrollbar>
|
|
53
54
|
</template>
|
|
54
55
|
|
|
55
56
|
<script lang="ts">
|
|
56
|
-
import { computed, defineComponent, inject,
|
|
57
|
+
import { computed, defineComponent, inject, Ref, ref, watchEffect } from 'vue';
|
|
57
58
|
import type { ElTree } from 'element-plus';
|
|
58
59
|
import { throttle } from 'lodash-es';
|
|
59
60
|
|
|
60
61
|
import type { MNode, MPage } from '@tmagic/schema';
|
|
61
62
|
import { NodeType } from '@tmagic/schema';
|
|
63
|
+
import StageCore from '@tmagic/stage';
|
|
62
64
|
|
|
63
65
|
import type { EditorService } from '@editor/services/editor';
|
|
64
66
|
import type { Services } from '@editor/type';
|
|
@@ -67,12 +69,13 @@ import LayerMenu from './LayerMenu.vue';
|
|
|
67
69
|
|
|
68
70
|
const throttleTime = 150;
|
|
69
71
|
|
|
70
|
-
const select = (data: MNode, editorService?: EditorService) => {
|
|
72
|
+
const select = async (data: MNode, editorService?: EditorService) => {
|
|
71
73
|
if (!data.id) {
|
|
72
74
|
throw new Error('没有id');
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
editorService?.select(data);
|
|
77
|
+
await editorService?.select(data);
|
|
78
|
+
editorService?.get<StageCore>('stage')?.select(data.id);
|
|
76
79
|
};
|
|
77
80
|
|
|
78
81
|
const highlight = (data: MNode, editorService?: EditorService) => {
|
|
@@ -80,6 +83,7 @@ const highlight = (data: MNode, editorService?: EditorService) => {
|
|
|
80
83
|
throw new Error('没有id');
|
|
81
84
|
}
|
|
82
85
|
editorService?.highlight(data);
|
|
86
|
+
editorService?.get<StageCore>('stage')?.highlight(data.id);
|
|
83
87
|
};
|
|
84
88
|
|
|
85
89
|
const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => ({
|
|
@@ -140,6 +144,7 @@ const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorSer
|
|
|
140
144
|
|
|
141
145
|
highlightNode,
|
|
142
146
|
clickNode: node,
|
|
147
|
+
expandedKeys: computed(() => (node.value ? [node.value.id] : [])),
|
|
143
148
|
};
|
|
144
149
|
};
|
|
145
150
|
|
|
@@ -153,12 +158,10 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
|
|
|
153
158
|
let name = '';
|
|
154
159
|
if (data.name) {
|
|
155
160
|
name = data.name;
|
|
156
|
-
} else if (data.type) {
|
|
157
|
-
name = data.type;
|
|
158
161
|
} else if (data.items) {
|
|
159
162
|
name = 'container';
|
|
160
163
|
}
|
|
161
|
-
return name.indexOf(value) !== -1;
|
|
164
|
+
return `${data.id}${name}${data.type}`.indexOf(value) !== -1;
|
|
162
165
|
},
|
|
163
166
|
|
|
164
167
|
filterTextChangeHandler(val: string) {
|
|
@@ -166,46 +169,6 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
|
|
|
166
169
|
},
|
|
167
170
|
});
|
|
168
171
|
|
|
169
|
-
const useContentMenu = (editorService?: EditorService) => {
|
|
170
|
-
const menuStyle = ref({
|
|
171
|
-
position: 'absolute',
|
|
172
|
-
left: '0',
|
|
173
|
-
top: '0',
|
|
174
|
-
display: 'none',
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
onMounted(() => {
|
|
178
|
-
document.addEventListener(
|
|
179
|
-
'click',
|
|
180
|
-
() => {
|
|
181
|
-
menuStyle.value.display = 'none';
|
|
182
|
-
},
|
|
183
|
-
true,
|
|
184
|
-
);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
menuStyle,
|
|
189
|
-
|
|
190
|
-
contextmenu(event: MouseEvent, data: MNode) {
|
|
191
|
-
const bodyHeight = globalThis.document.body.clientHeight;
|
|
192
|
-
|
|
193
|
-
const left = `${event.clientX + 20}px`;
|
|
194
|
-
let top = `${event.clientY - 10}px`;
|
|
195
|
-
|
|
196
|
-
if (event.clientY + 300 > bodyHeight) {
|
|
197
|
-
top = `${bodyHeight - 300}px`;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
menuStyle.value.left = left;
|
|
201
|
-
menuStyle.value.top = top;
|
|
202
|
-
menuStyle.value.display = '';
|
|
203
|
-
|
|
204
|
-
select(data, editorService);
|
|
205
|
-
},
|
|
206
|
-
};
|
|
207
|
-
};
|
|
208
|
-
|
|
209
172
|
export default defineComponent({
|
|
210
173
|
name: 'magic-editor-layer-panel',
|
|
211
174
|
|
|
@@ -214,13 +177,14 @@ export default defineComponent({
|
|
|
214
177
|
setup() {
|
|
215
178
|
const services = inject<Services>('services');
|
|
216
179
|
const tree = ref<InstanceType<typeof ElTree>>();
|
|
180
|
+
const menu = ref<InstanceType<typeof LayerMenu>>();
|
|
217
181
|
const clicked = ref(false);
|
|
218
182
|
const editorService = services?.editorService;
|
|
219
183
|
const highlightHandler = throttle((data: MNode) => {
|
|
220
184
|
highlight(data, editorService);
|
|
221
185
|
}, throttleTime);
|
|
222
186
|
|
|
223
|
-
const
|
|
187
|
+
const toggleClickFlag = () => {
|
|
224
188
|
clicked.value = !clicked.value;
|
|
225
189
|
};
|
|
226
190
|
|
|
@@ -229,12 +193,22 @@ export default defineComponent({
|
|
|
229
193
|
() => statusData.highlightNode.value?.id !== statusData.clickNode.value?.id && !clicked.value,
|
|
230
194
|
);
|
|
231
195
|
|
|
196
|
+
editorService?.on('remove', () => {
|
|
197
|
+
setTimeout(() => {
|
|
198
|
+
tree.value?.getNode(editorService.get('node').id)?.updateChildren();
|
|
199
|
+
}, 0);
|
|
200
|
+
});
|
|
201
|
+
|
|
232
202
|
return {
|
|
233
203
|
tree,
|
|
204
|
+
menu,
|
|
234
205
|
...statusData,
|
|
235
206
|
...useDrop(tree, editorService),
|
|
236
207
|
...useFilter(tree),
|
|
237
|
-
|
|
208
|
+
|
|
209
|
+
highlightHandler,
|
|
210
|
+
toggleClickFlag,
|
|
211
|
+
canHighlight,
|
|
238
212
|
|
|
239
213
|
clickHandler(data: MNode): void {
|
|
240
214
|
if (services?.uiService.get<boolean>('uiSelectMode')) {
|
|
@@ -244,9 +218,12 @@ export default defineComponent({
|
|
|
244
218
|
tree.value?.setCurrentKey(data.id);
|
|
245
219
|
select(data, editorService);
|
|
246
220
|
},
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
221
|
+
|
|
222
|
+
async contextmenu(event: MouseEvent, data: MNode) {
|
|
223
|
+
event.preventDefault();
|
|
224
|
+
await select(data, editorService);
|
|
225
|
+
menu.value?.show(event);
|
|
226
|
+
},
|
|
250
227
|
};
|
|
251
228
|
},
|
|
252
229
|
});
|
|
@@ -1,36 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<el-tabs
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<component :is="item.component" v-bind="item.props || {}" v-on="item.listeners || {}">
|
|
12
|
-
<template #layer-node-content="{ data, node }" v-if="item.slots?.layerNodeContent">
|
|
13
|
-
<component :is="item.slots.layerNodeContent" :data="data" :node="node" />
|
|
14
|
-
</template>
|
|
15
|
-
</component>
|
|
16
|
-
</el-tab-pane>
|
|
2
|
+
<el-tabs
|
|
3
|
+
v-if="data.type === 'tabs' && data.items.length"
|
|
4
|
+
class="m-editor-sidebar"
|
|
5
|
+
v-model="activeTabName"
|
|
6
|
+
type="card"
|
|
7
|
+
tab-position="left"
|
|
8
|
+
>
|
|
9
|
+
<tab-pane v-for="(item, index) in data.items" :key="index" :data="item"></tab-pane>
|
|
17
10
|
</el-tabs>
|
|
18
11
|
</template>
|
|
19
12
|
|
|
20
13
|
<script lang="ts">
|
|
21
|
-
import {
|
|
22
|
-
import { Coin, Files } from '@element-plus/icons';
|
|
14
|
+
import { defineComponent, PropType, ref, watch } from 'vue';
|
|
23
15
|
|
|
24
|
-
import
|
|
25
|
-
import { SideBarData, SideComponent } from '@editor/type';
|
|
16
|
+
import { SideBarData } from '@editor/type';
|
|
26
17
|
|
|
27
|
-
import
|
|
28
|
-
import LayerPanel from './LayerPanel.vue';
|
|
18
|
+
import TabPane from './TabPane.vue';
|
|
29
19
|
|
|
30
20
|
export default defineComponent({
|
|
31
|
-
|
|
21
|
+
components: { TabPane },
|
|
32
22
|
|
|
33
|
-
|
|
23
|
+
name: 'm-sidebar',
|
|
34
24
|
|
|
35
25
|
props: {
|
|
36
26
|
data: {
|
|
@@ -51,35 +41,6 @@ export default defineComponent({
|
|
|
51
41
|
|
|
52
42
|
return {
|
|
53
43
|
activeTabName,
|
|
54
|
-
|
|
55
|
-
items: computed<SideComponent[] | Record<string, any>[]>(() =>
|
|
56
|
-
props.data?.items.map((item) => {
|
|
57
|
-
if (typeof item !== 'string') {
|
|
58
|
-
return item;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
switch (item) {
|
|
62
|
-
case 'component-list':
|
|
63
|
-
return {
|
|
64
|
-
type: 'component',
|
|
65
|
-
icon: Coin,
|
|
66
|
-
text: '组件',
|
|
67
|
-
component: ComponentListPanel,
|
|
68
|
-
slots: {},
|
|
69
|
-
};
|
|
70
|
-
case 'layer':
|
|
71
|
-
return {
|
|
72
|
-
type: 'component',
|
|
73
|
-
icon: Files,
|
|
74
|
-
text: '已选组件',
|
|
75
|
-
component: LayerPanel,
|
|
76
|
-
slots: {},
|
|
77
|
-
};
|
|
78
|
-
default:
|
|
79
|
-
return {};
|
|
80
|
-
}
|
|
81
|
-
}),
|
|
82
|
-
),
|
|
83
44
|
};
|
|
84
45
|
},
|
|
85
46
|
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-tab-pane v-if="config" :name="config.text">
|
|
3
|
+
<template #label>
|
|
4
|
+
<div :key="config.text">
|
|
5
|
+
<m-icon v-if="config.icon" :icon="config.icon"></m-icon>
|
|
6
|
+
<div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<component :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
|
|
11
|
+
<template #layer-node-content="{ data, node }" v-if="config.slots?.layerNodeContent">
|
|
12
|
+
<component :is="config.slots?.layerNodeContent" :data="data" :node="node" />
|
|
13
|
+
</template>
|
|
14
|
+
</component>
|
|
15
|
+
</el-tab-pane>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script lang="ts">
|
|
19
|
+
import { computed, defineComponent, PropType } from 'vue';
|
|
20
|
+
import { Coin, Files } from '@element-plus/icons';
|
|
21
|
+
|
|
22
|
+
import MIcon from '@editor/components/Icon.vue';
|
|
23
|
+
import { SideComponent, SideItem } from '@editor/type';
|
|
24
|
+
|
|
25
|
+
import ComponentListPanel from './ComponentListPanel.vue';
|
|
26
|
+
import LayerPanel from './LayerPanel.vue';
|
|
27
|
+
|
|
28
|
+
export default defineComponent({
|
|
29
|
+
components: { MIcon },
|
|
30
|
+
|
|
31
|
+
props: {
|
|
32
|
+
data: {
|
|
33
|
+
type: Object as PropType<SideItem>,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
setup(props) {
|
|
38
|
+
return {
|
|
39
|
+
config: computed<SideComponent | undefined>(() => {
|
|
40
|
+
if (typeof props.data !== 'string') {
|
|
41
|
+
return props.data;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
switch (props.data) {
|
|
45
|
+
case 'component-list':
|
|
46
|
+
return {
|
|
47
|
+
type: 'component',
|
|
48
|
+
icon: Coin,
|
|
49
|
+
text: '组件',
|
|
50
|
+
component: ComponentListPanel,
|
|
51
|
+
slots: {},
|
|
52
|
+
};
|
|
53
|
+
case 'layer':
|
|
54
|
+
return {
|
|
55
|
+
type: 'component',
|
|
56
|
+
icon: Files,
|
|
57
|
+
text: '已选组件',
|
|
58
|
+
component: LayerPanel,
|
|
59
|
+
slots: {},
|
|
60
|
+
};
|
|
61
|
+
default:
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="m-editor-page-bar">
|
|
3
|
-
<div class="m-editor-page-bar-item" @click="addPage">
|
|
4
|
-
<el-icon
|
|
2
|
+
<div class="m-editor-page-bar" ref="pageBar">
|
|
3
|
+
<div id="m-editor-page-bar-add-icon" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="addPage">
|
|
4
|
+
<el-icon><plus></plus></el-icon>
|
|
5
5
|
</div>
|
|
6
|
-
<
|
|
6
|
+
<div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('left')">
|
|
7
|
+
<el-icon><arrow-left-bold></arrow-left-bold></el-icon>
|
|
8
|
+
</div>
|
|
9
|
+
<div v-if="root" class="m-editor-page-bar-items" ref="itemsContainer" :style="`width: ${itemsContainerWidth}px`">
|
|
7
10
|
<div
|
|
8
11
|
v-for="item in root.items"
|
|
9
12
|
:key="item.key"
|
|
@@ -19,11 +22,25 @@
|
|
|
19
22
|
</slot>
|
|
20
23
|
</div>
|
|
21
24
|
|
|
22
|
-
<el-popover placement="top" :width="160" trigger="hover">
|
|
25
|
+
<el-popover popper-class="page-bar-popover" placement="top" :width="160" trigger="hover">
|
|
23
26
|
<div>
|
|
24
27
|
<slot name="page-bar-popover" :page="item">
|
|
25
|
-
<
|
|
26
|
-
|
|
28
|
+
<tool-button
|
|
29
|
+
:data="{
|
|
30
|
+
type: 'button',
|
|
31
|
+
text: '复制',
|
|
32
|
+
icon: DocumentCopy,
|
|
33
|
+
handler: () => copy(item),
|
|
34
|
+
}"
|
|
35
|
+
></tool-button>
|
|
36
|
+
<tool-button
|
|
37
|
+
:data="{
|
|
38
|
+
type: 'button',
|
|
39
|
+
text: '删除',
|
|
40
|
+
icon: Delete,
|
|
41
|
+
handler: () => remove(item),
|
|
42
|
+
}"
|
|
43
|
+
></tool-button>
|
|
27
44
|
</slot>
|
|
28
45
|
</div>
|
|
29
46
|
<template #reference>
|
|
@@ -33,29 +50,135 @@
|
|
|
33
50
|
</template>
|
|
34
51
|
</el-popover>
|
|
35
52
|
</div>
|
|
36
|
-
</
|
|
53
|
+
</div>
|
|
54
|
+
<div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('right')">
|
|
55
|
+
<el-icon><arrow-right-bold></arrow-right-bold></el-icon>
|
|
56
|
+
</div>
|
|
37
57
|
</div>
|
|
38
58
|
</template>
|
|
39
59
|
|
|
40
60
|
<script lang="ts">
|
|
41
|
-
import {
|
|
42
|
-
|
|
61
|
+
import {
|
|
62
|
+
computed,
|
|
63
|
+
ComputedRef,
|
|
64
|
+
defineComponent,
|
|
65
|
+
inject,
|
|
66
|
+
markRaw,
|
|
67
|
+
onMounted,
|
|
68
|
+
onUnmounted,
|
|
69
|
+
ref,
|
|
70
|
+
toRaw,
|
|
71
|
+
watch,
|
|
72
|
+
} from 'vue';
|
|
73
|
+
import { ArrowLeftBold, ArrowRightBold, CaretBottom, Delete, DocumentCopy, Plus } from '@element-plus/icons';
|
|
43
74
|
|
|
44
|
-
import type { MPage } from '@tmagic/schema';
|
|
75
|
+
import type { MApp, MPage } from '@tmagic/schema';
|
|
45
76
|
import { NodeType } from '@tmagic/schema';
|
|
46
77
|
|
|
78
|
+
import ToolButton from '@editor/components/ToolButton.vue';
|
|
47
79
|
import type { Services } from '@editor/type';
|
|
48
80
|
import { generatePageNameByApp } from '@editor/utils/editor';
|
|
49
81
|
|
|
82
|
+
const useScroll = (root: ComputedRef<MApp | undefined>) => {
|
|
83
|
+
const pageBar = ref<HTMLDivElement>();
|
|
84
|
+
const itemsContainer = ref<HTMLDivElement>();
|
|
85
|
+
|
|
86
|
+
const pageBarWidth = ref(0);
|
|
87
|
+
const canScroll = ref(false);
|
|
88
|
+
|
|
89
|
+
const itemsContainerWidth = computed(() => pageBarWidth.value - 105);
|
|
90
|
+
|
|
91
|
+
let translateLeft = 0;
|
|
92
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
93
|
+
for (const { contentRect } of entries) {
|
|
94
|
+
const { width } = contentRect;
|
|
95
|
+
pageBarWidth.value = width || 0;
|
|
96
|
+
|
|
97
|
+
setCanScroll();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const setCanScroll = () => {
|
|
102
|
+
if (itemsContainer.value) {
|
|
103
|
+
canScroll.value = itemsContainer.value.scrollWidth > pageBarWidth.value - 105;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
|
|
108
|
+
if (!itemsContainer.value) return;
|
|
109
|
+
|
|
110
|
+
const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
|
|
111
|
+
|
|
112
|
+
if (type === 'left') {
|
|
113
|
+
translateLeft += 100;
|
|
114
|
+
|
|
115
|
+
if (translateLeft > 0) {
|
|
116
|
+
translateLeft = 0;
|
|
117
|
+
}
|
|
118
|
+
} else if (type === 'right') {
|
|
119
|
+
translateLeft -= 100;
|
|
120
|
+
|
|
121
|
+
if (-translateLeft > maxScrollLeft) {
|
|
122
|
+
translateLeft = -maxScrollLeft;
|
|
123
|
+
}
|
|
124
|
+
} else if (type === 'start') {
|
|
125
|
+
translateLeft = 0;
|
|
126
|
+
} else if (type === 'end') {
|
|
127
|
+
translateLeft = -maxScrollLeft;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
itemsContainer.value.style.transform = `translate(${translateLeft}px, 0px)`;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
onMounted(() => {
|
|
134
|
+
pageBar.value && resizeObserver.observe(pageBar.value);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
onUnmounted(() => {
|
|
138
|
+
resizeObserver.disconnect();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
watch(
|
|
142
|
+
() => root.value?.items.length,
|
|
143
|
+
(length = 0, preLength = 0) => {
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
setCanScroll();
|
|
146
|
+
if (length < preLength) {
|
|
147
|
+
scroll('start');
|
|
148
|
+
} else {
|
|
149
|
+
scroll('end');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
pageBar,
|
|
157
|
+
itemsContainer,
|
|
158
|
+
canScroll,
|
|
159
|
+
|
|
160
|
+
itemsContainerWidth,
|
|
161
|
+
|
|
162
|
+
scroll,
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
|
|
50
166
|
export default defineComponent({
|
|
51
|
-
components: { CaretBottom, Plus },
|
|
167
|
+
components: { ArrowLeftBold, ArrowRightBold, CaretBottom, Plus, ToolButton },
|
|
52
168
|
|
|
53
169
|
setup() {
|
|
54
170
|
const services = inject<Services>('services');
|
|
55
171
|
const editorService = services?.editorService;
|
|
56
172
|
|
|
173
|
+
const root = computed(() => editorService?.get<MApp>('root'));
|
|
174
|
+
|
|
57
175
|
return {
|
|
58
|
-
|
|
176
|
+
Delete: markRaw(Delete),
|
|
177
|
+
DocumentCopy: markRaw(DocumentCopy),
|
|
178
|
+
|
|
179
|
+
...useScroll(root),
|
|
180
|
+
|
|
181
|
+
root,
|
|
59
182
|
page: computed(() => editorService?.get('page')),
|
|
60
183
|
|
|
61
184
|
switchPage(page: MPage) {
|