active_canvas 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +318 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/active_canvas/editor/ai_panel.js +1607 -0
- data/app/assets/javascripts/active_canvas/editor/asset_manager.js +498 -0
- data/app/assets/javascripts/active_canvas/editor/blocks.js +1083 -0
- data/app/assets/javascripts/active_canvas/editor/code_panel.js +572 -0
- data/app/assets/javascripts/active_canvas/editor/component_toolbar.js +394 -0
- data/app/assets/javascripts/active_canvas/editor/panels.js +460 -0
- data/app/assets/javascripts/active_canvas/editor/utils.js +56 -0
- data/app/assets/javascripts/active_canvas/editor.js +295 -0
- data/app/assets/stylesheets/active_canvas/application.css +15 -0
- data/app/assets/stylesheets/active_canvas/editor.css +2929 -0
- data/app/controllers/active_canvas/admin/ai_controller.rb +181 -0
- data/app/controllers/active_canvas/admin/application_controller.rb +56 -0
- data/app/controllers/active_canvas/admin/media_controller.rb +61 -0
- data/app/controllers/active_canvas/admin/page_types_controller.rb +57 -0
- data/app/controllers/active_canvas/admin/page_versions_controller.rb +23 -0
- data/app/controllers/active_canvas/admin/pages_controller.rb +133 -0
- data/app/controllers/active_canvas/admin/partials_controller.rb +88 -0
- data/app/controllers/active_canvas/admin/settings_controller.rb +256 -0
- data/app/controllers/active_canvas/application_controller.rb +20 -0
- data/app/controllers/active_canvas/pages_controller.rb +18 -0
- data/app/controllers/concerns/active_canvas/current_user.rb +12 -0
- data/app/controllers/concerns/active_canvas/rate_limitable.rb +75 -0
- data/app/controllers/concerns/active_canvas/tailwind_compilation.rb +39 -0
- data/app/helpers/active_canvas/application_helper.rb +4 -0
- data/app/jobs/active_canvas/application_job.rb +4 -0
- data/app/jobs/active_canvas/compile_tailwind_job.rb +64 -0
- data/app/mailers/active_canvas/application_mailer.rb +6 -0
- data/app/models/active_canvas/ai_model.rb +136 -0
- data/app/models/active_canvas/application_record.rb +5 -0
- data/app/models/active_canvas/media.rb +141 -0
- data/app/models/active_canvas/page.rb +85 -0
- data/app/models/active_canvas/page_type.rb +22 -0
- data/app/models/active_canvas/page_version.rb +80 -0
- data/app/models/active_canvas/partial.rb +73 -0
- data/app/models/active_canvas/setting.rb +292 -0
- data/app/services/active_canvas/ai_configuration.rb +40 -0
- data/app/services/active_canvas/ai_models.rb +128 -0
- data/app/services/active_canvas/ai_service.rb +289 -0
- data/app/services/active_canvas/content_sanitizer.rb +112 -0
- data/app/services/active_canvas/tailwind_compiler.rb +156 -0
- data/app/views/active_canvas/admin/media/index.html.erb +401 -0
- data/app/views/active_canvas/admin/media/show.html.erb +297 -0
- data/app/views/active_canvas/admin/page_types/_form.html.erb +25 -0
- data/app/views/active_canvas/admin/page_types/edit.html.erb +13 -0
- data/app/views/active_canvas/admin/page_types/index.html.erb +29 -0
- data/app/views/active_canvas/admin/page_types/new.html.erb +9 -0
- data/app/views/active_canvas/admin/page_types/show.html.erb +18 -0
- data/app/views/active_canvas/admin/page_versions/show.html.erb +469 -0
- data/app/views/active_canvas/admin/pages/_form.html.erb +62 -0
- data/app/views/active_canvas/admin/pages/content.html.erb +139 -0
- data/app/views/active_canvas/admin/pages/edit.html.erb +335 -0
- data/app/views/active_canvas/admin/pages/editor.html.erb +710 -0
- data/app/views/active_canvas/admin/pages/index.html.erb +149 -0
- data/app/views/active_canvas/admin/pages/new.html.erb +19 -0
- data/app/views/active_canvas/admin/pages/show.html.erb +258 -0
- data/app/views/active_canvas/admin/pages/versions.html.erb +333 -0
- data/app/views/active_canvas/admin/partials/edit.html.erb +182 -0
- data/app/views/active_canvas/admin/partials/editor.html.erb +703 -0
- data/app/views/active_canvas/admin/partials/index.html.erb +131 -0
- data/app/views/active_canvas/admin/settings/show.html.erb +1864 -0
- data/app/views/active_canvas/pages/no_homepage.html.erb +45 -0
- data/app/views/active_canvas/pages/show.html.erb +113 -0
- data/app/views/layouts/active_canvas/admin/application.html.erb +960 -0
- data/app/views/layouts/active_canvas/admin/editor.html.erb +826 -0
- data/app/views/layouts/active_canvas/application.html.erb +55 -0
- data/config/routes.rb +48 -0
- data/db/migrate/20260202000001_create_active_canvas_tables.rb +113 -0
- data/db/migrate/20260202000002_create_active_canvas_ai_models.rb +26 -0
- data/lib/active_canvas/configuration.rb +232 -0
- data/lib/active_canvas/engine.rb +44 -0
- data/lib/active_canvas/version.rb +3 -0
- data/lib/active_canvas.rb +26 -0
- data/lib/generators/active_canvas/install/install_generator.rb +263 -0
- data/lib/generators/active_canvas/install/templates/initializer.rb.tt +163 -0
- data/lib/tasks/active_canvas_tasks.rake +69 -0
- metadata +150 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ActiveCanvas Visual Editor
|
|
3
|
+
*
|
|
4
|
+
* Main entry point that orchestrates all editor modules.
|
|
5
|
+
* Configuration is passed via window.ActiveCanvasEditor.config
|
|
6
|
+
*
|
|
7
|
+
* Module dependencies (loaded in order):
|
|
8
|
+
* - editor/utils.js - Utility functions
|
|
9
|
+
* - editor/blocks.js - Custom block definitions
|
|
10
|
+
* - editor/asset_manager.js - Asset manager modal
|
|
11
|
+
* - editor/code_panel.js - Monaco code editor
|
|
12
|
+
* - editor/component_toolbar.js - Component toolbar/menu
|
|
13
|
+
* - editor/panels.js - Panel controls, save, devices
|
|
14
|
+
* - editor.js - This file (main orchestrator)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
(function() {
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// Initialize namespace
|
|
21
|
+
window.ActiveCanvasEditor = window.ActiveCanvasEditor || {};
|
|
22
|
+
|
|
23
|
+
// Wait for DOM and config to be ready
|
|
24
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
25
|
+
if (!window.ActiveCanvasEditor || !window.ActiveCanvasEditor.config) {
|
|
26
|
+
console.error('ActiveCanvasEditor config not found');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const config = window.ActiveCanvasEditor.config;
|
|
31
|
+
initEditor(config);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the GrapeJS editor and all modules
|
|
36
|
+
* @param {Object} config - Editor configuration from Rails
|
|
37
|
+
*/
|
|
38
|
+
function initEditor(config) {
|
|
39
|
+
const csrfToken = window.ActiveCanvasEditor.getCsrfToken();
|
|
40
|
+
|
|
41
|
+
// Parse components JSON if available, otherwise use HTML content
|
|
42
|
+
let componentsToLoad = config.content || '';
|
|
43
|
+
if (config.contentComponents) {
|
|
44
|
+
try {
|
|
45
|
+
componentsToLoad = JSON.parse(config.contentComponents);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.warn('Could not parse components JSON, falling back to HTML content');
|
|
48
|
+
componentsToLoad = config.content || '';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Determine canvas configuration based on framework
|
|
53
|
+
const canvasConfig = buildCanvasConfig(config);
|
|
54
|
+
|
|
55
|
+
// Initialize GrapeJS
|
|
56
|
+
const editor = grapesjs.init({
|
|
57
|
+
container: '#gjs',
|
|
58
|
+
height: '100%',
|
|
59
|
+
width: 'auto',
|
|
60
|
+
fromElement: false,
|
|
61
|
+
|
|
62
|
+
// Load existing content
|
|
63
|
+
components: componentsToLoad,
|
|
64
|
+
style: config.contentCss || '',
|
|
65
|
+
|
|
66
|
+
// Storage - we'll handle saving manually
|
|
67
|
+
storageManager: false,
|
|
68
|
+
|
|
69
|
+
// Device Manager
|
|
70
|
+
deviceManager: {
|
|
71
|
+
devices: [
|
|
72
|
+
{ name: 'Desktop', width: '' },
|
|
73
|
+
{ name: 'Tablet', width: '768px', widthMedia: '992px' },
|
|
74
|
+
{ name: 'Mobile', width: '320px', widthMedia: '480px' }
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Panels - we'll use custom panels
|
|
79
|
+
panels: { defaults: [] },
|
|
80
|
+
|
|
81
|
+
// Block Manager
|
|
82
|
+
blockManager: {
|
|
83
|
+
appendTo: '#blocks-container'
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Layer Manager
|
|
87
|
+
layerManager: {
|
|
88
|
+
appendTo: '#layers-container'
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
// Style Manager
|
|
92
|
+
styleManager: {
|
|
93
|
+
appendTo: '#styles-container',
|
|
94
|
+
sectors: [
|
|
95
|
+
{
|
|
96
|
+
name: 'Dimension',
|
|
97
|
+
open: true,
|
|
98
|
+
buildProps: ['width', 'min-width', 'max-width', 'height', 'min-height', 'max-height', 'padding', 'margin']
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'Typography',
|
|
102
|
+
open: false,
|
|
103
|
+
buildProps: ['font-family', 'font-size', 'font-weight', 'letter-spacing', 'color', 'line-height', 'text-align', 'text-decoration', 'text-shadow']
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'Decorations',
|
|
107
|
+
open: false,
|
|
108
|
+
buildProps: ['background-color', 'border-radius', 'border', 'box-shadow']
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'Extra',
|
|
112
|
+
open: false,
|
|
113
|
+
buildProps: ['opacity', 'transition', 'transform']
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Trait Manager
|
|
119
|
+
traitManager: {
|
|
120
|
+
appendTo: '#traits-container'
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// Selector Manager
|
|
124
|
+
selectorManager: {
|
|
125
|
+
appendTo: '#styles-container',
|
|
126
|
+
componentFirst: true
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Asset Manager (basic config, custom modal handles most functionality)
|
|
130
|
+
assetManager: {
|
|
131
|
+
uploadName: 'media[file]',
|
|
132
|
+
uploadFile: createUploadHandler(config, csrfToken),
|
|
133
|
+
assets: []
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// Canvas
|
|
137
|
+
canvas: canvasConfig,
|
|
138
|
+
|
|
139
|
+
// Plugins
|
|
140
|
+
plugins: [
|
|
141
|
+
'gjs-blocks-basic',
|
|
142
|
+
'grapesjs-plugin-forms',
|
|
143
|
+
'grapesjs-preset-webpage',
|
|
144
|
+
'grapesjs-style-bg',
|
|
145
|
+
'grapesjs-tabs',
|
|
146
|
+
'grapesjs-custom-code',
|
|
147
|
+
'grapesjs-touch',
|
|
148
|
+
'grapesjs-parser-postcss',
|
|
149
|
+
'grapesjs-tooltip',
|
|
150
|
+
'grapesjs-typed'
|
|
151
|
+
],
|
|
152
|
+
|
|
153
|
+
pluginsOpts: {
|
|
154
|
+
'gjs-blocks-basic': {
|
|
155
|
+
flexGrid: true,
|
|
156
|
+
stylePrefix: 'gjs-'
|
|
157
|
+
},
|
|
158
|
+
'grapesjs-plugin-forms': {},
|
|
159
|
+
'grapesjs-preset-webpage': {
|
|
160
|
+
modalImportTitle: 'Import Template',
|
|
161
|
+
modalImportLabel: '<div style="margin-bottom: 10px; font-size: 13px;">Paste your HTML/CSS here</div>',
|
|
162
|
+
modalImportContent: function(editor) {
|
|
163
|
+
return editor.getHtml() + '<style>' + editor.getCss() + '</style>';
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
'grapesjs-tabs': {
|
|
167
|
+
tabsBlock: { category: 'Extra' }
|
|
168
|
+
},
|
|
169
|
+
'grapesjs-typed': {
|
|
170
|
+
block: {
|
|
171
|
+
category: 'Extra',
|
|
172
|
+
content: {
|
|
173
|
+
type: 'typed',
|
|
174
|
+
'type-speed': 40,
|
|
175
|
+
strings: ['Text row one', 'Text row two', 'Text row three']
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Setup all modules
|
|
183
|
+
setupModules(editor, config, csrfToken);
|
|
184
|
+
|
|
185
|
+
// Expose editor instance for debugging
|
|
186
|
+
window.ActiveCanvasEditor.instance = editor;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Build canvas configuration based on CSS framework
|
|
191
|
+
*/
|
|
192
|
+
function buildCanvasConfig(config) {
|
|
193
|
+
const canvasStyles = [];
|
|
194
|
+
const canvasScripts = [];
|
|
195
|
+
|
|
196
|
+
if (config.cssFrameworkUrl) {
|
|
197
|
+
if (config.cssFrameworkType === 'script') {
|
|
198
|
+
canvasScripts.push(config.cssFrameworkUrl);
|
|
199
|
+
} else if (config.cssFrameworkType === 'stylesheet') {
|
|
200
|
+
canvasStyles.push(config.cssFrameworkUrl);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
styles: canvasStyles,
|
|
206
|
+
scripts: canvasScripts
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Create the upload handler for the asset manager
|
|
212
|
+
*/
|
|
213
|
+
function createUploadHandler(config, csrfToken) {
|
|
214
|
+
const { showToast } = window.ActiveCanvasEditor;
|
|
215
|
+
|
|
216
|
+
return function(e) {
|
|
217
|
+
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files;
|
|
218
|
+
const formData = new FormData();
|
|
219
|
+
const editor = window.ActiveCanvasEditor.instance;
|
|
220
|
+
|
|
221
|
+
for (let i = 0; i < files.length; i++) {
|
|
222
|
+
formData.append('media[file]', files[i]);
|
|
223
|
+
formData.append('media[filename]', files[i].name);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
fetch(config.uploadUrl, {
|
|
227
|
+
method: 'POST',
|
|
228
|
+
headers: {
|
|
229
|
+
'X-CSRF-Token': csrfToken
|
|
230
|
+
},
|
|
231
|
+
body: formData
|
|
232
|
+
})
|
|
233
|
+
.then(response => response.json())
|
|
234
|
+
.then(result => {
|
|
235
|
+
if (result.src) {
|
|
236
|
+
editor.AssetManager.add(result);
|
|
237
|
+
showToast('Image uploaded successfully', 'success');
|
|
238
|
+
} else if (result.errors) {
|
|
239
|
+
showToast(result.errors.join(', '), 'error');
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
.catch(error => {
|
|
243
|
+
showToast('Upload failed', 'error');
|
|
244
|
+
console.error('Upload error:', error);
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Setup all editor modules
|
|
251
|
+
*/
|
|
252
|
+
function setupModules(editor, config, csrfToken) {
|
|
253
|
+
const AC = window.ActiveCanvasEditor;
|
|
254
|
+
|
|
255
|
+
// Add custom blocks (framework-specific based on config.cssFramework)
|
|
256
|
+
AC.addCustomBlocks(editor, config);
|
|
257
|
+
|
|
258
|
+
// Load existing assets
|
|
259
|
+
AC.loadAssets(editor, config.mediaUrl);
|
|
260
|
+
|
|
261
|
+
// Setup component toolbar and context menu
|
|
262
|
+
AC.setupComponentToolbar(editor);
|
|
263
|
+
|
|
264
|
+
// Inject global and page-specific CSS/JS into canvas
|
|
265
|
+
AC.setupCanvasInjection(editor, config);
|
|
266
|
+
|
|
267
|
+
// Setup panel controls
|
|
268
|
+
AC.setupPanelControls(editor);
|
|
269
|
+
|
|
270
|
+
// Setup device switching
|
|
271
|
+
AC.setupDeviceSwitching(editor);
|
|
272
|
+
|
|
273
|
+
// Setup undo/redo
|
|
274
|
+
AC.setupUndoRedo(editor);
|
|
275
|
+
|
|
276
|
+
// Setup code panel
|
|
277
|
+
AC.setupCodePanel(editor, config);
|
|
278
|
+
|
|
279
|
+
// Setup save functionality
|
|
280
|
+
AC.setupSave(editor, config, csrfToken);
|
|
281
|
+
|
|
282
|
+
// Setup add section button
|
|
283
|
+
AC.setupAddSection(editor);
|
|
284
|
+
|
|
285
|
+
// Setup RTE toolbar visibility
|
|
286
|
+
AC.setupRteToolbar(editor);
|
|
287
|
+
|
|
288
|
+
// Setup assets panel
|
|
289
|
+
AC.setupAssetsPanel(editor, config, csrfToken);
|
|
290
|
+
|
|
291
|
+
// Setup custom asset manager modal
|
|
292
|
+
AC.setupCustomAssetManager(editor, config, csrfToken);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
})();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
|
11
|
+
* It is generally better to create a new file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_tree .
|
|
14
|
+
*= require_self
|
|
15
|
+
*/
|