mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-05 19:41:40 +08:00
chore(editor): 重构tool-button,将功能逻辑移到nav-menu中
This commit is contained in:
parent
ca5e4d2702
commit
4872e5352b
@ -8,7 +8,7 @@
|
||||
"build": "npm run clean:top && vuepress build src -d dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.6",
|
||||
"@element-plus/icons-vue": "^2.0.9",
|
||||
"@tmagic/form": "1.1.0-beta.12",
|
||||
"@tmagic/schema": "1.1.0-beta.12",
|
||||
"@tmagic/utils": "1.1.0-beta.12",
|
||||
|
@ -44,7 +44,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.0",
|
||||
"@element-plus/icons-vue": "^2.0.6",
|
||||
"@element-plus/icons-vue": "^2.0.9",
|
||||
"@tmagic/core": "1.1.0-beta.12",
|
||||
"@tmagic/form": "1.1.0-beta.12",
|
||||
"@tmagic/schema": "1.1.0-beta.12",
|
||||
|
@ -64,7 +64,7 @@ import historyService from './services/history';
|
||||
import propsService from './services/props';
|
||||
import storageService from './services/storage';
|
||||
import uiService from './services/ui';
|
||||
import type { ComponentGroup, MenuBarData, MenuItem, Services, SideBarData, StageRect } from './type';
|
||||
import type { ComponentGroup, MenuBarData, MenuButton, MenuComponent, Services, SideBarData, StageRect } from './type';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'm-editor',
|
||||
@ -97,12 +97,12 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
layerContentMenu: {
|
||||
type: Array as PropType<MenuItem[]>,
|
||||
type: Array as PropType<(MenuButton | MenuComponent)[]>,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
stageContentMenu: {
|
||||
type: Array as PropType<MenuItem[]>,
|
||||
type: Array as PropType<(MenuButton | MenuComponent)[]>,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
|
@ -25,13 +25,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
|
||||
import { MenuButton, MenuItem } from '../type';
|
||||
import { MenuButton, MenuComponent } from '../type';
|
||||
|
||||
import ToolButton from './ToolButton.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
menuData?: MenuItem[];
|
||||
menuData?: (MenuButton | MenuComponent)[];
|
||||
isSubMenu?: boolean;
|
||||
}>(),
|
||||
{
|
||||
@ -45,7 +45,7 @@ const emit = defineEmits(['hide', 'show']);
|
||||
const menu = ref<HTMLDivElement>();
|
||||
const subMenu = ref<any>();
|
||||
const visible = ref(false);
|
||||
const subMenuData = ref<MenuItem[]>([]);
|
||||
const subMenuData = ref<(MenuButton | MenuComponent)[]>([]);
|
||||
const menuStyle = ref({
|
||||
left: '0',
|
||||
top: '0',
|
||||
@ -94,7 +94,7 @@ const show = (e: MouseEvent) => {
|
||||
}, 300);
|
||||
};
|
||||
|
||||
const showSubMenu = (item: MenuItem) => {
|
||||
const showSubMenu = (item: MenuButton | MenuComponent) => {
|
||||
const menuItem = item as MenuButton;
|
||||
if (typeof item !== 'object' || !menuItem.items?.length) {
|
||||
return;
|
||||
|
@ -1,29 +1,15 @@
|
||||
<template>
|
||||
<el-icon v-if="!icon"><edit></edit></el-icon>
|
||||
<el-icon v-if="!icon"><Edit></Edit></el-icon>
|
||||
<el-icon v-else-if="typeof icon === 'string' && icon.startsWith('http')"><img :src="icon" /></el-icon>
|
||||
<i v-else-if="typeof icon === 'string'" :class="icon"></i>
|
||||
<el-icon v-else><component :is="toRaw(icon)"></component></el-icon>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, defineComponent, PropType, toRaw } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { toRaw } from 'vue';
|
||||
import { Edit } from '@element-plus/icons-vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'm-icon',
|
||||
|
||||
components: { Edit },
|
||||
|
||||
props: {
|
||||
icon: {
|
||||
type: [String, Object] as PropType<string | Component>,
|
||||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
toRaw,
|
||||
};
|
||||
},
|
||||
});
|
||||
defineProps<{
|
||||
icon?: any;
|
||||
}>();
|
||||
</script>
|
||||
|
@ -2,169 +2,80 @@
|
||||
<div
|
||||
v-if="display"
|
||||
class="menu-item"
|
||||
:class="item.type"
|
||||
@click="clickHandler(item, $event)"
|
||||
@mousedown="mousedownHandler(item, $event)"
|
||||
@mouseup="mouseupHandler(item, $event)"
|
||||
:class="`${data.type} ${data.className}`"
|
||||
@click="clickHandler(data, $event)"
|
||||
@mousedown="mousedownHandler(data, $event)"
|
||||
@mouseup="mouseupHandler(data, $event)"
|
||||
>
|
||||
<el-divider v-if="item.type === 'divider'" :direction="item.direction || 'vertical'"></el-divider>
|
||||
<div v-else-if="item.type === 'text'" class="menu-item-text">{{ item.text }}</div>
|
||||
<el-divider v-if="data.type === 'divider'" :direction="data.direction || 'vertical'"></el-divider>
|
||||
<div v-else-if="data.type === 'text'" class="menu-item-text">{{ data.text }}</div>
|
||||
|
||||
<template v-else-if="item.type === 'zoom'">
|
||||
<tool-button
|
||||
:data="{ type: 'button', icon: ZoomOut, handler: zoomOutHandler, tooltip: '缩小' }"
|
||||
:event-type="eventType"
|
||||
></tool-button>
|
||||
<span class="menu-item-text" style="margin: 0 5px">{{ parseInt(`${zoom * 100}`, 10) }}%</span>
|
||||
<tool-button
|
||||
:data="{ type: 'button', icon: ZoomIn, handler: zoomInHandler, tooltip: '放大' }"
|
||||
:event-type="eventType"
|
||||
></tool-button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="item.type === 'button'">
|
||||
<el-tooltip v-if="item.tooltip" effect="dark" placement="bottom-start" :content="item.tooltip">
|
||||
<template v-else-if="data.type === 'button'">
|
||||
<el-tooltip v-if="data.tooltip" effect="dark" placement="bottom-start" :content="data.tooltip">
|
||||
<el-button size="small" text :disabled="disabled"
|
||||
><m-icon v-if="item.icon" :icon="item.icon"></m-icon><span>{{ item.text }}</span></el-button
|
||||
><MIcon v-if="data.icon" :icon="data.icon"></MIcon><span>{{ data.text }}</span></el-button
|
||||
>
|
||||
</el-tooltip>
|
||||
<el-button v-else size="small" text :disabled="disabled"
|
||||
><m-icon v-if="item.icon" :icon="item.icon"></m-icon><span>{{ item.text }}</span></el-button
|
||||
><MIcon v-if="data.icon" :icon="data.icon"></MIcon><span>{{ data.text }}</span></el-button
|
||||
>
|
||||
</template>
|
||||
|
||||
<el-dropdown v-else-if="item.type === 'dropdown'" trigger="click" :disabled="disabled" @command="dropdownHandler">
|
||||
<el-dropdown v-else-if="data.type === 'dropdown'" trigger="click" :disabled="disabled" @command="dropdownHandler">
|
||||
<span class="el-dropdown-link menubar-menu-button">
|
||||
{{ item.text }}<el-icon class="el-icon--right"><arrow-down></arrow-down></el-icon>
|
||||
{{ data.text }}<el-icon class="el-icon--right"><ArrowDown></ArrowDown></el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu v-if="item.items && item.items.length">
|
||||
<el-dropdown-item v-for="(subItem, index) in item.items" :key="index" :command="{ item, subItem }">{{
|
||||
<el-dropdown-menu v-if="data.items && data.items.length">
|
||||
<el-dropdown-item v-for="(subItem, index) in data.items" :key="index" :command="{ data, subItem }">{{
|
||||
subItem.text
|
||||
}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<component v-else-if="item.type === 'component'" v-bind="item.props || {}" :is="item.component"></component>
|
||||
<component v-else-if="data.type === 'component'" v-bind="data.props || {}" :is="data.component"></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, markRaw, PropType } from 'vue';
|
||||
import { ArrowDown, Back, Delete, Grid, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons-vue';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
import { computed, inject } from 'vue';
|
||||
import { ArrowDown } from '@element-plus/icons-vue';
|
||||
|
||||
import MIcon from '../components/Icon.vue';
|
||||
import type { MenuButton, MenuComponent, MenuItem, Services } from '../type';
|
||||
import type { MenuButton, MenuComponent, Services } from '../type';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: [Object, String] as PropType<MenuItem | string>,
|
||||
require: true,
|
||||
default: () => ({
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
data?: MenuButton | MenuComponent;
|
||||
eventType?: 'mousedown' | 'mouseup' | 'click';
|
||||
}>(),
|
||||
{
|
||||
data: () => ({
|
||||
type: 'text',
|
||||
display: false,
|
||||
}),
|
||||
eventType: 'click',
|
||||
},
|
||||
|
||||
eventType: {
|
||||
type: String as PropType<'mousedown' | 'mouseup' | 'click'>,
|
||||
default: 'click',
|
||||
},
|
||||
});
|
||||
|
||||
);
|
||||
const services = inject<Services>('services');
|
||||
const uiService = services?.uiService;
|
||||
|
||||
const zoom = computed((): number => uiService?.get<number>('zoom') ?? 1);
|
||||
const showGuides = computed((): boolean => uiService?.get<boolean>('showGuides') ?? true);
|
||||
const showRule = computed((): boolean => uiService?.get<boolean>('showRule') ?? true);
|
||||
|
||||
const zoomInHandler = () => uiService?.zoom(0.1);
|
||||
const zoomOutHandler = () => uiService?.zoom(-0.1);
|
||||
|
||||
const item = computed((): MenuButton | MenuComponent => {
|
||||
if (typeof props.data !== 'string') {
|
||||
return props.data;
|
||||
}
|
||||
switch (props.data) {
|
||||
case '/':
|
||||
return {
|
||||
type: 'divider',
|
||||
};
|
||||
case 'zoom':
|
||||
return {
|
||||
type: 'zoom',
|
||||
};
|
||||
case 'delete':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(Delete),
|
||||
tooltip: '刪除',
|
||||
disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
|
||||
handler: () => services?.editorService.remove(services?.editorService.get('node')),
|
||||
};
|
||||
case 'undo':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(Back),
|
||||
tooltip: '后退',
|
||||
disabled: () => !services?.historyService.state.canUndo,
|
||||
handler: () => services?.editorService.undo(),
|
||||
};
|
||||
case 'redo':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(Right),
|
||||
tooltip: '前进',
|
||||
disabled: () => !services?.historyService.state.canRedo,
|
||||
handler: () => services?.editorService.redo(),
|
||||
};
|
||||
case 'zoom-in':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(ZoomIn),
|
||||
tooltip: '放大',
|
||||
handler: zoomInHandler,
|
||||
};
|
||||
case 'zoom-out':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(ZoomOut),
|
||||
tooltip: '縮小',
|
||||
handler: zoomOutHandler,
|
||||
};
|
||||
case 'rule':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(ScaleToOriginal),
|
||||
tooltip: showRule.value ? '隐藏标尺' : '显示标尺',
|
||||
handler: () => uiService?.set('showRule', !showRule.value),
|
||||
};
|
||||
case 'guides':
|
||||
return {
|
||||
type: 'button',
|
||||
icon: markRaw(Grid),
|
||||
tooltip: showGuides.value ? '隐藏参考线' : '显示参考线',
|
||||
handler: () => uiService?.set('showGuides', !showGuides.value),
|
||||
};
|
||||
default:
|
||||
return {
|
||||
type: 'text',
|
||||
text: props.data,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const disabled = computed(() => {
|
||||
if (typeof item.value === 'string') return false;
|
||||
if (item.value.type === 'component') return false;
|
||||
if (typeof item.value.disabled === 'function') {
|
||||
return item.value.disabled(services);
|
||||
if (typeof props.data === 'string') return false;
|
||||
if (props.data.type === 'component') return false;
|
||||
if (typeof props.data.disabled === 'function') {
|
||||
return props.data.disabled(services);
|
||||
}
|
||||
return item.value.disabled;
|
||||
return props.data.disabled;
|
||||
});
|
||||
|
||||
const display = computed(() => {
|
||||
if (!props.data) return false;
|
||||
if (typeof props.data === 'string') return true;
|
||||
if (typeof props.data.display === 'function') {
|
||||
return props.data.display(services);
|
||||
}
|
||||
return props.data.display ?? true;
|
||||
});
|
||||
|
||||
const buttonHandler = (item: MenuButton | MenuComponent, event: MouseEvent) => {
|
||||
@ -174,15 +85,6 @@ const buttonHandler = (item: MenuButton | MenuComponent, event: MouseEvent) => {
|
||||
}
|
||||
};
|
||||
|
||||
const display = computed(() => {
|
||||
if (!item.value) return false;
|
||||
if (typeof item.value === 'string') return true;
|
||||
if (typeof item.value.display === 'function') {
|
||||
return item.value.display(services);
|
||||
}
|
||||
return item.value.display ?? true;
|
||||
});
|
||||
|
||||
const dropdownHandler = (command: any) => {
|
||||
if (command.item.handler) {
|
||||
command.item.handler(services);
|
||||
|
@ -45,6 +45,7 @@ export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
|
||||
export { default as PropsPanel } from './layouts/PropsPanel.vue';
|
||||
export { default as ToolButton } from './components/ToolButton.vue';
|
||||
export { default as ContentMenu } from './components/ContentMenu.vue';
|
||||
export { default as Icon } from './components/Icon.vue';
|
||||
|
||||
const defaultInstallOpt: InstallOptions = {
|
||||
// @todo, 自定义图片上传方法等编辑器依赖的外部选项
|
||||
|
@ -1,41 +1,151 @@
|
||||
<template>
|
||||
<div class="m-editor-nav-menu" :style="{ height: `${height}px` }">
|
||||
<div v-for="key in keys" :class="`menu-${key}`" :key="key" :style="`width: ${columnWidth?.[key]}px`">
|
||||
<tool-button :data="item" v-for="(item, index) in data[key]" :key="index"></tool-button>
|
||||
<tool-button :data="item" v-for="(item, index) in buttons[key]" :key="index"></tool-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, PropType } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, markRaw } from 'vue';
|
||||
import { Back, Delete, Grid, Memo, Right, ZoomIn, ZoomOut } from '@element-plus/icons-vue';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import ToolButton from '../components/ToolButton.vue';
|
||||
import { GetColumnWidth, MenuBarData, Services } from '../type';
|
||||
import { ColumnLayout, GetColumnWidth, MenuBarData, MenuButton, MenuComponent, MenuItem, Services } from '../type';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'nav-menu',
|
||||
|
||||
components: { ToolButton },
|
||||
|
||||
props: {
|
||||
data: {
|
||||
type: Object as PropType<MenuBarData>,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
height: {
|
||||
type: Number,
|
||||
},
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
data?: MenuBarData;
|
||||
height?: number;
|
||||
}>(),
|
||||
{
|
||||
data: () => ({}),
|
||||
height: 35,
|
||||
},
|
||||
);
|
||||
|
||||
setup(props) {
|
||||
const services = inject<Services>('services');
|
||||
const services = inject<Services>('services');
|
||||
const uiService = services?.uiService;
|
||||
|
||||
return {
|
||||
keys: computed(() => Object.keys(props.data) as Array<keyof MenuBarData>),
|
||||
const columnWidth = computed(() => services?.uiService.get<GetColumnWidth>('columnWidth'));
|
||||
const keys = Object.values(ColumnLayout);
|
||||
|
||||
columnWidth: computed(() => services?.uiService.get<GetColumnWidth>('columnWidth')),
|
||||
};
|
||||
},
|
||||
const showGuides = computed((): boolean => uiService?.get<boolean>('showGuides') ?? true);
|
||||
const showRule = computed((): boolean => uiService?.get<boolean>('showRule') ?? true);
|
||||
const zoom = computed((): number => uiService?.get<number>('zoom') ?? 1);
|
||||
|
||||
const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
|
||||
if (typeof item !== 'string') {
|
||||
return [item];
|
||||
}
|
||||
const config: (MenuButton | MenuComponent)[] = [];
|
||||
switch (item) {
|
||||
case '/':
|
||||
config.push({
|
||||
type: 'divider',
|
||||
className: 'divider',
|
||||
});
|
||||
break;
|
||||
case 'zoom':
|
||||
config.push(
|
||||
...getConfig('zoom-out'),
|
||||
...getConfig(`${parseInt(`${zoom.value * 100}`, 10)}%`),
|
||||
...getConfig('zoom-in'),
|
||||
);
|
||||
break;
|
||||
case 'delete':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'delete',
|
||||
icon: markRaw(Delete),
|
||||
tooltip: '刪除',
|
||||
disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
|
||||
handler: () => services?.editorService.remove(services?.editorService.get('node')),
|
||||
});
|
||||
break;
|
||||
case 'undo':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'undo',
|
||||
icon: markRaw(Back),
|
||||
tooltip: '后退',
|
||||
disabled: () => !services?.historyService.state.canUndo,
|
||||
handler: () => services?.editorService.undo(),
|
||||
});
|
||||
break;
|
||||
case 'redo':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'redo',
|
||||
icon: markRaw(Right),
|
||||
tooltip: '前进',
|
||||
disabled: () => !services?.historyService.state.canRedo,
|
||||
handler: () => services?.editorService.redo(),
|
||||
});
|
||||
break;
|
||||
case 'zoom-in':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'zoom-in',
|
||||
icon: markRaw(ZoomIn),
|
||||
tooltip: '放大',
|
||||
handler: () => uiService?.zoom(0.1),
|
||||
});
|
||||
break;
|
||||
case 'zoom-out':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'zoom-out',
|
||||
icon: markRaw(ZoomOut),
|
||||
tooltip: '縮小',
|
||||
handler: () => uiService?.zoom(-0.1),
|
||||
});
|
||||
break;
|
||||
case 'rule':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'rule',
|
||||
icon: markRaw(Memo),
|
||||
tooltip: showRule.value ? '隐藏标尺' : '显示标尺',
|
||||
handler: () => uiService?.set('showRule', !showRule.value),
|
||||
});
|
||||
break;
|
||||
case 'guides':
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'guides',
|
||||
icon: markRaw(Grid),
|
||||
tooltip: showGuides.value ? '隐藏参考线' : '显示参考线',
|
||||
handler: () => uiService?.set('showGuides', !showGuides.value),
|
||||
});
|
||||
break;
|
||||
default:
|
||||
config.push({
|
||||
type: 'text',
|
||||
text: item,
|
||||
});
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
||||
const buttons = computed(() => {
|
||||
const data: {
|
||||
[ColumnLayout.LEFT]: (MenuButton | MenuComponent)[];
|
||||
[ColumnLayout.CENTER]: (MenuButton | MenuComponent)[];
|
||||
[ColumnLayout.RIGHT]: (MenuButton | MenuComponent)[];
|
||||
} = {
|
||||
[ColumnLayout.LEFT]: [],
|
||||
[ColumnLayout.CENTER]: [],
|
||||
[ColumnLayout.RIGHT]: [],
|
||||
};
|
||||
keys.forEach((key) => {
|
||||
const items = props.data[key] || [];
|
||||
items.forEach((item) => {
|
||||
data[key].push(...getConfig(item));
|
||||
});
|
||||
});
|
||||
return data;
|
||||
});
|
||||
</script>
|
||||
|
@ -9,7 +9,7 @@ import { Delete, DocumentCopy, Files, Plus } from '@element-plus/icons-vue';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import ContentMenu from '../../components/ContentMenu.vue';
|
||||
import type { ComponentGroup, MenuButton, MenuItem, Services } from '../../type';
|
||||
import type { ComponentGroup, MenuButton, MenuComponent, Services } from '../../type';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ContentMenu },
|
||||
@ -22,7 +22,7 @@ export default defineComponent({
|
||||
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
||||
const componentList = computed(() => services?.componentListService.getList() || []);
|
||||
|
||||
const layerContentMenu = inject<MenuItem[]>('layerContentMenu', []);
|
||||
const layerContentMenu = inject<(MenuComponent | MenuButton)[]>('layerContentMenu', []);
|
||||
|
||||
const createMenuItems = (group: ComponentGroup): MenuButton[] =>
|
||||
group.items.map((component) => ({
|
||||
@ -77,7 +77,7 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
menu,
|
||||
menuData: computed<MenuItem[]>(() => [
|
||||
menuData: computed<(MenuButton | MenuComponent)[]>(() => [
|
||||
{
|
||||
type: 'button',
|
||||
text: '新增',
|
||||
|
@ -12,7 +12,7 @@ import { isPage } from '@tmagic/utils';
|
||||
|
||||
import ContentMenu from '../../components/ContentMenu.vue';
|
||||
import storageService from '../../services/storage';
|
||||
import { LayerOffset, Layout, MenuItem, Services } from '../../type';
|
||||
import { LayerOffset, Layout, MenuButton, MenuComponent, Services } from '../../type';
|
||||
import { COPY_STORAGE_KEY } from '../../utils/editor';
|
||||
|
||||
const props = withDefaults(defineProps<{ isMultiSelect?: boolean }>(), { isMultiSelect: false });
|
||||
@ -28,9 +28,9 @@ const nodes = computed(() => editorService?.get<MNode[]>('nodes'));
|
||||
const parent = computed(() => editorService?.get('parent'));
|
||||
const stage = computed(() => editorService?.get<StageCore>('stage'));
|
||||
|
||||
const stageContentMenu = inject<MenuItem[]>('stageContentMenu', []);
|
||||
const stageContentMenu = inject<(MenuButton | MenuComponent)[]>('stageContentMenu', []);
|
||||
|
||||
const menuData = reactive<MenuItem[]>([
|
||||
const menuData = reactive<(MenuButton | MenuComponent)[]>([
|
||||
{
|
||||
type: 'button',
|
||||
text: '水平居中',
|
||||
|
@ -69,5 +69,11 @@
|
||||
.menu-item-text {
|
||||
color: $--nav-color;
|
||||
}
|
||||
|
||||
&.rule {
|
||||
.el-icon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,16 +82,22 @@ export interface ComponentGroupState {
|
||||
list: ComponentGroup[];
|
||||
}
|
||||
|
||||
export enum ColumnLayout {
|
||||
LEFT = 'left',
|
||||
CENTER = 'center',
|
||||
RIGHT = 'right',
|
||||
}
|
||||
|
||||
export interface SetColumnWidth {
|
||||
left?: number;
|
||||
center?: number | 'auto';
|
||||
right?: number;
|
||||
[ColumnLayout.LEFT]?: number;
|
||||
[ColumnLayout.CENTER]?: number | 'auto';
|
||||
[ColumnLayout.RIGHT]?: number;
|
||||
}
|
||||
|
||||
export interface GetColumnWidth {
|
||||
left: number;
|
||||
center: number;
|
||||
right: number;
|
||||
[ColumnLayout.LEFT]: number;
|
||||
[ColumnLayout.CENTER]: number;
|
||||
[ColumnLayout.RIGHT]: number;
|
||||
}
|
||||
|
||||
export interface StageRect {
|
||||
@ -174,6 +180,7 @@ export interface MenuButton {
|
||||
/** type为button/dropdown时点击运行的方法 */
|
||||
handler?: (data: Services, event: MouseEvent) => Promise<any> | any;
|
||||
/** type为dropdown时,下拉的菜单列表, 或者有子菜单时 */
|
||||
className?: string;
|
||||
items?: MenuButton[];
|
||||
}
|
||||
|
||||
@ -187,6 +194,7 @@ export interface MenuComponent {
|
||||
listeners?: Record<string, Function>;
|
||||
slots?: Record<string, any>;
|
||||
/** 是否显示,默认为true */
|
||||
className?: string;
|
||||
display?: boolean | ((data?: Services) => Promise<boolean> | boolean);
|
||||
}
|
||||
|
||||
@ -209,16 +217,17 @@ export type MenuItem =
|
||||
| 'guides'
|
||||
| 'rule'
|
||||
| MenuButton
|
||||
| MenuComponent;
|
||||
| MenuComponent
|
||||
| string;
|
||||
|
||||
/** 工具栏 */
|
||||
export interface MenuBarData {
|
||||
/** 顶部工具栏左边项 */
|
||||
left?: MenuItem[];
|
||||
[ColumnLayout.LEFT]?: MenuItem[];
|
||||
/** 顶部工具栏中间项 */
|
||||
center?: MenuItem[];
|
||||
[ColumnLayout.CENTER]?: MenuItem[];
|
||||
/** 顶部工具栏右边项 */
|
||||
right?: MenuItem[];
|
||||
[ColumnLayout.RIGHT]?: MenuItem[];
|
||||
}
|
||||
|
||||
export interface SideComponent extends MenuComponent {
|
||||
|
@ -34,7 +34,7 @@
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.6",
|
||||
"@element-plus/icons-vue": "^2.0.9",
|
||||
"@tmagic/utils": "1.1.0-beta.12",
|
||||
"element-plus": "^2.2.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
@ -11,7 +11,7 @@
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.6",
|
||||
"@element-plus/icons-vue": "^2.0.9",
|
||||
"@tmagic/editor": "1.1.0-beta.12",
|
||||
"@tmagic/form": "1.1.0-beta.12",
|
||||
"@tmagic/schema": "1.1.0-beta.12",
|
||||
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@ -74,7 +74,7 @@ importers:
|
||||
|
||||
docs:
|
||||
specifiers:
|
||||
'@element-plus/icons-vue': ^2.0.6
|
||||
'@element-plus/icons-vue': ^2.0.9
|
||||
'@tmagic/form': 1.1.0-beta.12
|
||||
'@tmagic/schema': 1.1.0-beta.12
|
||||
'@tmagic/utils': 1.1.0-beta.12
|
||||
@ -92,7 +92,7 @@ importers:
|
||||
vue: ^3.2.37
|
||||
vuepress: ^2.0.0-beta.49
|
||||
dependencies:
|
||||
'@element-plus/icons-vue': 2.0.6_vue@3.2.37
|
||||
'@element-plus/icons-vue': 2.0.9_vue@3.2.37
|
||||
'@tmagic/form': link:../packages/form
|
||||
'@tmagic/schema': link:../packages/schema
|
||||
'@tmagic/utils': link:../packages/utils
|
||||
@ -154,7 +154,7 @@ importers:
|
||||
packages/editor:
|
||||
specifiers:
|
||||
'@babel/core': ^7.18.0
|
||||
'@element-plus/icons-vue': ^2.0.6
|
||||
'@element-plus/icons-vue': ^2.0.9
|
||||
'@tmagic/core': 1.1.0-beta.12
|
||||
'@tmagic/form': 1.1.0-beta.12
|
||||
'@tmagic/schema': 1.1.0-beta.12
|
||||
@ -184,7 +184,7 @@ importers:
|
||||
vue-tsc: ^0.39.4
|
||||
dependencies:
|
||||
'@babel/core': 7.18.2
|
||||
'@element-plus/icons-vue': 2.0.6_vue@3.2.37
|
||||
'@element-plus/icons-vue': 2.0.9_vue@3.2.37
|
||||
'@tmagic/core': link:../core
|
||||
'@tmagic/form': link:../form
|
||||
'@tmagic/schema': link:../schema
|
||||
@ -217,7 +217,7 @@ importers:
|
||||
packages/form:
|
||||
specifiers:
|
||||
'@babel/core': ^7.18.0
|
||||
'@element-plus/icons-vue': ^2.0.6
|
||||
'@element-plus/icons-vue': ^2.0.9
|
||||
'@tmagic/utils': 1.1.0-beta.12
|
||||
'@types/lodash-es': ^4.17.4
|
||||
'@types/node': ^15.12.4
|
||||
@ -235,7 +235,7 @@ importers:
|
||||
vue: ^3.2.37
|
||||
vue-tsc: ^0.39.4
|
||||
dependencies:
|
||||
'@element-plus/icons-vue': 2.0.6_vue@3.2.37
|
||||
'@element-plus/icons-vue': 2.0.9_vue@3.2.37
|
||||
'@tmagic/utils': link:../utils
|
||||
element-plus: 2.2.6_vue@3.2.37
|
||||
lodash-es: 4.17.21
|
||||
@ -427,7 +427,7 @@ importers:
|
||||
|
||||
playground:
|
||||
specifiers:
|
||||
'@element-plus/icons-vue': ^2.0.6
|
||||
'@element-plus/icons-vue': ^2.0.9
|
||||
'@tmagic/editor': 1.1.0-beta.12
|
||||
'@tmagic/form': 1.1.0-beta.12
|
||||
'@tmagic/schema': 1.1.0-beta.12
|
||||
@ -450,7 +450,7 @@ importers:
|
||||
vue-router: ^4.0.10
|
||||
vue-tsc: ^0.39.4
|
||||
dependencies:
|
||||
'@element-plus/icons-vue': 2.0.6_vue@3.2.37
|
||||
'@element-plus/icons-vue': 2.0.9_vue@3.2.37
|
||||
'@tmagic/editor': link:../packages/editor
|
||||
'@tmagic/form': link:../packages/form
|
||||
'@tmagic/schema': link:../packages/schema
|
||||
@ -1175,8 +1175,8 @@ packages:
|
||||
resolution: {integrity: sha512-HsbMKc0ZAQH+EUeCmI/2PvTYSybmkaWwakU8QGDYYgMVIg9BQ5sM0A0Nnombjxo2+JzXHxmH+jw//yGX+y6GYw==}
|
||||
dev: false
|
||||
|
||||
/@element-plus/icons-vue/2.0.6_vue@3.2.37:
|
||||
resolution: {integrity: sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==}
|
||||
/@element-plus/icons-vue/2.0.9_vue@3.2.37:
|
||||
resolution: {integrity: sha512-okdrwiVeKBmW41Hkl0eMrXDjzJwhQMuKiBOu17rOszqM+LS/yBYpNQNV5Jvoh06Wc+89fMmb/uhzf8NZuDuUaQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.2.0
|
||||
dependencies:
|
||||
@ -3324,7 +3324,7 @@ packages:
|
||||
vue: ^3.2.0
|
||||
dependencies:
|
||||
'@ctrl/tinycolor': 3.4.1
|
||||
'@element-plus/icons-vue': 2.0.6_vue@3.2.37
|
||||
'@element-plus/icons-vue': 2.0.9_vue@3.2.37
|
||||
'@floating-ui/dom': 0.5.4
|
||||
'@popperjs/core': /@sxzz/popperjs-es/2.11.7
|
||||
'@types/lodash': 4.14.182
|
||||
|
Loading…
x
Reference in New Issue
Block a user