everbee-landing-page-builder 1.0.0

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,20 @@
1
+ /** @type { import('@storybook/react-webpack5').StorybookConfig } */
2
+ const config = {
3
+ stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
4
+ addons: [
5
+ "@storybook/addon-webpack5-compiler-swc",
6
+ "@storybook/addon-onboarding",
7
+ "@storybook/addon-links",
8
+ "@storybook/addon-essentials",
9
+ "@chromatic-com/storybook",
10
+ "@storybook/addon-interactions",
11
+ ],
12
+ framework: {
13
+ name: "@storybook/react-webpack5",
14
+ options: {},
15
+ },
16
+ docs: {
17
+ autodocs: "tag",
18
+ },
19
+ };
20
+ export default config;
@@ -0,0 +1,13 @@
1
+ /** @type { import('@storybook/react').Preview } */
2
+ const preview = {
3
+ parameters: {
4
+ controls: {
5
+ matchers: {
6
+ color: /(background|color)$/i,
7
+ date: /Date$/i,
8
+ },
9
+ },
10
+ },
11
+ };
12
+
13
+ export default preview;
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "everbee-landing-page-builder",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "storybook": "storybook dev -p 6006",
9
+ "build-storybook": "storybook build",
10
+ "build-lib": "rollup -c"
11
+ },
12
+ "author": "abhay-everbee",
13
+ "license": "MIT",
14
+ "devDependencies": {
15
+ "@babel/preset-react": "^7.24.1",
16
+ "@chromatic-com/storybook": "^1.3.1",
17
+ "@rollup/plugin-commonjs": "^25.0.7",
18
+ "@rollup/plugin-node-resolve": "^15.2.3",
19
+ "@storybook/addon-essentials": "^8.0.6",
20
+ "@storybook/addon-interactions": "^8.0.6",
21
+ "@storybook/addon-links": "^8.0.6",
22
+ "@storybook/addon-onboarding": "^8.0.6",
23
+ "@storybook/addon-webpack5-compiler-swc": "^1.0.2",
24
+ "@storybook/blocks": "^8.0.6",
25
+ "@storybook/react": "^8.0.6",
26
+ "@storybook/react-webpack5": "^8.0.6",
27
+ "@storybook/test": "^8.0.6",
28
+ "grapesjs": "^0.21.9",
29
+ "grapesjs-blocks-basic": "^1.0.2",
30
+ "grapesjs-custom-code": "^1.0.2",
31
+ "grapesjs-navbar": "^1.0.2",
32
+ "grapesjs-parser-postcss": "^1.0.3",
33
+ "grapesjs-plugin-export": "^1.0.12",
34
+ "grapesjs-plugin-forms": "^2.0.6",
35
+ "grapesjs-preset-webpage": "^1.0.3",
36
+ "grapesjs-style-bg": "^2.0.2",
37
+ "grapesjs-tabs": "^1.0.6",
38
+ "grapesjs-tooltip": "^0.1.8",
39
+ "grapesjs-tui-image-editor": "^1.0.2",
40
+ "grapesjs-typed": "^2.0.1",
41
+ "prop-types": "^15.8.1",
42
+ "react": "^18.2.0",
43
+ "react-dom": "^18.2.0",
44
+ "rollup": "^2.79.1",
45
+ "rollup-plugin-babel": "^4.4.0",
46
+ "rollup-plugin-peer-deps-external": "^2.2.4",
47
+ "rollup-plugin-postcss": "^4.0.2",
48
+ "rollup-plugin-terser": "^7.0.2",
49
+ "storybook": "^8.0.6"
50
+ },
51
+ "peerDependencies": {
52
+ "react": "^18.2.0",
53
+ "react-dom": "^18.2.0"
54
+ }
55
+ }
@@ -0,0 +1,42 @@
1
+ import babel from "rollup-plugin-babel";
2
+ import resolve from "@rollup/plugin-node-resolve";
3
+ import external from "rollup-plugin-peer-deps-external";
4
+ import { terser } from "rollup-plugin-terser";
5
+ import postcss from 'rollup-plugin-postcss';
6
+ import commonjs from '@rollup/plugin-commonjs';
7
+
8
+ export default [
9
+ {
10
+ context: 'window',
11
+ input: "./src/index.js",
12
+ external: ['dist/css/grapes.min.css'],
13
+ output: [
14
+ {
15
+ file: "dist/index.js",
16
+ format: "cjs",
17
+ },
18
+ {
19
+ file: "dist/index.es.js",
20
+ format: "es",
21
+ exports: "named",
22
+ },
23
+ ],
24
+ plugins: [
25
+ babel({
26
+ exclude: "node_modules/**",
27
+ presets: ["@babel/preset-react"],
28
+ }),
29
+ external(),
30
+ resolve(),
31
+ terser(),
32
+ postcss({
33
+ // Include any postcss plugins or options here
34
+ extract: true, // Extract CSS to a separate file
35
+ minimize: true, // Minimize CSS output
36
+ modules: true, // Enable CSS modules if needed
37
+ // Add any other postcss plugins or options here as needed
38
+ }),
39
+ commonjs()
40
+ ],
41
+ },
42
+ ];
@@ -0,0 +1,552 @@
1
+ import React from "react";
2
+ import "grapesjs/dist/css/grapes.min.css";
3
+ import grapesjs from "grapesjs";
4
+ import { useEffect, useState } from "react";
5
+ import grapesjsPresetWebpage from "grapesjs-preset-webpage";
6
+ import blocksBasic from "grapesjs-blocks-basic";
7
+ import tuiImageEditor from "grapesjs-tui-image-editor";
8
+ import navbarEditor from "grapesjs-navbar";
9
+ import typed from "grapesjs-typed";
10
+ import gjsForms from "grapesjs-plugin-forms";
11
+
12
+ const LandingPageEditor = ({ cssContent = "", htmlContent = "" }) => {
13
+ // const [htmlComponents, setHtmlComponents] = useState(false);
14
+ const [editorState, setEditorState] = useState(null);
15
+ const script = function () {
16
+ alert("This is a custom component test");
17
+ // `this` is bound to the component element
18
+ console.log("the element", this);
19
+ };
20
+
21
+ const mergeTags = editor => {
22
+ const newType = 'var-placeholder';
23
+ // Define a component with `textable` property
24
+ editor.DomComponents.addType(newType, {
25
+ model: {
26
+ defaults: {
27
+ textable: 1,
28
+ placeholder: 'VARIABLE-1',
29
+ },
30
+ toHTML() {
31
+ return `{{ ${this.get('placeholder')} }}`;
32
+ },
33
+ },
34
+ // The view below it's just an example of creating a different UX
35
+ view: {
36
+ tagName: 'span',
37
+ events: {
38
+ 'change': 'updatePlh',
39
+ },
40
+ // Update the model once the select is changed
41
+ updatePlh(ev) {
42
+ this.model.set({ placeholder: ev.target.value });
43
+ this.updateProps();
44
+ },
45
+ // When we blur from a TextComponent, all its children components are
46
+ // flattened via innerHTML and parsed by the editor. So to keep the state
47
+ // of our props in sync with the model so we need to expose props in the HTML
48
+ updateProps() {
49
+ const { el, model } = this;
50
+ el.setAttribute('data-gjs-placeholder', model.get('placeholder'));
51
+ },
52
+ onRender() {
53
+ const { model, el } = this;
54
+ const currentPlh = model.get('placeholder');
55
+ const select = document.createElement('select');
56
+ const options = [ 'VARIABLE-1', 'VARIABLE-2', 'VARIABLE-3' ];
57
+ select.innerHTML = options.map(item => `<option value="${item}" ${item === currentPlh ? 'selected' : ''}>
58
+ ${item}
59
+ </option>`).join('');
60
+ while (el.firstChild) el.removeChild(el.firstChild);
61
+ el.appendChild(select);
62
+ select.setAttribute('style', 'padding: 5px; border-radius: 3px; border: none; -webkit-appearance: none;border: 2px solid black; background: aliceblue; border-radius:9px;');
63
+ this.updateProps();
64
+ },
65
+ }
66
+ });
67
+
68
+ // Use the component in blocks
69
+ editor.BlockManager.add(newType, {
70
+ label: 'Merge Tags',
71
+ content: { type: newType },
72
+ });
73
+
74
+ // const extendedTextType = 'extended-cmp'
75
+ // editor.Components.addType(extendedTextType, {
76
+ // extend: "text",
77
+ // model: {
78
+ // defaults: {
79
+ // tagName: 'p',
80
+ // style: {padding: "25px"},
81
+ // droppable: true,
82
+ // components: "Hello extended text component World!!"
83
+ // },
84
+ // },
85
+ // });
86
+ // editor.Blocks.add(extendedTextType, {
87
+ // label: 'Extended Text component',
88
+ // content: { type: extendedTextType },
89
+ // select: true,
90
+ // });
91
+
92
+
93
+ }
94
+ const myNewComponentTypes = editor => {
95
+ editor.DomComponents.addType('my-input-type', {
96
+ // Make the editor understand when to bind `my-input-type`
97
+ isComponent: el => el.tagName === 'INPUT',
98
+
99
+ // Model definition
100
+ model: {
101
+ // Default properties
102
+ defaults: {
103
+ tagName: 'input',
104
+ //draggable: 'form, form *', // Can be dropped only inside `form` elements
105
+ //droppable: false, // Can't drop other elements inside
106
+ attributes: { // Default attributes
107
+ type: 'text',
108
+ name: 'default-name',
109
+ placeholder: 'Insert text here',
110
+ },
111
+ traits: [
112
+ 'name',
113
+ 'placeholder',
114
+ { type: 'checkbox', name: 'required' },
115
+ 'id'
116
+ ],
117
+ }
118
+ }
119
+ });
120
+
121
+ // Define a new custom component
122
+ editor.Components.addType("img-text-col", {
123
+ model: {
124
+ defaults: {
125
+ attributes: { class: 'cmp-css' },
126
+ components: `
127
+ <div type='wrapper'>
128
+ <div class='gjs-row'>
129
+ <div class='gjs-cell' style='text-align:center'>
130
+ I'm a text node
131
+ <span>Component with styles<span>
132
+ <div class="cmp-css-a">Component A</div>
133
+ <div class="cmp-css-b">Component B</div>
134
+ <input type='my-input-type' />
135
+ </div>
136
+ <div class='gjs-cell'><img alt="Image here"/></div>
137
+ </div>
138
+ </div>
139
+ `,
140
+ styles: `
141
+ .cmp-css { color: red }
142
+ .cmp-css-a { color: green }
143
+ .cmp-css-b { color: blue }
144
+ .gjs-row {display:flex;}
145
+ .gjs-cell {min-height:75px; flex-grow:1; flex-basis:100%; border:1px solid green; padding: 2px; }
146
+ @media (max-width: 992px) {
147
+ .cmp-css{ color: darkred; }
148
+ .cmp-css-a { color: darkgreen }
149
+ .cmp-css-b { color: darkblue }
150
+ }
151
+ `,
152
+ },
153
+ },
154
+ });
155
+
156
+ };
157
+
158
+ const btnScript = function(props) {
159
+ console.log('My lib options: ');
160
+
161
+ //console.log('My lib options: ',props);
162
+ };
163
+
164
+
165
+ const btnss = (editor) => {
166
+ var newType = 'my-button';
167
+ editor.DomComponents.addType(newType, {
168
+ // ...
169
+ model: {
170
+ defaults: {
171
+ attributes: {itemsCounter: 0},
172
+ script: btnScript,
173
+ // Define traits, in order to change your properties
174
+ // traits: [
175
+ // {
176
+ // type: 'number',
177
+ // name: 'itemsCounter',
178
+ // changeProp: true,
179
+ // min: 0, // Minimum number value
180
+ // max: 100, // Maximum number value
181
+ // step: 1, // Number of steps
182
+ // }
183
+ // ],
184
+ },
185
+ toHTML() {
186
+ console.log('this',this);
187
+ return `<div>${this.get('itemsCounter')}</div>`;
188
+ },
189
+ 'script-props': ['itemsCounter'],
190
+ },
191
+ view: {
192
+ // Be default, the tag of the element is the same of the model
193
+ tagName: 'div',
194
+
195
+ // Add easily component specific listeners with `events`
196
+ // Being component specific (eg. you can't attach here listeners to window)
197
+ // you don't need to care about removing them when the component is removed,
198
+ // they will be managed automatically by the editor
199
+ events: {
200
+ click: 'clickOnElement',
201
+ // You can also make use of event delegation
202
+ // and listen to events bubbled from some inner element
203
+ 'dblclick .inner-el': 'innerElClick',
204
+ },
205
+
206
+ innerElClick(ev) {
207
+ ev.stopPropagation();
208
+ // ...
209
+
210
+ // If you need you can access the model from any function in the view
211
+ this.model.components('Update inner components');
212
+ },
213
+
214
+ // On init you can create listeners, like in the model, or start some other
215
+ // function at the beginning
216
+ init({ model }) {
217
+ var itemCount = 0;
218
+ // Do something in view on model property change
219
+ this.listenTo(model, 'change:itemsCounter', this.handlePropChange);
220
+ this.on('change:attributes:itemsCounter', this.handlePropChange);
221
+
222
+ // If you attach listeners on outside objects remember to unbind
223
+ // them in `removed` function in order to avoid memory leaks
224
+ //this.onDocClick = this.onDocClick.bind(this);
225
+ document.addEventListener('click', this.onDocClick)
226
+ },
227
+ handlePropChange(e) {
228
+ console.log('handlePropChange',e);
229
+ const btn = this.el.querySelector('#add_to_cart');
230
+ btn.innerHTML = `+ ${e.get('itemsCounter')}`;
231
+
232
+ },
233
+ // Callback triggered when the element is removed from the canvas
234
+ removed() {
235
+ document.removeEventListener('click', this.onDocClick)
236
+ },
237
+
238
+ // Do something with the content once the element is rendered.
239
+ // The DOM element is passed as `el` in the argument object,
240
+ // but you can access it from any function via `this.el`
241
+ async onRender({ el, model }) {
242
+ var itemsCounter = this.model.attributes.itemsCounter;
243
+ const btn = document.createElement('button');
244
+ const label = document.createElement('button');
245
+ label.innerHTML = `${itemsCounter}`;
246
+ label.id='add_to_cart'
247
+ btn.value = '+';
248
+ btn.innerHTML = '+';
249
+ btn.addEventListener('click', () => {
250
+ var itemsCounter = this.model.attributes.itemsCounter;
251
+ this.model.attributes.itemsCounter = itemsCounter + 1;
252
+ const btn = this.el.querySelector('#add_to_cart');
253
+ btn.innerHTML = ` ${this.model.attributes.itemsCounter}`;
254
+
255
+ //const component = editor.getSelected();
256
+ // console.log(component.getTrait('itemsCounter').props());
257
+ // const component = editor.getSelected(); // Component selected in canvas
258
+ // const traits = component.get('traits');
259
+ //var trait = component.getTrait('itemsCounter');
260
+ //console.log('trait',trait);
261
+ //trait.set('itemsCounter', parseInt(this.model.attributes.itemsCounter) + 1);
262
+ //trait.set({name: 'itemsCounter', itemsCounter: parseInt(this.model.attributes.itemsCounter) + 1});
263
+ //console.log('after update', this.model.getTrait('itemsCounter'));
264
+
265
+ //this.model.dispatchEvent(new CustomEvent('change'));
266
+ // trait.attributes.itemsCounter = parseInt(this.model.attributes.itemsCounter) + 1;
267
+ });
268
+ el.appendChild(btn);
269
+ el.appendChild(label);
270
+
271
+ const btn1 = document.createElement('button');
272
+ btn1.id='remove_to_cart'
273
+ btn1.value = '-';
274
+ btn1.innerHTML = '-';;
275
+ btn1.addEventListener('click', () => {
276
+ var itemsCounter = this.model.attributes.itemsCounter;
277
+ this.model.attributes.itemsCounter = itemsCounter - 1;
278
+ const btn = this.el.querySelector('#add_to_cart');
279
+ btn.innerHTML = ` ${this.model.attributes.itemsCounter}`;
280
+ });
281
+ el.appendChild(btn1);
282
+
283
+
284
+ fetch("https://email.everbee.com/api/v1/shops/best_products?category=newest", {
285
+ method: "GET",headers: {
286
+ 'Authorization-Token': 'b86e5a9b-8678-41fe-b3b9-0d156ad45938',
287
+ }, }).then((response) => response.json())
288
+ .then((json) =>{
289
+ console.log(json);
290
+ json.products.map((product,index)=>{
291
+ var child = document.createElement('img');
292
+ child.title = `Product ${index}`;
293
+ child.src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIHZpZXdCb3g9IjAgMCAyNCAyNCIgc3R5bGU9ImZpbGw6IHJnYmEoMCwwLDAsMC4xNSk7IHRyYW5zZm9ybTogc2NhbGUoMC43NSkiPgogICAgICAgIDxwYXRoIGQ9Ik04LjUgMTMuNWwyLjUgMyAzLjUtNC41IDQuNSA2SDVtMTYgMVY1YTIgMiAwIDAgMC0yLTJINWMtMS4xIDAtMiAuOS0yIDJ2MTRjMCAxLjEuOSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMnoiPjwvcGF0aD4KICAgICAgPC9zdmc+'
294
+ el.appendChild(child);
295
+ })
296
+ });
297
+ },
298
+
299
+ // Example of async content
300
+ // async onRender({ el, model }) {
301
+ // const asyncContent = await fetchSomething({
302
+ // someDataFromModel: model.get('someData'),
303
+ // });
304
+ // // Remember, these changes exist only inside the editor canvas
305
+ // // None of the DOM change is stored in your template data,
306
+ // // if you need to store something, update the model properties
307
+ // el.appendChild(asyncContent);
308
+ // }
309
+ },
310
+ });
311
+
312
+ // Use the component in blocks
313
+ editor.BlockManager.add(newType, {
314
+ label: 'ADD to CART',
315
+ asd: '11',
316
+ content: { type: newType, itemsCounter: 0 },
317
+ });
318
+
319
+ }
320
+
321
+ useEffect(() => {
322
+ console.log("useEff");
323
+ const editor = grapesjs.init({
324
+ richTextEditor: {
325
+ actions: [
326
+ 'bold',
327
+ 'italic',
328
+ 'underline',
329
+ 'strikethrough',
330
+ 'link',
331
+ 'wrap',
332
+ {
333
+ name: 'custom-vars',
334
+ icon: `<select class="gjs-rte-action" style='min-width:100px;'>
335
+ <option value="">- Select -</option>
336
+ <option value="{{firstname}}">FirstName</option>
337
+ <option value="{{lastname}}">LastName</option>
338
+ <option value="{{age}}">Age</option>
339
+ </select>`,
340
+ // Bind the 'result' on 'change' listener
341
+ event: 'change',
342
+ result: (rte, action) => rte.insertHTML(action.btn.firstChild.value),
343
+ // Reset the select on change
344
+ update: (rte, action) => {
345
+ action.btn.firstChild.value = ''
346
+ },
347
+ },
348
+ ],
349
+ },
350
+ container: "#gjs",
351
+ components: htmlContent,
352
+ style: cssContent,
353
+ height: "700px",
354
+ width: "100%",
355
+ plugins: [
356
+ blocksBasic,
357
+ grapesjsPresetWebpage,
358
+ tuiImageEditor,
359
+ navbarEditor,
360
+ typed,
361
+ gjsForms,
362
+ myNewComponentTypes,
363
+ mergeTags,
364
+ btnss
365
+ ],
366
+ storageManager: false,
367
+ deviceManager: {
368
+ devices: [
369
+ {
370
+ id: "desktop",
371
+ name: "Desktop",
372
+ width: "",
373
+ },
374
+ {
375
+ id: "tablet",
376
+ name: "Tablet",
377
+ width: "768px",
378
+ widthMedia: "992px",
379
+ },
380
+ {
381
+ id: "mobilePortrait",
382
+ name: "Mobile portrait",
383
+ width: "320px",
384
+ widthMedia: "575px",
385
+ },
386
+ ],
387
+ },
388
+ pluginsOpts: {
389
+ [blocksBasic]: { flexGrid: true, labelImage: "null" },
390
+ [grapesjsPresetWebpage]: {},
391
+ [tuiImageEditor]: {
392
+ script: [
393
+ // 'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.7/fabric.min.js',
394
+ "https://uicdn.toast.com/tui.code-snippet/v1.5.2/tui-code-snippet.min.js",
395
+ "https://uicdn.toast.com/tui-color-picker/v2.2.7/tui-color-picker.min.js",
396
+ "https://uicdn.toast.com/tui-image-editor/v3.15.2/tui-image-editor.min.js",
397
+ ],
398
+ style: [
399
+ "https://uicdn.toast.com/tui-color-picker/v2.2.7/tui-color-picker.min.css",
400
+ "https://uicdn.toast.com/tui-image-editor/v3.15.2/tui-image-editor.min.css",
401
+ ],
402
+ },
403
+ gjsForms: { category: "Forms" },
404
+ [typed]: {
405
+ block: {
406
+ category: "Extra",
407
+ content: {
408
+ type: "typed",
409
+ "type-speed": 40,
410
+ strings: ["Text row one", "Text row two", "Text row three"],
411
+ },
412
+ },
413
+ },
414
+ [grapesjsPresetWebpage]: {
415
+ modalImportTitle: "Import Template",
416
+ modalImportLabel:
417
+ '<div style="margin-bottom: 10px; font-size: 13px;">Paste here your HTML/CSS and click Import</div>',
418
+ modalImportContent: function (editor) {
419
+ return editor.getHtml() + "<style>" + editor.getCss() + "</style>";
420
+ },
421
+ },
422
+ },
423
+ });
424
+
425
+
426
+ // Define a new custom component
427
+ editor.Components.addType("comp-with-js", {
428
+ model: {
429
+ defaults: {
430
+ script,
431
+ // Add some style, just to make the component visible
432
+ style: {
433
+ width: "100px",
434
+ height: "100px",
435
+ background: "green",
436
+ },
437
+ },
438
+ },
439
+ });
440
+
441
+ // Create a block for the component, so we can drop it easily
442
+ editor.Blocks.add("test-block", {
443
+ label: "Custom Component test",
444
+ attributes: { class: "fa fa-text" },
445
+ content: [
446
+ { type: "comp-with-js" },
447
+ `<div style="color:red">Hello this is a custom component. <div>Hello this is a custom component</div> </div>`,
448
+ ],
449
+ });
450
+
451
+ editor.Blocks.add("img-text-col-block", {
452
+ label: "Custom Div",
453
+ attributes: { class: "fa fa-text" },
454
+ content: [
455
+ { type: 'img-text-col'},
456
+ //`<div type='wrapper'><div class='gjs-row'> <div class='gjs-cell'> I'm a text node <input/> </div> <div class='gjs-cell'><img alt="Image here"/></div> </div></div>`
457
+ ],
458
+ });
459
+
460
+
461
+ // editor.addComponents(`<div>
462
+ // <span title="foo" >Hello world!!!</span>
463
+ // <span title="foo" type='var-placeholder'>{{ VARIABLE-1 }}</span>
464
+ // </div>`);
465
+
466
+
467
+ setEditorState(editor);
468
+ return () => {};
469
+ }, []);
470
+
471
+ const downloadEditor = () => {
472
+ const jsonData = {
473
+ html: editorState.getHtml(),
474
+ css: editorState.getCss(),
475
+ components: editorState.getComponents(),
476
+ };
477
+
478
+ const html = editorState.getHtml();
479
+ console.log("everything", jsonData);
480
+ console.log("html editor", html);
481
+ };
482
+ var htmlContent1 = {
483
+ "html": "<body id=\"igmq\"><div id=\"i4af\">Hi {{ VARIABLE-1 }},<br/>How are you<br/><br/>Thanks,<br/>Dave</div></body>",
484
+ "css": "* { box-sizing: border-box; } body {margin: 0;}#i4af{padding:10px;}",
485
+ "components": [
486
+ {
487
+ "type": "text",
488
+ "attributes": {
489
+ "id": "i4af"
490
+ },
491
+ "components": [
492
+ {
493
+ "type": "textnode",
494
+ "content": "Hi "
495
+ },
496
+ {
497
+ "tagName": "span",
498
+ "type": "var-placeholder",
499
+ "attributes": {
500
+ "id": "ix3w"
501
+ }
502
+ },
503
+ {
504
+ "type": "textnode",
505
+ "content": ","
506
+ },
507
+ {
508
+ "tagName": "br",
509
+ "void": true
510
+ },
511
+ {
512
+ "type": "textnode",
513
+ "content": "How are you"
514
+ },
515
+ {
516
+ "tagName": "br",
517
+ "void": true
518
+ },
519
+ {
520
+ "tagName": "br",
521
+ "void": true
522
+ },
523
+ {
524
+ "type": "textnode",
525
+ "content": "Thanks,"
526
+ },
527
+ {
528
+ "tagName": "br",
529
+ "void": true
530
+ },
531
+ {
532
+ "type": "textnode",
533
+ "content": "Dave"
534
+ }
535
+ ]
536
+ }
537
+ ]
538
+ }
539
+ const importHTML = () => {
540
+ editorState?.setComponents(htmlContent1);
541
+ };
542
+ return (
543
+ <>
544
+ <div id="gjs"></div>
545
+ <div id="blocks"></div>
546
+ <button onClick={downloadEditor}>Console details</button>
547
+ <button onClick={importHTML(htmlContent)}>import html</button>
548
+ </>
549
+ );
550
+ };
551
+
552
+ export default LandingPageEditor;
@@ -0,0 +1,5 @@
1
+ import React from "react"
2
+ import LandingPageEditor from "./Editor";
3
+ export const PageBuilder = () => {
4
+ return <div><LandingPageEditor/></div>
5
+ }
package/src/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from './components/PageBuilder'
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import { PageBuilder } from "../components/PageBuilder";
3
+
4
+ export default {
5
+ title: "PageBuilder",
6
+ component: PageBuilder,
7
+ };
8
+
9
+ export const pagebuilder = () => <PageBuilder />;