@tailor-cms/tce-preview-runtime 0.0.23 → 0.0.28

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-cms/tce-preview-runtime",
3
- "version": "0.0.23",
3
+ "version": "0.0.28",
4
4
  "dependencies": {
5
5
  "@mdi/font": "^7.0.96",
6
6
  "@vitejs/plugin-vue": "4.3.4",
package/src/App.vue CHANGED
@@ -17,13 +17,19 @@ onMounted(async () => {
17
17
  });
18
18
  });
19
19
 
20
+ function timeout(ms: number) {
21
+ return new Promise((resolve) => setTimeout(resolve, ms));
22
+ }
23
+
20
24
  async function getElement() {
21
25
  try {
22
26
  const response = await api('content-element').json();
23
27
  return response || {};
24
28
  } catch (error) {
25
29
  console.log('Error on element get', error);
26
- return { msg: 'Error upon retrieving element state' };
30
+ await timeout(2000);
31
+ console.log('Retrying element get...');
32
+ return getElement();
27
33
  }
28
34
  }
29
35
  </script>
@@ -7,23 +7,28 @@ const { isDark, toggleDark, showEdit, showDisplay, showBothComponents } =
7
7
  </script>
8
8
 
9
9
  <template>
10
- <v-app-bar :color="isDark ? '#29292f' : 'grey-lighten-5'">
10
+ <v-app-bar :color="isDark ? 'grey-darken-4' : 'grey-lighten-4'" elevation="1">
11
11
  <template #prepend>
12
- <v-app-bar-nav-icon class="ml-3">
13
- <v-avatar :color="isDark ? 'transparent' : '#29292f'" size="48">
14
- <img :src="logoUrl" alt="Tailor logo" width="30" />
15
- </v-avatar>
12
+ <v-app-bar-nav-icon class="ml-2">
13
+ <img :src="logoUrl" alt="Tailor logo" width="24" />
16
14
  </v-app-bar-nav-icon>
17
15
  </template>
18
- <v-app-bar-title class="ml-3 font-weight-bold">Dev Kit</v-app-bar-title>
16
+ <v-app-bar-title class="ml-1 font-weight-bold">
17
+ Content Element Kit
18
+ <span class="pl-1 text-body-2 font-weight-bold">0.0.1</span>
19
+ </v-app-bar-title>
19
20
  <v-spacer />
20
- <v-btn-toggle class="mr-4" density="compact" borderless>
21
+ <v-btn-toggle
22
+ :variant="isDark ? 'flat' : 'tonal'"
23
+ class="mr-4"
24
+ density="compact"
25
+ >
21
26
  <v-btn @click="showEdit">
22
27
  <span>Edit</span>
23
28
  <v-icon end>mdi-pencil</v-icon>
24
29
  </v-btn>
25
30
  <v-btn @click="showDisplay">
26
- <span>Preview</span>
31
+ <span>Display</span>
27
32
  <v-icon end>mdi-fullscreen</v-icon>
28
33
  </v-btn>
29
34
  <v-btn @click="showBothComponents">
@@ -31,7 +36,7 @@ const { isDark, toggleDark, showEdit, showDisplay, showBothComponents } =
31
36
  <v-icon end>mdi-math-norm-box</v-icon>
32
37
  </v-btn>
33
38
  </v-btn-toggle>
34
- <v-btn href="https://github.com/tailor-cms/t-xt" icon>
39
+ <v-btn href="https://github.com/tailor-cms/tce-template" icon>
35
40
  <v-icon>mdi-github</v-icon>
36
41
  </v-btn>
37
42
  <v-btn icon @click.prevent="toggleDark()">
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <div v-show="isLoaded">
3
+ <v-tabs density="compact" hide-slider>
4
+ <v-tab>Server state</v-tab>
5
+ </v-tabs>
6
+ <div class="pa-6">
7
+ <JsonEditor
8
+ v-if="isLoaded"
9
+ :main-menu-bar="false"
10
+ :status-bar="false"
11
+ :value="orderKeys(props.element)"
12
+ mode="text"
13
+ />
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import JsonEditor from 'vue3-ts-jsoneditor';
20
+
21
+ const props = defineProps<{ element: any; isLoaded: Boolean }>();
22
+
23
+ const orderKeys = (val: any) => {
24
+ return [
25
+ 'id',
26
+ 'uid',
27
+ 'type',
28
+ 'position',
29
+ 'data',
30
+ 'meta',
31
+ 'refs',
32
+ 'contentId',
33
+ 'contentSignature',
34
+ 'linked',
35
+ 'detached',
36
+ 'createdAt',
37
+ 'updatedAt',
38
+ 'deletedAt',
39
+ ].reduce((acc: any, key: string) => {
40
+ acc[key] = val[key];
41
+ return acc;
42
+ }, {});
43
+ };
44
+ </script>
@@ -1,100 +1,55 @@
1
1
  <script setup lang="ts">
2
2
  import { onMounted, ref } from 'vue';
3
- import JsonEditor from 'vue3-ts-jsoneditor';
4
3
  import Split from 'split.js';
5
4
 
6
- import { PANELS, useGlobalState } from '../state';
7
- import VueSplash from './SplashLoader.vue';
8
-
9
- // TODO: Enforce order
10
- // const SERVER_PROP_ORDER = [
11
- // 'id',
12
- // 'uid',
13
- // 'type',
14
- // 'position',
15
- // 'data',
16
- // 'meta',
17
- // 'refs',
18
- // 'contentId',
19
- // 'contentSignature',
20
- // 'linked',
21
- // 'detached',
22
- // 'createdAt',
23
- // 'updatedAt',
24
- // 'deletedAt',
25
- // ];
5
+ import BottomPanel from './BottomPanel.vue';
6
+ import PreviewPanel from './PreviewPanel.vue';
7
+ import SplashLoader from './SplashLoader.vue';
8
+ import { useGlobalState } from '../state';
26
9
 
27
10
  const props = defineProps<{ element: any }>();
28
11
 
12
+ const { isDark } = useGlobalState();
29
13
  const isLoaded = ref(false);
30
- const editPanel = ref(null);
31
- const displayPanel = ref(null);
32
-
33
- const { isDark, splitJs } = useGlobalState();
34
14
 
35
- const reloadPreview = () => {
36
- setTimeout(() => {
37
- editPanel.value.src = editPanel.value.src;
38
- displayPanel.value.src = displayPanel.value.src;
39
- }, 2000);
40
- };
15
+ const runtimeId = import.meta.env.VITE_RUNTIME_ID;
16
+ const bootRegistry = JSON.parse(
17
+ localStorage.getItem('element-kit-boot') || '{}',
18
+ );
19
+ const isFirstBoot = !bootRegistry[runtimeId];
41
20
 
42
21
  onMounted(() => {
43
- setTimeout(() => {
44
- isLoaded.value = true;
45
- reloadPreview();
46
- // Client/server vertical split
47
- Split([`#panelTop`, `#panelBottom`], {
48
- direction: 'vertical',
49
- sizes: [70, 30],
50
- });
51
- // Component preview split
52
- splitJs.value = Split([`#${PANELS.EDIT}`, `#${PANELS.DISPLAY}`], {
53
- minSize: [0, 0],
54
- });
55
- }, 6000);
22
+ // Client/server vertical split
23
+ Split([`#panelTop`, `#panelBottom`], {
24
+ direction: 'vertical',
25
+ sizes: [70, 30],
26
+ });
27
+ setTimeout(
28
+ () => {
29
+ isLoaded.value = true;
30
+ localStorage.setItem(
31
+ 'element-kit-boot',
32
+ JSON.stringify({
33
+ ...bootRegistry,
34
+ [runtimeId]: true,
35
+ }),
36
+ );
37
+ },
38
+ isFirstBoot ? 17000 : 5000,
39
+ );
56
40
  });
57
41
  </script>
58
42
 
59
43
  <template>
60
44
  <main :class="{ 'dark-theme': isDark }">
61
- <VueSplash v-show="!isLoaded" color="#00bfa5" />
62
- <div v-show="isLoaded" id="panelTop" class="d-flex panel">
63
- <div class="d-flex flex-grow-1">
64
- <iframe
65
- :id="PANELS.EDIT"
66
- ref="editPanel"
67
- frameBorder="0"
68
- sandbox="allow-scripts"
69
- src="http://localhost:8010"
70
- title="Edit component container"
71
- >
72
- </iframe>
73
- <iframe
74
- :id="PANELS.DISPLAY"
75
- ref="displayPanel"
76
- frameBorder="0"
77
- sandbox="allow-scripts"
78
- src="http://localhost:8020"
79
- title="Display component container"
80
- >
81
- </iframe>
82
- </div>
83
- </div>
84
- <div v-show="isLoaded" id="panelBottom" class="panel">
85
- <v-tabs density="compact" hide-slider>
86
- <v-tab>Server state</v-tab>
87
- </v-tabs>
88
- <div class="pa-5">
89
- <JsonEditor
90
- v-if="isLoaded"
91
- :main-menu-bar="false"
92
- :status-bar="false"
93
- :value="props.element"
94
- mode="text"
95
- />
96
- </div>
97
- </div>
45
+ <SplashLoader v-show="!isLoaded" :is-first-boot="isFirstBoot" />
46
+ <PreviewPanel id="panelTop" :is-loaded="isLoaded" />
47
+ <BottomPanel
48
+ id="panelBottom"
49
+ :element="props.element"
50
+ :is-loaded="isLoaded"
51
+ class="preview-panel"
52
+ />
98
53
  </main>
99
54
  </template>
100
55
 
@@ -102,8 +57,9 @@ onMounted(() => {
102
57
  main {
103
58
  height: calc(100vh - var(--nav-height));
104
59
 
105
- .panel {
60
+ .preview-panel {
106
61
  background-color: #eceff1;
62
+ overflow-y: auto;
107
63
  }
108
64
  }
109
65
 
@@ -118,9 +74,9 @@ main {
118
74
  }
119
75
 
120
76
  .gutter.gutter-vertical {
121
- cursor: row-resize !important;
77
+ cursor: row-resize;
122
78
  background-color: #fff;
123
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
79
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
124
80
  }
125
81
 
126
82
  .dark-theme {
@@ -128,10 +84,5 @@ main {
128
84
  .gutter.gutter-vertical {
129
85
  background-color: #333;
130
86
  }
131
-
132
- .jse-theme-dark .cm-content,
133
- .jse-theme-dark .cm-gutters {
134
- background-color: #29292f !important;
135
- }
136
87
  }
137
88
  </style>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div v-show="isLoaded" class="d-flex flex-grow-1 preview-panel">
3
+ <iframe
4
+ :id="PANELS.EDIT"
5
+ ref="editPanel"
6
+ frameBorder="0"
7
+ sandbox="allow-scripts"
8
+ src="http://localhost:8010"
9
+ title="Edit component container"
10
+ >
11
+ </iframe>
12
+ <iframe
13
+ :id="PANELS.DISPLAY"
14
+ ref="displayPanel"
15
+ frameBorder="0"
16
+ sandbox="allow-scripts"
17
+ src="http://localhost:8020"
18
+ title="Display component container"
19
+ >
20
+ </iframe>
21
+ </div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { onMounted, ref, watch } from 'vue';
26
+ import Split from 'split.js';
27
+
28
+ import { PANELS, useGlobalState } from '../state';
29
+
30
+ const props = defineProps<{ isLoaded: Boolean }>();
31
+
32
+ const editPanel = ref(null);
33
+ const displayPanel = ref(null);
34
+ const { previewPanelSplit } = useGlobalState();
35
+
36
+ onMounted(() => {
37
+ previewPanelSplit.value = Split([`#${PANELS.EDIT}`, `#${PANELS.DISPLAY}`], {
38
+ minSize: [0, 0],
39
+ });
40
+ });
41
+
42
+ watch(props.isLoaded, (isLoaded) => {
43
+ if (!isLoaded) return;
44
+ reloadPreview();
45
+ });
46
+
47
+ const reloadPreview = () => {
48
+ /* eslint-disable */
49
+ // @ts-ignore
50
+ editPanel.value.src = editPanel.value.src;
51
+ // @ts-ignore
52
+ displayPanel.value.src = displayPanel.value.src;
53
+ /* eslint-enable */
54
+ };
55
+ </script>
@@ -1,15 +1,17 @@
1
1
  <template>
2
2
  <transition name="fade">
3
- <div
4
- :class="['vue-splash', { 'vue-splash--fixed': fixed }]"
5
- :style="containerStyle"
6
- >
3
+ <div :style="{ backgroundColor }" class="splash-loader">
7
4
  <div>
8
- <div class="vue-splash__anim">
9
- <img :src="logo" :style="imageStyle" alt="Logo" />
5
+ <div class="splash-loader__anim">
6
+ <img :src="logo" alt="Logo" width="88" />
10
7
  </div>
11
- <div class="vue-splash__text text-body-1">
8
+ <div class="splash-loader__text text-body-1">
12
9
  <div>Booting Teaching Element Kit....</div>
10
+ <v-progress-linear
11
+ v-if="isFirstBoot"
12
+ :model-value="progress"
13
+ class="my-3"
14
+ />
13
15
  <div class="font-weight-bold">Alpha preview v0.0.1</div>
14
16
  </div>
15
17
  </div>
@@ -22,6 +24,10 @@ import logoUrl from '../assets/logo.png';
22
24
 
23
25
  export default {
24
26
  props: {
27
+ isFirstBoot: {
28
+ type: Boolean,
29
+ required: true,
30
+ },
25
31
  logo: {
26
32
  type: String,
27
33
  default: logoUrl,
@@ -32,19 +38,23 @@ export default {
32
38
  },
33
39
  backgroundColor: {
34
40
  type: String,
35
- default: '',
36
- },
37
- },
38
- computed: {
39
- imageStyle: () => ({ width: '88px' }),
40
- containerStyle() {
41
- return {
42
- backgroundColor: this.backgroundColor || '#fff',
43
- };
41
+ default: '#fff',
44
42
  },
45
43
  },
46
- created() {
44
+ data: () => ({
45
+ interval: 0,
46
+ progress: 0,
47
+ }),
48
+ mounted() {
47
49
  this.setColor();
50
+ if (!this.isFirstBoot) return;
51
+ this.interval = setInterval(() => {
52
+ this.progress += 1;
53
+ if (this.progress === 100) clearInterval(this.interval);
54
+ }, 160);
55
+ },
56
+ beforeUnmount() {
57
+ clearInterval(this.interval);
48
58
  },
49
59
  methods: {
50
60
  setColor() {
@@ -57,27 +67,16 @@ export default {
57
67
  <style lang="scss" scoped>
58
68
  $splash-color: var(--splash-color);
59
69
 
60
- .vue-splash {
70
+ .splash-loader {
61
71
  flex: 1;
62
72
  width: 100%;
63
73
  height: 100%;
64
74
  display: flex;
65
75
  align-items: center;
66
76
  justify-content: center;
67
-
68
- &--fixed {
69
- top: 0;
70
- left: 0;
71
- right: 0;
72
- bottom: 0;
73
- width: 100%;
74
- height: 100%;
75
- position: fixed;
76
- background-color: white;
77
- }
78
77
  }
79
78
 
80
- .vue-splash__anim {
79
+ .splash-loader__anim {
81
80
  text-align: center;
82
81
  animation: splashAnimation 1.3s infinite;
83
82
 
@@ -86,7 +85,7 @@ $splash-color: var(--splash-color);
86
85
  }
87
86
  }
88
87
 
89
- .vue-splash__text {
88
+ .splash-loader__text {
90
89
  margin-top: 50px;
91
90
  font-size: 1rem;
92
91
  text-align: center;
@@ -14,25 +14,25 @@ export const useGlobalState = createGlobalState(() => {
14
14
 
15
15
  // Control panels
16
16
  const visiblePanels = ref(['EDIT', 'DISPLAY', 'STATE']);
17
- const splitJs = ref();
17
+ const previewPanelSplit = ref();
18
18
  const showEdit = () => {
19
19
  visiblePanels.value = [PANELS.EDIT];
20
- if (splitJs.value) splitJs.value?.setSizes([100, 0]);
20
+ if (previewPanelSplit.value) previewPanelSplit.value?.setSizes([100, 0]);
21
21
  };
22
22
  const showDisplay = () => {
23
23
  visiblePanels.value = [PANELS.DISPLAY];
24
- if (splitJs.value) splitJs.value?.setSizes([0, 100]);
24
+ if (previewPanelSplit.value) previewPanelSplit.value?.setSizes([0, 100]);
25
25
  };
26
26
  const showBothComponents = () => {
27
27
  visiblePanels.value = [PANELS.EDIT, PANELS.DISPLAY];
28
- if (splitJs.value) splitJs.value?.setSizes([50, 50]);
28
+ if (previewPanelSplit.value) previewPanelSplit.value?.setSizes([50, 50]);
29
29
  };
30
30
 
31
31
  return {
32
32
  isDark,
33
33
  toggleDark,
34
34
  visiblePanels,
35
- splitJs,
35
+ previewPanelSplit,
36
36
  showEdit,
37
37
  showDisplay,
38
38
  showBothComponents,