polarvo-layout 1.0.2 → 1.0.4
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 +1 -1
- package/src/components/FastMenu/DisplayFastMenu.vue +4 -3
- package/src/components/FastMenu/HistoryFastMenu.vue +18 -3
- package/src/components/Layout/BaseLayout.vue +6 -4
- package/src/components/Layout/CanvasContainer.vue +6 -7
- package/src/components/Layout/FreeLayout.vue +4 -4
- package/src/components/Layout/GridLayout.vue +46 -45
- package/src/components/SideBar/LayoutSettingSideBar.vue +4 -4
- package/src/components/SideBar/LayoutSideBar.vue +4 -4
- package/src/configs/index.js +0 -5
- package/src/core/engines/DisplayEngine.js +86 -20
- package/src/core/engines/FreeDropEngine.js +147 -144
- package/src/core/engines/GridDropEngine.js +208 -142
- package/src/core/engines/HistoryEngine.js +259 -13
- package/src/core/engines/LayoutEngine.js +114 -77
- package/src/core/managers/EngineManager.js +214 -132
- package/src/library/DisplayLibrary.js +18 -8
- package/src/library/FreeDropLibrary.js +40 -17
- package/src/library/GridDropLibrary.js +66 -20
- package/src/library/HistoryLibrary.js +44 -5
- package/src/library/LayoutLibrary.js +61 -42
- package/src/library/index.js +1 -0
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
min="600"
|
|
25
25
|
max="2400"
|
|
26
26
|
step="50"
|
|
27
|
-
:value="displaySize
|
|
27
|
+
:value="displaySize?.px"
|
|
28
28
|
class="border-b-2 pr-1 border-white focus:outline-none focus:border-b-2 focus:border-blue-500"
|
|
29
29
|
@change="setDisplaySize('px', $event.target.value)"
|
|
30
30
|
/>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
min="0"
|
|
37
37
|
max="100"
|
|
38
38
|
step="10"
|
|
39
|
-
:value="displaySize
|
|
39
|
+
:value="displaySize?.percent"
|
|
40
40
|
class="border-b-2 pr-1 border-white focus:outline-none focus:border-b-2 focus:border-blue-500"
|
|
41
41
|
@change="setDisplaySize('percent', $event.target.value)"
|
|
42
42
|
/>
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</template>
|
|
47
47
|
|
|
48
48
|
<script setup>
|
|
49
|
-
import { toRefs } from 'vue';
|
|
49
|
+
import { toRefs, onMounted } from 'vue';
|
|
50
50
|
|
|
51
51
|
const props = defineProps({
|
|
52
52
|
polarvo: {
|
|
@@ -56,6 +56,7 @@ const props = defineProps({
|
|
|
56
56
|
});
|
|
57
57
|
const { displayMode, displaySize } = toRefs(props.polarvo.display.state);
|
|
58
58
|
const { setDisplayMode, setDisplaySize } = props.polarvo.display;
|
|
59
|
+
|
|
59
60
|
</script>
|
|
60
61
|
|
|
61
62
|
<style scoped>
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<!-- editor - title right -->
|
|
3
3
|
<div id="fast-menu" class="flex gap-2 text-gray-400">
|
|
4
|
-
<
|
|
5
|
-
|
|
4
|
+
<button @click="undo" :class="undoable ? 'cursor-pointer hover:opacity-70 ' : 'cursor-not-allowed opacity-50'" :disabled="!undoable">
|
|
5
|
+
<UndoIcon class="size-5 active:text-blue-600" />
|
|
6
|
+
</button>
|
|
7
|
+
<button @click="redo" :class="redoable ? 'cursor-pointer hover:opacity-70' : 'cursor-not-allowed opacity-50'" :disabled="!redoable">
|
|
8
|
+
<RedoIcon class="size-5 active:text-blue-600" />
|
|
9
|
+
</button>
|
|
6
10
|
</div>
|
|
7
11
|
</template>
|
|
8
12
|
|
|
9
13
|
<script setup>
|
|
10
|
-
import
|
|
14
|
+
import { toRefs } from 'vue';
|
|
15
|
+
import UndoIcon from '../../icons/history/UndoIcon.vue';
|
|
11
16
|
import RedoIcon from '../../icons/history/RedoIcon.vue';
|
|
17
|
+
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
polarvo: {
|
|
20
|
+
type: Object,
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const { undoable, redoable } = toRefs(props.polarvo.history.state);
|
|
26
|
+
const { undo, redo } = props.polarvo.history;
|
|
12
27
|
</script>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div
|
|
3
3
|
:id="preview ? 'previewLayout' : 'baseLayout'"
|
|
4
4
|
class="grid h-full p-2 bg-transparent rounded-lg"
|
|
5
|
-
:class="[layoutType + '-layout', `grid-cols-${gridNumber
|
|
5
|
+
:class="[layoutType + '-layout', `grid-cols-${gridNumber?.column}`, 'mb-4' ? layoutType === 'three-column-split' : '']"
|
|
6
6
|
:style="getBaseStyle"
|
|
7
7
|
>
|
|
8
8
|
<template v-for="(section, key) in layoutData" :key="key">
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
36
|
<script setup>
|
|
37
|
-
import { toRefs, computed } from 'vue';
|
|
37
|
+
import { toRefs, computed, onUnmounted } from 'vue';
|
|
38
38
|
|
|
39
39
|
import PolarLayout from './PolarLayout.vue';
|
|
40
40
|
import FreeLayout from './FreeLayout.vue';
|
|
@@ -67,8 +67,8 @@ const layoutType = computed(() => {
|
|
|
67
67
|
|
|
68
68
|
const getBaseStyle = computed(() => {
|
|
69
69
|
return {
|
|
70
|
-
gridTemplateColumns: gridRatio.value
|
|
71
|
-
gridTemplateRows: gridRatio.value
|
|
70
|
+
gridTemplateColumns: gridRatio.value?.column.map((ratio) => `${ratio}%`).join(' '),
|
|
71
|
+
gridTemplateRows: gridRatio.value?.row.map((ratio) => `${ratio}%`).join(' '),
|
|
72
72
|
marginRight: layoutType.value === 'no-split' ? '0' : layoutType.value === 'three-column-split' ? '14px' : '8px',
|
|
73
73
|
gap: `${gapSize.value}px`,
|
|
74
74
|
};
|
|
@@ -88,6 +88,8 @@ const getSectionClass = (key, section) => ({
|
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
const { layoutName, layoutData, activeSection, gapSize, gridNumber, gridRatio } = toRefs(props.polarvo.layout.state);
|
|
91
|
+
|
|
92
|
+
|
|
91
93
|
</script>
|
|
92
94
|
|
|
93
95
|
<style scoped>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
9
|
<script setup>
|
|
10
|
-
import { toRefs,
|
|
10
|
+
import { toRefs, computed, provide } from 'vue';
|
|
11
11
|
import BaseLayout from './BaseLayout.vue';
|
|
12
12
|
|
|
13
13
|
const props = defineProps({
|
|
@@ -18,14 +18,14 @@ const props = defineProps({
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
const { displaySize } = toRefs(props.polarvo.display.state);
|
|
21
|
-
const gridSize = computed(() => displaySize.value
|
|
21
|
+
const gridSize = computed(() => displaySize.value?.gridSize || 16);
|
|
22
22
|
|
|
23
23
|
const containerStyle = computed(() => {
|
|
24
24
|
return {
|
|
25
|
-
aspectRatio: displaySize.value
|
|
26
|
-
width: `${displaySize.value
|
|
25
|
+
aspectRatio: displaySize.value?.aspectRatio,
|
|
26
|
+
width: `${displaySize.value?.px}px`,
|
|
27
27
|
margin: `0 auto`,
|
|
28
|
-
transform: `scale(${displaySize.value
|
|
28
|
+
transform: `scale(${displaySize.value?.percent / 100})`,
|
|
29
29
|
transformOrigin: 'top center',
|
|
30
30
|
backgroundImage: `
|
|
31
31
|
linear-gradient(rgba(0,0,0,0.05) 1px, transparent 1px),
|
|
@@ -38,8 +38,7 @@ const containerStyle = computed(() => {
|
|
|
38
38
|
const { elements } = toRefs(props.polarvo.layout.state);
|
|
39
39
|
|
|
40
40
|
// 전체 elements
|
|
41
|
-
provide('elements', elements)
|
|
42
|
-
|
|
41
|
+
provide('elements', elements);
|
|
43
42
|
</script>
|
|
44
43
|
|
|
45
44
|
<style scoped lang="scss"></style>
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
class="hover:opacity-80 pointer-events-none"
|
|
31
31
|
/>
|
|
32
32
|
</div>
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
<!-- 가이드라인 -->
|
|
35
35
|
<div v-if="isActive">
|
|
36
36
|
<div v-if="guides.x !== null" class="guide absolute z-10 pointer-events-none vertical" :style="{ left: `${guides.x}px` }"></div>
|
|
@@ -109,6 +109,7 @@ function setComponentRef(el, elementId) {
|
|
|
109
109
|
|
|
110
110
|
const selectedElement = inject('selectedElement');
|
|
111
111
|
|
|
112
|
+
import { omit, cloneDeep } from 'lodash-es';
|
|
112
113
|
watch(
|
|
113
114
|
() => activeElement.value?.id,
|
|
114
115
|
(newId, oldId) => {
|
|
@@ -116,12 +117,11 @@ watch(
|
|
|
116
117
|
if (!newId) {
|
|
117
118
|
setActiveDesign(null);
|
|
118
119
|
}
|
|
119
|
-
selectedElement.value = structuredClone(toRaw(activeElement.value));
|
|
120
|
+
// selectedElement.value = structuredClone(toRaw(activeElement.value));
|
|
121
|
+
selectedElement.value = cloneDeep(activeElement.value);
|
|
120
122
|
},
|
|
121
|
-
{ immediate: true }
|
|
122
123
|
);
|
|
123
124
|
|
|
124
|
-
import { omit } from 'lodash-es';
|
|
125
125
|
// 특정 키 값을 제외하고 변경 감지
|
|
126
126
|
const selectedElementForWatch = computed(() => omit(selectedElement.value, ['position', 'size', 'id']));
|
|
127
127
|
|
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<div
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
|
|
2
|
+
<template v-if="!preview">
|
|
3
|
+
<div
|
|
4
|
+
v-for="(item, index) in filteredElements"
|
|
5
|
+
:key="index"
|
|
6
|
+
:id="item.id"
|
|
7
|
+
class="relative bg-gray-200"
|
|
8
|
+
:class="{
|
|
9
|
+
'z-50': activeElement?.id === item.id,
|
|
10
|
+
'bg-white border-2 border-blue-400': activeElement?.id === item.id,
|
|
11
|
+
}"
|
|
12
|
+
:style="getElementStyle('element', item)"
|
|
13
|
+
@mousedown.stop="startDrag($event, item.id)"
|
|
14
|
+
>
|
|
15
|
+
<!-- 리사이즈 핸들 -->
|
|
16
|
+
<div v-if="activeElement?.id === item.id">
|
|
17
|
+
<div class="absolute w-4 h-4 bottom-0 right-0 bg-blue-400 z-10 cursor-se-resize" @mousedown="startResize($event, item.id)"></div>
|
|
18
|
+
<div class="absolute z-10 pointer-events-auto cursor-pointer" @click="toggleLock()">
|
|
19
|
+
<LockIcon v-if="item.isLocked" />
|
|
20
|
+
<UnlockIcon v-else />
|
|
21
|
+
</div>
|
|
20
22
|
</div>
|
|
21
|
-
</div>
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
</div>
|
|
24
|
+
<component
|
|
25
|
+
:is="dynamicComponent(item.type)"
|
|
26
|
+
:id="`${sectionKey}-${index}`"
|
|
27
|
+
:ref="(el) => setComponentRef(el, item.id)"
|
|
28
|
+
v-bind="item"
|
|
29
|
+
class="hover:opacity-80 pointer-events-none"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
<div
|
|
35
|
-
v-for="(cell, index) in emptyData[sectionKey]"
|
|
36
|
-
:key="index"
|
|
37
|
-
class="flex items-center justify-center bg-gray-100 border border-gray-300"
|
|
38
|
-
:style="getElementStyle('empty', cell)"
|
|
39
|
-
@mouseenter="detectHoverCell(cell)"
|
|
40
|
-
>
|
|
33
|
+
<!-- 빈 그리드 설정 -->
|
|
41
34
|
<div
|
|
42
|
-
v-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
v-for="(cell, index) in emptyData[sectionKey]"
|
|
36
|
+
:key="index"
|
|
37
|
+
class="flex items-center justify-center bg-gray-100 border border-gray-300"
|
|
38
|
+
:style="getElementStyle('empty', cell)"
|
|
39
|
+
@mouseenter="detectHoverCell(cell)"
|
|
45
40
|
>
|
|
46
|
-
|
|
41
|
+
<div
|
|
42
|
+
class="text-sm w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-gray-500 hover:bg-blue-200 hover:text-white transition-colors cursor-pointer"
|
|
43
|
+
@click="setActiveElement({ position: cell }, 'click')"
|
|
44
|
+
>
|
|
45
|
+
+
|
|
46
|
+
</div>
|
|
47
47
|
</div>
|
|
48
|
-
</
|
|
48
|
+
</template>
|
|
49
49
|
</template>
|
|
50
50
|
|
|
51
51
|
<script setup>
|
|
@@ -70,13 +70,13 @@ const props = defineProps({
|
|
|
70
70
|
elementIds: {
|
|
71
71
|
type: Array,
|
|
72
72
|
required: true,
|
|
73
|
-
}
|
|
73
|
+
},
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
const { setActiveDesign } = props.polarvo.display;
|
|
77
77
|
const { updateActiveElement } = props.polarvo.layout;
|
|
78
78
|
const { elements, emptyData, activeCell, activeElement } = toRefs(props.polarvo.gridDrop.state);
|
|
79
|
-
const { getElementStyle,
|
|
79
|
+
const { getElementStyle, setActiveElement, toggleLock, startDrag, detectHoverCell, startResize } = props.polarvo.gridDrop;
|
|
80
80
|
const filteredElements = computed(() => {
|
|
81
81
|
return elements.value.filter((el) => props.elementIds?.includes(el.id) && el.section === props.sectionKey);
|
|
82
82
|
});
|
|
@@ -104,6 +104,7 @@ function setComponentRef(el, elementId) {
|
|
|
104
104
|
|
|
105
105
|
const selectedElement = inject('selectedElement');
|
|
106
106
|
|
|
107
|
+
import { omit, cloneDeep } from 'lodash-es';
|
|
107
108
|
watch(
|
|
108
109
|
() => activeElement.value?.id,
|
|
109
110
|
(newId, oldId) => {
|
|
@@ -111,12 +112,12 @@ watch(
|
|
|
111
112
|
if (!newId) {
|
|
112
113
|
setActiveDesign(null);
|
|
113
114
|
}
|
|
114
|
-
selectedElement.value = structuredClone(toRaw(activeElement.value));
|
|
115
|
+
// selectedElement.value = structuredClone(toRaw(activeElement.value));
|
|
116
|
+
selectedElement.value = cloneDeep(activeElement.value);
|
|
115
117
|
},
|
|
116
118
|
{ immediate: true }
|
|
117
119
|
);
|
|
118
120
|
|
|
119
|
-
import { omit } from 'lodash-es';
|
|
120
121
|
// 특정 키 값을 제외하고 변경 감지
|
|
121
122
|
const selectedElementForWatch = computed(() => omit(selectedElement.value, ['position', 'size', 'id']));
|
|
122
123
|
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
id="gap-size"
|
|
50
50
|
min="0"
|
|
51
51
|
max="12"
|
|
52
|
-
:value="
|
|
53
|
-
@change="
|
|
52
|
+
:value="activeData?.config?.gridGap"
|
|
53
|
+
@change="setSectionConfig('gap', $event.target.value)"
|
|
54
54
|
/>
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
@@ -81,8 +81,8 @@ const props = defineProps({
|
|
|
81
81
|
required: true,
|
|
82
82
|
},
|
|
83
83
|
});
|
|
84
|
-
const { activeData
|
|
85
|
-
const {
|
|
84
|
+
const { activeData } = toRefs(props.polarvo.layout.state);
|
|
85
|
+
const { setSectionMode, setSectionConfig } = props.polarvo.layout;
|
|
86
86
|
|
|
87
87
|
const sectionMode = computed(() => activeData.value?.mode);
|
|
88
88
|
</script>
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
29
|
<div class="px-4 py-0">
|
|
30
|
-
<div class="flex flex-row items-center gap-2 mb-2" v-if="gridNumber
|
|
31
|
-
<template v-for="column in gridNumber
|
|
30
|
+
<div class="flex flex-row items-center gap-2 mb-2" v-if="gridNumber?.column > 1">
|
|
31
|
+
<template v-for="column in gridNumber?.column" :key="column">
|
|
32
32
|
<label class="text-sm w-12 text-gray-500" :for="`col-ratio-${column}`" v-if="column === 1">열비율</label>
|
|
33
33
|
<input
|
|
34
34
|
class="text-sm w-12 border-b-2 border-white focus:outline-none focus:border-b-2 focus:border-blue-500"
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
</template>
|
|
41
41
|
</div>
|
|
42
42
|
|
|
43
|
-
<div class="flex flex-row items-center gap-2 mb-2" v-if="gridNumber
|
|
44
|
-
<template v-for="row in gridNumber
|
|
43
|
+
<div class="flex flex-row items-center gap-2 mb-2" v-if="gridNumber?.row > 1">
|
|
44
|
+
<template v-for="row in gridNumber?.row" :key="row">
|
|
45
45
|
<label class="text-sm w-12 text-gray-500" :for="`row-ratio-${row}`" v-if="row === 1">행비율</label>
|
|
46
46
|
<input
|
|
47
47
|
class="text-sm w-12 border-b-2 border-white focus:outline-none focus:border-b-2 focus:border-blue-500"
|
package/src/configs/index.js
CHANGED
|
@@ -3,13 +3,8 @@ import { resources } from './resources/index.js';
|
|
|
3
3
|
const createDefaultConfig = (overrides = {}) => {
|
|
4
4
|
return {
|
|
5
5
|
initialState: {
|
|
6
|
-
gridSize: 16,
|
|
7
|
-
gridNumber: { column: 1, row: 1 },
|
|
8
6
|
elements: [], // 요소들
|
|
9
|
-
// layoutData: null, // 레이아웃 데이터 - 캐시용
|
|
10
7
|
activeSection: null,
|
|
11
|
-
// activeData: null,
|
|
12
|
-
activeId: null,
|
|
13
8
|
},
|
|
14
9
|
resource: {
|
|
15
10
|
display: resources.display,
|
|
@@ -5,8 +5,8 @@ class DisplayEngine {
|
|
|
5
5
|
|
|
6
6
|
this.activeMenu = null; // 현재 활성화된 메뉴
|
|
7
7
|
this.activeDesign = null; // 현재 활성화된 디자인 메뉴
|
|
8
|
-
this.displayMode = 'desktop'; // 현재 디스플레이 모드
|
|
9
|
-
this.displaySize =
|
|
8
|
+
this.displayMode = 'desktop'; // 현재 디스플레이 모드 (초기값 = 'desktop')
|
|
9
|
+
this.displaySize = null;
|
|
10
10
|
|
|
11
11
|
this._subscriptions = []; // 구독 해제 함수 저장용
|
|
12
12
|
this._setupSubscriptions();
|
|
@@ -27,29 +27,65 @@ class DisplayEngine {
|
|
|
27
27
|
/** 구독 설정 */
|
|
28
28
|
_setupSubscriptions() {
|
|
29
29
|
// 초기화 완료 이벤트 구독 - from EngineManager
|
|
30
|
-
this._subscribe('system:engineInitialized', (
|
|
31
|
-
this.
|
|
32
|
-
});
|
|
30
|
+
this._subscribe('system:engineInitialized', () => {
|
|
31
|
+
this._resetDisplaySizeByMode(this.displayMode);
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
this.eventBus.emit('display:engineInitialized', {
|
|
34
|
+
displaySize: this.displaySize,
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
});
|
|
36
37
|
});
|
|
37
38
|
|
|
38
|
-
this._subscribe('
|
|
39
|
+
this._subscribe('system:setElements', () => {
|
|
40
|
+
this.setActiveMenu(null);
|
|
39
41
|
this.setActiveDesign(null);
|
|
40
42
|
});
|
|
41
43
|
|
|
42
|
-
this._subscribe('
|
|
44
|
+
this._subscribe('freeDrop:startDrag', () => {
|
|
43
45
|
this.setActiveMenu(null);
|
|
46
|
+
this.setActiveDesign(null);
|
|
44
47
|
});
|
|
45
48
|
|
|
46
|
-
this._subscribe('gridDrop:
|
|
47
|
-
if (
|
|
49
|
+
this._subscribe('gridDrop:setActiveElement', ({ action }) => {
|
|
50
|
+
if (action === 'click') {
|
|
48
51
|
this.setActiveMenu('element');
|
|
49
52
|
} else {
|
|
50
|
-
this.setActiveMenu(
|
|
53
|
+
this.setActiveMenu(null);
|
|
51
54
|
}
|
|
55
|
+
|
|
56
|
+
this.setActiveDesign(null);
|
|
52
57
|
});
|
|
58
|
+
|
|
59
|
+
// this._subscribe('freeDrop:closeActiveMenu', () => {
|
|
60
|
+
// this.setActiveMenu(null);
|
|
61
|
+
// });
|
|
62
|
+
|
|
63
|
+
// this._subscribe('freeDrop:closeDesignMenu', () => {
|
|
64
|
+
// this.setActiveDesign(null);
|
|
65
|
+
// });
|
|
66
|
+
|
|
67
|
+
// this._subscribe('system:closeActiveMenu', () => {
|
|
68
|
+
// this.setActiveMenu(null);
|
|
69
|
+
// });
|
|
70
|
+
|
|
71
|
+
// this._subscribe('gridDrop:updateActiveCell', ({ type, activeCell }) => {
|
|
72
|
+
// if (type === 'new' && activeCell != null) {
|
|
73
|
+
// this.setActiveMenu('element');
|
|
74
|
+
// } else {
|
|
75
|
+
// this.setActiveMenu(activeCell);
|
|
76
|
+
// }
|
|
77
|
+
// });
|
|
78
|
+
|
|
79
|
+
// this._subscribe('system:enginesReset', () => {
|
|
80
|
+
// this.reset();
|
|
81
|
+
// })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
reset() {
|
|
85
|
+
this.activeMenu = null;
|
|
86
|
+
this.activeDesign = null;
|
|
87
|
+
this.displayMode = 'desktop';
|
|
88
|
+
this.displaySize = { px: 1200, percent: 100, gridSize: 16, aspectRatio: '16/9' }; // 현재 디스플레이 사이즈
|
|
53
89
|
}
|
|
54
90
|
|
|
55
91
|
/** 삭제 및 정리 */
|
|
@@ -67,6 +103,27 @@ class DisplayEngine {
|
|
|
67
103
|
console.log('[DisplayEngine] 삭제 완료');
|
|
68
104
|
}
|
|
69
105
|
|
|
106
|
+
getState() {
|
|
107
|
+
return {
|
|
108
|
+
displayMode: this.displayMode,
|
|
109
|
+
displaySize: { ...this.displaySize },
|
|
110
|
+
activeMenu: this.activeMenu,
|
|
111
|
+
activeDesign: this.activeDesign,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
setState(state) {
|
|
116
|
+
this.displayMode = state.displayMode;
|
|
117
|
+
this.displaySize = { ...state.displaySize };
|
|
118
|
+
this.activeMenu = state.activeMenu;
|
|
119
|
+
this.activeDesign = state.activeDesign;
|
|
120
|
+
|
|
121
|
+
// this.eventBus.emit('display:restoredState', {
|
|
122
|
+
// prev: state,
|
|
123
|
+
// timestamp: Date.now(),
|
|
124
|
+
// });
|
|
125
|
+
}
|
|
126
|
+
|
|
70
127
|
/** ---------------------------------- 공통 메소드 ---------------------------------- **/
|
|
71
128
|
|
|
72
129
|
/** 아이콘바 메뉴 변경
|
|
@@ -105,19 +162,29 @@ class DisplayEngine {
|
|
|
105
162
|
}
|
|
106
163
|
|
|
107
164
|
if (this.displayMode === mode) return;
|
|
165
|
+
|
|
166
|
+
const prevDisplayMode = this.displayMode;
|
|
167
|
+
const prevDisplaySize = { ...this.displaySize };
|
|
168
|
+
|
|
108
169
|
this.displayMode = mode;
|
|
170
|
+
this._resetDisplaySizeByMode(mode);
|
|
109
171
|
|
|
172
|
+
// displayMode 변경 시, displaySize도 초기화 됨
|
|
110
173
|
this.eventBus.emit('display:updateDisplayMode', {
|
|
111
|
-
displayMode:
|
|
174
|
+
displayMode: this.displayMode,
|
|
175
|
+
displaySize: this.displaySize,
|
|
176
|
+
prev: {
|
|
177
|
+
displayMode: prevDisplayMode,
|
|
178
|
+
displaySize: prevDisplaySize,
|
|
179
|
+
},
|
|
112
180
|
timestamp: Date.now(),
|
|
113
181
|
});
|
|
114
|
-
this._setDisplaySizeByMode(mode);
|
|
115
182
|
}
|
|
116
183
|
|
|
117
184
|
/** 사이즈 설정
|
|
118
185
|
* @param {string} mode - 디스플레이 모드
|
|
119
186
|
*/
|
|
120
|
-
|
|
187
|
+
_resetDisplaySizeByMode(mode) {
|
|
121
188
|
if (this.resource[mode]) {
|
|
122
189
|
this.displaySize = {
|
|
123
190
|
px: this.resource[mode]?.defaultWidth || 1200,
|
|
@@ -125,11 +192,6 @@ class DisplayEngine {
|
|
|
125
192
|
gridSize: this.resource[mode]?.gridSize || 16,
|
|
126
193
|
aspectRatio: this.resource[mode]?.aspectRatio || '16/9',
|
|
127
194
|
};
|
|
128
|
-
|
|
129
|
-
this.eventBus.emit('display:updateDisplaySizeByMode', {
|
|
130
|
-
displaySize: this.displaySize,
|
|
131
|
-
timestamp: Date.now(),
|
|
132
|
-
});
|
|
133
195
|
}
|
|
134
196
|
}
|
|
135
197
|
|
|
@@ -159,10 +221,14 @@ class DisplayEngine {
|
|
|
159
221
|
alert(`설정 가능한 최대 ${typeLimit.name}는 ${typeLimit.max}${typeLimit.unit}입니다.`);
|
|
160
222
|
}
|
|
161
223
|
|
|
224
|
+
const prevDisplaySize = { ...this.displaySize };
|
|
162
225
|
this.displaySize[type] = Math.min(Math.max(0, numSize), typeLimit.max);
|
|
163
226
|
|
|
164
227
|
this.eventBus.emit('display:updateDisplaySize', {
|
|
165
228
|
displaySize: this.displaySize,
|
|
229
|
+
prev: {
|
|
230
|
+
displaySize: prevDisplaySize,
|
|
231
|
+
},
|
|
166
232
|
timestamp: Date.now(),
|
|
167
233
|
});
|
|
168
234
|
}
|