feat(editor): 新增Layout

This commit is contained in:
roymondchen 2022-09-16 17:43:49 +08:00 committed by jia000
parent 22c57f444f
commit 835189adc9
5 changed files with 195 additions and 167 deletions

View File

@ -277,8 +277,6 @@ export default defineComponent({
},
);
uiService.initColumnWidth();
onUnmounted(() => {
editorService.destroy();
historyService.destroy();

View File

@ -10,77 +10,96 @@
@save="saveCode"
></magic-code-editor>
<div class="m-editor-content" v-else>
<div class="m-editor-framework-left" :style="`width: ${columnWidth?.left}px`">
<layout
v-else
class="m-editor-content"
left-class="m-editor-framework-left"
center-class="m-editor-framework-center"
right-class="m-editor-framework-right"
v-model:left="columnWidth.left"
v-model:right="columnWidth.right"
:min-left="45"
:min-right="1"
@change="columnWidthChange"
>
<template #left>
<slot name="sidebar"></slot>
</div>
<resizer type="left"></resizer>
<template v-if="pageLength > 0">
<div class="m-editor-framework-center" :style="`width: ${columnWidth?.center}px`">
<slot name="workspace"></slot>
</div>
<resizer type="right"></resizer>
<div class="m-editor-framework-right" :style="`width: ${columnWidth?.right}px`">
<el-scrollbar>
<slot name="props-panel"></slot>
</el-scrollbar>
</div>
</template>
<slot v-else name="empty">
<add-page-box></add-page-box>
</slot>
</div>
<template #center>
<slot v-if="pageLength > 0" name="workspace"></slot>
<slot v-else name="empty">
<add-page-box></add-page-box>
</slot>
</template>
<template v-if="pageLength > 0" #right>
<el-scrollbar>
<slot name="props-panel"></slot>
</el-scrollbar>
</template>
</layout>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, inject } from 'vue';
<script lang="ts" setup>
import { computed, inject, ref } from 'vue';
import type { MApp } from '@tmagic/schema';
import { GetColumnWidth, Services } from '../type';
import AddPageBox from './AddPageBox.vue';
import Resizer from './Resizer.vue';
import Layout from './Layout.vue';
export default defineComponent({
components: {
AddPageBox,
Resizer,
const DEFAULT_LEFT_COLUMN_WIDTH = 310;
const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
withDefaults(
defineProps<{
codeOptions?: Record<string, any>;
}>(),
{
codeOptions: () => ({}),
},
);
props: {
codeOptions: {
type: Object,
default: () => ({}),
},
},
const { editorService, uiService } = inject<Services>('services') || {};
setup() {
const { editorService, uiService } = inject<Services>('services') || {};
const root = computed(() => editorService?.get<MApp>('root'));
const root = computed(() => editorService?.get<MApp>('root'));
return {
root,
pageLength: computed(() => editorService?.get<number>('pageLength') || 0),
showSrc: computed(() => uiService?.get<boolean>('showSrc')),
columnWidth: computed(() => uiService?.get<GetColumnWidth>('columnWidth')),
saveCode(value: string) {
try {
// eslint-disable-next-line no-eval
editorService?.set('root', eval(value));
} catch (e: any) {
console.error(e);
}
},
};
},
const pageLength = computed(() => editorService?.get<number>('pageLength') || 0);
const showSrc = computed(() => uiService?.get<boolean>('showSrc'));
const columnWidth = ref({
left: DEFAULT_LEFT_COLUMN_WIDTH,
center: globalThis.document.body.clientWidth - DEFAULT_LEFT_COLUMN_WIDTH - DEFAULT_RIGHT_COLUMN_WIDTH,
right: DEFAULT_RIGHT_COLUMN_WIDTH,
});
uiService?.set('columnWidth', columnWidth.value);
const saveCode = (value: string) => {
try {
// eslint-disable-next-line no-eval
editorService?.set('root', eval(value));
} catch (e: any) {
console.error(e);
}
};
const COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorColumnWidthData';
const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
if (columnWidthCacheData) {
try {
const columnWidthCache = JSON.parse(columnWidthCacheData);
columnWidth.value = columnWidthCache;
} catch (e) {
console.error(e);
}
}
const columnWidthChange = (columnWidth: GetColumnWidth) => {
uiService?.set('columnWidth', columnWidth);
globalThis.localStorage.setItem(COLUMN_WIDTH_STORAGE_KEY, JSON.stringify(columnWidth));
};
</script>

View File

@ -0,0 +1,100 @@
<template>
<div ref="el">
<template v-if="typeof props.left !== 'undefined'">
<div class="m-editor-layout-left" :class="leftClass" :style="`width: ${left}px`">
<slot name="left"></slot>
</div>
<Resizer @change="changeLeft"></Resizer>
</template>
<div class="m-editor-layout-center" :class="centerClass" :style="`width: ${center}px`">
<slot name="center"></slot>
</div>
<template v-if="typeof props.right !== 'undefined'">
<Resizer @change="changeRight"></Resizer>
<div class="m-editor-layout-right" :class="rightClass" :style="`width: ${right}px`">
<slot name="right"></slot>
</div>
</template>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue';
import Resizer from './Resizer.vue';
const emit = defineEmits(['update:left', 'change', 'update:right']);
const props = withDefaults(
defineProps<{
left?: number;
right?: number;
minLeft?: number;
minRight?: number;
leftClass?: string;
rightClass?: string;
centerClass?: string;
}>(),
{
minLeft: 1,
minRight: 1,
},
);
const el = ref<HTMLElement>();
let clientWidth = 0;
const resizerObserver = new ResizeObserver((entries) => {
for (const { contentRect } of entries) {
clientWidth = contentRect.width;
center.value = clientWidth - (props.left || 0) - (props.right || 0);
emit('change', {
left: props.left,
center: center.value,
right: props.right,
});
}
});
onMounted(() => {
if (el.value) {
resizerObserver.observe(el.value);
}
});
onUnmounted(() => {
resizerObserver.disconnect();
});
const center = ref(0);
const changeLeft = (deltaX: number) => {
if (typeof props.left === 'undefined') return;
const left = Math.max(props.left + deltaX, props.minLeft) || 0;
emit('update:left', left);
center.value = clientWidth - left - (props.right || 0);
emit('change', {
left,
center: center.value,
right: props.right,
});
};
const changeRight = (deltaX: number) => {
if (typeof props.right === 'undefined') return;
const right = Math.max(props.right - deltaX, props.minRight) || 0;
emit('update:right', right);
center.value = clientWidth - (props.left || 0) - right;
emit('change', {
left: props.left,
center: center.value,
right,
});
};
</script>

View File

@ -4,58 +4,29 @@
</span>
</template>
<script lang="ts">
import { defineComponent, inject, onMounted, onUnmounted, ref, toRaw } from 'vue';
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue';
import Gesto from 'gesto';
import { Services } from '../type';
const emit = defineEmits(['change']);
export default defineComponent({
name: 'm-editor-resize',
const target = ref<HTMLSpanElement>();
props: {
type: {
type: String,
},
},
let getso: Gesto;
setup(props) {
const services = inject<Services>('services');
onMounted(() => {
if (!target.value) return;
getso = new Gesto(target.value, {
container: window,
pinchOutside: true,
}).on('drag', (e) => {
if (!target.value) return;
const target = ref<HTMLSpanElement>();
emit('change', e.deltaX);
});
});
let getso: Gesto;
onMounted(() => {
if (!target.value) return;
getso = new Gesto(target.value, {
container: window,
pinchOutside: true,
}).on('drag', (e) => {
if (!target.value || !services) return;
let { left, right } = {
...toRaw(services.uiService.get('columnWidth')),
};
if (props.type === 'left') {
left += e.deltaX;
} else if (props.type === 'right') {
right -= e.deltaX;
}
services.uiService.set('columnWidth', {
left,
right,
});
});
});
onUnmounted(() => {
getso?.unset();
});
return {
target,
};
},
onUnmounted(() => {
getso?.unset();
});
</script>

View File

@ -16,28 +16,15 @@
* limitations under the License.
*/
import { reactive, toRaw } from 'vue';
import { reactive } from 'vue';
import type StageCore from '@tmagic/stage';
import editorService from '../services/editor';
import type { GetColumnWidth, SetColumnWidth, StageRect, UiState } from '../type';
import type { StageRect, UiState } from '../type';
import BaseService from './BaseService';
const DEFAULT_LEFT_COLUMN_WIDTH = 310;
const MIN_LEFT_COLUMN_WIDTH = 45;
const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
const MIN_RIGHT_COLUMN_WIDTH = 1;
const COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorColumnWidthData';
const defaultColumnWidth = {
left: DEFAULT_LEFT_COLUMN_WIDTH,
center: globalThis.document.body.clientWidth - DEFAULT_LEFT_COLUMN_WIDTH - DEFAULT_RIGHT_COLUMN_WIDTH,
right: DEFAULT_RIGHT_COLUMN_WIDTH,
};
const state = reactive<UiState>({
uiSelectMode: false,
showSrc: false,
@ -50,7 +37,7 @@ const state = reactive<UiState>({
width: 375,
height: 817,
},
columnWidth: defaultColumnWidth,
columnWidth: {},
showGuides: true,
showRule: true,
propsPanelSize: 'small',
@ -59,7 +46,7 @@ const state = reactive<UiState>({
class Ui extends BaseService {
constructor() {
super(['initColumnWidth', 'zoom', 'calcZoom']);
super(['zoom', 'calcZoom']);
globalThis.addEventListener('resize', () => {
this.setColumnWidth({
center: 'auto',
@ -70,11 +57,6 @@ class Ui extends BaseService {
public set<T = any>(name: keyof UiState, value: T) {
const mask = editorService.get<StageCore>('stage')?.mask;
if (name === 'columnWidth') {
this.setColumnWidth(value as unknown as SetColumnWidth);
return;
}
if (name === 'stageRect') {
this.setStageRect(value as unknown as StageRect);
return;
@ -95,18 +77,6 @@ class Ui extends BaseService {
return (state as any)[name];
}
public async initColumnWidth() {
const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
if (columnWidthCacheData) {
try {
const columnWidthCache = JSON.parse(columnWidthCacheData);
this.setColumnWidth(columnWidthCache);
} catch (e) {
console.error(e);
}
}
}
public async zoom(zoom: number) {
this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
@ -132,36 +102,6 @@ class Ui extends BaseService {
this.removeAllListeners();
}
private setColumnWidth({ left, center, right }: SetColumnWidth) {
const columnWidth = {
...toRaw(this.get<GetColumnWidth>('columnWidth')),
};
if (left) {
columnWidth.left = Math.max(left, MIN_LEFT_COLUMN_WIDTH);
}
if (right) {
columnWidth.right = Math.max(right, MIN_RIGHT_COLUMN_WIDTH);
}
if (!center || center === 'auto') {
const bodyWidth = globalThis.document.body.clientWidth;
columnWidth.center = bodyWidth - (columnWidth?.left || 0) - (columnWidth?.right || 0);
if (columnWidth.center <= 0) {
columnWidth.left = defaultColumnWidth.left;
columnWidth.center = defaultColumnWidth.center;
columnWidth.right = defaultColumnWidth.right;
}
} else {
columnWidth.center = center;
}
globalThis.localStorage.setItem(COLUMN_WIDTH_STORAGE_KEY, JSON.stringify(columnWidth));
state.columnWidth = columnWidth;
}
private async setStageRect(value: StageRect) {
state.stageRect = {
...state.stageRect,