@tailor-cms/tce-preview-runtime 0.5.5-beta.6 → 1.1.0-beta.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/eslint.config.js +19 -0
- package/package.json +19 -19
- package/src/App.vue +33 -56
- package/src/components/BottomPanel.vue +1 -2
- package/src/components/MainLayout.vue +7 -17
- package/src/components/PreviewPanel.vue +4 -4
- package/src/components/SplashLoader.vue +1 -1
- package/vite.config.ts +3 -6
- package/.eslintrc.cjs +0 -13
package/eslint.config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import tailorConfig from '@tailor-cms/eslint-config';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
...tailorConfig,
|
|
5
|
+
{
|
|
6
|
+
ignores: ['**/components.d.ts', '**/shims-vue.d.ts'],
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
languageOptions: {
|
|
10
|
+
parserOptions: {
|
|
11
|
+
projectService: true,
|
|
12
|
+
tsconfigRootDir: import.meta.dirname,
|
|
13
|
+
ecmaVersion: 'latest',
|
|
14
|
+
sourceType: 'module',
|
|
15
|
+
extraFileExtensions: ['.vue'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
];
|
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-cms/tce-preview-runtime",
|
|
3
|
-
"
|
|
3
|
+
"description": "Preview content element client side runtime",
|
|
4
|
+
"author": "Studion <info@gostudion.com>",
|
|
5
|
+
"version": "1.1.0-beta.1",
|
|
4
6
|
"type": "module",
|
|
5
7
|
"dependencies": {
|
|
6
|
-
"@lukeed/uuid": "^2.0.1",
|
|
7
|
-
"@lukeed/csprng": "^1.0.2",
|
|
8
8
|
"@mdi/font": "7.4.47",
|
|
9
|
-
"@vitejs/plugin-vue": "5.2.
|
|
10
|
-
"@vueuse/core": "
|
|
9
|
+
"@vitejs/plugin-vue": "5.2.4",
|
|
10
|
+
"@vueuse/core": "13.3.0",
|
|
11
11
|
"date-fns": "^4.1.0",
|
|
12
|
-
"ky": "1.
|
|
13
|
-
"lodash": "^4.17.21",
|
|
14
|
-
"sass": "1.
|
|
12
|
+
"ky": "1.8.1",
|
|
13
|
+
"lodash-es": "^4.17.21",
|
|
14
|
+
"sass": "1.89.1",
|
|
15
15
|
"split.js": "1.6.5",
|
|
16
16
|
"stringify-object": "^5.0.0",
|
|
17
|
-
"typescript": "5.
|
|
18
|
-
"
|
|
19
|
-
"vite": "
|
|
20
|
-
"
|
|
21
|
-
"vue": "
|
|
22
|
-
"
|
|
23
|
-
"
|
|
17
|
+
"typescript": "5.8.3",
|
|
18
|
+
"vite": "6.3.5",
|
|
19
|
+
"vite-plugin-vuetify": "2.1.1",
|
|
20
|
+
"vue": "3.5.16",
|
|
21
|
+
"vue-tsc": "2.2.10",
|
|
22
|
+
"vuetify": "3.8.7",
|
|
23
|
+
"@tailor-cms/cek-common": "1.1.0-beta.1"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
+
"@types/lodash-es": "^4.17.12",
|
|
26
27
|
"@types/stringify-object": "^4.0.5",
|
|
27
|
-
"
|
|
28
|
+
"eslint": ">=9.28.0",
|
|
29
|
+
"@tailor-cms/eslint-config": "0.0.3"
|
|
28
30
|
},
|
|
29
31
|
"publishConfig": {
|
|
30
32
|
"access": "public"
|
|
31
33
|
},
|
|
32
34
|
"scripts": {
|
|
33
35
|
"dev": "vite",
|
|
34
|
-
"
|
|
35
|
-
"serve": "vite preview",
|
|
36
|
-
"lint": "eslint --ext .ts,.vue .",
|
|
36
|
+
"lint": "eslint .",
|
|
37
37
|
"lint:fix": "pnpm lint --fix"
|
|
38
38
|
}
|
|
39
39
|
}
|
package/src/App.vue
CHANGED
|
@@ -1,79 +1,56 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
getApiClient,
|
|
4
|
+
initWebSocket,
|
|
5
|
+
resolveElementId,
|
|
6
|
+
} from '@tailor-cms/cek-common';
|
|
2
7
|
import { onMounted, ref } from 'vue';
|
|
3
|
-
import
|
|
4
|
-
import { v4 as uuid } from '@lukeed/uuid/secure';
|
|
8
|
+
import type { Element } from '@tailor-cms/cek-common';
|
|
5
9
|
|
|
6
10
|
import AppBar from './components/AppBar.vue';
|
|
7
11
|
import MainLayout from './components/MainLayout.vue';
|
|
8
12
|
|
|
9
|
-
interface ContentElement {
|
|
10
|
-
id: number;
|
|
11
|
-
uid: string;
|
|
12
|
-
}
|
|
13
13
|
const { VITE_SERVER_RUNTIME_URL } = import.meta.env;
|
|
14
14
|
const serverRuntimeUrl = new URL(VITE_SERVER_RUNTIME_URL);
|
|
15
|
-
const api =
|
|
16
|
-
const wsProtocol = serverRuntimeUrl.protocol === 'http:' ? 'ws:' : 'wss:';
|
|
15
|
+
const api = getApiClient(VITE_SERVER_RUNTIME_URL);
|
|
17
16
|
|
|
18
|
-
const element = ref<
|
|
17
|
+
const element = ref<Element>();
|
|
19
18
|
const userState = ref({});
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const elementId = url.searchParams.get('id');
|
|
24
|
-
if (!elementId) {
|
|
25
|
-
url.searchParams.set('id', uuid());
|
|
26
|
-
window.location.href = url.toString();
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
await getElement(elementId);
|
|
30
|
-
const wsUrl = `${wsProtocol}//${serverRuntimeUrl.host}?id=${elementId}`;
|
|
31
|
-
const ws = new WebSocket(wsUrl);
|
|
32
|
-
ws.addEventListener('message', (message) => {
|
|
33
|
-
const event = JSON.parse(message.data);
|
|
34
|
-
if (elementId && elementId !== event.entityId) return;
|
|
35
|
-
if (event.type === 'userState:update') {
|
|
36
|
-
userState.value = event.payload;
|
|
37
|
-
}
|
|
38
|
-
if (event.type === 'element:update') {
|
|
39
|
-
element.value = event.payload;
|
|
40
|
-
}
|
|
41
|
-
if (event.type === 'userContext:change') getElement(elementId);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
20
|
+
const timeout = (ms: number) =>
|
|
21
|
+
new Promise((resolve) => setTimeout(resolve, ms));
|
|
44
22
|
|
|
45
|
-
function
|
|
46
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function getElement(elementId: string): Promise<any> {
|
|
23
|
+
async function load(id: string): Promise<any> {
|
|
50
24
|
try {
|
|
51
|
-
const res = await api
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
userState.value = userStateVal;
|
|
25
|
+
const res = await api.getElement(id);
|
|
26
|
+
element.value = res.element;
|
|
27
|
+
userState.value = res.userState;
|
|
55
28
|
} catch (error) {
|
|
56
29
|
console.log('Error on element get', error);
|
|
57
30
|
await timeout(2000);
|
|
58
31
|
console.log('Retrying element get...');
|
|
59
|
-
return
|
|
32
|
+
return load(id);
|
|
60
33
|
}
|
|
61
34
|
}
|
|
62
35
|
|
|
63
|
-
async function resetElement() {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
await resetState();
|
|
67
|
-
const path = `content-element/${id}/reset-element`;
|
|
68
|
-
return api.post(path);
|
|
36
|
+
async function resetElement(id: string) {
|
|
37
|
+
await api.resetState(id);
|
|
38
|
+
return api.resetElement(id);
|
|
69
39
|
}
|
|
70
40
|
|
|
71
|
-
async
|
|
72
|
-
const
|
|
73
|
-
if (!
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
41
|
+
onMounted(async () => {
|
|
42
|
+
const elementId = resolveElementId();
|
|
43
|
+
if (!elementId) return;
|
|
44
|
+
await load(elementId);
|
|
45
|
+
const ws = initWebSocket(serverRuntimeUrl, elementId);
|
|
46
|
+
ws.addEventListener('message', (message) => {
|
|
47
|
+
const event = JSON.parse(message.data);
|
|
48
|
+
if (elementId && elementId !== event.entityId) return;
|
|
49
|
+
if (event.type === 'userState:update') userState.value = event.payload;
|
|
50
|
+
if (event.type === 'element:update') element.value = event.payload;
|
|
51
|
+
if (event.type === 'userContext:change') load(elementId);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
77
54
|
</script>
|
|
78
55
|
|
|
79
56
|
<template>
|
|
@@ -83,8 +60,8 @@ async function resetState() {
|
|
|
83
60
|
:element="element"
|
|
84
61
|
:user-state="userState"
|
|
85
62
|
class="mt-14"
|
|
86
|
-
@reset-element="resetElement"
|
|
87
|
-
@reset-state="resetState"
|
|
63
|
+
@reset-element="element && resetElement(element.uid)"
|
|
64
|
+
@reset-state="element && api.resetState(element.uid)"
|
|
88
65
|
/>
|
|
89
66
|
</VApp>
|
|
90
67
|
</template>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div>
|
|
3
3
|
<VTabs v-model="state.selectedTab">
|
|
4
4
|
<VTab :value="1">
|
|
5
5
|
<VChip append-icon="mdi-pen" class="mr-2" color="indigo" size="small">
|
|
@@ -58,7 +58,6 @@ import MutationList from './MutationList.vue';
|
|
|
58
58
|
|
|
59
59
|
defineEmits(['resetElement', 'resetState']);
|
|
60
60
|
const props = defineProps<{
|
|
61
|
-
isLoaded: Boolean;
|
|
62
61
|
element: any;
|
|
63
62
|
userState: any;
|
|
64
63
|
}>();
|
|
@@ -2,16 +2,11 @@
|
|
|
2
2
|
<main :class="{ 'dark-theme': isDark }">
|
|
3
3
|
<SplashLoader :is-visible="!isInitialized" />
|
|
4
4
|
<template v-if="isInitialized">
|
|
5
|
-
<PreviewPanel
|
|
6
|
-
id="panelTop"
|
|
7
|
-
:element-id="element?.uid"
|
|
8
|
-
:is-loaded="true"
|
|
9
|
-
/>
|
|
5
|
+
<PreviewPanel id="panelTop" :element-id="element.uid" />
|
|
10
6
|
<BottomPanel
|
|
11
7
|
id="panelBottom"
|
|
12
|
-
:element="
|
|
13
|
-
:
|
|
14
|
-
:user-state="props.userState"
|
|
8
|
+
:element="element"
|
|
9
|
+
:user-state="userState"
|
|
15
10
|
class="preview-panel-bottom"
|
|
16
11
|
@reset-element="$emit('resetElement')"
|
|
17
12
|
@reset-state="$emit('resetState')"
|
|
@@ -33,19 +28,17 @@ defineEmits(['resetElement', 'resetState']);
|
|
|
33
28
|
const props = defineProps<{ element: any; userState: any }>();
|
|
34
29
|
|
|
35
30
|
const { isDark } = useGlobalState();
|
|
36
|
-
|
|
37
|
-
const isLoaded = ref(false);
|
|
38
31
|
const isMounted = ref(false);
|
|
39
32
|
const isInitialized = computed(() => isMounted.value && props.element?.uid);
|
|
40
33
|
|
|
41
|
-
watch(isInitialized, (val) => {
|
|
42
|
-
if (val) setupPreview();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
34
|
onMounted(() => {
|
|
46
35
|
isMounted.value = true;
|
|
47
36
|
});
|
|
48
37
|
|
|
38
|
+
watch(isInitialized, (val) => {
|
|
39
|
+
if (val) setupPreview();
|
|
40
|
+
});
|
|
41
|
+
|
|
49
42
|
const setupPreview = () => {
|
|
50
43
|
setTimeout(() => {
|
|
51
44
|
Split([`#panelTop`, `#panelBottom`], {
|
|
@@ -53,9 +46,6 @@ const setupPreview = () => {
|
|
|
53
46
|
sizes: [70, 30],
|
|
54
47
|
});
|
|
55
48
|
}, 50);
|
|
56
|
-
setTimeout(() => {
|
|
57
|
-
isLoaded.value = true;
|
|
58
|
-
}, 2000);
|
|
59
49
|
};
|
|
60
50
|
</script>
|
|
61
51
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div class="d-flex flex-grow-1 preview-panel">
|
|
3
3
|
<div :id="PANELS.EDIT" class="d-flex flex-1-1-50">
|
|
4
4
|
<iframe
|
|
5
|
-
:key="`author-${
|
|
5
|
+
:key="`author-${new Date().getTime()}`"
|
|
6
6
|
:src="`${VITE_EDIT_RUNTIME_URL}?id=${elementId}`"
|
|
7
7
|
class="flex-1-1-100"
|
|
8
8
|
frameBorder="0"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
</div>
|
|
13
13
|
<div :id="PANELS.DISPLAY" class="d-flex flex-1-1-50">
|
|
14
14
|
<iframe
|
|
15
|
-
:key="`display-${
|
|
15
|
+
:key="`display-${new Date().getTime()}`"
|
|
16
16
|
:src="`${VITE_DISPLAY_RUNTIME_URL}?id=${elementId}`"
|
|
17
17
|
class="flex-1-1-100"
|
|
18
18
|
frameBorder="0"
|
|
@@ -32,7 +32,7 @@ import { PANELS, useGlobalState } from '../state';
|
|
|
32
32
|
const { VITE_DISPLAY_RUNTIME_URL, VITE_EDIT_RUNTIME_URL } = import.meta.env;
|
|
33
33
|
const { previewPanelSplit } = useGlobalState();
|
|
34
34
|
|
|
35
|
-
defineProps<{
|
|
35
|
+
defineProps<{ elementId: string }>();
|
|
36
36
|
|
|
37
37
|
const initPanels = () => {
|
|
38
38
|
previewPanelSplit.value = Split([`#${PANELS.EDIT}`, `#${PANELS.DISPLAY}`], {
|
package/vite.config.ts
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
import { defineConfig } from 'vite';
|
|
2
|
-
import pick from 'lodash
|
|
2
|
+
import { pick } from 'lodash-es';
|
|
3
3
|
import vue from '@vitejs/plugin-vue';
|
|
4
4
|
import vuetify from 'vite-plugin-vuetify';
|
|
5
5
|
|
|
6
|
-
const env = process
|
|
6
|
+
const { env } = process;
|
|
7
7
|
const config = pick(env, [
|
|
8
8
|
'EDIT_RUNTIME_URL',
|
|
9
9
|
'DISPLAY_RUNTIME_URL',
|
|
10
10
|
'SERVER_RUNTIME_URL',
|
|
11
|
-
'PREVIEW_RUNTIME_URL',
|
|
12
11
|
'PREVIEW_RUNTIME_PORT',
|
|
13
12
|
]);
|
|
14
13
|
|
|
15
14
|
// Expose to Frontend by prefixing with VITE_
|
|
16
|
-
Object.entries(config).forEach(
|
|
17
|
-
([k, v]) => (process.env[`VITE_${k}`] = v as string),
|
|
18
|
-
);
|
|
15
|
+
Object.entries(config).forEach(([k, v]) => (process.env[`VITE_${k}`] = v));
|
|
19
16
|
|
|
20
17
|
// https://vitejs.dev/config/
|
|
21
18
|
export default defineConfig((): any => {
|
package/.eslintrc.cjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
extends: '@tailor-cms/eslint-config',
|
|
4
|
-
parserOptions: {
|
|
5
|
-
tsconfigRootDir: __dirname,
|
|
6
|
-
ecmaVersion: 2022,
|
|
7
|
-
sourceType: 'module',
|
|
8
|
-
parser: '@typescript-eslint/parser',
|
|
9
|
-
project: ['./tsconfig.json', './tsconfig.node.json'],
|
|
10
|
-
extraFileExtensions: ['vue'],
|
|
11
|
-
},
|
|
12
|
-
ignorePatterns: ['**/components.d.ts', '**/shims-vue.d.ts'],
|
|
13
|
-
};
|