@dcodegroup-au/page-builder 0.0.2 → 0.0.3

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.
@@ -248,12 +248,18 @@ const sites = [
248
248
  </script>
249
249
 
250
250
  <template>
251
- <PageRender :page="page"/>
252
- <PageBuilder :page="page"/>
253
- <div class="flex">
254
- <div class="w-1/4">
255
- left panel
251
+ <div style="margin: auto 200px;">
252
+ <div style="margin: 40px 0">
253
+ <h1 style="margin-bottom: 20px; font-size: 50px;">Page Render</h1>
254
+ <PageRender :page="page"/>
255
+ </div>
256
+ <div style="margin: 40px 0">
257
+ <h1 style="margin-bottom: 20px; font-size: 50px;">Slider Edit</h1>
258
+ <SlideEdit :slide="slide" :sites="sites"/>
259
+ </div>
260
+ <div style="margin: 40px 0">
261
+ <h1 style="margin-bottom: 20px; font-size: 50px;">Page Builder</h1>
262
+ <PageBuilder v-model="page"/>
256
263
  </div>
257
- <SlideEdit :slide="slide" :sites="sites"/>
258
264
  </div>
259
265
  </template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcodegroup-au/page-builder",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/page-builder.es.js"
@@ -12,7 +12,7 @@
12
12
  [multiple],
13
13
  textarea,
14
14
  select {
15
- @apply text-base block w-full rounded-lg border border-gray-300 !border-double placeholder:text-gray-400 focus:border-sky-300 focus:ring focus:ring-sky-200 focus:ring-opacity-50 py-2 px-3 font-normal;
15
+ @apply !text-base block !w-full !rounded-lg !border !border-gray-300 !border-double placeholder:text-gray-400 focus:border-sky-300 focus:ring focus:ring-sky-200 focus:ring-opacity-50 !py-2 !px-3 !font-normal;
16
16
  }
17
17
 
18
18
  .q-editor {
@@ -1,51 +1,64 @@
1
1
  <template>
2
- <div class="flex gap-4">
3
- <div class="flex w-[356px] flex-col gap-2">
4
- <div v-for="(parent, sectionIndex) in page.sections" class="border-b border-gray-200 pb-2">
5
- <div
6
- @click="openStates[sectionIndex] = !openStates[sectionIndex]"
7
- class="flex cursor-pointer items-center justify-between px-2 py-4"
8
- >
2
+ <div>
3
+ <div class="flex gap-4 px-6 overflow-auto">
4
+ <div class="flex w-[356px] flex-col gap-2">
5
+ <div v-for="(parent, sectionIndex) in modelValue.sections" class="border-b border-gray-200 pb-2">
6
+ <div
7
+ @click="openStates[sectionIndex] = !openStates[sectionIndex]"
8
+ class="flex cursor-pointer items-center justify-between px-2 py-4"
9
+ >
9
10
  <span class="text-lg font-semibold text-brand-800">
10
11
  {{ parent.title }}
11
12
  </span>
12
- <div class="relative z-10 flex items-center gap-3">
13
- <div class="cursor-pointer">
14
- <ChevronRight class="h-5 w-5" v-if="!openStates[sectionIndex]" />
15
- <ChevronDown class="h-5 w-5" v-else />
13
+ <div class="relative flex items-center gap-3">
14
+ <div class="cursor-pointer">
15
+ <ChevronRight class="h-5 w-5" v-if="!openStates[sectionIndex]" />
16
+ <ChevronDown class="h-5 w-5" v-else />
17
+ </div>
16
18
  </div>
17
19
  </div>
18
- </div>
19
- <div class="flex flex-col gap-2" v-if="openStates[sectionIndex]">
20
- <template v-for="(component, index) in parent.components">
21
- <div
22
- @click="selectComponent(sectionIndex, component, index)"
23
- class="flex cursor-pointer items-center justify-between rounded-lg py-1 pl-6 pr-2 hover:bg-gray-200"
24
- >
25
- <div class="flex flex-col">
26
- <div class="text-xs text-gray-600">Sub-module</div>
27
- <div class="text-sm font-medium text-gray-900">
28
- {{ component.name }}
20
+ <div class="flex flex-col gap-2" v-if="openStates[sectionIndex]">
21
+ <template v-for="(component, index) in parent.components">
22
+ <div
23
+ @click="selectComponent(sectionIndex, component, index)"
24
+ class="flex cursor-pointer items-center justify-between rounded-lg py-1 pl-6 pr-2 hover:bg-gray-200"
25
+ >
26
+ <div class="flex flex-col">
27
+ <div class="text-xs text-gray-600">Sub-module</div>
28
+ <div class="text-sm font-medium text-gray-900">
29
+ {{ component.name }}
30
+ </div>
31
+ </div>
32
+ <div class="flex items-center justify-between gap-3">
33
+ <ChevronRight class="h-5 w-5" />
29
34
  </div>
30
35
  </div>
31
- <div class="flex items-center justify-between gap-3">
32
- <ChevronRight class="h-5 w-5" />
33
- </div>
34
- </div>
35
- </template>
36
+ </template>
37
+ </div>
36
38
  </div>
37
39
  </div>
40
+ <div class="flex h-full flex-1 flex-col rounded-xl bg-gray-50 px-6 py-5 mb-20">
41
+ <Instructions v-if="!selected" />
42
+ <component
43
+ :is="currentComponent"
44
+ :key="selected?.sectionIndex + selected?.componentIndex"
45
+ :data="selected"
46
+ :sites="sites"
47
+ @update="update"
48
+ ></component>
49
+ </div>
38
50
  </div>
39
- <div class="flex h-full flex-1 flex-col rounded-xl bg-gray-50 px-6 py-5">
40
- <Instructions v-if="!selected" />
41
- <component
42
- :is="currentComponent"
43
- :key="selected?.sectionIndex + selected?.componentIndex"
44
- :data="selected"
45
- :sites="sites"
46
- @update="update"
47
- ></component>
48
- </div>
51
+ <slot>
52
+ <div class="flex justify-between space-x-xsSpace pt-xsSpace gap-4 fixed bottom-0 w-full bg-gray-200 py-2 px-6">
53
+ <a @click="close"
54
+ class="w-[200px] py-[9px] bg-white rounded-full border border-gray-300 shadow-xs text-md font-semibold hover:bg-gray-100 text-gray-700 text-center cursor-pointer">
55
+ Cancel
56
+ </a>
57
+ <a @click.prevent="save"
58
+ class="w-full py-[9px] rounded-full shadow-xs text-md font-semibold text-white bg-brand-600 hover:bg-brand-700 border border-brand-600 text-center cursor-pointer"
59
+ >Save changes</a>
60
+ </div>
61
+ </slot>
49
62
  </div>
50
63
  </template>
51
64
  <script setup>
@@ -56,8 +69,9 @@ import Instructions from "@/components/builders/Instructions.vue";
56
69
  import VSliders from "@/components/builders/VSliders.vue";
57
70
  import VLinks from "@/components/builders/VLinks.vue";
58
71
 
72
+ const emit = defineEmits(["save", "close"]);
59
73
  const props = defineProps({
60
- page: {
74
+ modelValue: {
61
75
  required: true,
62
76
  type: Object,
63
77
  },
@@ -79,9 +93,8 @@ const props = defineProps({
79
93
  });
80
94
 
81
95
  const openStates = ref(JSON.parse(window.localStorage.getItem("pageBuilderOpenStates")));
82
- const sections = ref(props.page?.sections ?? []);
96
+ const sections = ref(props.modelValue?.sections ?? []);
83
97
  let selected = ref(null);
84
- const contentUnchanged = ref(true);
85
98
  const componentMaps = ref({
86
99
  sliders: markRaw(VSliders),
87
100
  links: markRaw(VLinks),
@@ -99,18 +112,20 @@ if (!openStates.value) {
99
112
 
100
113
  const selectComponent = (sectionIndex, component, index) => {
101
114
  selected.value = {
102
- page: props.page,
115
+ page: props.modelValue,
103
116
  component: component,
104
117
  componentIndex: index,
105
118
  sectionIndex: sectionIndex,
106
119
  };
107
- console.log(selected, currentComponent);
108
120
  };
109
121
 
110
- setTimeout(() => {
111
- console.log(sections)
112
- selectComponent(0, sections.value[0].components[1], 0)
113
- })
122
+ const close = () => {
123
+ emit("close", props.modelValue);
124
+ };
125
+
126
+ const save = () => {
127
+ emit("save", props.modelValue);
128
+ };
114
129
 
115
130
  const currentComponent = computed(() => {
116
131
  if (!selected.value?.component?.type) {
@@ -134,10 +149,4 @@ const update = (data) => {
134
149
  // console.error(error);
135
150
  // });
136
151
  };
137
-
138
- watch(
139
- () => sections.value,
140
- () => (contentUnchanged.value = false),
141
- { deep: true },
142
- );
143
152
  </script>
@@ -106,15 +106,17 @@
106
106
  </card>
107
107
  </div>
108
108
  </div>
109
- <div class="flex justify-between space-x-xsSpace pt-xsSpace gap-4 sticky bottom-0 w-full bg-gray-200 py-2 px-6">
110
- <a @click="close"
111
- class="w-[200px] py-[9px] bg-white rounded-full border border-gray-300 shadow-xs text-md font-semibold hover:bg-gray-100 text-gray-700 text-center cursor-pointer">
112
- Cancel
113
- </a>
114
- <a @click.prevent="save"
115
- class="w-full py-[9px] rounded-full shadow-xs text-md font-semibold text-white bg-brand-600 hover:bg-brand-700 border border-brand-600 text-center cursor-pointer"
116
- >Save changes</a>
117
- </div>
109
+ <slot>
110
+ <div class="flex justify-between space-x-xsSpace pt-xsSpace gap-4 sticky bottom-0 w-full bg-gray-200 py-2 px-6">
111
+ <a @click="close"
112
+ class="w-[200px] py-[9px] bg-white rounded-full border border-gray-300 shadow-xs text-md font-semibold hover:bg-gray-100 text-gray-700 text-center cursor-pointer">
113
+ Cancel
114
+ </a>
115
+ <a @click.prevent="save"
116
+ class="w-full py-[9px] rounded-full shadow-xs text-md font-semibold text-white bg-brand-600 hover:bg-brand-700 border border-brand-600 text-center cursor-pointer"
117
+ >Save changes</a>
118
+ </div>
119
+ </slot>
118
120
  </div>
119
121
  </template>
120
122
  <script setup>
@@ -125,6 +127,7 @@ import LinkedTo from "@/components/common/LinkedTo.vue";
125
127
  import InputWrapper from "@/components/common/InputWrapper.vue";
126
128
  import VToggle from "@/components/common/VToggle.vue";
127
129
  import FileUpload from "@/components/common/FileUpload.vue";
130
+ import axios from "axios";
128
131
 
129
132
  const emit = defineEmits(["update"]);
130
133
 
@@ -133,6 +136,14 @@ const props = defineProps({
133
136
  type: Object,
134
137
  required: true,
135
138
  },
139
+ saveEndpoint: {
140
+ type: String,
141
+ required: false,
142
+ },
143
+ cancelEndpoint: {
144
+ type: String,
145
+ required: false,
146
+ },
136
147
  sites: {
137
148
  type: Object,
138
149
  required: true,
@@ -150,10 +161,22 @@ const form = ref({
150
161
 
151
162
  const save = () => {
152
163
  emit("update", form.value);
164
+
165
+ if (props.saveEndpoint) {
166
+ axios.post(props.saveEndpoint, form.value).then(() => {
167
+ if (props.cancelEndpoint) {
168
+ window.location.href = props.cancelEndpoint;
169
+ }
170
+ })
171
+ }
153
172
  };
154
173
 
155
174
  const close = () => {
156
175
  emit("close", form.value);
176
+
177
+ if (props.cancelEndpoint) {
178
+ window.location.href = props.cancelEndpoint;
179
+ }
157
180
  };
158
181
 
159
182
  const descriptionWordCount = computed(() => {
@@ -30,7 +30,7 @@
30
30
  <div class="flex flex-col gap-3">
31
31
  <div class="flex items-center gap-4 px-2 py-1 hover:bg-gray-100 rounded-lg" v-for="(item, index) in dataRef.data">
32
32
  <div class="flex flex-1 cursor-pointer items-center justify-between relative">
33
- <div class="flex flex-1 flex-col" @click="edit(index)">
33
+ <div class="flex flex-1 flex-col" @click="edit(item, index)">
34
34
  <div class="text-xs text-gray-600">
35
35
  Slider #{{ index + 1 }}
36
36
  </div>
@@ -76,12 +76,11 @@ const deleteCallback = (index) => {
76
76
  emit("update", dataRef.value);
77
77
  };
78
78
 
79
- const edit = (index) => {
80
- // window.location.href = route("admin.pages.edit-attribute", {
81
- // page: props.data.pageAttribute.page_id,
82
- // attribute: props.data.pageAttribute.id,
83
- // moduleIndex: props.data.subModuleIndex,
84
- // itemIndex: index,
85
- // });
79
+ const edit = (item, index) => {
80
+ if (item.hasOwnProperty('edit_url')) {
81
+ window.location.href = item.edit_url;
82
+ }
83
+
84
+ window.location.href = `/admin/pages/${props?.data?.page?.id}/sections/${props?.data?.sectionIndex}/components/${props?.data?.componentIndex}/slides/${index}`;
86
85
  };
87
86
  </script>
@@ -1,7 +1,17 @@
1
1
  <template>
2
2
  <div class="file-upload">
3
3
  <input type="hidden" :name="name" :value="valueJson"/>
4
- <div v-if="file.length" class="preview">
4
+ <div v-if="modelValue" class="preview">
5
+ @todo handle upload here
6
+ <span class="file-upload-preview">
7
+ <img
8
+ class="img rounded-lg"
9
+ :src="modelValue"
10
+ title="Image"
11
+ />
12
+ </span>
13
+ </div>
14
+ <div v-else-if="file && file.length" class="preview">
5
15
  <span class="file-upload-preview">
6
16
  <img
7
17
  class="img"
@@ -17,7 +27,7 @@
17
27
  <i class="fal fa-times" @click="deleteFile(file)"></i>
18
28
  </a>
19
29
  </div>
20
- <div class="relative">
30
+ <div class="relative" v-show="!modelValue">
21
31
  <div class="dropzone border border-dashed rounded-lg z-10 h-[200px] w-full cursor-pointer relative"
22
32
  ref="dropzone">
23
33
  </div>
@@ -47,7 +57,7 @@ Dropzone.autoDiscover = false;
47
57
  const props = defineProps({
48
58
  name: {
49
59
  type: String,
50
- required: true,
60
+ required: false,
51
61
  },
52
62
  modelValue: {
53
63
  type: [String, Object],
@@ -55,11 +65,11 @@ const props = defineProps({
55
65
  },
56
66
  submitEndpoint: {
57
67
  type: String,
58
- required: true,
68
+ required: false,
59
69
  },
60
70
  deleteEndpoint: {
61
71
  type: String,
62
- required: true,
72
+ required: false,
63
73
  },
64
74
  formData: {
65
75
  type: Object,
@@ -67,7 +77,7 @@ const props = defineProps({
67
77
  },
68
78
  csrf: {
69
79
  type: String,
70
- required: true,
80
+ required: false,
71
81
  },
72
82
  });
73
83
  const emit = defineEmits(["update:modelValue"]);
@@ -17,25 +17,43 @@
17
17
  </span>
18
18
  <slot />
19
19
  <span class="absolute right-0 -bottom-6 text-sm text-gray-600 font-normal" v-if="limit">
20
- {{value.length}}/{{limit}} characters
20
+ {{ value?.length }}/{{ limit }} characters
21
21
  </span>
22
22
  <span class="absolute left-0 -bottom-6 text-sm text-gray-600 font-normal" v-if="showCount">
23
- Word count: {{value}}
23
+ Word count: {{ value }}
24
24
  </span>
25
25
  </label>
26
26
  </template>
27
27
 
28
- <script setup lang="ts">
29
-
30
- interface Props {
31
- field: string;
32
- labelText?: string;
33
- value?: any;
34
- limit?: number;
35
- showCount?: boolean;
36
- darkTheme?: boolean;
37
- isRequired?: boolean;
38
- }
39
-
40
- const props = defineProps<Props>();
28
+ <script setup>
29
+ const props = defineProps({
30
+ field: {
31
+ type: String,
32
+ required: true,
33
+ },
34
+ labelText: {
35
+ type: String,
36
+ default: "",
37
+ },
38
+ value: {
39
+ type: [String, Number],
40
+ default: "",
41
+ },
42
+ limit: {
43
+ type: Number,
44
+ default: null,
45
+ },
46
+ showCount: {
47
+ type: Boolean,
48
+ default: false,
49
+ },
50
+ darkTheme: {
51
+ type: Boolean,
52
+ default: false,
53
+ },
54
+ isRequired: {
55
+ type: Boolean,
56
+ default: false,
57
+ },
58
+ });
41
59
  </script>
@@ -45,10 +45,8 @@ export default {
45
45
  onMounted(() => {
46
46
  quillInstance = new Quill(editorContainer.value, props.options);
47
47
 
48
- // Set initial content
49
48
  quillInstance.root.innerHTML = props.modelValue;
50
49
 
51
- // Listen for text changes
52
50
  quillInstance.on("text-change", () => {
53
51
  emit("update:modelValue", quillInstance.root.innerHTML);
54
52
  });
@@ -1,22 +1,23 @@
1
1
  export function createSlide(overrides = {}) {
2
2
  return {
3
3
  title: "New slide",
4
+ description: "New description",
4
5
  public: false,
5
6
  featured_image: "",
6
7
  primary_button: {
7
8
  show: false,
8
9
  label: "",
9
10
  type: "site-content",
10
- url: "",
11
- open_in_new_tab: false,
11
+ link_to: '',
12
+ is_new_tab: false,
12
13
  ...(overrides.primary_button || {}),
13
14
  },
14
15
  secondary_button: {
15
16
  show: false,
16
17
  label: "",
17
18
  type: "site-content",
18
- url: "",
19
- open_in_new_tab: false,
19
+ link_to: '',
20
+ is_new_tab: false,
20
21
  ...(overrides.secondary_button || {}),
21
22
  },
22
23
  ...overrides,
@@ -11,7 +11,7 @@
11
11
  ></a>
12
12
  </div>
13
13
  <h3 class="lg:text-[48px] text-[40px] font-semibold text-white mb-3 lg:leading-normal leading-[48px]">{{ slide?.title }}</h3>
14
- <p class="text-lg font-normal text-navy-50">{{ slide?.description }}</p>
14
+ <p class="text-lg font-normal text-navy-50" v-html="slide?.description"></p>
15
15
  <div class="flex gap-3 mt-8 flex-col lg:flex-row">
16
16
  <a class="text-white text-base font-semibold border border-white px-6 py-2 rounded-full hover:bg-navy-800 hover:opacity-60"
17
17
  :href="slide.secondary_button.link_to"
@@ -1,43 +0,0 @@
1
- <script setup>
2
- import { ref } from 'vue'
3
-
4
- defineProps({
5
- msg: String,
6
- })
7
-
8
- const count = ref(0)
9
- </script>
10
-
11
- <template>
12
- <h1>{{ msg }}</h1>
13
-
14
- <div class="card">
15
- <button type="button" @click="count++">count is {{ count }}</button>
16
- <p>
17
- Edit
18
- <code>components/HelloWorld.vue</code> to test HMR
19
- </p>
20
- </div>
21
-
22
- <p>
23
- Check out
24
- <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
25
- >create-vue</a
26
- >, the official Vue + Vite starter
27
- </p>
28
- <p>
29
- Learn more about IDE Support for Vue in the
30
- <a
31
- href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
32
- target="_blank"
33
- >Vue Docs Scaling up Guide</a
34
- >.
35
- </p>
36
- <p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
37
- </template>
38
-
39
- <style scoped>
40
- .read-the-docs {
41
- color: #888;
42
- }
43
- </style>