@mixd-id/web-scaffold 0.1.230406106 → 0.1.230406108
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 +2 -1
- package/src/components/Article.vue +85 -3
- package/src/components/MonacoEditor.vue +136 -0
- package/src/index.js +1 -0
- package/src/widgets/ArticleSetting.vue +192 -0
- package/src/widgets/ComponentSetting.vue +0 -13
- package/src/widgets/WebPageBuilder.vue +46 -15
- package/src/widgets/WebPageSelector.vue +3 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mixd-id/web-scaffold",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.230406108",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite serve",
|
|
7
7
|
"build": "vite build",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"glob": "^8.0.3",
|
|
44
44
|
"lodash": "^4.17.21",
|
|
45
45
|
"md5": "^2.3.0",
|
|
46
|
+
"monaco-editor": "^0.41.0",
|
|
46
47
|
"nprogress": "^0.2.0",
|
|
47
48
|
"pinia": "^2.0.14",
|
|
48
49
|
"prismjs": "^1.28.0",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<script>
|
|
11
11
|
|
|
12
12
|
import { componentMixin } from '../mixin/component';
|
|
13
|
-
import {
|
|
13
|
+
import {getSelection, restoreSelection, saveSelection} from "../utils/selection";
|
|
14
14
|
|
|
15
15
|
export default{
|
|
16
16
|
|
|
@@ -24,6 +24,27 @@ export default{
|
|
|
24
24
|
|
|
25
25
|
methods: {
|
|
26
26
|
|
|
27
|
+
getSelection(){
|
|
28
|
+
const { text = '', href = '', target = '' } = saveSelection(this.$el)
|
|
29
|
+
return {
|
|
30
|
+
text,
|
|
31
|
+
href,
|
|
32
|
+
target
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
addLink(link){
|
|
37
|
+
|
|
38
|
+
restoreSelection()
|
|
39
|
+
|
|
40
|
+
document.execCommand("insertHTML", false,
|
|
41
|
+
"<a style='font-size:inherit;font-family:inherit;background-color:inherit' " +
|
|
42
|
+
"href=\"" + link.href + "\" " +
|
|
43
|
+
"target=\"" + link.target + "\">" +
|
|
44
|
+
link.text +
|
|
45
|
+
"</a>");
|
|
46
|
+
},
|
|
47
|
+
|
|
27
48
|
onInput(){
|
|
28
49
|
if(this.editable){
|
|
29
50
|
this.triggerUpdate()
|
|
@@ -198,13 +219,72 @@ export default{
|
|
|
198
219
|
|
|
199
220
|
mounted() {
|
|
200
221
|
if('edit-mode' in this.$route.query){
|
|
201
|
-
window.addEventListener('message', (
|
|
222
|
+
window.addEventListener('message', (e) => {
|
|
223
|
+
|
|
224
|
+
const { data, source } = e
|
|
225
|
+
|
|
202
226
|
if(data.uid === this.uid){
|
|
203
227
|
|
|
204
|
-
const { action, type, value } = data.data
|
|
228
|
+
const { action, type, value } = data.data ?? {}
|
|
229
|
+
|
|
230
|
+
let result
|
|
205
231
|
|
|
206
232
|
switch(action){
|
|
207
233
|
|
|
234
|
+
case 'saveSelection':
|
|
235
|
+
case 'getSelection':
|
|
236
|
+
const sel = saveSelection(this.$el)
|
|
237
|
+
const { text, target, href } = sel
|
|
238
|
+
result = {
|
|
239
|
+
text,
|
|
240
|
+
target,
|
|
241
|
+
href
|
|
242
|
+
}
|
|
243
|
+
break
|
|
244
|
+
|
|
245
|
+
case 'restoreSelection':
|
|
246
|
+
restoreSelection()
|
|
247
|
+
break
|
|
248
|
+
|
|
249
|
+
case 'insertLink':
|
|
250
|
+
restoreSelection()
|
|
251
|
+
|
|
252
|
+
document.execCommand("insertHTML", false,
|
|
253
|
+
"<a style='font-size:inherit;font-family:inherit;background-color:inherit' " +
|
|
254
|
+
"href=\"" + value.href + "\" " +
|
|
255
|
+
"target=\"" + value.target + "\">" +
|
|
256
|
+
value.text +
|
|
257
|
+
"</a>");
|
|
258
|
+
break
|
|
259
|
+
|
|
260
|
+
case 'removeLink':
|
|
261
|
+
const { element } = getSelection(this.$el)
|
|
262
|
+
|
|
263
|
+
let a = element
|
|
264
|
+
while(a && a.tagName !== 'A'){
|
|
265
|
+
a = a.parentNode
|
|
266
|
+
}
|
|
267
|
+
if(a){
|
|
268
|
+
a.parentNode.replaceChild(element, a)
|
|
269
|
+
}
|
|
270
|
+
break
|
|
271
|
+
|
|
272
|
+
case 'insertImage':
|
|
273
|
+
const props = {}
|
|
274
|
+
if(value.width)
|
|
275
|
+
props.width = parseInt(value.width) + 'px'
|
|
276
|
+
if(value.height)
|
|
277
|
+
props.height = parseInt(value.height) + 'px'
|
|
278
|
+
|
|
279
|
+
let propHtml = []
|
|
280
|
+
for(let key in props){
|
|
281
|
+
propHtml.push(`${key}='${props[key]}'`)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
document.execCommand("insertHTML", false,
|
|
285
|
+
"<img src=\"" + value.url + "\" " + propHtml.join(' ') + "/>");
|
|
286
|
+
break
|
|
287
|
+
|
|
208
288
|
case 'insertTable':
|
|
209
289
|
this.insertTable()
|
|
210
290
|
break
|
|
@@ -241,7 +321,9 @@ export default{
|
|
|
241
321
|
|
|
242
322
|
}
|
|
243
323
|
|
|
324
|
+
source.postMessage(result, '*')
|
|
244
325
|
}
|
|
326
|
+
|
|
245
327
|
})
|
|
246
328
|
this.editable = true
|
|
247
329
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
<div class="flex flex-row p-2">
|
|
4
|
+
<code>{{ language }}</code>
|
|
5
|
+
<div class="flex-1"></div>
|
|
6
|
+
<button type="button" class="text-primary" @click="reformat">Beautify</button>
|
|
7
|
+
</div>
|
|
8
|
+
<div ref="editorContainer" :class="$style['monaco-editor-container']"></div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import * as monaco from 'monaco-editor'
|
|
14
|
+
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
|
|
15
|
+
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
|
|
16
|
+
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
|
|
17
|
+
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
|
|
18
|
+
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
|
|
19
|
+
|
|
20
|
+
self.MonacoEnvironment = {
|
|
21
|
+
getWorker(_, label) {
|
|
22
|
+
if (label === 'json') {
|
|
23
|
+
return new jsonWorker()
|
|
24
|
+
}
|
|
25
|
+
if (label === 'css' || label === 'scss' || label === 'less') {
|
|
26
|
+
return new cssWorker()
|
|
27
|
+
}
|
|
28
|
+
if (label === 'html' || label === 'handlebars' || label === 'razor') {
|
|
29
|
+
return new htmlWorker()
|
|
30
|
+
}
|
|
31
|
+
if (label === 'typescript' || label === 'javascript') {
|
|
32
|
+
return new tsWorker()
|
|
33
|
+
}
|
|
34
|
+
return new editorWorker()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default {
|
|
39
|
+
|
|
40
|
+
props: {
|
|
41
|
+
|
|
42
|
+
language: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: 'json'
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
theme: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: 'vs-dark'
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
lineNumbers: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "off"
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
modelValue: String
|
|
58
|
+
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
methods: {
|
|
62
|
+
|
|
63
|
+
createEditor() {
|
|
64
|
+
this.editor = monaco.editor.create(this.$refs.editorContainer, {
|
|
65
|
+
value: this.modelValue,
|
|
66
|
+
language: this.language,
|
|
67
|
+
lineNumbers: this.lineNumbers,
|
|
68
|
+
minimap: {
|
|
69
|
+
enabled: false
|
|
70
|
+
},
|
|
71
|
+
theme: this.theme
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
this.editor.onDidChangeModelContent(event => {
|
|
75
|
+
const updatedCode = this.editor.getValue();
|
|
76
|
+
this.$emit('update:modelValue', updatedCode)
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
getErrors(){
|
|
81
|
+
const markers = monaco.editor.getModelMarkers({ owner: this.editor.getModel() });
|
|
82
|
+
|
|
83
|
+
let errors = []
|
|
84
|
+
if (markers.length >= 0) {
|
|
85
|
+
markers.forEach(marker => {
|
|
86
|
+
errors.push({
|
|
87
|
+
message: marker.message,
|
|
88
|
+
line: marker.startLineNumber,
|
|
89
|
+
column: marker.startColumn
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return errors.length > 0 ? errors : null
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
reformat(){
|
|
98
|
+
const formatAction = this.editor.getAction('editor.action.formatDocument');
|
|
99
|
+
formatAction.run();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
beforeDestroy() {
|
|
105
|
+
this.editor.dispose();
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
mounted() {
|
|
109
|
+
this.createEditor();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<style module>
|
|
116
|
+
|
|
117
|
+
.comp{
|
|
118
|
+
@apply flex-1 flex flex-col;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.monaco-editor-container {
|
|
122
|
+
width: 100%;
|
|
123
|
+
height: 300px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.monaco-editor-container *{
|
|
127
|
+
font-family: Menlo, Monaco, "Courier New", monospace;
|
|
128
|
+
--vscode-editor-background: rgb(var(--base-300));
|
|
129
|
+
--vscode-editorGutter-background: rgb(var(--base-400));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.monaco-editor-container .margin-view-overlays .line-numbers {
|
|
133
|
+
font-family: 'Menlo', monospace;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
</style>
|
package/src/index.js
CHANGED
|
@@ -321,6 +321,7 @@ export default{
|
|
|
321
321
|
app.component('Grid', defineAsyncComponent(() => import("./components/Grid.vue")))
|
|
322
322
|
app.component('Modal', defineAsyncComponent(() => import("./components/Modal.vue")))
|
|
323
323
|
app.component('Modal2', defineAsyncComponent(() => import("./components/Modal2.vue")))
|
|
324
|
+
app.component('MonacoEditor', defineAsyncComponent(() => import("./components/MonacoEditor.vue")))
|
|
324
325
|
app.component('OTPField', defineAsyncComponent(() => import("./components/OTPField.vue")))
|
|
325
326
|
app.component('PageBuilder', defineAsyncComponent(() => import("./components/PageBuilder.vue")))
|
|
326
327
|
app.component('Radio', defineAsyncComponent(() => import("./components/Radio.vue")))
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
<button class="p-3" type="button" ref="listBtn" @click="$refs.listContext.open($refs.listBtn)">
|
|
23
23
|
<svg width="14" height="14" class="fill-text-400 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M64 144c26.5 0 48-21.5 48-48s-21.5-48-48-48S16 69.5 16 96s21.5 48 48 48zM192 64c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zM64 464c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm48-208c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48z"/></svg>
|
|
24
24
|
</button>
|
|
25
|
+
<button class="p-3" type="button" @click="createImage">
|
|
26
|
+
<svg width="14" height="14" class="fill-text-400 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M152 120c-26.51 0-48 21.49-48 48s21.49 48 48 48s48-21.49 48-48S178.5 120 152 120zM447.1 32h-384C28.65 32-.0091 60.65-.0091 96v320c0 35.35 28.65 64 63.1 64h384c35.35 0 64-28.65 64-64V96C511.1 60.65 483.3 32 447.1 32zM463.1 409.3l-136.8-185.9C323.8 218.8 318.1 216 312 216c-6.113 0-11.82 2.768-15.21 7.379l-106.6 144.1l-37.09-46.1c-3.441-4.279-8.934-6.809-14.77-6.809c-5.842 0-11.33 2.529-14.78 6.809l-75.52 93.81c0-.0293 0 .0293 0 0L47.99 96c0-8.822 7.178-16 16-16h384c8.822 0 16 7.178 16 16V409.3z"/></svg>
|
|
27
|
+
</button>
|
|
28
|
+
<button class="p-3" type="button" @click="insertLink">
|
|
29
|
+
<svg width="14" height="14" class="fill-text-400 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M314.222 197.78c51.091 51.091 54.377 132.287 9.75 187.16-6.242 7.73-2.784 3.865-84.94 86.02-54.696 54.696-143.266 54.745-197.99 0-54.711-54.69-54.734-143.255 0-197.99 32.773-32.773 51.835-51.899 63.409-63.457 7.463-7.452 20.331-2.354 20.486 8.192a173.31 173.31 0 0 0 4.746 37.828c.966 4.029-.272 8.269-3.202 11.198L80.632 312.57c-32.755 32.775-32.887 85.892 0 118.8 32.775 32.755 85.892 32.887 118.8 0l75.19-75.2c32.718-32.725 32.777-86.013 0-118.79a83.722 83.722 0 0 0-22.814-16.229c-4.623-2.233-7.182-7.25-6.561-12.346 1.356-11.122 6.296-21.885 14.815-30.405l4.375-4.375c3.625-3.626 9.177-4.594 13.76-2.294 12.999 6.524 25.187 15.211 36.025 26.049zM470.958 41.04c-54.724-54.745-143.294-54.696-197.99 0-82.156 82.156-78.698 78.29-84.94 86.02-44.627 54.873-41.341 136.069 9.75 187.16 10.838 10.838 23.026 19.525 36.025 26.049 4.582 2.3 10.134 1.331 13.76-2.294l4.375-4.375c8.52-8.519 13.459-19.283 14.815-30.405.621-5.096-1.938-10.113-6.561-12.346a83.706 83.706 0 0 1-22.814-16.229c-32.777-32.777-32.718-86.065 0-118.79l75.19-75.2c32.908-32.887 86.025-32.755 118.8 0 32.887 32.908 32.755 86.025 0 118.8l-45.848 45.84c-2.93 2.929-4.168 7.169-3.202 11.198a173.31 173.31 0 0 1 4.746 37.828c.155 10.546 13.023 15.644 20.486 8.192 11.574-11.558 30.636-30.684 63.409-63.457 54.733-54.735 54.71-143.3-.001-197.991z"/></svg>
|
|
30
|
+
</button>
|
|
25
31
|
<button class="p-3" type="button" @click="insertTable">
|
|
26
32
|
<svg width="14" height="14" class="fill-text-400 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM224 416H64v-96h160v96zm0-160H64v-96h160v96zm224 160H288v-96h160v96zm0-160H288v-96h160v96z"/></svg>
|
|
27
33
|
</button>
|
|
@@ -216,6 +222,94 @@
|
|
|
216
222
|
</div>
|
|
217
223
|
</ContextMenu>
|
|
218
224
|
|
|
225
|
+
<Modal ref="linkModal" width="360" height="400" dismissable="true">
|
|
226
|
+
<template v-slot:head>
|
|
227
|
+
<div class="relative p-5">
|
|
228
|
+
<h3>Add Link</h3>
|
|
229
|
+
<div class="absolute top-0 right-0 p-2">
|
|
230
|
+
<button type="button" class="p-2" @click="$refs.linkModal.close()">
|
|
231
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
232
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
233
|
+
</svg>
|
|
234
|
+
</button>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</template>
|
|
238
|
+
<template v-slot:foot="{ context }">
|
|
239
|
+
<div class="p-5 flex flex-row gap-3">
|
|
240
|
+
<Button variant="secondary" class="w-[100px]" @click="removeLink">Remove</Button>
|
|
241
|
+
<Button class="flex-1" @click="addLink(context)">Add Link</Button>
|
|
242
|
+
</div>
|
|
243
|
+
</template>
|
|
244
|
+
<template #default="{ context }">
|
|
245
|
+
<div class="flex-1 flex flex-col gap-5 p-5">
|
|
246
|
+
<div>
|
|
247
|
+
<label>Text</label>
|
|
248
|
+
<Textbox class="w-full mt-1" v-model="context.text" />
|
|
249
|
+
</div>
|
|
250
|
+
<div>
|
|
251
|
+
<label>Href</label>
|
|
252
|
+
<Textbox class="w-full mt-1" v-model="context.href" />
|
|
253
|
+
</div>
|
|
254
|
+
<div>
|
|
255
|
+
<label>Target</label>
|
|
256
|
+
<Dropdown class="w-[150px] mt-1" v-model="context.target">
|
|
257
|
+
<option value="">_self</option>
|
|
258
|
+
<option value="_blank">_blank</option>
|
|
259
|
+
<option value="_parent">_parent</option>
|
|
260
|
+
<option value="_top">_top</option>
|
|
261
|
+
</Dropdown>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</template>
|
|
265
|
+
</Modal>
|
|
266
|
+
|
|
267
|
+
<Modal ref="imageModal" width="360" height="420" dismissable="true">
|
|
268
|
+
<template v-slot:head>
|
|
269
|
+
<div class="relative p-5">
|
|
270
|
+
<h3>Add Image</h3>
|
|
271
|
+
<div class="absolute top-0 right-0 p-2">
|
|
272
|
+
<button type="button" class="p-2" @click="$refs.imageModal.close()">
|
|
273
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
274
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
275
|
+
</svg>
|
|
276
|
+
</button>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</template>
|
|
280
|
+
<template #foot="{ context }">
|
|
281
|
+
<div class="p-5">
|
|
282
|
+
<Button class="w-full" @click="addImage(context)" :state="!context.src ? -1 : 1">Add Image</Button>
|
|
283
|
+
</div>
|
|
284
|
+
</template>
|
|
285
|
+
<template #default="{ context }">
|
|
286
|
+
<div class="flex-1 flex flex-col gap-5 p-5">
|
|
287
|
+
<div>
|
|
288
|
+
<Image class="min-h-[100px] bg-base-300 rounded-xl" ref="image" :src="context.src" editable="true"
|
|
289
|
+
@click="$refs.image.edit()" @change="(_, file) => context.src = file">
|
|
290
|
+
<template #empty="{ instance }">
|
|
291
|
+
<div class="absolute right-0 top-0 bottom-0 left-0 flex items-center justify-center">
|
|
292
|
+
Click to Add Image...
|
|
293
|
+
</div>
|
|
294
|
+
</template>
|
|
295
|
+
</Image>
|
|
296
|
+
</div>
|
|
297
|
+
<div class="grid grid-cols-2 gap-5">
|
|
298
|
+
<div>
|
|
299
|
+
<label>Width</label>
|
|
300
|
+
<Textbox class="mt-1" v-model="context.width" maxlength="3" />
|
|
301
|
+
</div>
|
|
302
|
+
<div>
|
|
303
|
+
<label>Height</label>
|
|
304
|
+
<Textbox class="mt-1" v-model="context.height" maxlength="3" />
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
<br />
|
|
308
|
+
<br />
|
|
309
|
+
</div>
|
|
310
|
+
</template>
|
|
311
|
+
</Modal>
|
|
312
|
+
|
|
219
313
|
<ComponentSetting :item="item"
|
|
220
314
|
:view-type="viewType"
|
|
221
315
|
:view-types="viewTypes"
|
|
@@ -227,10 +321,16 @@
|
|
|
227
321
|
|
|
228
322
|
<script>
|
|
229
323
|
|
|
324
|
+
import {restoreSelection} from "../utils/selection";
|
|
325
|
+
import {downsizeImage} from "../utils/helpers.mjs";
|
|
326
|
+
import axios from "axios";
|
|
327
|
+
|
|
230
328
|
export default{
|
|
231
329
|
|
|
232
330
|
emits: [ 'change', 'postMessageToIframe' ],
|
|
233
331
|
|
|
332
|
+
inject: [ 'alert', 'postIframe' ],
|
|
333
|
+
|
|
234
334
|
props: {
|
|
235
335
|
|
|
236
336
|
item: {
|
|
@@ -246,6 +346,64 @@ export default{
|
|
|
246
346
|
|
|
247
347
|
methods: {
|
|
248
348
|
|
|
349
|
+
createImage(){
|
|
350
|
+
this.postIframe({ uid:this.item.uid, data: { action: 'saveSelection' } })
|
|
351
|
+
.then(_ => {
|
|
352
|
+
this.$refs.imageModal.open()
|
|
353
|
+
})
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
async addImage(image){
|
|
357
|
+
|
|
358
|
+
this.postIframe({ uid:this.item.uid, data: { action: 'restoreSelection' }})
|
|
359
|
+
.then(_ => {
|
|
360
|
+
|
|
361
|
+
downsizeImage(image.src, image.width ?? 300)
|
|
362
|
+
.then(async (blob) => {
|
|
363
|
+
|
|
364
|
+
const data = new FormData()
|
|
365
|
+
data.append('image', blob)
|
|
366
|
+
|
|
367
|
+
try{
|
|
368
|
+
const res = await axios.post(import.meta.env.VITE_API_HOST + '/import/image',
|
|
369
|
+
data,
|
|
370
|
+
{
|
|
371
|
+
headers: {
|
|
372
|
+
"Content-Type": "multipart/form-data",
|
|
373
|
+
},
|
|
374
|
+
}
|
|
375
|
+
)
|
|
376
|
+
image.url = res.data.url
|
|
377
|
+
|
|
378
|
+
const value = JSON.parse(JSON.stringify(image))
|
|
379
|
+
await this.postIframe({ uid:this.item.uid, data:{ action: 'insertImage', value }})
|
|
380
|
+
}
|
|
381
|
+
catch(e){
|
|
382
|
+
this.alert(e)
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
.finally(_ => {
|
|
386
|
+
this.$refs.imageModal.close()
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
/*const props = {}
|
|
391
|
+
if(this.newImage.width)
|
|
392
|
+
props.width = this.newImage.width
|
|
393
|
+
if(this.newImage.height)
|
|
394
|
+
props.height = this.newImage.height
|
|
395
|
+
|
|
396
|
+
let propHtml = []
|
|
397
|
+
for(let key in props){
|
|
398
|
+
propHtml.push(`${key}='${props[key]}'`)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
document.execCommand("insertHTML", false,
|
|
402
|
+
"<img src=\"" + this.newImage.base64 + "\" " + propHtml.join(' ') + "/>");*/
|
|
403
|
+
|
|
404
|
+
})
|
|
405
|
+
},
|
|
406
|
+
|
|
249
407
|
format(type, value){
|
|
250
408
|
|
|
251
409
|
switch(type){
|
|
@@ -259,6 +417,40 @@ export default{
|
|
|
259
417
|
}
|
|
260
418
|
},
|
|
261
419
|
|
|
420
|
+
insertLink(){
|
|
421
|
+
this.postIframe({
|
|
422
|
+
uid:this.item.uid,
|
|
423
|
+
data: {
|
|
424
|
+
action: 'getSelection'
|
|
425
|
+
}
|
|
426
|
+
})
|
|
427
|
+
.then(res => {
|
|
428
|
+
this.$refs.linkModal.open(res)
|
|
429
|
+
})
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
addLink(link){
|
|
433
|
+
link = JSON.parse(JSON.stringify(link))
|
|
434
|
+
this.postIframe({
|
|
435
|
+
uid:this.item.uid,
|
|
436
|
+
data: {
|
|
437
|
+
action: 'insertLink',
|
|
438
|
+
value: link
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
this.$refs.linkModal.close()
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
removeLink(){
|
|
445
|
+
this.postIframe({
|
|
446
|
+
uid:this.item.uid,
|
|
447
|
+
data: {
|
|
448
|
+
action: 'removeLink'
|
|
449
|
+
}
|
|
450
|
+
})
|
|
451
|
+
this.$refs.linkModal.close()
|
|
452
|
+
},
|
|
453
|
+
|
|
262
454
|
insertTable(){
|
|
263
455
|
this.$emit('postMessageToIframe', this.item.uid, { action:'insertTable' })
|
|
264
456
|
},
|
|
@@ -444,19 +444,6 @@
|
|
|
444
444
|
|
|
445
445
|
</div>
|
|
446
446
|
|
|
447
|
-
<div class="h-[1px] bg-text-50"></div>
|
|
448
|
-
|
|
449
|
-
<div class="flex flex-row items-center gap-4">
|
|
450
|
-
<label class="flex-1 text-text-400">ID</label>
|
|
451
|
-
<Textbox v-model="item.props.id" :maxlength="10" @keyup.enter="apply" class="w-[120px]"/>
|
|
452
|
-
</div>
|
|
453
|
-
|
|
454
|
-
<div v-if="item.uid" class="h-[1px] bg-text-50"></div>
|
|
455
|
-
|
|
456
|
-
<div v-if="item.uid" class="py-6 text-center">
|
|
457
|
-
<small class="text-text-400">uid: {{ item.uid }}</small>
|
|
458
|
-
</div>
|
|
459
|
-
|
|
460
447
|
<br />
|
|
461
448
|
<br />
|
|
462
449
|
|
|
@@ -242,6 +242,7 @@
|
|
|
242
242
|
<option value="75%">75%</option>
|
|
243
243
|
<option value="50%">50%</option>
|
|
244
244
|
</Dropdown>
|
|
245
|
+
|
|
245
246
|
<Textbox :readonly="1" :value="iframeSrc" class="w-full">
|
|
246
247
|
<template #start>
|
|
247
248
|
<button @click="reloadIframe" class="p-3">
|
|
@@ -379,7 +380,7 @@
|
|
|
379
380
|
</template>
|
|
380
381
|
</Modal>
|
|
381
382
|
|
|
382
|
-
<Modal ref="ldjsonModal" width="
|
|
383
|
+
<Modal ref="ldjsonModal" width="600" height="480">
|
|
383
384
|
<template v-slot:head>
|
|
384
385
|
<div class="relative p-5">
|
|
385
386
|
<h3>JSON-LD</h3>
|
|
@@ -395,18 +396,14 @@
|
|
|
395
396
|
<template #foot="{ context }">
|
|
396
397
|
<div class="p-5">
|
|
397
398
|
<Button type="button" class="w-[100px]"
|
|
398
|
-
@click="
|
|
399
|
-
page.ldjson[context.index] = context.code :
|
|
400
|
-
page.ldjson.push(context.code);
|
|
401
|
-
$refs.ldjsonModal.close()
|
|
402
|
-
save()">
|
|
399
|
+
@click="saveLdjson(context)">
|
|
403
400
|
Save
|
|
404
401
|
</Button>
|
|
405
402
|
</div>
|
|
406
403
|
</template>
|
|
407
404
|
<template #default="{ context }">
|
|
408
405
|
<div class="flex-1 p-5">
|
|
409
|
-
<
|
|
406
|
+
<MonacoEditor ref="monacoEditor" v-model="context.code"/>
|
|
410
407
|
</div>
|
|
411
408
|
</template>
|
|
412
409
|
</Modal>
|
|
@@ -511,6 +508,7 @@ export default{
|
|
|
511
508
|
|
|
512
509
|
this.page = page
|
|
513
510
|
this.layouts = layouts
|
|
511
|
+
this.iframeSrc = import.meta.env.VITE_WEB_HOST + '/' + (this.page.path ?? '')
|
|
514
512
|
this.$nextTick(() => this.resize())
|
|
515
513
|
})
|
|
516
514
|
.catch((err) => {
|
|
@@ -532,6 +530,19 @@ export default{
|
|
|
532
530
|
}
|
|
533
531
|
},
|
|
534
532
|
|
|
533
|
+
postIframe(data){
|
|
534
|
+
return new Promise((resolve, reject) => {
|
|
535
|
+
const handleResponse = (e) => {
|
|
536
|
+
window.removeEventListener('message', handleResponse)
|
|
537
|
+
resolve(e.data)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
window.addEventListener('message', handleResponse)
|
|
541
|
+
|
|
542
|
+
this.$refs.iframe.contentWindow.postMessage(data, '*')
|
|
543
|
+
})
|
|
544
|
+
},
|
|
545
|
+
|
|
535
546
|
resize(){
|
|
536
547
|
|
|
537
548
|
const transformOrigin = this.store.viewType === '' ? 'center top' : '0 0'
|
|
@@ -640,11 +651,13 @@ export default{
|
|
|
640
651
|
if(!component.instance)
|
|
641
652
|
component.instance = {}
|
|
642
653
|
|
|
654
|
+
const compUid = '_' + component.uid.substring(0, 4) + ' '
|
|
655
|
+
|
|
643
656
|
Object.assign(component.instance, {
|
|
644
657
|
type: component.type,
|
|
645
658
|
uid: component.uid,
|
|
646
659
|
|
|
647
|
-
class: this.compClasses.map(key => {
|
|
660
|
+
class: compUid + this.compClasses.map(key => {
|
|
648
661
|
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
649
662
|
})
|
|
650
663
|
.filter(_ => _)
|
|
@@ -686,6 +699,7 @@ export default{
|
|
|
686
699
|
this.socketEmit2('page.save', this.page)
|
|
687
700
|
.then(() => {
|
|
688
701
|
if(reload){
|
|
702
|
+
this.iframeSrc = import.meta.env.VITE_WEB_HOST + '/' + (this.page.path ?? '')
|
|
689
703
|
this.reloadIframe()
|
|
690
704
|
}
|
|
691
705
|
})
|
|
@@ -709,6 +723,20 @@ export default{
|
|
|
709
723
|
})
|
|
710
724
|
}, 300),
|
|
711
725
|
|
|
726
|
+
saveLdjson(context){
|
|
727
|
+
const errors = this.$refs.monacoEditor.getErrors()
|
|
728
|
+
if(errors){
|
|
729
|
+
this.alert('JSON is not valid', errors.map(_ => _.message).join("\n"))
|
|
730
|
+
return
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
'index' in context ?
|
|
734
|
+
this.page.ldjson[context.index] = context.code :
|
|
735
|
+
this.page.ldjson.push(context.code);
|
|
736
|
+
this.$refs.ldjsonModal.close()
|
|
737
|
+
this.save()
|
|
738
|
+
},
|
|
739
|
+
|
|
712
740
|
imageSrc(imageUrl){
|
|
713
741
|
return typeof imageUrl === 'string' ? import.meta.env.VITE_IMAGE_HOST + '/' + imageUrl : imageUrl
|
|
714
742
|
},
|
|
@@ -765,6 +793,10 @@ export default{
|
|
|
765
793
|
}
|
|
766
794
|
}
|
|
767
795
|
}
|
|
796
|
+
},
|
|
797
|
+
|
|
798
|
+
getPage(){
|
|
799
|
+
return this.page
|
|
768
800
|
}
|
|
769
801
|
|
|
770
802
|
},
|
|
@@ -848,10 +880,6 @@ export default{
|
|
|
848
880
|
|
|
849
881
|
},
|
|
850
882
|
|
|
851
|
-
iframeSrc(){
|
|
852
|
-
return import.meta.env.VITE_WEB_HOST + '/' + (this.page.path ?? '')
|
|
853
|
-
},
|
|
854
|
-
|
|
855
883
|
layout(){
|
|
856
884
|
if(this.page){
|
|
857
885
|
return this.layouts.find((_) => _.id === parseInt(this.page.layoutId))
|
|
@@ -889,6 +917,7 @@ export default{
|
|
|
889
917
|
data(){
|
|
890
918
|
return {
|
|
891
919
|
iframeStyle: {},
|
|
920
|
+
iframeSrc: '',
|
|
892
921
|
page: null,
|
|
893
922
|
layouts: [],
|
|
894
923
|
tabItems: [
|
|
@@ -1012,14 +1041,14 @@ export default{
|
|
|
1012
1041
|
|
|
1013
1042
|
emits: [ 'close' ],
|
|
1014
1043
|
|
|
1015
|
-
inject: [ 'confirm', 'socket', 'socketEmit2', 'toast' ],
|
|
1044
|
+
inject: [ 'alert', 'confirm', 'socket', 'socketEmit2', 'toast' ],
|
|
1016
1045
|
|
|
1017
1046
|
mounted() {
|
|
1018
1047
|
this.load()
|
|
1019
1048
|
|
|
1020
1049
|
window.addEventListener('message', (event) => {
|
|
1021
1050
|
|
|
1022
|
-
const { uid, type, value } = event.data
|
|
1051
|
+
const { uid, type, value } = event.data ?? {}
|
|
1023
1052
|
|
|
1024
1053
|
let comp
|
|
1025
1054
|
let compType
|
|
@@ -1074,7 +1103,9 @@ export default{
|
|
|
1074
1103
|
return {
|
|
1075
1104
|
imageUrl: this.imageUrl,
|
|
1076
1105
|
imageSrc: this.imageSrc,
|
|
1077
|
-
store: this.store
|
|
1106
|
+
store: this.store,
|
|
1107
|
+
postIframe: this.postIframe,
|
|
1108
|
+
getPage: this.getPage
|
|
1078
1109
|
}
|
|
1079
1110
|
},
|
|
1080
1111
|
|
|
@@ -52,6 +52,8 @@ import groupBy from "lodash/groupBy";
|
|
|
52
52
|
|
|
53
53
|
export default{
|
|
54
54
|
|
|
55
|
+
emits: [ 'save' ],
|
|
56
|
+
|
|
55
57
|
inject: [ 'alert', 'socketEmit2' ],
|
|
56
58
|
|
|
57
59
|
props: {
|
|
@@ -96,7 +98,7 @@ export default{
|
|
|
96
98
|
async create(){
|
|
97
99
|
try{
|
|
98
100
|
const res = await this.socketEmit2('page.create', this.selectedTemplate.page)
|
|
99
|
-
this.$
|
|
101
|
+
this.$emit('save', res)
|
|
100
102
|
this.close()
|
|
101
103
|
}
|
|
102
104
|
catch(err){
|