@bagelink/blox 1.5.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.
- package/LICENSE +21 -0
- package/README.md +844 -0
- package/components/base/Button.vue +140 -0
- package/components/base/Container.vue +64 -0
- package/components/base/Image.vue +75 -0
- package/components/base/Spacer.vue +33 -0
- package/components/base/Text.vue +37 -0
- package/components/base/Title.vue +55 -0
- package/components/index.ts +20 -0
- package/config/baseComponents.ts +342 -0
- package/core/communication.ts +140 -0
- package/core/registry.ts +108 -0
- package/core/renderer.ts +217 -0
- package/core/types.ts +148 -0
- package/dist/blox.css +296 -0
- package/dist/components/base/Button.vue.d.ts +26 -0
- package/dist/components/base/Button.vue.d.ts.map +1 -0
- package/dist/components/base/Container.vue.d.ts +37 -0
- package/dist/components/base/Container.vue.d.ts.map +1 -0
- package/dist/components/base/Image.vue.d.ts +26 -0
- package/dist/components/base/Image.vue.d.ts.map +1 -0
- package/dist/components/base/Spacer.vue.d.ts +16 -0
- package/dist/components/base/Spacer.vue.d.ts.map +1 -0
- package/dist/components/base/Text.vue.d.ts +13 -0
- package/dist/components/base/Text.vue.d.ts.map +1 -0
- package/dist/components/base/Title.vue.d.ts +14 -0
- package/dist/components/base/Title.vue.d.ts.map +1 -0
- package/dist/components/index.d.ts +18 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/config/baseComponents.d.ts +39 -0
- package/dist/config/baseComponents.d.ts.map +1 -0
- package/dist/core/communication.d.ts +44 -0
- package/dist/core/communication.d.ts.map +1 -0
- package/dist/core/registry.d.ts +56 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/renderer.d.ts +27 -0
- package/dist/core/renderer.d.ts.map +1 -0
- package/dist/core/types.d.ts +105 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.cjs +1305 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1260 -0
- package/dist/setup.d.ts +24 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/utils/normalizer.d.ts +18 -0
- package/dist/utils/normalizer.d.ts.map +1 -0
- package/dist/utils/styles.d.ts +13 -0
- package/dist/utils/styles.d.ts.map +1 -0
- package/dist/views/ExternalPreview.vue.d.ts +12 -0
- package/dist/views/ExternalPreview.vue.d.ts.map +1 -0
- package/dist/views/RenderPage.vue.d.ts +10 -0
- package/dist/views/RenderPage.vue.d.ts.map +1 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.d.ts.map +1 -0
- package/index.ts +27 -0
- package/package.json +94 -0
- package/setup.ts +56 -0
- package/utils/normalizer.ts +74 -0
- package/utils/styles.ts +228 -0
- package/views/ExternalPreview.vue +420 -0
- package/views/RenderPage.vue +127 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1260 @@
|
|
|
1
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useCssVars, withCtx, withModifiers } from "vue";
|
|
2
|
+
var _hoisted_1$4 = [
|
|
3
|
+
"href",
|
|
4
|
+
"target",
|
|
5
|
+
"rel"
|
|
6
|
+
];
|
|
7
|
+
var Button_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
8
|
+
__name: "Button",
|
|
9
|
+
props: {
|
|
10
|
+
btnTxt: { default: "Click Me" },
|
|
11
|
+
btnUrl: { default: "#" },
|
|
12
|
+
btnTarget: { default: "_self" },
|
|
13
|
+
variant: { default: "primary" },
|
|
14
|
+
size: { default: "md" },
|
|
15
|
+
align: { default: "left" },
|
|
16
|
+
fullWidth: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: false
|
|
19
|
+
},
|
|
20
|
+
isMobile: { type: Boolean }
|
|
21
|
+
},
|
|
22
|
+
setup(__props) {
|
|
23
|
+
const props = __props;
|
|
24
|
+
function handleClick(e) {
|
|
25
|
+
console.log("Button clicked:", props.btnTxt);
|
|
26
|
+
}
|
|
27
|
+
return (_ctx, _cache) => {
|
|
28
|
+
return openBlock(), createElementBlock("div", { class: normalizeClass(`button-wrapper align-${_ctx.align}`) }, [createElementVNode("a", {
|
|
29
|
+
href: _ctx.btnUrl,
|
|
30
|
+
target: _ctx.btnTarget,
|
|
31
|
+
rel: _ctx.btnTarget === "_blank" ? "noopener noreferrer" : void 0,
|
|
32
|
+
class: normalizeClass(["btn", [
|
|
33
|
+
`btn-${_ctx.variant}`,
|
|
34
|
+
`btn-${_ctx.size}`,
|
|
35
|
+
{ "btn-full-width": _ctx.fullWidth }
|
|
36
|
+
]]),
|
|
37
|
+
onClick: handleClick
|
|
38
|
+
}, toDisplayString(_ctx.btnTxt), 11, _hoisted_1$4)], 2);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
var __plugin_vue_export_helper_default = (sfc, props) => {
|
|
43
|
+
const target = sfc.__vccOpts || sfc;
|
|
44
|
+
for (const [key, val] of props) target[key] = val;
|
|
45
|
+
return target;
|
|
46
|
+
};
|
|
47
|
+
var Button_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-04e758bb"]]);
|
|
48
|
+
var Container_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
49
|
+
__name: "Container",
|
|
50
|
+
props: {
|
|
51
|
+
maxWidth: { default: 1200 },
|
|
52
|
+
padding: { default: 20 },
|
|
53
|
+
gap: { default: 16 },
|
|
54
|
+
layout: { default: "vertical" },
|
|
55
|
+
columns: { default: 3 },
|
|
56
|
+
isMobile: { type: Boolean }
|
|
57
|
+
},
|
|
58
|
+
setup(__props) {
|
|
59
|
+
useCssVars((_ctx) => ({ "6936d1aa": _ctx.columns }));
|
|
60
|
+
const props = __props;
|
|
61
|
+
const containerStyle = {
|
|
62
|
+
maxWidth: typeof props.maxWidth === "number" ? `${props.maxWidth}px` : props.maxWidth,
|
|
63
|
+
padding: typeof props.padding === "number" ? `${props.padding}px` : props.padding,
|
|
64
|
+
gap: `${props.gap}px`
|
|
65
|
+
};
|
|
66
|
+
return (_ctx, _cache) => {
|
|
67
|
+
return openBlock(), createElementBlock("div", {
|
|
68
|
+
class: normalizeClass(["container", [`layout-${_ctx.layout}`]]),
|
|
69
|
+
style: containerStyle
|
|
70
|
+
}, [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 2);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}), [["__scopeId", "data-v-144084df"]]);
|
|
74
|
+
var _hoisted_1$3 = { class: "image-wrapper" };
|
|
75
|
+
var _hoisted_2$2 = [
|
|
76
|
+
"href",
|
|
77
|
+
"target",
|
|
78
|
+
"rel"
|
|
79
|
+
];
|
|
80
|
+
var _hoisted_3$2 = ["src", "alt"];
|
|
81
|
+
var _hoisted_4$2 = ["src", "alt"];
|
|
82
|
+
var _hoisted_5$1 = {
|
|
83
|
+
key: 2,
|
|
84
|
+
class: "image-caption"
|
|
85
|
+
};
|
|
86
|
+
var Image_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
87
|
+
__name: "Image",
|
|
88
|
+
props: {
|
|
89
|
+
src: { default: "" },
|
|
90
|
+
alt: { default: "" },
|
|
91
|
+
caption: { default: "" },
|
|
92
|
+
link: { default: "" },
|
|
93
|
+
linkTarget: { default: "_self" },
|
|
94
|
+
objectFit: { default: "cover" },
|
|
95
|
+
aspectRatio: { default: "auto" },
|
|
96
|
+
isMobile: { type: Boolean }
|
|
97
|
+
},
|
|
98
|
+
setup(__props) {
|
|
99
|
+
const props = __props;
|
|
100
|
+
const imageStyle = {
|
|
101
|
+
objectFit: props.objectFit,
|
|
102
|
+
aspectRatio: props.aspectRatio
|
|
103
|
+
};
|
|
104
|
+
return (_ctx, _cache) => {
|
|
105
|
+
return openBlock(), createElementBlock("figure", _hoisted_1$3, [_ctx.link ? (openBlock(), createElementBlock("a", {
|
|
106
|
+
key: 0,
|
|
107
|
+
href: _ctx.link,
|
|
108
|
+
target: _ctx.linkTarget,
|
|
109
|
+
rel: _ctx.linkTarget === "_blank" ? "noopener noreferrer" : void 0,
|
|
110
|
+
class: "image-link"
|
|
111
|
+
}, [createElementVNode("img", {
|
|
112
|
+
src: _ctx.src,
|
|
113
|
+
alt: _ctx.alt,
|
|
114
|
+
style: imageStyle,
|
|
115
|
+
class: "image"
|
|
116
|
+
}, null, 8, _hoisted_3$2)], 8, _hoisted_2$2)) : (openBlock(), createElementBlock("img", {
|
|
117
|
+
key: 1,
|
|
118
|
+
src: _ctx.src,
|
|
119
|
+
alt: _ctx.alt,
|
|
120
|
+
style: imageStyle,
|
|
121
|
+
class: "image"
|
|
122
|
+
}, null, 8, _hoisted_4$2)), _ctx.caption ? (openBlock(), createElementBlock("figcaption", _hoisted_5$1, toDisplayString(_ctx.caption), 1)) : createCommentVNode("", true)]);
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}), [["__scopeId", "data-v-dcfd7570"]]);
|
|
126
|
+
var Spacer_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
127
|
+
__name: "Spacer",
|
|
128
|
+
props: {
|
|
129
|
+
height: { default: 40 },
|
|
130
|
+
heightMobile: { default: void 0 },
|
|
131
|
+
isMobile: { type: Boolean }
|
|
132
|
+
},
|
|
133
|
+
setup(__props) {
|
|
134
|
+
const props = __props;
|
|
135
|
+
function computedHeight() {
|
|
136
|
+
const h = props.isMobile && props.heightMobile ? props.heightMobile : props.height;
|
|
137
|
+
return typeof h === "number" ? `${h}px` : h;
|
|
138
|
+
}
|
|
139
|
+
return (_ctx, _cache) => {
|
|
140
|
+
return openBlock(), createElementBlock("div", {
|
|
141
|
+
class: "spacer",
|
|
142
|
+
style: normalizeStyle({ height: computedHeight() })
|
|
143
|
+
}, null, 4);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}), [["__scopeId", "data-v-73a7e941"]]);
|
|
147
|
+
var Text_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
148
|
+
__name: "Text",
|
|
149
|
+
props: {
|
|
150
|
+
content: { default: "" },
|
|
151
|
+
tag: { default: "div" },
|
|
152
|
+
align: { default: "left" }
|
|
153
|
+
},
|
|
154
|
+
setup(__props) {
|
|
155
|
+
return (_ctx, _cache) => {
|
|
156
|
+
return openBlock(), createBlock(resolveDynamicComponent(_ctx.tag), {
|
|
157
|
+
class: normalizeClass(`text-align-${_ctx.align}`),
|
|
158
|
+
innerHTML: _ctx.content
|
|
159
|
+
}, null, 8, ["class", "innerHTML"]);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}), [["__scopeId", "data-v-a6173468"]]);
|
|
163
|
+
var _hoisted_1$2 = {
|
|
164
|
+
key: 1,
|
|
165
|
+
class: "subtitle"
|
|
166
|
+
};
|
|
167
|
+
var Title_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
168
|
+
__name: "Title",
|
|
169
|
+
props: {
|
|
170
|
+
title: { default: "" },
|
|
171
|
+
subTitle: { default: "" },
|
|
172
|
+
tag: { default: "h2" },
|
|
173
|
+
align: { default: "left" }
|
|
174
|
+
},
|
|
175
|
+
setup(__props) {
|
|
176
|
+
return (_ctx, _cache) => {
|
|
177
|
+
return openBlock(), createElementBlock("div", { class: normalizeClass(`title-wrapper text-align-${_ctx.align}`) }, [_ctx.title ? (openBlock(), createBlock(resolveDynamicComponent(_ctx.tag), {
|
|
178
|
+
key: 0,
|
|
179
|
+
class: "title"
|
|
180
|
+
}, {
|
|
181
|
+
default: withCtx(() => [createTextVNode(toDisplayString(_ctx.title), 1)]),
|
|
182
|
+
_: 1
|
|
183
|
+
})) : createCommentVNode("", true), _ctx.subTitle ? (openBlock(), createElementBlock("p", _hoisted_1$2, toDisplayString(_ctx.subTitle), 1)) : createCommentVNode("", true)], 2);
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}), [["__scopeId", "data-v-ae0634d1"]]);
|
|
187
|
+
const baseComponentConfigs = [
|
|
188
|
+
{
|
|
189
|
+
id: "Text",
|
|
190
|
+
label: "Text",
|
|
191
|
+
icon: "text_fields",
|
|
192
|
+
order: 10,
|
|
193
|
+
component: Text_default,
|
|
194
|
+
content: [{
|
|
195
|
+
type: "richtext",
|
|
196
|
+
key: "content",
|
|
197
|
+
label: "Content",
|
|
198
|
+
defaultValue: "<p>Enter your text here...</p>",
|
|
199
|
+
height: 200
|
|
200
|
+
}],
|
|
201
|
+
settings: [{
|
|
202
|
+
type: "select",
|
|
203
|
+
key: "tag",
|
|
204
|
+
label: "HTML Tag",
|
|
205
|
+
defaultValue: "div",
|
|
206
|
+
options: [
|
|
207
|
+
{
|
|
208
|
+
label: "Div",
|
|
209
|
+
value: "div"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
label: "Paragraph",
|
|
213
|
+
value: "p"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
label: "Span",
|
|
217
|
+
value: "span"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
label: "Article",
|
|
221
|
+
value: "article"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
label: "Section",
|
|
225
|
+
value: "section"
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}, {
|
|
229
|
+
type: "select",
|
|
230
|
+
key: "align",
|
|
231
|
+
label: "Text Alignment",
|
|
232
|
+
defaultValue: "left",
|
|
233
|
+
options: [
|
|
234
|
+
{
|
|
235
|
+
label: "Left",
|
|
236
|
+
value: "left"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
label: "Center",
|
|
240
|
+
value: "center"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
label: "Right",
|
|
244
|
+
value: "right"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
label: "Justify",
|
|
248
|
+
value: "justify"
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}]
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
id: "Title",
|
|
255
|
+
label: "Title",
|
|
256
|
+
icon: "title",
|
|
257
|
+
order: 5,
|
|
258
|
+
component: Title_default,
|
|
259
|
+
content: [{
|
|
260
|
+
type: "text",
|
|
261
|
+
key: "title",
|
|
262
|
+
label: "Title",
|
|
263
|
+
defaultValue: "Your Title Here"
|
|
264
|
+
}, {
|
|
265
|
+
type: "text",
|
|
266
|
+
key: "subtitle",
|
|
267
|
+
label: "Subtitle",
|
|
268
|
+
defaultValue: ""
|
|
269
|
+
}],
|
|
270
|
+
settings: [
|
|
271
|
+
{
|
|
272
|
+
type: "select",
|
|
273
|
+
key: "tag",
|
|
274
|
+
label: "Heading Tag",
|
|
275
|
+
defaultValue: "h2",
|
|
276
|
+
options: [
|
|
277
|
+
{
|
|
278
|
+
label: "H1",
|
|
279
|
+
value: "h1"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
label: "H2",
|
|
283
|
+
value: "h2"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
label: "H3",
|
|
287
|
+
value: "h3"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
label: "H4",
|
|
291
|
+
value: "h4"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
label: "H5",
|
|
295
|
+
value: "h5"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
label: "H6",
|
|
299
|
+
value: "h6"
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
type: "select",
|
|
305
|
+
key: "align",
|
|
306
|
+
label: "Text Alignment",
|
|
307
|
+
defaultValue: "center",
|
|
308
|
+
options: [
|
|
309
|
+
{
|
|
310
|
+
label: "Left",
|
|
311
|
+
value: "left"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
label: "Center",
|
|
315
|
+
value: "center"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
label: "Right",
|
|
319
|
+
value: "right"
|
|
320
|
+
}
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
type: "number",
|
|
325
|
+
key: "size",
|
|
326
|
+
label: "Font Size (px)",
|
|
327
|
+
defaultValue: 32
|
|
328
|
+
}
|
|
329
|
+
]
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
id: "Button",
|
|
333
|
+
label: "Button",
|
|
334
|
+
icon: "smart_button",
|
|
335
|
+
order: 15,
|
|
336
|
+
component: Button_default,
|
|
337
|
+
content: [{
|
|
338
|
+
type: "text",
|
|
339
|
+
key: "btnTxt",
|
|
340
|
+
label: "Button Text",
|
|
341
|
+
defaultValue: "Click Me"
|
|
342
|
+
}, {
|
|
343
|
+
type: "text",
|
|
344
|
+
key: "btnUrl",
|
|
345
|
+
label: "Button URL",
|
|
346
|
+
defaultValue: "#"
|
|
347
|
+
}],
|
|
348
|
+
settings: [
|
|
349
|
+
{
|
|
350
|
+
type: "select",
|
|
351
|
+
key: "variant",
|
|
352
|
+
label: "Button Style",
|
|
353
|
+
defaultValue: "primary",
|
|
354
|
+
options: [
|
|
355
|
+
{
|
|
356
|
+
label: "Primary",
|
|
357
|
+
value: "primary"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
label: "Secondary",
|
|
361
|
+
value: "secondary"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
label: "Outline",
|
|
365
|
+
value: "outline"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
label: "Ghost",
|
|
369
|
+
value: "ghost"
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
type: "select",
|
|
375
|
+
key: "size",
|
|
376
|
+
label: "Size",
|
|
377
|
+
defaultValue: "md",
|
|
378
|
+
options: [
|
|
379
|
+
{
|
|
380
|
+
label: "Small",
|
|
381
|
+
value: "sm"
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
label: "Medium",
|
|
385
|
+
value: "md"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
label: "Large",
|
|
389
|
+
value: "lg"
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
type: "select",
|
|
395
|
+
key: "align",
|
|
396
|
+
label: "Alignment",
|
|
397
|
+
defaultValue: "left",
|
|
398
|
+
options: [
|
|
399
|
+
{
|
|
400
|
+
label: "Left",
|
|
401
|
+
value: "left"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
label: "Center",
|
|
405
|
+
value: "center"
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
label: "Right",
|
|
409
|
+
value: "right"
|
|
410
|
+
}
|
|
411
|
+
]
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
type: "checkbox",
|
|
415
|
+
key: "fullWidth",
|
|
416
|
+
label: "Full Width",
|
|
417
|
+
defaultValue: false
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
type: "select",
|
|
421
|
+
key: "btnTarget",
|
|
422
|
+
label: "Link Target",
|
|
423
|
+
defaultValue: "_self",
|
|
424
|
+
options: [{
|
|
425
|
+
label: "Same Window",
|
|
426
|
+
value: "_self"
|
|
427
|
+
}, {
|
|
428
|
+
label: "New Window",
|
|
429
|
+
value: "_blank"
|
|
430
|
+
}]
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
id: "Image",
|
|
436
|
+
label: "Image",
|
|
437
|
+
icon: "image",
|
|
438
|
+
order: 20,
|
|
439
|
+
component: Image_default,
|
|
440
|
+
content: [{
|
|
441
|
+
type: "upload",
|
|
442
|
+
key: "src",
|
|
443
|
+
label: "Image",
|
|
444
|
+
defaultValue: "",
|
|
445
|
+
height: 200
|
|
446
|
+
}, {
|
|
447
|
+
type: "text",
|
|
448
|
+
key: "alt",
|
|
449
|
+
label: "Alt Text",
|
|
450
|
+
defaultValue: ""
|
|
451
|
+
}],
|
|
452
|
+
settings: [
|
|
453
|
+
{
|
|
454
|
+
type: "select",
|
|
455
|
+
key: "objectFit",
|
|
456
|
+
label: "Object Fit",
|
|
457
|
+
defaultValue: "cover",
|
|
458
|
+
options: [
|
|
459
|
+
{
|
|
460
|
+
label: "Cover",
|
|
461
|
+
value: "cover"
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
label: "Contain",
|
|
465
|
+
value: "contain"
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
label: "Fill",
|
|
469
|
+
value: "fill"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
label: "None",
|
|
473
|
+
value: "none"
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
label: "Scale Down",
|
|
477
|
+
value: "scale-down"
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
type: "number",
|
|
483
|
+
key: "maxWidth",
|
|
484
|
+
label: "Max Width (px)",
|
|
485
|
+
defaultValue: null
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
type: "number",
|
|
489
|
+
key: "height",
|
|
490
|
+
label: "Height (px)",
|
|
491
|
+
defaultValue: null
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
type: "select",
|
|
495
|
+
key: "align",
|
|
496
|
+
label: "Alignment",
|
|
497
|
+
defaultValue: "center",
|
|
498
|
+
options: [
|
|
499
|
+
{
|
|
500
|
+
label: "Left",
|
|
501
|
+
value: "left"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
label: "Center",
|
|
505
|
+
value: "center"
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
label: "Right",
|
|
509
|
+
value: "right"
|
|
510
|
+
}
|
|
511
|
+
]
|
|
512
|
+
}
|
|
513
|
+
]
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
id: "Spacer",
|
|
517
|
+
label: "Spacer",
|
|
518
|
+
icon: "height",
|
|
519
|
+
order: 25,
|
|
520
|
+
component: Spacer_default,
|
|
521
|
+
content: [],
|
|
522
|
+
settings: [{
|
|
523
|
+
type: "number",
|
|
524
|
+
key: "height",
|
|
525
|
+
label: "Height (px)",
|
|
526
|
+
defaultValue: 40
|
|
527
|
+
}]
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
id: "Container",
|
|
531
|
+
label: "Container",
|
|
532
|
+
icon: "view_module",
|
|
533
|
+
order: 30,
|
|
534
|
+
component: Container_default,
|
|
535
|
+
content: [{
|
|
536
|
+
type: "richtext",
|
|
537
|
+
key: "content",
|
|
538
|
+
label: "Content",
|
|
539
|
+
defaultValue: "<p>Container content...</p>",
|
|
540
|
+
height: 200
|
|
541
|
+
}],
|
|
542
|
+
settings: [{
|
|
543
|
+
type: "select",
|
|
544
|
+
key: "maxWidth",
|
|
545
|
+
label: "Max Width",
|
|
546
|
+
defaultValue: "lg",
|
|
547
|
+
options: [
|
|
548
|
+
{
|
|
549
|
+
label: "Small (640px)",
|
|
550
|
+
value: "sm"
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
label: "Medium (768px)",
|
|
554
|
+
value: "md"
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
label: "Large (1024px)",
|
|
558
|
+
value: "lg"
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
label: "Extra Large (1280px)",
|
|
562
|
+
value: "xl"
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
label: "Full Width",
|
|
566
|
+
value: "full"
|
|
567
|
+
}
|
|
568
|
+
]
|
|
569
|
+
}, {
|
|
570
|
+
type: "checkbox",
|
|
571
|
+
key: "centered",
|
|
572
|
+
label: "Center Content",
|
|
573
|
+
defaultValue: true
|
|
574
|
+
}]
|
|
575
|
+
}
|
|
576
|
+
];
|
|
577
|
+
function getBaseComponentConfigs() {
|
|
578
|
+
return baseComponentConfigs;
|
|
579
|
+
}
|
|
580
|
+
function getBaseComponentConfig(id) {
|
|
581
|
+
return baseComponentConfigs.find((config) => config.id === id);
|
|
582
|
+
}
|
|
583
|
+
var CommunicationBridge = class {
|
|
584
|
+
origin;
|
|
585
|
+
targetWindow;
|
|
586
|
+
handlers;
|
|
587
|
+
boundMessageHandler;
|
|
588
|
+
constructor(config) {
|
|
589
|
+
this.origin = config.origin;
|
|
590
|
+
this.targetWindow = config.targetWindow || window.parent;
|
|
591
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
592
|
+
this.boundMessageHandler = this.handleMessage.bind(this);
|
|
593
|
+
window.addEventListener("message", this.boundMessageHandler);
|
|
594
|
+
console.log(`🌉 Communication bridge initialized for origin: ${this.origin}`);
|
|
595
|
+
}
|
|
596
|
+
handleMessage(event) {
|
|
597
|
+
if (this.origin !== "*" && event.origin !== this.origin) {
|
|
598
|
+
console.warn(`⚠️ Rejected message from unauthorized origin: ${event.origin}`);
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const { type, message, data, isMobile } = event.data;
|
|
602
|
+
if (!type) return;
|
|
603
|
+
console.log(`📨 Received message: ${type}`, {
|
|
604
|
+
message,
|
|
605
|
+
data,
|
|
606
|
+
isMobile
|
|
607
|
+
});
|
|
608
|
+
const typeHandlers = this.handlers.get(type);
|
|
609
|
+
if (typeHandlers) typeHandlers.forEach((handler) => {
|
|
610
|
+
try {
|
|
611
|
+
handler({
|
|
612
|
+
type,
|
|
613
|
+
message,
|
|
614
|
+
data,
|
|
615
|
+
isMobile
|
|
616
|
+
});
|
|
617
|
+
} catch (error) {
|
|
618
|
+
console.error(`Error in handler for ${type}:`, error);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
const globalHandlers = this.handlers.get("*");
|
|
622
|
+
if (globalHandlers) globalHandlers.forEach((handler) => {
|
|
623
|
+
try {
|
|
624
|
+
handler({
|
|
625
|
+
type,
|
|
626
|
+
message,
|
|
627
|
+
data,
|
|
628
|
+
isMobile
|
|
629
|
+
});
|
|
630
|
+
} catch (error) {
|
|
631
|
+
console.error("Error in global handler:", error);
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
on(type, handler) {
|
|
636
|
+
if (!this.handlers.has(type)) this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
637
|
+
this.handlers.get(type).add(handler);
|
|
638
|
+
return () => {
|
|
639
|
+
this.off(type, handler);
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
off(type, handler) {
|
|
643
|
+
const typeHandlers = this.handlers.get(type);
|
|
644
|
+
if (typeHandlers) typeHandlers.delete(handler);
|
|
645
|
+
}
|
|
646
|
+
send(type, message, data) {
|
|
647
|
+
const payload = {
|
|
648
|
+
type,
|
|
649
|
+
message,
|
|
650
|
+
data
|
|
651
|
+
};
|
|
652
|
+
this.targetWindow.postMessage(payload, this.origin === "*" ? "*" : this.origin);
|
|
653
|
+
console.log(`📤 Sent message: ${type}`, payload);
|
|
654
|
+
}
|
|
655
|
+
destroy() {
|
|
656
|
+
window.removeEventListener("message", this.boundMessageHandler);
|
|
657
|
+
this.handlers.clear();
|
|
658
|
+
console.log("🧹 Communication bridge destroyed");
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
function createCommunicationBridge(config) {
|
|
662
|
+
return new CommunicationBridge(config);
|
|
663
|
+
}
|
|
664
|
+
function sendMessage(type, message, targetWindow = window.parent, origin = "*") {
|
|
665
|
+
const payload = {
|
|
666
|
+
type,
|
|
667
|
+
message
|
|
668
|
+
};
|
|
669
|
+
targetWindow.postMessage(payload, origin);
|
|
670
|
+
}
|
|
671
|
+
var registry = {};
|
|
672
|
+
function registerComponent(type, component) {
|
|
673
|
+
if (registry[type]) console.warn(`Component "${type}" is already registered. Overwriting...`);
|
|
674
|
+
registry[type] = component;
|
|
675
|
+
console.log(`✅ Registered component: ${type}`);
|
|
676
|
+
}
|
|
677
|
+
function registerComponents(components) {
|
|
678
|
+
Object.entries(components).forEach(([type, component]) => {
|
|
679
|
+
registerComponent(type, component);
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
function getComponent(type) {
|
|
683
|
+
return registry[type];
|
|
684
|
+
}
|
|
685
|
+
function hasComponent(type) {
|
|
686
|
+
return type in registry;
|
|
687
|
+
}
|
|
688
|
+
function getAllComponents() {
|
|
689
|
+
return { ...registry };
|
|
690
|
+
}
|
|
691
|
+
function unregisterComponent(type) {
|
|
692
|
+
delete registry[type];
|
|
693
|
+
console.log(`❌ Unregistered component: ${type}`);
|
|
694
|
+
}
|
|
695
|
+
function clearRegistry() {
|
|
696
|
+
Object.keys(registry).forEach((key) => delete registry[key]);
|
|
697
|
+
console.log("🗑️ Registry cleared");
|
|
698
|
+
}
|
|
699
|
+
function getRegisteredTypes() {
|
|
700
|
+
return Object.keys(registry);
|
|
701
|
+
}
|
|
702
|
+
function createNamespacedRegistry(namespace) {
|
|
703
|
+
const namespacedRegistry = {};
|
|
704
|
+
return {
|
|
705
|
+
register: (type, component) => {
|
|
706
|
+
const key = `${namespace}:${type}`;
|
|
707
|
+
namespacedRegistry[key] = component;
|
|
708
|
+
registry[key] = component;
|
|
709
|
+
},
|
|
710
|
+
get: (type) => {
|
|
711
|
+
return namespacedRegistry[`${namespace}:${type}`];
|
|
712
|
+
},
|
|
713
|
+
getAll: () => ({ ...namespacedRegistry })
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
function generateBlockStyles(data, isMobile = false) {
|
|
717
|
+
const styles = {};
|
|
718
|
+
function toNumber(v) {
|
|
719
|
+
if (v === void 0 || v === null || v === "") return null;
|
|
720
|
+
const n = Number(v);
|
|
721
|
+
return Number.isNaN(n) ? null : n;
|
|
722
|
+
}
|
|
723
|
+
function getValue(desktopKey, mobileKey) {
|
|
724
|
+
if (isMobile && data[mobileKey] !== void 0 && data[mobileKey] !== null) return data[mobileKey];
|
|
725
|
+
return data[desktopKey];
|
|
726
|
+
}
|
|
727
|
+
const mTop = toNumber(getValue("marginTop", "marginTopMobile"));
|
|
728
|
+
const mBottom = toNumber(getValue("marginBottom", "marginBottomMobile"));
|
|
729
|
+
const pad = toNumber(getValue("padding", "paddingMobile"));
|
|
730
|
+
if (mTop !== null) {
|
|
731
|
+
styles["margin-top"] = `${mTop}rem`;
|
|
732
|
+
styles["--margin-top"] = `${mTop}rem`;
|
|
733
|
+
} else styles["--margin-top"] = "0rem";
|
|
734
|
+
if (mBottom !== null) {
|
|
735
|
+
styles["margin-bottom"] = `${mBottom}rem`;
|
|
736
|
+
styles["--margin-bottom"] = `${mBottom}rem`;
|
|
737
|
+
} else styles["--margin-bottom"] = "0rem";
|
|
738
|
+
if (pad !== null) {
|
|
739
|
+
styles.padding = `${pad}rem`;
|
|
740
|
+
styles["--block-padding"] = `${pad}rem`;
|
|
741
|
+
}
|
|
742
|
+
const wDesktop = toNumber(data.width);
|
|
743
|
+
const wMobile = toNumber(data.widthMobile);
|
|
744
|
+
const wPercentDesktop = toNumber(data.widthPercent) || 96;
|
|
745
|
+
const wPercentMobile = toNumber(data.widthPercentMobile) || wPercentDesktop;
|
|
746
|
+
const fullWidthDesktop = data.fullWidth;
|
|
747
|
+
styles["--max-width-desktop"] = wDesktop !== null ? `${wDesktop}px` : "800px";
|
|
748
|
+
styles["--max-width-mobile"] = wMobile !== null ? `${wMobile}px` : wDesktop !== null ? `${wDesktop}px` : "800px";
|
|
749
|
+
styles["--width-percent-desktop"] = `${wPercentDesktop}%`;
|
|
750
|
+
styles["--width-percent-mobile"] = `${wPercentMobile}%`;
|
|
751
|
+
if (!(fullWidthDesktop === true || fullWidthDesktop === "true") && wDesktop !== null) {
|
|
752
|
+
styles["margin-left"] = "auto";
|
|
753
|
+
styles["margin-right"] = "auto";
|
|
754
|
+
}
|
|
755
|
+
const borderW = toNumber(getValue("borderWidth", "borderWidthMobile"));
|
|
756
|
+
if (borderW !== null && borderW > 0) {
|
|
757
|
+
styles["border-width"] = `${borderW}px`;
|
|
758
|
+
styles["border-style"] = getValue("borderStyle", "borderStyleMobile") || "solid";
|
|
759
|
+
const borderColor = getValue("borderColor", "borderColorMobile");
|
|
760
|
+
if (borderColor) styles["border-color"] = borderColor;
|
|
761
|
+
}
|
|
762
|
+
const isCenter = getValue("center", "centerMobile");
|
|
763
|
+
if (isCenter === true || isCenter === "true") styles["text-align"] = "center";
|
|
764
|
+
const borderR = toNumber(getValue("borderRadius", "borderRadiusMobile"));
|
|
765
|
+
if (borderR !== null) styles["border-radius"] = `${borderR}px`;
|
|
766
|
+
const bgColorDesktop = data.backgroundColor;
|
|
767
|
+
const bgColorMobile = data.backgroundColorMobile;
|
|
768
|
+
const textColorDesktop = data.textColor;
|
|
769
|
+
const { textColorMobile } = data;
|
|
770
|
+
if (bgColorDesktop) styles["--bg-color-desktop"] = bgColorDesktop;
|
|
771
|
+
if (bgColorMobile) styles["--bg-color-mobile"] = bgColorMobile;
|
|
772
|
+
if (textColorDesktop) styles["--text-color-desktop"] = textColorDesktop;
|
|
773
|
+
if (textColorMobile) styles["--text-color-mobile"] = textColorMobile;
|
|
774
|
+
const shadowMap = {
|
|
775
|
+
none: "none",
|
|
776
|
+
sm: "0 0 10px 0 rgba(0, 0, 0, 0.05)",
|
|
777
|
+
md: "0 0 20px 0 rgba(0, 0, 0, 0.15)",
|
|
778
|
+
lg: "0 0 30px 0 rgba(0, 0, 0, 0.15)",
|
|
779
|
+
xl: "0 0 40px 0 rgba(0, 0, 0, 0.5)",
|
|
780
|
+
custom: "0 4px 6px -1px rgba(0, 0, 0, 0.15)"
|
|
781
|
+
};
|
|
782
|
+
const shadowType = getValue("shadowType", "shadowTypeMobile");
|
|
783
|
+
if (shadowType && shadowType !== "none") styles["box-shadow"] = shadowMap[shadowType] || shadowMap.md;
|
|
784
|
+
const z = toNumber(getValue("zIndex", "zIndexMobile"));
|
|
785
|
+
if (z !== null && z > 0) {
|
|
786
|
+
styles.position = "relative";
|
|
787
|
+
styles["z-index"] = z.toString();
|
|
788
|
+
}
|
|
789
|
+
if (!isMobile && data.showDesktop === false) styles.display = "none";
|
|
790
|
+
else if (isMobile && data.showMobile === false) styles.display = "none";
|
|
791
|
+
const fontFamilyDesktop = data.fontFamily;
|
|
792
|
+
const { fontFamilyMobile } = data;
|
|
793
|
+
if (isMobile && fontFamilyMobile && fontFamilyMobile.trim() !== "") styles["font-family"] = `"${fontFamilyMobile}", sans-serif`;
|
|
794
|
+
else if (fontFamilyDesktop && fontFamilyDesktop.trim() !== "") styles["font-family"] = `"${fontFamilyDesktop}", sans-serif`;
|
|
795
|
+
if (data.customCSS) try {
|
|
796
|
+
data.customCSS.split(";").filter((rule) => rule.trim()).map((rule) => rule.trim().split(":")).filter((parts) => parts.length === 2).forEach(([property, value]) => {
|
|
797
|
+
const prop = property.trim();
|
|
798
|
+
const val = value.trim();
|
|
799
|
+
if (prop && val) styles[prop] = val;
|
|
800
|
+
});
|
|
801
|
+
} catch (e) {
|
|
802
|
+
console.warn("Invalid custom CSS:", data.customCSS);
|
|
803
|
+
}
|
|
804
|
+
return styles;
|
|
805
|
+
}
|
|
806
|
+
function getResponsiveClasses(data) {
|
|
807
|
+
const classes = ["blox-block", "responsive-colors"];
|
|
808
|
+
const effectiveDesktopFullWidth = Boolean(data.fullWidth);
|
|
809
|
+
const effectiveMobileFullWidth = data.fullWidthMobile !== null ? Boolean(data.fullWidthMobile) : effectiveDesktopFullWidth;
|
|
810
|
+
if (effectiveDesktopFullWidth) classes.push("full-width-desktop");
|
|
811
|
+
if (effectiveMobileFullWidth) classes.push("full-width-mobile");
|
|
812
|
+
return classes;
|
|
813
|
+
}
|
|
814
|
+
function getResponsiveCSS() {
|
|
815
|
+
return `
|
|
816
|
+
/* Blox Responsive System */
|
|
817
|
+
.responsive-colors {
|
|
818
|
+
color: var(--text-color-desktop, inherit);
|
|
819
|
+
background-color: var(--bg-color-desktop, transparent);
|
|
820
|
+
margin-inline: auto;
|
|
821
|
+
max-width: var(--max-width-desktop, 800px);
|
|
822
|
+
width: var(--width-percent-desktop, 96%);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
.responsive-colors.full-width-desktop {
|
|
826
|
+
width: 100% !important;
|
|
827
|
+
max-width: none !important;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
@media (max-width: 910px) {
|
|
831
|
+
.responsive-colors {
|
|
832
|
+
color: var(--text-color-mobile, var(--text-color-desktop, inherit));
|
|
833
|
+
background-color: var(--bg-color-mobile, var(--bg-color-desktop, transparent));
|
|
834
|
+
max-width: var(--max-width-mobile, var(--max-width-desktop, 800px));
|
|
835
|
+
width: var(--width-percent-mobile, var(--width-percent-desktop, 96%));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.responsive-colors.full-width-mobile {
|
|
839
|
+
width: 100% !important;
|
|
840
|
+
max-width: none !important;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
`;
|
|
844
|
+
}
|
|
845
|
+
function injectResponsiveCSS() {
|
|
846
|
+
if (document.getElementById("blox-responsive-css")) return;
|
|
847
|
+
const style = document.createElement("style");
|
|
848
|
+
style.id = "blox-responsive-css";
|
|
849
|
+
style.textContent = getResponsiveCSS();
|
|
850
|
+
document.head.appendChild(style);
|
|
851
|
+
}
|
|
852
|
+
function injectCode(code, target) {
|
|
853
|
+
if (!code) return;
|
|
854
|
+
const element = document.querySelector(target);
|
|
855
|
+
if (element) {
|
|
856
|
+
const div = document.createElement("div");
|
|
857
|
+
div.innerHTML = code;
|
|
858
|
+
element.appendChild(div);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
var loadedFonts = /* @__PURE__ */ new Set();
|
|
862
|
+
function loadGoogleFont(fontName) {
|
|
863
|
+
if (!fontName || loadedFonts.has(fontName)) return Promise.resolve();
|
|
864
|
+
return new Promise((resolve, reject) => {
|
|
865
|
+
const fontUrl = `https://fonts.googleapis.com/css2?family=${fontName.trim().replace(/\s+/g, "+")}:wght@400;500;600;700&display=swap`;
|
|
866
|
+
const linkElement = document.createElement("link");
|
|
867
|
+
linkElement.rel = "stylesheet";
|
|
868
|
+
linkElement.href = fontUrl;
|
|
869
|
+
linkElement.setAttribute("data-font-name", fontName);
|
|
870
|
+
linkElement.onload = () => {
|
|
871
|
+
console.log(`✅ Font loaded: ${fontName}`);
|
|
872
|
+
loadedFonts.add(fontName);
|
|
873
|
+
resolve();
|
|
874
|
+
};
|
|
875
|
+
linkElement.onerror = () => {
|
|
876
|
+
console.error(`❌ Failed to load font: ${fontName}`);
|
|
877
|
+
reject(/* @__PURE__ */ new Error(`Failed to load font: ${fontName}`));
|
|
878
|
+
};
|
|
879
|
+
document.head.appendChild(linkElement);
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
async function loadComponentFonts(components) {
|
|
883
|
+
const fontsToLoad = /* @__PURE__ */ new Set();
|
|
884
|
+
components.forEach((comp) => {
|
|
885
|
+
if (comp.data?.fontFamily) fontsToLoad.add(comp.data.fontFamily);
|
|
886
|
+
if (comp.data?.fontFamilyMobile) fontsToLoad.add(comp.data.fontFamilyMobile);
|
|
887
|
+
});
|
|
888
|
+
await Promise.all(Array.from(fontsToLoad).map((font) => loadGoogleFont(font)));
|
|
889
|
+
}
|
|
890
|
+
function applyGlobalFont(fontName) {
|
|
891
|
+
if (!fontName) return;
|
|
892
|
+
const existingStyle = document.getElementById("blox-global-font");
|
|
893
|
+
if (existingStyle) existingStyle.remove();
|
|
894
|
+
const style = document.createElement("style");
|
|
895
|
+
style.id = "blox-global-font";
|
|
896
|
+
style.textContent = `
|
|
897
|
+
body {
|
|
898
|
+
font-family: "${fontName}", sans-serif;
|
|
899
|
+
}
|
|
900
|
+
.blox-page-wrapper {
|
|
901
|
+
font-family: "${fontName}", sans-serif !important;
|
|
902
|
+
}
|
|
903
|
+
.blox-page-wrapper * {
|
|
904
|
+
font-family: inherit;
|
|
905
|
+
}
|
|
906
|
+
`;
|
|
907
|
+
document.head.appendChild(style);
|
|
908
|
+
loadGoogleFont(fontName);
|
|
909
|
+
}
|
|
910
|
+
function applyPageSettings(pageData) {
|
|
911
|
+
const { pageSettings } = pageData;
|
|
912
|
+
if (!pageSettings) return;
|
|
913
|
+
if (pageSettings.pageLanguage) document.documentElement.lang = pageSettings.pageLanguage;
|
|
914
|
+
if (pageSettings.pageDirection) {
|
|
915
|
+
document.documentElement.dir = pageSettings.pageDirection;
|
|
916
|
+
document.body.dir = pageSettings.pageDirection;
|
|
917
|
+
}
|
|
918
|
+
if (pageSettings.selectedGoogleFont) applyGlobalFont(pageSettings.selectedGoogleFont);
|
|
919
|
+
injectCode(pageSettings.additionalHeadCode, "head");
|
|
920
|
+
injectCode(pageSettings.additionalBodyCode, "body");
|
|
921
|
+
if (pageSettings.customFavicon) {
|
|
922
|
+
let faviconLink = document.querySelector("link[rel=\"icon\"]");
|
|
923
|
+
if (!faviconLink) {
|
|
924
|
+
faviconLink = document.createElement("link");
|
|
925
|
+
faviconLink.rel = "icon";
|
|
926
|
+
document.head.appendChild(faviconLink);
|
|
927
|
+
}
|
|
928
|
+
faviconLink.href = pageSettings.customFavicon;
|
|
929
|
+
}
|
|
930
|
+
applyMetaTags(pageSettings);
|
|
931
|
+
}
|
|
932
|
+
function applyMetaTags(settings) {
|
|
933
|
+
if (settings.customOgImage) updateOrCreateMeta("og:image", settings.customOgImage, "property");
|
|
934
|
+
if (settings.customKeywords) updateOrCreateMeta("keywords", settings.customKeywords);
|
|
935
|
+
if (settings.customRobotsMeta) updateOrCreateMeta("robots", settings.customRobotsMeta);
|
|
936
|
+
}
|
|
937
|
+
function updateOrCreateMeta(name, content, attribute = "name") {
|
|
938
|
+
const selector = `meta[${attribute}="${name}"]`;
|
|
939
|
+
let metaTag = document.querySelector(selector);
|
|
940
|
+
if (!metaTag) {
|
|
941
|
+
metaTag = document.createElement("meta");
|
|
942
|
+
metaTag.setAttribute(attribute, name);
|
|
943
|
+
document.head.appendChild(metaTag);
|
|
944
|
+
}
|
|
945
|
+
metaTag.content = content;
|
|
946
|
+
}
|
|
947
|
+
async function initializePage(pageData) {
|
|
948
|
+
injectResponsiveCSS();
|
|
949
|
+
applyPageSettings(pageData);
|
|
950
|
+
await loadComponentFonts(pageData.components);
|
|
951
|
+
injectCode(pageData.header_code, "head");
|
|
952
|
+
injectCode(pageData.body_code, "body");
|
|
953
|
+
}
|
|
954
|
+
function registerBaseComponents() {
|
|
955
|
+
const componentMap = {};
|
|
956
|
+
baseComponentConfigs.forEach((config) => {
|
|
957
|
+
componentMap[config.id] = config.component;
|
|
958
|
+
});
|
|
959
|
+
registerComponents(componentMap);
|
|
960
|
+
console.log("✅ Registered base components:", Object.keys(componentMap));
|
|
961
|
+
}
|
|
962
|
+
function getAllComponentConfigs(customConfigs = []) {
|
|
963
|
+
return [...baseComponentConfigs, ...customConfigs];
|
|
964
|
+
}
|
|
965
|
+
function normalizeComponentData(data) {
|
|
966
|
+
const normalized = {};
|
|
967
|
+
const stringFields = [
|
|
968
|
+
"title",
|
|
969
|
+
"subTitle",
|
|
970
|
+
"btnTxt",
|
|
971
|
+
"tag",
|
|
972
|
+
"customId",
|
|
973
|
+
"height",
|
|
974
|
+
"url",
|
|
975
|
+
"href"
|
|
976
|
+
];
|
|
977
|
+
for (const [key, value] of Object.entries(data)) if (typeof value === "string") if (value === "true") normalized[key] = true;
|
|
978
|
+
else if (value === "false") normalized[key] = false;
|
|
979
|
+
else if (!Number.isNaN(Number(value)) && value !== "" && !stringFields.includes(key)) normalized[key] = Number(value);
|
|
980
|
+
else normalized[key] = value;
|
|
981
|
+
else normalized[key] = value;
|
|
982
|
+
if (!normalized.items) normalized.items = [];
|
|
983
|
+
if (normalized.height !== void 0 && typeof normalized.height === "number") normalized.height = String(normalized.height);
|
|
984
|
+
if (normalized.height === "auto") delete normalized.height;
|
|
985
|
+
return normalized;
|
|
986
|
+
}
|
|
987
|
+
function deepClone(obj) {
|
|
988
|
+
return JSON.parse(JSON.stringify(obj));
|
|
989
|
+
}
|
|
990
|
+
function deepMerge(target, source) {
|
|
991
|
+
const result = { ...target };
|
|
992
|
+
for (const key in source) if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) result[key] = deepMerge(result[key] || {}, source[key]);
|
|
993
|
+
else result[key] = source[key];
|
|
994
|
+
return result;
|
|
995
|
+
}
|
|
996
|
+
var _hoisted_1$1 = { class: "blox-page-wrapper" };
|
|
997
|
+
var _hoisted_2$1 = {
|
|
998
|
+
key: 0,
|
|
999
|
+
class: "blox-loading"
|
|
1000
|
+
};
|
|
1001
|
+
var _hoisted_3$1 = {
|
|
1002
|
+
key: 1,
|
|
1003
|
+
class: "blox-empty-state"
|
|
1004
|
+
};
|
|
1005
|
+
var _hoisted_4$1 = {
|
|
1006
|
+
key: 2,
|
|
1007
|
+
class: "blox-empty-preview"
|
|
1008
|
+
};
|
|
1009
|
+
var _hoisted_5 = [
|
|
1010
|
+
"data-block-id",
|
|
1011
|
+
"onClick",
|
|
1012
|
+
"onMouseenter",
|
|
1013
|
+
"onFocus"
|
|
1014
|
+
];
|
|
1015
|
+
var _hoisted_6 = {
|
|
1016
|
+
key: 0,
|
|
1017
|
+
class: "blox-block-label"
|
|
1018
|
+
};
|
|
1019
|
+
var _hoisted_7 = { key: 0 };
|
|
1020
|
+
var _hoisted_8 = ["id"];
|
|
1021
|
+
var _hoisted_9 = {
|
|
1022
|
+
key: 1,
|
|
1023
|
+
class: "blox-missing-component"
|
|
1024
|
+
};
|
|
1025
|
+
var _hoisted_10 = ["onClick"];
|
|
1026
|
+
var ExternalPreview_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
1027
|
+
__name: "ExternalPreview",
|
|
1028
|
+
props: {
|
|
1029
|
+
origin: { default: "*" },
|
|
1030
|
+
initialPageData: {},
|
|
1031
|
+
componentConfigs: { default: () => [] }
|
|
1032
|
+
},
|
|
1033
|
+
setup(__props) {
|
|
1034
|
+
const props = __props;
|
|
1035
|
+
const components = ref([]);
|
|
1036
|
+
const highlightID = ref("");
|
|
1037
|
+
const selectedID = ref("");
|
|
1038
|
+
const isMobile = ref(false);
|
|
1039
|
+
const previewMode = ref(false);
|
|
1040
|
+
const linksDisabled = ref(false);
|
|
1041
|
+
const loading = ref(true);
|
|
1042
|
+
const updateCounter = ref(0);
|
|
1043
|
+
let bridge = null;
|
|
1044
|
+
const registeredComponents = getAllComponents();
|
|
1045
|
+
const getBlockStyles = computed(() => {
|
|
1046
|
+
updateCounter.value;
|
|
1047
|
+
return (data, mobile = false) => generateBlockStyles(data, mobile);
|
|
1048
|
+
});
|
|
1049
|
+
function setFocus(id, emit = false) {
|
|
1050
|
+
selectedID.value = id;
|
|
1051
|
+
highlightID.value = id;
|
|
1052
|
+
document.querySelector(`[data-block-id="${id}"]`)?.scrollIntoView({
|
|
1053
|
+
behavior: "smooth",
|
|
1054
|
+
block: "center"
|
|
1055
|
+
});
|
|
1056
|
+
if (emit && bridge) bridge.send("focus", id);
|
|
1057
|
+
}
|
|
1058
|
+
function setHighlight(id, emit = false) {
|
|
1059
|
+
highlightID.value = id;
|
|
1060
|
+
if (emit && bridge) bridge.send("highlight", id);
|
|
1061
|
+
}
|
|
1062
|
+
function keyboardHandler(event) {
|
|
1063
|
+
if (previewMode.value) return;
|
|
1064
|
+
if (event.key === "ArrowDown") {
|
|
1065
|
+
const next = components.value.findIndex((comp) => comp.id === highlightID.value) + 1;
|
|
1066
|
+
if (next < components.value.length) setFocus(components.value[next].id, true);
|
|
1067
|
+
} else if (event.key === "ArrowUp") {
|
|
1068
|
+
const prev = components.value.findIndex((comp) => comp.id === highlightID.value) - 1;
|
|
1069
|
+
if (prev >= 0) setFocus(components.value[prev].id, true);
|
|
1070
|
+
} else if (event.key === "Enter") {
|
|
1071
|
+
if (bridge) bridge.send("focus", highlightID.value);
|
|
1072
|
+
} else if (event.key === "Escape") {
|
|
1073
|
+
setHighlight("");
|
|
1074
|
+
selectedID.value = "";
|
|
1075
|
+
} else if (event.key === "Delete") {
|
|
1076
|
+
if (bridge) bridge.send("delete", highlightID.value);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function clickHandler(event) {
|
|
1080
|
+
if (!linksDisabled.value) return;
|
|
1081
|
+
let element = event.target;
|
|
1082
|
+
while (element) {
|
|
1083
|
+
if (element.tagName === "A" && element.getAttribute("href")) if (!(element.classList.contains("btn") || element.classList.contains("button") || element.getAttribute("role") === "button")) {
|
|
1084
|
+
event.preventDefault();
|
|
1085
|
+
event.stopPropagation();
|
|
1086
|
+
return false;
|
|
1087
|
+
} else {
|
|
1088
|
+
event.preventDefault();
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
element = element.parentElement;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function setupBridge() {
|
|
1095
|
+
bridge = createCommunicationBridge({
|
|
1096
|
+
origin: props.origin,
|
|
1097
|
+
targetWindow: window.parent
|
|
1098
|
+
});
|
|
1099
|
+
bridge.on("update", ({ message, data, isMobile: mobile }) => {
|
|
1100
|
+
const componentData = message?.data || data;
|
|
1101
|
+
const mobileMode = message?.isMobile !== void 0 ? message.isMobile : mobile;
|
|
1102
|
+
if (componentData) {
|
|
1103
|
+
components.value = [...componentData];
|
|
1104
|
+
updateCounter.value++;
|
|
1105
|
+
console.log("📦 Updated components:", components.value.length);
|
|
1106
|
+
}
|
|
1107
|
+
if (mobileMode !== void 0) {
|
|
1108
|
+
isMobile.value = mobileMode;
|
|
1109
|
+
console.log("📱 Mobile mode:", mobileMode);
|
|
1110
|
+
}
|
|
1111
|
+
loading.value = false;
|
|
1112
|
+
});
|
|
1113
|
+
bridge.on("highlight", ({ message }) => {
|
|
1114
|
+
setHighlight(message);
|
|
1115
|
+
});
|
|
1116
|
+
bridge.on("focus", ({ message }) => {
|
|
1117
|
+
setFocus(message);
|
|
1118
|
+
});
|
|
1119
|
+
bridge.on("preview", ({ message }) => {
|
|
1120
|
+
previewMode.value = message;
|
|
1121
|
+
if (previewMode.value) {
|
|
1122
|
+
document.body.classList.add("blox-preview-mode");
|
|
1123
|
+
document.body.classList.remove("blox-edit-mode");
|
|
1124
|
+
} else {
|
|
1125
|
+
document.body.classList.remove("blox-preview-mode");
|
|
1126
|
+
document.body.classList.add("blox-edit-mode");
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
bridge.on("disableLinks", ({ message }) => {
|
|
1130
|
+
linksDisabled.value = message;
|
|
1131
|
+
});
|
|
1132
|
+
const registeredTypes = Object.keys(registeredComponents);
|
|
1133
|
+
const configsToSend = props.componentConfigs.map((config) => ({
|
|
1134
|
+
id: config.id,
|
|
1135
|
+
label: config.label,
|
|
1136
|
+
icon: config.icon,
|
|
1137
|
+
img: config.img,
|
|
1138
|
+
order: config.order || 999,
|
|
1139
|
+
content: config.content || [],
|
|
1140
|
+
settings: config.settings || []
|
|
1141
|
+
}));
|
|
1142
|
+
bridge.send("ready", {
|
|
1143
|
+
registeredTypes,
|
|
1144
|
+
componentConfigs: configsToSend
|
|
1145
|
+
});
|
|
1146
|
+
console.log("📤 Sent component configurations:", configsToSend);
|
|
1147
|
+
}
|
|
1148
|
+
onMounted(async () => {
|
|
1149
|
+
console.log("🚀 External Preview mounted");
|
|
1150
|
+
console.log("📦 Registered components:", Object.keys(registeredComponents));
|
|
1151
|
+
setupBridge();
|
|
1152
|
+
window.addEventListener("keydown", keyboardHandler);
|
|
1153
|
+
document.addEventListener("click", clickHandler, true);
|
|
1154
|
+
document.body.classList.add("blox-edit-mode");
|
|
1155
|
+
if (props.initialPageData) {
|
|
1156
|
+
await initializePage(props.initialPageData);
|
|
1157
|
+
components.value = props.initialPageData.components;
|
|
1158
|
+
loading.value = false;
|
|
1159
|
+
}
|
|
1160
|
+
});
|
|
1161
|
+
onUnmounted(() => {
|
|
1162
|
+
if (bridge) bridge.destroy();
|
|
1163
|
+
window.removeEventListener("keydown", keyboardHandler);
|
|
1164
|
+
document.removeEventListener("click", clickHandler, true);
|
|
1165
|
+
document.body.classList.remove("blox-preview-mode", "blox-edit-mode");
|
|
1166
|
+
});
|
|
1167
|
+
return (_ctx, _cache) => {
|
|
1168
|
+
return openBlock(), createElementBlock("div", _hoisted_1$1, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_2$1, _cache[0] || (_cache[0] = [createElementVNode("p", null, "Loading preview...", -1)]))) : !components.value.length && !previewMode.value ? (openBlock(), createElementBlock("div", _hoisted_3$1, _cache[1] || (_cache[1] = [createElementVNode("p", null, "No blocks yet. Add a block from the editor to get started!", -1)]))) : !components.value.length && previewMode.value ? (openBlock(), createElementBlock("div", _hoisted_4$1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(components.value, (comp) => {
|
|
1169
|
+
return openBlock(), createElementBlock("div", {
|
|
1170
|
+
key: comp.id,
|
|
1171
|
+
class: normalizeClass(["blox-block-wrapper", {
|
|
1172
|
+
"blox-highlight": !previewMode.value && highlightID.value === comp.id,
|
|
1173
|
+
"blox-selected": !previewMode.value && selectedID.value === comp.id
|
|
1174
|
+
}]),
|
|
1175
|
+
"data-block-id": comp.id,
|
|
1176
|
+
onClick: ($event) => !previewMode.value ? setFocus(comp.id, true) : null,
|
|
1177
|
+
onMouseenter: ($event) => !previewMode.value ? setHighlight(comp.id, true) : null,
|
|
1178
|
+
onFocus: ($event) => !previewMode.value ? setHighlight(comp.id, true) : null
|
|
1179
|
+
}, [
|
|
1180
|
+
!previewMode.value ? (openBlock(), createElementBlock("p", _hoisted_6, [createTextVNode(toDisplayString(comp.type) + " ", 1), comp.data?.title ? (openBlock(), createElementBlock("span", _hoisted_7, " | " + toDisplayString(comp.data.title), 1)) : createCommentVNode("", true)])) : createCommentVNode("", true),
|
|
1181
|
+
(openBlock(), createElementBlock("div", {
|
|
1182
|
+
id: comp.data.customId,
|
|
1183
|
+
key: `${comp.id}-${updateCounter.value}`,
|
|
1184
|
+
style: normalizeStyle(getBlockStyles.value(comp.data, isMobile.value)),
|
|
1185
|
+
class: normalizeClass(unref(getResponsiveClasses)(comp.data))
|
|
1186
|
+
}, [unref(registeredComponents)[comp.type] ? (openBlock(), createBlock(resolveDynamicComponent(unref(registeredComponents)[comp.type]), mergeProps({
|
|
1187
|
+
key: 0,
|
|
1188
|
+
ref_for: true
|
|
1189
|
+
}, {
|
|
1190
|
+
...unref(normalizeComponentData)(comp.data),
|
|
1191
|
+
isMobile: isMobile.value
|
|
1192
|
+
}), null, 16)) : (openBlock(), createElementBlock("div", _hoisted_9, " ⚠️ Component not registered: " + toDisplayString(comp.type), 1))], 14, _hoisted_8)),
|
|
1193
|
+
!previewMode.value ? (openBlock(), createElementBlock("div", {
|
|
1194
|
+
key: 1,
|
|
1195
|
+
class: "blox-block-overlay",
|
|
1196
|
+
onClick: withModifiers(($event) => setFocus(comp.id, true), ["self"])
|
|
1197
|
+
}, null, 8, _hoisted_10)) : createCommentVNode("", true)
|
|
1198
|
+
], 42, _hoisted_5);
|
|
1199
|
+
}), 128))]);
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
}), [["__scopeId", "data-v-8110f424"]]);
|
|
1203
|
+
var _hoisted_1 = { class: "blox-page-wrapper" };
|
|
1204
|
+
var _hoisted_2 = {
|
|
1205
|
+
key: 0,
|
|
1206
|
+
class: "blox-loading"
|
|
1207
|
+
};
|
|
1208
|
+
var _hoisted_3 = ["id"];
|
|
1209
|
+
var _hoisted_4 = {
|
|
1210
|
+
key: 1,
|
|
1211
|
+
class: "blox-missing-component"
|
|
1212
|
+
};
|
|
1213
|
+
var RenderPage_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
1214
|
+
__name: "RenderPage",
|
|
1215
|
+
props: {
|
|
1216
|
+
pageData: {},
|
|
1217
|
+
mobileBreakpoint: { default: 910 }
|
|
1218
|
+
},
|
|
1219
|
+
setup(__props) {
|
|
1220
|
+
const props = __props;
|
|
1221
|
+
const isMobile = ref(false);
|
|
1222
|
+
const loading = ref(true);
|
|
1223
|
+
const updateCounter = ref(0);
|
|
1224
|
+
const registeredComponents = getAllComponents();
|
|
1225
|
+
const getBlockStyles = computed(() => {
|
|
1226
|
+
updateCounter.value;
|
|
1227
|
+
return (data, mobile = false) => generateBlockStyles(data, mobile);
|
|
1228
|
+
});
|
|
1229
|
+
function updateMobileStatus() {
|
|
1230
|
+
const wasMobile = isMobile.value;
|
|
1231
|
+
isMobile.value = window.innerWidth <= props.mobileBreakpoint;
|
|
1232
|
+
if (wasMobile !== isMobile.value) updateCounter.value++;
|
|
1233
|
+
}
|
|
1234
|
+
onMounted(async () => {
|
|
1235
|
+
console.log("🚀 Render Page mounted");
|
|
1236
|
+
console.log("📦 Registered components:", Object.keys(registeredComponents));
|
|
1237
|
+
await initializePage(props.pageData);
|
|
1238
|
+
updateMobileStatus();
|
|
1239
|
+
window.addEventListener("resize", updateMobileStatus);
|
|
1240
|
+
loading.value = false;
|
|
1241
|
+
});
|
|
1242
|
+
return (_ctx, _cache) => {
|
|
1243
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_2, _cache[0] || (_cache[0] = [createElementVNode("p", null, "Loading...", -1)]))) : (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(_ctx.pageData.components, (comp) => {
|
|
1244
|
+
return openBlock(), createElementBlock("div", {
|
|
1245
|
+
key: `${comp.id}-${updateCounter.value}`,
|
|
1246
|
+
id: comp.data.customId,
|
|
1247
|
+
style: normalizeStyle(getBlockStyles.value(comp.data, isMobile.value)),
|
|
1248
|
+
class: normalizeClass(unref(getResponsiveClasses)(comp.data))
|
|
1249
|
+
}, [unref(registeredComponents)[comp.type] ? (openBlock(), createBlock(resolveDynamicComponent(unref(registeredComponents)[comp.type]), mergeProps({
|
|
1250
|
+
key: 0,
|
|
1251
|
+
ref_for: true
|
|
1252
|
+
}, {
|
|
1253
|
+
...unref(normalizeComponentData)(comp.data),
|
|
1254
|
+
isMobile: isMobile.value
|
|
1255
|
+
}), null, 16)) : (openBlock(), createElementBlock("div", _hoisted_4, " Component not found: " + toDisplayString(comp.type), 1))], 14, _hoisted_3);
|
|
1256
|
+
}), 128))]);
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
}), [["__scopeId", "data-v-1a340b1b"]]);
|
|
1260
|
+
export { Button_default as Button, CommunicationBridge, Container_default as Container, ExternalPreview_default as ExternalPreview, Image_default as Image, RenderPage_default as RenderPage, Spacer_default as Spacer, Text_default as Text, Title_default as Title, applyGlobalFont, applyPageSettings, baseComponentConfigs, clearRegistry, createCommunicationBridge, createNamespacedRegistry, deepClone, deepMerge, generateBlockStyles, getAllComponentConfigs, getAllComponents, getBaseComponentConfig, getBaseComponentConfigs, getComponent, getRegisteredTypes, getResponsiveCSS, getResponsiveClasses, hasComponent, initializePage, injectCode, injectResponsiveCSS, loadComponentFonts, loadGoogleFont, normalizeComponentData, registerBaseComponents, registerComponent, registerComponents, registry, sendMessage, unregisterComponent };
|