webspresso 0.0.86 → 0.0.87

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
@@ -885,7 +885,7 @@ if (adminApi) {
885
885
  | `scripts` | External script URLs, script objects, or inline scripts injected into SSR Admin Panel (`registerScript`) |
886
886
  | `styles` | External stylesheet URLs or inline CSS injected into SSR Admin Panel (`registerStyle`) |
887
887
 
888
- Pages support JavaScript client components (`componentFile`, `pagesDir`, `component`) as well as **custom HTML & external URL pages** (`url` or `iframeUrl` for external web apps, and `html` or `htmlFile` for local HTML files like EUIX Engine apps). By default (`layout: true`), custom page views are automatically wrapped in the Admin Layout with Breadcrumbs. Set `layout: false` for full-screen / custom canvas pages.
888
+ Pages support JavaScript client components (`componentFile`, `pagesDir`, `component`), external URLs (`url` or `iframeUrl` inside `<iframe>`), as well as **native custom HTML pages** (`html` or `htmlFile` for local HTML files like EUIX Engine apps, Vue, or Alpine). HTML pages render directly in the page DOM with full Tailwind CSS styling, dark mode, and script execution without iframe overhead. Set `iframe: true` to isolate in an iframe if needed. By default (`layout: true`), custom page views are automatically wrapped in the Admin Layout with Breadcrumbs. Set `layout: false` for full-screen / custom canvas pages.
889
889
 
890
890
  **Example component file (`admin/reports.js`):**
891
891
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.86",
3
+ "version": "0.0.87",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -272,6 +272,7 @@ function registerPages(moduleId, pages, deps) {
272
272
  description: page.description,
273
273
  permission: page.permission,
274
274
  layout: page.layout !== undefined ? page.layout : true,
275
+ iframe: page.iframe,
275
276
  url: page.url || page.iframeUrl || undefined,
276
277
  html: htmlContent || undefined,
277
278
  });
@@ -479,6 +479,7 @@ class AdminRegistry {
479
479
  description: p.description,
480
480
  permission: p.permission,
481
481
  layout: p.layout !== undefined ? p.layout : true,
482
+ iframe: p.iframe,
482
483
  url: p.url || p.iframeUrl,
483
484
  html: p.html,
484
485
  hasClientComponent: this.clientComponents.has(p.id),
@@ -156,7 +156,7 @@ function generateCustomPageComponent() {
156
156
  return `
157
157
  // Custom Page Component Factory
158
158
  function createCustomPage(pageConfig) {
159
- if (pageConfig && (pageConfig.url || pageConfig.html)) {
159
+ if (pageConfig && (pageConfig.url || (pageConfig.html && pageConfig.iframe))) {
160
160
  var iframeAttrs = {
161
161
  src: pageConfig.url || undefined,
162
162
  srcdoc: pageConfig.html || undefined,
@@ -187,6 +187,46 @@ function createCustomPage(pageConfig) {
187
187
  };
188
188
  }
189
189
 
190
+ if (pageConfig && pageConfig.html) {
191
+ var executeScripts = function(vnode) {
192
+ if (!vnode.dom) return;
193
+ var scripts = vnode.dom.querySelectorAll('script');
194
+ scripts.forEach(function(oldScript) {
195
+ if (oldScript.dataset && oldScript.dataset.executed) return;
196
+ var newScript = document.createElement('script');
197
+ Array.from(oldScript.attributes).forEach(function(attr) {
198
+ newScript.setAttribute(attr.name, attr.value);
199
+ });
200
+ newScript.dataset.executed = 'true';
201
+ newScript.appendChild(document.createTextNode(oldScript.innerHTML));
202
+ oldScript.parentNode.replaceChild(newScript, oldScript);
203
+ });
204
+ };
205
+ if (pageConfig.layout === false) {
206
+ return {
207
+ oncreate: executeScripts,
208
+ view: function() {
209
+ return m('div.custom-html-container', m.trust(pageConfig.html));
210
+ }
211
+ };
212
+ }
213
+ return {
214
+ oncreate: executeScripts,
215
+ view: function() {
216
+ return m(Layout, [
217
+ m(Breadcrumb, { items: [{ label: pageConfig.title, href: pageConfig.path }] }),
218
+ m('div.mb-4.flex.items-start.justify-between.gap-4', [
219
+ m('div', [
220
+ m('h1.text-2xl.font-bold.text-gray-900.dark:text-slate-100', pageConfig.title),
221
+ pageConfig.description && m('p.text-gray-500.dark:text-slate-400.mt-1', pageConfig.description)
222
+ ])
223
+ ]),
224
+ m('div.custom-html-container', m.trust(pageConfig.html))
225
+ ]);
226
+ }
227
+ };
228
+ }
229
+
190
230
  return {
191
231
  oninit(vnode) {
192
232
  vnode.state.data = null;