editor-ts 0.0.1
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 +401 -0
- package/index.ts +81 -0
- package/package.json +42 -0
- package/src/core/AssetManager.ts +127 -0
- package/src/core/ComponentManager.ts +206 -0
- package/src/core/Page.ts +138 -0
- package/src/core/StyleManager.ts +221 -0
- package/src/core/ToolbarManager.ts +170 -0
- package/src/core/init.ts +374 -0
- package/src/styles/branding.css +109 -0
- package/src/types.ts +157 -0
- package/src/utils/helpers.ts +199 -0
- package/src/utils/toolbar.ts +140 -0
package/README.md
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
|
|
2
|
+
# EditorTs
|
|
3
|
+
|
|
4
|
+
DO NOT USE THIS IN PRODUCTION YET IT IS A WORK IN PROGRESS - EARLY DEVELOPMENT
|
|
5
|
+
|
|
6
|
+
A powerful TypeScript library for editing HTML content while maintaining its structure in a JSON representation. EditorTs provides a simple `init()` function to create a fully-functional WYSIWYG editor with minimal configuration.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **One-Line Setup**: Initialize a complete editor with `init()`
|
|
11
|
+
- **WYSIWYG Editing**: Click-to-edit interface with context toolbars
|
|
12
|
+
- **Runtime Configuration**: Toolbars configured in JavaScript, not stored in JSON
|
|
13
|
+
- **Iframe Sandboxing**: Template runs in isolated iframe for proper CSS/JS scoping
|
|
14
|
+
- **Event System**: Hook into component selection, editing, deletion, etc.
|
|
15
|
+
- **Type-Safe**: Full TypeScript support
|
|
16
|
+
- **Clean JSON**: Only stores component metadata and styles, no behavioral config
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bun install
|
|
22
|
+
bun run dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Open http://localhost:5021 to see the editor!
|
|
26
|
+
|
|
27
|
+
## Simple Usage with `init()`
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { init } from 'editorts';
|
|
31
|
+
import pageData from './page.json';
|
|
32
|
+
|
|
33
|
+
// Initialize editor with one function call
|
|
34
|
+
const editor = init({
|
|
35
|
+
containerId: 'root',
|
|
36
|
+
data: pageData,
|
|
37
|
+
|
|
38
|
+
// Configure toolbars (runtime only, not saved to JSON)
|
|
39
|
+
toolbars: {
|
|
40
|
+
byId: {
|
|
41
|
+
'header': {
|
|
42
|
+
enabled: true,
|
|
43
|
+
actions: [
|
|
44
|
+
{ id: 'edit', label: 'Edit', icon: '✏️', enabled: true },
|
|
45
|
+
{ id: 'duplicate', label: 'Duplicate', icon: '📋', enabled: true }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
byType: {
|
|
50
|
+
'custom-code': {
|
|
51
|
+
actions: [
|
|
52
|
+
{ id: 'editJS', label: 'Edit Code', icon: '📜', enabled: true }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Optional callbacks
|
|
59
|
+
onComponentSelect: (component) => {
|
|
60
|
+
console.log('Selected:', component.attributes?.id);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Access the Page API
|
|
65
|
+
editor.page.components.findById('header');
|
|
66
|
+
editor.page.styles.updateStyle('#header', { 'color': 'red' });
|
|
67
|
+
|
|
68
|
+
// Add event listeners
|
|
69
|
+
editor.on('componentEdit', (component) => {
|
|
70
|
+
console.log('Editing:', component);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Save the page (clean JSON, no toolbar configs)
|
|
74
|
+
const json = editor.save();
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Architecture: Runtime vs. Stored Data
|
|
78
|
+
|
|
79
|
+
EditorTs follows a clean separation between **data** (stored in JSON) and **behavior** (configured in JavaScript).
|
|
80
|
+
|
|
81
|
+
**See [AGENTS.md](./AGENTS.md) for full architecture principles.**
|
|
82
|
+
|
|
83
|
+
### What's Stored in JSON (Database)
|
|
84
|
+
- Component metadata (type, attributes, tagName)
|
|
85
|
+
- Styling (CSS, inline styles)
|
|
86
|
+
- Content (text, HTML, assets)
|
|
87
|
+
- Component structure
|
|
88
|
+
|
|
89
|
+
### What's Configured in JavaScript (Runtime)
|
|
90
|
+
- Toolbar configurations
|
|
91
|
+
- Editor behaviors
|
|
92
|
+
- UI interactions
|
|
93
|
+
- Event handlers
|
|
94
|
+
- Permissions
|
|
95
|
+
|
|
96
|
+
**Example:**
|
|
97
|
+
```typescript
|
|
98
|
+
// JSON stays clean
|
|
99
|
+
const page = new Page(jsonData);
|
|
100
|
+
|
|
101
|
+
// Configure at runtime
|
|
102
|
+
page.toolbars.configureById('header', { ... });
|
|
103
|
+
|
|
104
|
+
// Export is still clean
|
|
105
|
+
page.toJSON(); // No toolbar property in output
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Toolbar System
|
|
109
|
+
|
|
110
|
+
### Configure Toolbars at Runtime
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const editor = init({
|
|
114
|
+
containerId: 'root',
|
|
115
|
+
data: pageData,
|
|
116
|
+
toolbars: {
|
|
117
|
+
// By component ID
|
|
118
|
+
byId: {
|
|
119
|
+
'header': { enabled: true, actions: [...] },
|
|
120
|
+
'footer': { enabled: false, actions: [] }
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// By component type
|
|
124
|
+
byType: {
|
|
125
|
+
'custom-code': { actions: [...] },
|
|
126
|
+
'box': { actions: [...] }
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// By tag name
|
|
130
|
+
byTag: {
|
|
131
|
+
'div': { actions: [...] }
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// Global default
|
|
135
|
+
default: { actions: [...] }
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Or configure after init
|
|
140
|
+
editor.page.toolbars.configureById('sidebar', {
|
|
141
|
+
enabled: true,
|
|
142
|
+
actions: [
|
|
143
|
+
{ id: 'edit', label: 'Edit', icon: '✏️', enabled: true },
|
|
144
|
+
{ id: 'delete', label: 'Delete', icon: '🗑️', enabled: false, danger: true }
|
|
145
|
+
]
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Toolbar Actions
|
|
150
|
+
|
|
151
|
+
- **Edit (✏️)** - Edit component properties
|
|
152
|
+
- **Edit JS (📜)** - Edit component JavaScript with Monaco editor
|
|
153
|
+
- **Duplicate (📋)** - Create a copy of the component
|
|
154
|
+
- **Delete (🗑️)** - Remove component from page
|
|
155
|
+
|
|
156
|
+
### Toolbar Presets
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { toolbarPresets } from 'editorts';
|
|
160
|
+
|
|
161
|
+
// Use presets
|
|
162
|
+
page.toolbars.configureById('header', toolbarPresets.full);
|
|
163
|
+
page.toolbars.configureById('footer', toolbarPresets.editOnly);
|
|
164
|
+
page.toolbars.configureById('banner', toolbarPresets.minimal);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Available presets:
|
|
168
|
+
- `full` - All actions enabled
|
|
169
|
+
- `editOnly` - Edit, Edit JS, Duplicate (no delete)
|
|
170
|
+
- `minimal` - Edit and Delete only
|
|
171
|
+
- `readOnly` - View only
|
|
172
|
+
- `disabled` - No toolbar
|
|
173
|
+
|
|
174
|
+
## API Reference
|
|
175
|
+
|
|
176
|
+
### `init(config)` → EditorTsEditor
|
|
177
|
+
|
|
178
|
+
Initialize the editor with configuration.
|
|
179
|
+
|
|
180
|
+
**Returns:** EditorTsEditor instance
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
interface EditorTsEditor {
|
|
184
|
+
page: Page; // Full Page instance
|
|
185
|
+
on(event, callback): void; // Add event listener
|
|
186
|
+
off(event, callback): void; // Remove event listener
|
|
187
|
+
refresh(): void; // Refresh preview
|
|
188
|
+
save(): string; // Export JSON
|
|
189
|
+
destroy(): void; // Clean up
|
|
190
|
+
elements: { // Access DOM elements
|
|
191
|
+
container: HTMLElement;
|
|
192
|
+
sidebar?: HTMLElement;
|
|
193
|
+
canvas: HTMLElement;
|
|
194
|
+
iframe: HTMLIFrameElement;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Events:**
|
|
200
|
+
- `componentSelect` - When component is clicked
|
|
201
|
+
- `componentEdit` - When edit action is triggered
|
|
202
|
+
- `componentDuplicate` - When component is duplicated
|
|
203
|
+
- `componentDelete` - When component is deleted
|
|
204
|
+
- `componentEditJS` - When Edit JS is triggered
|
|
205
|
+
|
|
206
|
+
### Page Class
|
|
207
|
+
|
|
208
|
+
Direct API for programmatic manipulation:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { Page } from 'editorts';
|
|
212
|
+
|
|
213
|
+
const page = new Page(jsonData);
|
|
214
|
+
|
|
215
|
+
// Page methods
|
|
216
|
+
page.getTitle();
|
|
217
|
+
page.setTitle(title);
|
|
218
|
+
page.getHTML();
|
|
219
|
+
page.getCSS();
|
|
220
|
+
page.toJSON();
|
|
221
|
+
page.clone();
|
|
222
|
+
|
|
223
|
+
// Managers
|
|
224
|
+
page.components.findById(id);
|
|
225
|
+
page.components.updateComponent(id, updates);
|
|
226
|
+
page.styles.updateStyle(selector, properties);
|
|
227
|
+
page.assets.getImages();
|
|
228
|
+
page.toolbars.configureById(id, config);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### ComponentManager
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
page.components.find(query);
|
|
235
|
+
page.components.findById(id);
|
|
236
|
+
page.components.findByType(type);
|
|
237
|
+
page.components.addComponent(component);
|
|
238
|
+
page.components.removeComponent(id);
|
|
239
|
+
page.components.updateComponent(id, updates);
|
|
240
|
+
page.components.getAll();
|
|
241
|
+
page.components.count();
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### StyleManager
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
page.styles.findBySelector(selector);
|
|
248
|
+
page.styles.findByMedia(mediaText);
|
|
249
|
+
page.styles.addStyle(style);
|
|
250
|
+
page.styles.updateStyle(selector, properties);
|
|
251
|
+
page.styles.removeBySelector(selector);
|
|
252
|
+
page.styles.compileToCSS();
|
|
253
|
+
page.styles.getAll();
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### AssetManager
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
page.assets.findByType(type);
|
|
260
|
+
page.assets.getImages();
|
|
261
|
+
page.assets.addAsset(asset);
|
|
262
|
+
page.assets.removeAsset(src);
|
|
263
|
+
page.assets.updateAsset(src, updates);
|
|
264
|
+
page.assets.getAll();
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### ToolbarManager
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
page.toolbars.configureById(id, config);
|
|
271
|
+
page.toolbars.configureByType(type, config);
|
|
272
|
+
page.toolbars.configureByTag(tagName, config);
|
|
273
|
+
page.toolbars.configureCustom(matcher, config);
|
|
274
|
+
page.toolbars.getToolbarForComponent(component);
|
|
275
|
+
page.toolbars.setGlobalDefault(config);
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Examples
|
|
279
|
+
|
|
280
|
+
### Basic Editor Setup
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { init } from 'editorts';
|
|
284
|
+
|
|
285
|
+
const editor = init({
|
|
286
|
+
containerId: 'root',
|
|
287
|
+
data: pageData
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
console.log('Components:', editor.page.components.count());
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### With Toolbar Configuration
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
const editor = init({
|
|
297
|
+
containerId: 'root',
|
|
298
|
+
data: pageData,
|
|
299
|
+
toolbars: {
|
|
300
|
+
byType: {
|
|
301
|
+
'custom-code': {
|
|
302
|
+
actions: [
|
|
303
|
+
{ id: 'editJS', label: 'Edit Code', icon: '📜', enabled: true }
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### With Event Handlers
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
const editor = init({
|
|
315
|
+
containerId: 'root',
|
|
316
|
+
data: pageData,
|
|
317
|
+
onComponentSelect: (comp) => console.log('Selected:', comp),
|
|
318
|
+
onComponentDelete: (comp) => console.log('Deleted:', comp)
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Add more listeners after init
|
|
322
|
+
editor.on('componentEdit', (component) => {
|
|
323
|
+
// Custom edit logic
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Programmatic Page Manipulation
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { Page } from 'editorts';
|
|
331
|
+
|
|
332
|
+
const page = new Page(jsonData);
|
|
333
|
+
|
|
334
|
+
// Find components
|
|
335
|
+
const header = page.components.findById('header');
|
|
336
|
+
const boxes = page.components.findByType('box');
|
|
337
|
+
|
|
338
|
+
// Update styles
|
|
339
|
+
page.styles.updateStyle('#header', {
|
|
340
|
+
'background-color': '#333',
|
|
341
|
+
'padding': '2rem'
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Manage assets
|
|
345
|
+
const images = page.assets.getImages();
|
|
346
|
+
|
|
347
|
+
// Export clean JSON
|
|
348
|
+
const json = page.toJSON();
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Project Structure
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
editorts/
|
|
355
|
+
├── src/
|
|
356
|
+
│ ├── core/
|
|
357
|
+
│ │ ├── init.ts # Editor initialization
|
|
358
|
+
│ │ ├── Page.ts # Main Page class
|
|
359
|
+
│ │ ├── ComponentManager.ts # Component operations
|
|
360
|
+
│ │ ├── StyleManager.ts # Style operations
|
|
361
|
+
│ │ ├── AssetManager.ts # Asset operations
|
|
362
|
+
│ │ └── ToolbarManager.ts # Runtime toolbar config
|
|
363
|
+
│ ├── styles/
|
|
364
|
+
│ │ └── branding.css # Editor branding
|
|
365
|
+
│ ├── utils/
|
|
366
|
+
│ │ ├── helpers.ts # Utility functions
|
|
367
|
+
│ │ └── toolbar.ts # Toolbar utilities
|
|
368
|
+
│ └── types.ts # Type definitions
|
|
369
|
+
├── examples/
|
|
370
|
+
│ ├── quickstart.ts # Simple editor example
|
|
371
|
+
│ ├── basic-usage.ts # Library API examples
|
|
372
|
+
│ └── toolbar-example.ts # Toolbar configuration examples
|
|
373
|
+
├── samples/
|
|
374
|
+
│ └── page_template.json # Sample page data
|
|
375
|
+
├── index.html # Editor HTML template
|
|
376
|
+
├── local-server.ts # Simple Bun dev server
|
|
377
|
+
├── index.ts # Main library exports
|
|
378
|
+
└── AGENTS.md # Architecture principles
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Development
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
# Run the editor
|
|
385
|
+
bun run dev
|
|
386
|
+
|
|
387
|
+
# Run examples
|
|
388
|
+
bun run examples/basic-usage.ts
|
|
389
|
+
bun run examples/toolbar-example.ts
|
|
390
|
+
|
|
391
|
+
# Build
|
|
392
|
+
bun build index.ts --outdir=dist
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## License
|
|
396
|
+
|
|
397
|
+
MIT
|
|
398
|
+
|
|
399
|
+
## Contributing
|
|
400
|
+
|
|
401
|
+
Contributions are welcome! Please read [AGENTS.md](./AGENTS.md) for architecture guidelines.
|
package/index.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditorTs - TypeScript library for HTML content editing with JSON representation
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import { Page } from 'editorts';
|
|
7
|
+
*
|
|
8
|
+
* // Load from JSON
|
|
9
|
+
* const page = new Page(jsonData);
|
|
10
|
+
*
|
|
11
|
+
* // Find and update components
|
|
12
|
+
* const header = page.components.findById('header');
|
|
13
|
+
* page.components.updateComponent('header', { style: 'color: red;' });
|
|
14
|
+
*
|
|
15
|
+
* // Manage styles
|
|
16
|
+
* page.styles.updateStyle('#header', { 'font-size': '2rem' });
|
|
17
|
+
*
|
|
18
|
+
* // Export back to JSON
|
|
19
|
+
* const json = page.toJSON();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Core exports
|
|
24
|
+
export { Page } from './src/core/Page';
|
|
25
|
+
export { ComponentManager } from './src/core/ComponentManager';
|
|
26
|
+
export { StyleManager } from './src/core/StyleManager';
|
|
27
|
+
export { AssetManager } from './src/core/AssetManager';
|
|
28
|
+
export { ToolbarManager } from './src/core/ToolbarManager';
|
|
29
|
+
export { init } from './src/core/init';
|
|
30
|
+
|
|
31
|
+
// Type exports
|
|
32
|
+
export type {
|
|
33
|
+
PageData,
|
|
34
|
+
PageBody,
|
|
35
|
+
Component,
|
|
36
|
+
Asset,
|
|
37
|
+
Style,
|
|
38
|
+
CSSProperties,
|
|
39
|
+
ComponentQuery,
|
|
40
|
+
StyleQuery,
|
|
41
|
+
UpdateOptions,
|
|
42
|
+
SelectorObject,
|
|
43
|
+
ParsedComponents,
|
|
44
|
+
ToolbarConfig,
|
|
45
|
+
ToolbarAction,
|
|
46
|
+
ToolbarRule,
|
|
47
|
+
ComponentSelector,
|
|
48
|
+
InitConfig,
|
|
49
|
+
ToolbarInitConfig,
|
|
50
|
+
EditorTsEditor,
|
|
51
|
+
} from './src/types';
|
|
52
|
+
|
|
53
|
+
// Utility exports
|
|
54
|
+
export {
|
|
55
|
+
deepClone,
|
|
56
|
+
generateId,
|
|
57
|
+
cssObjectToString,
|
|
58
|
+
cssStringToObject,
|
|
59
|
+
flattenComponents,
|
|
60
|
+
getComponentByPath,
|
|
61
|
+
sanitizeHTML,
|
|
62
|
+
extractComponentIds,
|
|
63
|
+
mergeCSSProperties,
|
|
64
|
+
isIdSelector,
|
|
65
|
+
isClassSelector,
|
|
66
|
+
parseSelector,
|
|
67
|
+
formatFileSize,
|
|
68
|
+
isValidURL,
|
|
69
|
+
extractDomain,
|
|
70
|
+
} from './src/utils/helpers';
|
|
71
|
+
|
|
72
|
+
// Toolbar exports
|
|
73
|
+
export {
|
|
74
|
+
defaultToolbarActions,
|
|
75
|
+
defaultToolbarConfig,
|
|
76
|
+
createToolbarConfig,
|
|
77
|
+
mergeToolbarConfigs,
|
|
78
|
+
getEnabledActions,
|
|
79
|
+
findToolbarAction,
|
|
80
|
+
toolbarPresets,
|
|
81
|
+
} from './src/utils/toolbar';
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "editor-ts",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TypeScript library for editing HTML content with JSON representation",
|
|
5
|
+
"module": "index.ts",
|
|
6
|
+
"main": "index.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"html",
|
|
10
|
+
"json",
|
|
11
|
+
"editor",
|
|
12
|
+
"page-builder",
|
|
13
|
+
"cms",
|
|
14
|
+
"typescript",
|
|
15
|
+
"web"
|
|
16
|
+
],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "bun run local-server.ts",
|
|
21
|
+
"server": "bun run server.ts",
|
|
22
|
+
"build": "bun build index.ts --outdir=dist",
|
|
23
|
+
"example": "bun run examples/basic-usage.ts",
|
|
24
|
+
"test": "bun run examples/basic-usage.ts",
|
|
25
|
+
"test:api": "bun run examples/test-api.ts"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/bun": "latest",
|
|
29
|
+
"playwright": "^1.57.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"typescript": "^5"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"src",
|
|
36
|
+
"index.ts",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"modern-monaco": "^0.3.6"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { PageBody, Asset } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Manager for handling assets
|
|
5
|
+
*/
|
|
6
|
+
export class AssetManager {
|
|
7
|
+
private body: PageBody;
|
|
8
|
+
private assets: Asset[];
|
|
9
|
+
|
|
10
|
+
constructor(body: PageBody) {
|
|
11
|
+
this.body = body;
|
|
12
|
+
this.assets = body.assets || [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Find assets by type
|
|
17
|
+
*/
|
|
18
|
+
findByType(type: Asset['type']): Asset[] {
|
|
19
|
+
return this.assets.filter((asset) => asset.type === type);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Find assets by source URL
|
|
24
|
+
*/
|
|
25
|
+
findBySource(src: string): Asset[] {
|
|
26
|
+
return this.assets.filter((asset) => asset.src === src || asset.src.includes(src));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find asset by exact source URL
|
|
31
|
+
*/
|
|
32
|
+
findByExactSource(src: string): Asset | null {
|
|
33
|
+
const asset = this.assets.find((asset) => asset.src === src);
|
|
34
|
+
return asset || null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Add a new asset
|
|
39
|
+
*/
|
|
40
|
+
addAsset(asset: Asset): void {
|
|
41
|
+
this.assets.push(asset);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Remove asset by source URL
|
|
46
|
+
*/
|
|
47
|
+
removeAsset(src: string): boolean {
|
|
48
|
+
const initialLength = this.assets.length;
|
|
49
|
+
this.assets = this.assets.filter((asset) => asset.src !== src);
|
|
50
|
+
return this.assets.length < initialLength;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Update an asset
|
|
55
|
+
*/
|
|
56
|
+
updateAsset(src: string, updates: Partial<Asset>): boolean {
|
|
57
|
+
const asset = this.assets.find((a) => a.src === src);
|
|
58
|
+
if (asset) {
|
|
59
|
+
Object.assign(asset, updates);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get all assets
|
|
67
|
+
*/
|
|
68
|
+
getAll(): Asset[] {
|
|
69
|
+
return this.assets;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get all image assets
|
|
74
|
+
*/
|
|
75
|
+
getImages(): Asset[] {
|
|
76
|
+
return this.findByType('image');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get all video assets
|
|
81
|
+
*/
|
|
82
|
+
getVideos(): Asset[] {
|
|
83
|
+
return this.findByType('video');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get all audio assets
|
|
88
|
+
*/
|
|
89
|
+
getAudio(): Asset[] {
|
|
90
|
+
return this.findByType('audio');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get all document assets
|
|
95
|
+
*/
|
|
96
|
+
getDocuments(): Asset[] {
|
|
97
|
+
return this.findByType('document');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get asset count
|
|
102
|
+
*/
|
|
103
|
+
count(): number {
|
|
104
|
+
return this.assets.length;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get assets from CDN
|
|
109
|
+
*/
|
|
110
|
+
getCDNAssets(): Asset[] {
|
|
111
|
+
return this.assets.filter((asset) => asset.blinkCDN === true);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Sync changes back to page body
|
|
116
|
+
*/
|
|
117
|
+
sync(): void {
|
|
118
|
+
this.body.assets = this.assets;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Replace all assets
|
|
123
|
+
*/
|
|
124
|
+
replaceAll(assets: Asset[]): void {
|
|
125
|
+
this.assets = assets;
|
|
126
|
+
}
|
|
127
|
+
}
|