@bagelink/blox 1.5.13 → 1.5.17

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/README.md CHANGED
@@ -22,7 +22,111 @@ pnpm add @bagelink/blox
22
22
  yarn add @bagelink/blox
23
23
  ```
24
24
 
25
- ## Quick Start
25
+ # @bagelink/blox
26
+
27
+ Blox is a Vue 3 library for building drag-and-drop page builders and managing static data for web applications. It provides a complete solution for creating external preview systems and rendering dynamic page content.
28
+
29
+ ## Features
30
+
31
+ - 🎨 **Page Builder Integration** - Full support for drag-and-drop page building
32
+ - 📄 **Static Page Management** - Manage JSON-based static page data
33
+ - 🔌 **Component Registry** - Flexible component registration system
34
+ - 📡 **Communication System** - Built-in messaging for builder-preview communication
35
+ - 🎯 **Type-Safe** - Full TypeScript support
36
+ - 🖼️ **Base Components** - Pre-built components (Button, Text, Image, etc.)
37
+ - 📱 **Responsive** - Mobile and desktop support
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ npm install @bagelink/blox vue-router
43
+ # or
44
+ pnpm add @bagelink/blox vue-router
45
+ # or
46
+ yarn add @bagelink/blox vue-router
47
+ ```
48
+
49
+ ## Quick Start (Recommended)
50
+
51
+ The simplest way to set up Blox in your Vue application:
52
+
53
+ ```typescript
54
+ // main.ts
55
+ import { createApp } from 'vue'
56
+ import { createRouter, createWebHistory } from 'vue-router'
57
+ import { createBlox, ButtonConfig, TextConfig, TitleConfig } from '@bagelink/blox'
58
+ import '@bagelink/blox/dist/blox.css'
59
+
60
+ import App from './App.vue'
61
+
62
+ const app = createApp(App)
63
+ const router = createRouter({
64
+ history: createWebHistory(),
65
+ routes: [
66
+ // Your app routes
67
+ ],
68
+ })
69
+
70
+ // Create and configure Blox
71
+ const blox = createBlox()
72
+ blox
73
+ .registerComponents([ButtonConfig, TextConfig, TitleConfig])
74
+ .registerRoutes(router)
75
+
76
+ app.use(blox)
77
+ app.use(router)
78
+ app.mount('#app')
79
+ ```
80
+
81
+ That's it! Preview routes are now available at:
82
+ - `/blox/preview/:pageId?` - External preview with editor communication
83
+ - `/blox/render/:pageId?` - Static page rendering
84
+
85
+ ### With Custom Components
86
+
87
+ ```typescript
88
+ import { createBlox, createComponentConfig, ButtonConfig } from '@bagelink/blox'
89
+ import MyHeroSection from './components/MyHeroSection.vue'
90
+
91
+ const MyHeroConfig = createComponentConfig({
92
+ id: 'MyHero',
93
+ label: 'Hero Section',
94
+ icon: 'hero_section',
95
+ component: MyHeroSection,
96
+ content: [
97
+ {
98
+ type: 'text',
99
+ key: 'title',
100
+ label: 'Hero Title',
101
+ defaultValue: 'Welcome!',
102
+ },
103
+ ],
104
+ })
105
+
106
+ const blox = createBlox()
107
+ blox
108
+ .registerComponents([ButtonConfig, MyHeroConfig])
109
+ .registerRoutes(router)
110
+
111
+ app.use(blox)
112
+ ```
113
+
114
+ ### Available Built-in Component Configs
115
+
116
+ Import these configs to register built-in components:
117
+
118
+ - `ButtonConfig` - Customizable button/link
119
+ - `TextConfig` - Rich text content
120
+ - `TitleConfig` - Heading with optional subtitle
121
+ - `ImageConfig` - Responsive image
122
+ - `SpacerConfig` - Vertical spacing
123
+ - `ContainerConfig` - Content container with max-width
124
+
125
+ For more examples, see [SETUP_EXAMPLE.md](./SETUP_EXAMPLE.md).
126
+
127
+ ---
128
+
129
+ ## Alternative Setup (Legacy)
26
130
 
27
131
  ### 1. Register Base Components
28
132
 
@@ -33,298 +33,320 @@ export interface ComponentConfig {
33
33
  icon: string
34
34
  img?: string
35
35
  order?: number
36
- component: ComponentConstructor
36
+ component: ComponentConstructor | (() => Promise<any>) // Support async components
37
37
  content?: ComponentSchema[] // Content editing schema
38
38
  settings?: ComponentSchema[] // Settings schema
39
+ category?: string // Component category for organization
39
40
  }
40
41
 
41
42
  /**
42
- * Base component configurations
43
+ * Individual component configurations for easy importing
44
+ */
45
+ export const TextConfig: ComponentConfig = {
46
+ id: 'Text',
47
+ label: 'Text',
48
+ icon: 'text_fields',
49
+ order: 10,
50
+ category: 'basic',
51
+ component: Text,
52
+ content: [
53
+ {
54
+ type: 'richtext',
55
+ key: 'content',
56
+ label: 'Content',
57
+ defaultValue: '<p>Enter your text here...</p>',
58
+ height: 200,
59
+ },
60
+ ],
61
+ settings: [
62
+ {
63
+ type: 'select',
64
+ key: 'tag',
65
+ label: 'HTML Tag',
66
+ defaultValue: 'div',
67
+ options: [
68
+ { label: 'Div', value: 'div' },
69
+ { label: 'Paragraph', value: 'p' },
70
+ { label: 'Span', value: 'span' },
71
+ { label: 'Article', value: 'article' },
72
+ { label: 'Section', value: 'section' },
73
+ ],
74
+ },
75
+ {
76
+ type: 'select',
77
+ key: 'align',
78
+ label: 'Text Alignment',
79
+ defaultValue: 'left',
80
+ options: [
81
+ { label: 'Left', value: 'left' },
82
+ { label: 'Center', value: 'center' },
83
+ { label: 'Right', value: 'right' },
84
+ { label: 'Justify', value: 'justify' },
85
+ ],
86
+ },
87
+ ],
88
+ }
89
+
90
+ export const TitleConfig: ComponentConfig = {
91
+ id: 'Title',
92
+ label: 'Title',
93
+ icon: 'title',
94
+ order: 5,
95
+ category: 'basic',
96
+ component: Title,
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ key: 'title',
101
+ label: 'Title',
102
+ defaultValue: 'Your Title Here',
103
+ },
104
+ {
105
+ type: 'text',
106
+ key: 'subtitle',
107
+ label: 'Subtitle',
108
+ defaultValue: '',
109
+ },
110
+ ],
111
+ settings: [
112
+ {
113
+ type: 'select',
114
+ key: 'tag',
115
+ label: 'Heading Tag',
116
+ defaultValue: 'h2',
117
+ options: [
118
+ { label: 'H1', value: 'h1' },
119
+ { label: 'H2', value: 'h2' },
120
+ { label: 'H3', value: 'h3' },
121
+ { label: 'H4', value: 'h4' },
122
+ { label: 'H5', value: 'h5' },
123
+ { label: 'H6', value: 'h6' },
124
+ ],
125
+ },
126
+ {
127
+ type: 'select',
128
+ key: 'align',
129
+ label: 'Text Alignment',
130
+ defaultValue: 'center',
131
+ options: [
132
+ { label: 'Left', value: 'left' },
133
+ { label: 'Center', value: 'center' },
134
+ { label: 'Right', value: 'right' },
135
+ ],
136
+ },
137
+ {
138
+ type: 'number',
139
+ key: 'size',
140
+ label: 'Font Size (px)',
141
+ defaultValue: 32,
142
+ },
143
+ ],
144
+ }
145
+
146
+ export const ButtonConfig: ComponentConfig = {
147
+ id: 'Button',
148
+ label: 'Button',
149
+ icon: 'smart_button',
150
+ order: 15,
151
+ category: 'basic',
152
+ component: Button,
153
+ content: [
154
+ {
155
+ type: 'text',
156
+ key: 'btnTxt',
157
+ label: 'Button Text',
158
+ defaultValue: 'Click Me',
159
+ },
160
+ {
161
+ type: 'text',
162
+ key: 'btnUrl',
163
+ label: 'Button URL',
164
+ defaultValue: '#',
165
+ },
166
+ ],
167
+ settings: [
168
+ {
169
+ type: 'select',
170
+ key: 'variant',
171
+ label: 'Button Style',
172
+ defaultValue: 'primary',
173
+ options: [
174
+ { label: 'Primary', value: 'primary' },
175
+ { label: 'Secondary', value: 'secondary' },
176
+ { label: 'Outline', value: 'outline' },
177
+ { label: 'Ghost', value: 'ghost' },
178
+ ],
179
+ },
180
+ {
181
+ type: 'select',
182
+ key: 'size',
183
+ label: 'Size',
184
+ defaultValue: 'md',
185
+ options: [
186
+ { label: 'Small', value: 'sm' },
187
+ { label: 'Medium', value: 'md' },
188
+ { label: 'Large', value: 'lg' },
189
+ ],
190
+ },
191
+ {
192
+ type: 'select',
193
+ key: 'align',
194
+ label: 'Alignment',
195
+ defaultValue: 'left',
196
+ options: [
197
+ { label: 'Left', value: 'left' },
198
+ { label: 'Center', value: 'center' },
199
+ { label: 'Right', value: 'right' },
200
+ ],
201
+ },
202
+ {
203
+ type: 'checkbox',
204
+ key: 'fullWidth',
205
+ label: 'Full Width',
206
+ defaultValue: false,
207
+ },
208
+ {
209
+ type: 'select',
210
+ key: 'btnTarget',
211
+ label: 'Link Target',
212
+ defaultValue: '_self',
213
+ options: [
214
+ { label: 'Same Window', value: '_self' },
215
+ { label: 'New Window', value: '_blank' },
216
+ ],
217
+ },
218
+ ],
219
+ }
220
+
221
+ export const ImageConfig: ComponentConfig = {
222
+ id: 'Image',
223
+ label: 'Image',
224
+ icon: 'image',
225
+ order: 20,
226
+ category: 'media',
227
+ component: Image,
228
+ content: [
229
+ {
230
+ type: 'upload',
231
+ key: 'src',
232
+ label: 'Image',
233
+ defaultValue: '',
234
+ height: 200,
235
+ },
236
+ {
237
+ type: 'text',
238
+ key: 'alt',
239
+ label: 'Alt Text',
240
+ defaultValue: '',
241
+ },
242
+ ],
243
+ settings: [
244
+ {
245
+ type: 'select',
246
+ key: 'objectFit',
247
+ label: 'Object Fit',
248
+ defaultValue: 'cover',
249
+ options: [
250
+ { label: 'Cover', value: 'cover' },
251
+ { label: 'Contain', value: 'contain' },
252
+ { label: 'Fill', value: 'fill' },
253
+ { label: 'None', value: 'none' },
254
+ { label: 'Scale Down', value: 'scale-down' },
255
+ ],
256
+ },
257
+ {
258
+ type: 'number',
259
+ key: 'maxWidth',
260
+ label: 'Max Width (px)',
261
+ defaultValue: null,
262
+ },
263
+ {
264
+ type: 'number',
265
+ key: 'height',
266
+ label: 'Height (px)',
267
+ defaultValue: null,
268
+ },
269
+ {
270
+ type: 'select',
271
+ key: 'align',
272
+ label: 'Alignment',
273
+ defaultValue: 'center',
274
+ options: [
275
+ { label: 'Left', value: 'left' },
276
+ { label: 'Center', value: 'center' },
277
+ { label: 'Right', value: 'right' },
278
+ ],
279
+ },
280
+ ],
281
+ }
282
+
283
+ export const SpacerConfig: ComponentConfig = {
284
+ id: 'Spacer',
285
+ label: 'Spacer',
286
+ icon: 'height',
287
+ order: 25,
288
+ category: 'layout',
289
+ component: Spacer,
290
+ content: [],
291
+ settings: [
292
+ {
293
+ type: 'number',
294
+ key: 'height',
295
+ label: 'Height (px)',
296
+ defaultValue: 40,
297
+ },
298
+ ],
299
+ }
300
+
301
+ export const ContainerConfig: ComponentConfig = {
302
+ id: 'Container',
303
+ label: 'Container',
304
+ icon: 'view_module',
305
+ order: 30,
306
+ category: 'layout',
307
+ component: Container,
308
+ content: [
309
+ {
310
+ type: 'richtext',
311
+ key: 'content',
312
+ label: 'Content',
313
+ defaultValue: '<p>Container content...</p>',
314
+ height: 200,
315
+ },
316
+ ],
317
+ settings: [
318
+ {
319
+ type: 'select',
320
+ key: 'maxWidth',
321
+ label: 'Max Width',
322
+ defaultValue: 'lg',
323
+ options: [
324
+ { label: 'Small (640px)', value: 'sm' },
325
+ { label: 'Medium (768px)', value: 'md' },
326
+ { label: 'Large (1024px)', value: 'lg' },
327
+ { label: 'Extra Large (1280px)', value: 'xl' },
328
+ { label: 'Full Width', value: 'full' },
329
+ ],
330
+ },
331
+ {
332
+ type: 'checkbox',
333
+ key: 'centered',
334
+ label: 'Center Content',
335
+ defaultValue: true,
336
+ },
337
+ ],
338
+ }
339
+
340
+ /**
341
+ * Base component configurations array
43
342
  */
44
343
  export const baseComponentConfigs: ComponentConfig[] = [
45
- {
46
- id: 'Text',
47
- label: 'Text',
48
- icon: 'text_fields',
49
- order: 10,
50
- component: Text,
51
- content: [
52
- {
53
- type: 'richtext',
54
- key: 'content',
55
- label: 'Content',
56
- defaultValue: '<p>Enter your text here...</p>',
57
- height: 200,
58
- },
59
- ],
60
- settings: [
61
- {
62
- type: 'select',
63
- key: 'tag',
64
- label: 'HTML Tag',
65
- defaultValue: 'div',
66
- options: [
67
- { label: 'Div', value: 'div' },
68
- { label: 'Paragraph', value: 'p' },
69
- { label: 'Span', value: 'span' },
70
- { label: 'Article', value: 'article' },
71
- { label: 'Section', value: 'section' },
72
- ],
73
- },
74
- {
75
- type: 'select',
76
- key: 'align',
77
- label: 'Text Alignment',
78
- defaultValue: 'left',
79
- options: [
80
- { label: 'Left', value: 'left' },
81
- { label: 'Center', value: 'center' },
82
- { label: 'Right', value: 'right' },
83
- { label: 'Justify', value: 'justify' },
84
- ],
85
- },
86
- ],
87
- },
88
- {
89
- id: 'Title',
90
- label: 'Title',
91
- icon: 'title',
92
- order: 5,
93
- component: Title,
94
- content: [
95
- {
96
- type: 'text',
97
- key: 'title',
98
- label: 'Title',
99
- defaultValue: 'Your Title Here',
100
- },
101
- {
102
- type: 'text',
103
- key: 'subtitle',
104
- label: 'Subtitle',
105
- defaultValue: '',
106
- },
107
- ],
108
- settings: [
109
- {
110
- type: 'select',
111
- key: 'tag',
112
- label: 'Heading Tag',
113
- defaultValue: 'h2',
114
- options: [
115
- { label: 'H1', value: 'h1' },
116
- { label: 'H2', value: 'h2' },
117
- { label: 'H3', value: 'h3' },
118
- { label: 'H4', value: 'h4' },
119
- { label: 'H5', value: 'h5' },
120
- { label: 'H6', value: 'h6' },
121
- ],
122
- },
123
- {
124
- type: 'select',
125
- key: 'align',
126
- label: 'Text Alignment',
127
- defaultValue: 'center',
128
- options: [
129
- { label: 'Left', value: 'left' },
130
- { label: 'Center', value: 'center' },
131
- { label: 'Right', value: 'right' },
132
- ],
133
- },
134
- {
135
- type: 'number',
136
- key: 'size',
137
- label: 'Font Size (px)',
138
- defaultValue: 32,
139
- },
140
- ],
141
- },
142
- {
143
- id: 'Button',
144
- label: 'Button',
145
- icon: 'smart_button',
146
- order: 15,
147
- component: Button,
148
- content: [
149
- {
150
- type: 'text',
151
- key: 'btnTxt',
152
- label: 'Button Text',
153
- defaultValue: 'Click Me',
154
- },
155
- {
156
- type: 'text',
157
- key: 'btnUrl',
158
- label: 'Button URL',
159
- defaultValue: '#',
160
- },
161
- ],
162
- settings: [
163
- {
164
- type: 'select',
165
- key: 'variant',
166
- label: 'Button Style',
167
- defaultValue: 'primary',
168
- options: [
169
- { label: 'Primary', value: 'primary' },
170
- { label: 'Secondary', value: 'secondary' },
171
- { label: 'Outline', value: 'outline' },
172
- { label: 'Ghost', value: 'ghost' },
173
- ],
174
- },
175
- {
176
- type: 'select',
177
- key: 'size',
178
- label: 'Size',
179
- defaultValue: 'md',
180
- options: [
181
- { label: 'Small', value: 'sm' },
182
- { label: 'Medium', value: 'md' },
183
- { label: 'Large', value: 'lg' },
184
- ],
185
- },
186
- {
187
- type: 'select',
188
- key: 'align',
189
- label: 'Alignment',
190
- defaultValue: 'left',
191
- options: [
192
- { label: 'Left', value: 'left' },
193
- { label: 'Center', value: 'center' },
194
- { label: 'Right', value: 'right' },
195
- ],
196
- },
197
- {
198
- type: 'checkbox',
199
- key: 'fullWidth',
200
- label: 'Full Width',
201
- defaultValue: false,
202
- },
203
- {
204
- type: 'select',
205
- key: 'btnTarget',
206
- label: 'Link Target',
207
- defaultValue: '_self',
208
- options: [
209
- { label: 'Same Window', value: '_self' },
210
- { label: 'New Window', value: '_blank' },
211
- ],
212
- },
213
- ],
214
- },
215
- {
216
- id: 'Image',
217
- label: 'Image',
218
- icon: 'image',
219
- order: 20,
220
- component: Image,
221
- content: [
222
- {
223
- type: 'upload',
224
- key: 'src',
225
- label: 'Image',
226
- defaultValue: '',
227
- height: 200,
228
- },
229
- {
230
- type: 'text',
231
- key: 'alt',
232
- label: 'Alt Text',
233
- defaultValue: '',
234
- },
235
- ],
236
- settings: [
237
- {
238
- type: 'select',
239
- key: 'objectFit',
240
- label: 'Object Fit',
241
- defaultValue: 'cover',
242
- options: [
243
- { label: 'Cover', value: 'cover' },
244
- { label: 'Contain', value: 'contain' },
245
- { label: 'Fill', value: 'fill' },
246
- { label: 'None', value: 'none' },
247
- { label: 'Scale Down', value: 'scale-down' },
248
- ],
249
- },
250
- {
251
- type: 'number',
252
- key: 'maxWidth',
253
- label: 'Max Width (px)',
254
- defaultValue: null,
255
- },
256
- {
257
- type: 'number',
258
- key: 'height',
259
- label: 'Height (px)',
260
- defaultValue: null,
261
- },
262
- {
263
- type: 'select',
264
- key: 'align',
265
- label: 'Alignment',
266
- defaultValue: 'center',
267
- options: [
268
- { label: 'Left', value: 'left' },
269
- { label: 'Center', value: 'center' },
270
- { label: 'Right', value: 'right' },
271
- ],
272
- },
273
- ],
274
- },
275
- {
276
- id: 'Spacer',
277
- label: 'Spacer',
278
- icon: 'height',
279
- order: 25,
280
- component: Spacer,
281
- content: [],
282
- settings: [
283
- {
284
- type: 'number',
285
- key: 'height',
286
- label: 'Height (px)',
287
- defaultValue: 40,
288
- },
289
- ],
290
- },
291
- {
292
- id: 'Container',
293
- label: 'Container',
294
- icon: 'view_module',
295
- order: 30,
296
- component: Container,
297
- content: [
298
- {
299
- type: 'richtext',
300
- key: 'content',
301
- label: 'Content',
302
- defaultValue: '<p>Container content...</p>',
303
- height: 200,
304
- },
305
- ],
306
- settings: [
307
- {
308
- type: 'select',
309
- key: 'maxWidth',
310
- label: 'Max Width',
311
- defaultValue: 'lg',
312
- options: [
313
- { label: 'Small (640px)', value: 'sm' },
314
- { label: 'Medium (768px)', value: 'md' },
315
- { label: 'Large (1024px)', value: 'lg' },
316
- { label: 'Extra Large (1280px)', value: 'xl' },
317
- { label: 'Full Width', value: 'full' },
318
- ],
319
- },
320
- {
321
- type: 'checkbox',
322
- key: 'centered',
323
- label: 'Center Content',
324
- defaultValue: true,
325
- },
326
- ],
327
- },
344
+ TextConfig,
345
+ TitleConfig,
346
+ ButtonConfig,
347
+ ImageConfig,
348
+ SpacerConfig,
349
+ ContainerConfig,
328
350
  ]
329
351
 
330
352
  /**