@tailor-cms/tce-preview-runtime 0.5.5-beta.6 → 1.1.0-beta.5

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.
@@ -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
- "version": "0.5.5-beta.6",
3
+ "description": "Preview content element client side runtime",
4
+ "author": "Studion <info@gostudion.com>",
5
+ "version": "1.1.0-beta.5",
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.1",
10
- "@vueuse/core": "12.5.0",
9
+ "@vitejs/plugin-vue": "5.2.4",
10
+ "@vueuse/core": "13.3.0",
11
11
  "date-fns": "^4.1.0",
12
- "ky": "1.7.4",
13
- "lodash": "^4.17.21",
14
- "sass": "1.84.0",
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.7.3",
18
- "universal-cookie": "^7.2.2",
19
- "vite": "6.1.0",
20
- "vite-plugin-vuetify": "2.1.0",
21
- "vue": "3.5.13",
22
- "vue-tsc": "2.2.0",
23
- "vuetify": "3.7.11"
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.5"
24
24
  },
25
25
  "devDependencies": {
26
+ "@types/lodash-es": "^4.17.12",
26
27
  "@types/stringify-object": "^4.0.5",
27
- "@tailor-cms/eslint-config": "0.0.2"
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
- "build": "vue-tsc --noEmit && vite build",
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,52 @@
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 ky from 'ky';
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 = ky.create({ prefixUrl: VITE_SERVER_RUNTIME_URL });
16
- const wsProtocol = serverRuntimeUrl.protocol === 'http:' ? 'ws:' : 'wss:';
15
+ const api = getApiClient(VITE_SERVER_RUNTIME_URL);
17
16
 
18
- const element = ref<ContentElement>();
17
+ const element = ref<Element>();
19
18
  const userState = ref({});
20
19
 
21
- onMounted(async () => {
22
- const url = new URL(window.location.href);
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 timeout(ms: number) {
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(`content-element/${elementId}`).json();
52
- const { element: elementVal, userState: userStateVal } = res as any;
53
- element.value = elementVal;
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 getElement(elementId);
32
+ return load(id);
60
33
  }
61
34
  }
62
35
 
63
- async function resetElement() {
64
- const id = element.value?.uid;
65
- if (!id) return;
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 function resetState() {
72
- const id = element.value?.uid;
73
- if (!id) return;
74
- const path = `content-element/${id}/reset-state`;
75
- return api.post(path);
76
- }
41
+ onMounted(async () => {
42
+ const elementId = resolveElementId();
43
+ if (!elementId) return;
44
+ await load(elementId);
45
+ const wsBus = initWebSocket(serverRuntimeUrl, elementId);
46
+ wsBus.on('element:update', (v: Element) => (element.value = v));
47
+ wsBus.on('userState:update', (v: any) => (userState.value = v));
48
+ wsBus.on('userContext:change', (v: { index: number }) => load(elementId));
49
+ });
77
50
  </script>
78
51
 
79
52
  <template>
@@ -83,8 +56,8 @@ async function resetState() {
83
56
  :element="element"
84
57
  :user-state="userState"
85
58
  class="mt-14"
86
- @reset-element="resetElement"
87
- @reset-state="resetState"
59
+ @reset-element="element && resetElement(element.uid)"
60
+ @reset-state="element && api.resetState(element.uid)"
88
61
  />
89
62
  </VApp>
90
63
  </template>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div v-show="isLoaded">
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
  }>();
@@ -102,7 +101,7 @@ watch(
102
101
  });
103
102
  state.selectedTab = 1;
104
103
  },
105
- { deep: true },
104
+ { deep: true, immediate: true },
106
105
  );
107
106
 
108
107
  watch(
@@ -115,6 +114,6 @@ watch(
115
114
  });
116
115
  state.selectedTab = 2;
117
116
  },
118
- { deep: true },
117
+ { deep: true, immediate: true },
119
118
  );
120
119
  </script>
@@ -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="props.element"
13
- :is-loaded="true"
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 v-show="isLoaded" class="d-flex flex-grow-1 preview-panel">
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-${isLoaded ? new Date().getTime() : 0}`"
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-${isLoaded ? new Date().getTime() : 0}`"
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<{ isLoaded: Boolean, elementId: string }>();
35
+ defineProps<{ elementId: string }>();
36
36
 
37
37
  const initPanels = () => {
38
38
  previewPanelSplit.value = Split([`#${PANELS.EDIT}`, `#${PANELS.DISPLAY}`], {
@@ -21,7 +21,7 @@ import logoUrl from '../assets/logo-new.svg';
21
21
  import { version } from './../../package.json';
22
22
 
23
23
  interface Props {
24
- isVisible: boolean;
24
+ isVisible?: boolean;
25
25
  logo?: string;
26
26
  color?: string;
27
27
  backgroundColor?: string;
package/vite.config.ts CHANGED
@@ -1,21 +1,18 @@
1
1
  import { defineConfig } from 'vite';
2
- import pick from 'lodash/pick';
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.env;
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
- };