@genispace/geniapp 0.2.0 → 0.3.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.
- package/README.md +17 -1
- package/dist/workbench/runtime.d.ts +3 -0
- package/dist/workbench/styles.css +197 -0
- package/dist/workbench/types.d.ts +48 -0
- package/dist/workbench.d.ts +8 -0
- package/dist/workbench.js +356 -0
- package/dist/workbench.js.map +1 -0
- package/package.json +18 -12
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ frontend/ geniapp/ applications/
|
|
|
24
24
|
Install both public packages from npm. GeniApp releases pin their supported SDK version exactly, so applications should use the matching SDK version shown below.
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
pnpm add @genispace/geniapp@0.
|
|
27
|
+
pnpm add @genispace/geniapp@0.3.0 @genispace/sdk@3.1.0 react react-dom react-router-dom i18next react-i18next
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
## Public entries
|
|
@@ -42,6 +42,8 @@ pnpm add @genispace/geniapp@0.2.0 @genispace/sdk@3.1.0 react react-dom react-rou
|
|
|
42
42
|
| `@genispace/geniapp/dashboard` | stable | Dashboard filters, KPI and chart patterns |
|
|
43
43
|
| `@genispace/geniapp/case-workspace` | stable | Case workspace contract |
|
|
44
44
|
| `@genispace/geniapp/task-workspace` | stable | Task workspace contract |
|
|
45
|
+
| `@genispace/geniapp/workbench` | stable | Versioned renderer for GeniApps exported from Workbench |
|
|
46
|
+
| `@genispace/geniapp/workbench/styles.css` | stable | Responsive shell and component styles for exported Workbench apps |
|
|
45
47
|
|
|
46
48
|
Only symbols exported by these entries are public. Files below `src/` and `dist/` are implementation details and cannot be imported through package exports.
|
|
47
49
|
|
|
@@ -93,6 +95,20 @@ export default {
|
|
|
93
95
|
|
|
94
96
|
The stylesheet contains the platform light/dark semantic tokens, local fonts, responsive application layout rules and component CSS. Locale text remains owned by each application; shared components accept labels or use the host `react-i18next` provider.
|
|
95
97
|
|
|
98
|
+
### Workbench export runtime
|
|
99
|
+
|
|
100
|
+
Workbench exports pin an exact GeniApp version and keep each page and component in a separate source module. The public runtime renders that portable configuration without importing the private Workbench editor:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { mountWorkbench } from '@genispace/geniapp/workbench';
|
|
104
|
+
import '@genispace/geniapp/workbench/styles.css';
|
|
105
|
+
import workbenchConfig from './config/workbench.config';
|
|
106
|
+
|
|
107
|
+
mountWorkbench(document.getElementById('root')!, workbenchConfig);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The runtime owns portable component behavior, desktop/mobile navigation, the theme bridge and the locale bridge. Exported component modules own application-specific props, data and custom styles, so developers can edit or replace one component without reading a monolithic snapshot. The exported prebuilt bundle remains frozen to the same runtime version recorded in `contracts/workbench-export.lock.json`.
|
|
111
|
+
|
|
96
112
|
## Vite
|
|
97
113
|
|
|
98
114
|
```ts
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: light;
|
|
3
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
4
|
+
font-synthesis: none;
|
|
5
|
+
--background: 0 0% 98%;
|
|
6
|
+
--foreground: 0 0% 10%;
|
|
7
|
+
--card: 0 0% 100%;
|
|
8
|
+
--card-foreground: 0 0% 10%;
|
|
9
|
+
--muted: 0 0% 94%;
|
|
10
|
+
--muted-foreground: 0 0% 42%;
|
|
11
|
+
--accent: 0 0% 92%;
|
|
12
|
+
--accent-foreground: 0 0% 12%;
|
|
13
|
+
--border: 0 0% 88%;
|
|
14
|
+
--primary: 225 70% 52%;
|
|
15
|
+
--primary-foreground: 0 0% 100%;
|
|
16
|
+
--portable-accent: hsl(var(--primary));
|
|
17
|
+
--portable-accent-soft: hsl(225 70% 96%);
|
|
18
|
+
--portable-surface: hsl(var(--card));
|
|
19
|
+
--portable-line: hsl(var(--border));
|
|
20
|
+
--portable-muted: hsl(var(--muted-foreground));
|
|
21
|
+
--portable-radius: 14px;
|
|
22
|
+
color: hsl(var(--foreground));
|
|
23
|
+
background: hsl(var(--background));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:root.dark {
|
|
27
|
+
color-scheme: dark;
|
|
28
|
+
--background: 0 0% 4%;
|
|
29
|
+
--foreground: 0 0% 95%;
|
|
30
|
+
--card: 0 0% 8%;
|
|
31
|
+
--card-foreground: 0 0% 95%;
|
|
32
|
+
--muted: 0 0% 14%;
|
|
33
|
+
--muted-foreground: 0 0% 64%;
|
|
34
|
+
--accent: 0 0% 17%;
|
|
35
|
+
--accent-foreground: 0 0% 96%;
|
|
36
|
+
--border: 0 0% 20%;
|
|
37
|
+
--primary: 225 82% 66%;
|
|
38
|
+
--primary-foreground: 0 0% 100%;
|
|
39
|
+
--portable-accent-soft: hsl(225 30% 18%);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
* { box-sizing: border-box; }
|
|
43
|
+
html, body, #root { min-height: 100%; margin: 0; }
|
|
44
|
+
body { min-width: 320px; overflow-x: hidden; background: hsl(var(--background)); color: hsl(var(--foreground)); }
|
|
45
|
+
button, input, textarea { font: inherit; }
|
|
46
|
+
button { cursor: pointer; }
|
|
47
|
+
.portable-icon { width: 18px; height: 18px; flex: 0 0 auto; }
|
|
48
|
+
|
|
49
|
+
.portable-shell { min-height: 100vh; background: hsl(var(--background)); }
|
|
50
|
+
.portable-sidebar {
|
|
51
|
+
position: fixed; inset: 0 auto 0 0; z-index: 20; display: flex; width: 256px; flex-direction: column;
|
|
52
|
+
overflow: visible; border-right: 1px solid hsl(var(--border)); background: hsl(var(--muted));
|
|
53
|
+
transition: width 220ms ease, background 180ms ease, border-color 180ms ease;
|
|
54
|
+
}
|
|
55
|
+
.sidebar-collapsed .portable-sidebar { width: 80px; }
|
|
56
|
+
.portable-sidebar-header { display: flex; height: 69px; flex: 0 0 69px; align-items: center; padding: 0 16px; border-bottom: 1px solid hsl(var(--border)); }
|
|
57
|
+
.sidebar-collapsed .portable-sidebar-header { justify-content: center; padding: 0 8px; }
|
|
58
|
+
.portable-brand { display: flex; min-width: 0; align-items: center; gap: 10px; }
|
|
59
|
+
.portable-brand > span { display: grid; width: 36px; height: 36px; flex: 0 0 36px; place-items: center; border-radius: 12px; background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); font-weight: 750; box-shadow: 0 1px 3px rgb(0 0 0 / 0.12); }
|
|
60
|
+
.portable-brand > div { min-width: 0; }
|
|
61
|
+
.portable-brand strong, .portable-brand small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
62
|
+
.portable-brand strong { color: hsl(var(--foreground)); font-size: 14px; font-weight: 650; }
|
|
63
|
+
.portable-brand small { max-width: 175px; margin-top: 2px; color: hsl(var(--muted-foreground)); font-size: 10px; }
|
|
64
|
+
.portable-sidebar nav, .portable-mobile-drawer nav { display: grid; min-height: 0; flex: 1; align-content: start; gap: 4px; overflow-y: auto; padding: 12px; }
|
|
65
|
+
.portable-nav-item { display: flex; width: 100%; min-height: 44px; align-items: center; gap: 10px; padding: 8px 12px 8px calc(12px + var(--nav-depth, 0) * 14px); border: 0; border-radius: 12px; background: transparent; color: hsl(var(--foreground)); text-align: left; transition: color 150ms ease, background 150ms ease; }
|
|
66
|
+
.portable-nav-item span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; font-weight: 520; }
|
|
67
|
+
.portable-nav-item:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
|
|
68
|
+
.portable-nav-item.active { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); box-shadow: 0 1px 3px rgb(0 0 0 / 0.12); }
|
|
69
|
+
.sidebar-collapsed .portable-nav-item { width: 44px; justify-content: center; margin-inline: auto; padding: 0; }
|
|
70
|
+
.sidebar-collapsed .portable-nav-item span { display: none; }
|
|
71
|
+
.portable-sidebar footer, .portable-mobile-drawer footer { margin-top: auto; padding: 12px; border-top: 1px solid hsl(var(--border)); }
|
|
72
|
+
.portable-controls { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
|
|
73
|
+
.portable-controls button { display: flex; min-height: 40px; align-items: center; justify-content: center; gap: 7px; border: 1px solid hsl(var(--border)); border-radius: 10px; background: hsl(var(--background)); color: hsl(var(--muted-foreground)); }
|
|
74
|
+
.portable-controls button:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
|
|
75
|
+
.portable-controls button span { font-size: 11px; font-weight: 650; }
|
|
76
|
+
.sidebar-collapsed .portable-controls { grid-template-columns: 1fr; }
|
|
77
|
+
.sidebar-collapsed .portable-controls button span, .portable-controls.compact button span { display: none; }
|
|
78
|
+
.portable-controls.compact { display: flex; margin-left: auto; }
|
|
79
|
+
.portable-controls.compact button { width: 38px; min-height: 38px; }
|
|
80
|
+
.portable-collapse { position: absolute; z-index: 10; top: 69px; right: -12px; display: grid; width: 24px; height: 24px; place-items: center; transform: translateY(-50%); border: 1px solid hsl(var(--border)); border-radius: 999px; background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); box-shadow: 0 1px 4px rgb(0 0 0 / 0.1); }
|
|
81
|
+
.portable-collapse .portable-icon { width: 15px; height: 15px; }
|
|
82
|
+
.portable-content { min-width: 0; min-height: 100vh; padding-left: 256px; transition: padding-left 220ms ease; }
|
|
83
|
+
.sidebar-collapsed .portable-content { padding-left: 80px; }
|
|
84
|
+
.portable-mobile-header, .portable-mobile-nav { display: none; }
|
|
85
|
+
|
|
86
|
+
.portable-page { min-height: 100vh; padding: 30px clamp(18px, 3vw, 44px) 48px; background: hsl(var(--background)); color: hsl(var(--foreground)); transition: color 180ms ease, background 180ms ease; }
|
|
87
|
+
.portable-page-header { margin-bottom: 22px; }
|
|
88
|
+
.portable-page-header h1 { margin: 4px 0 5px; color: hsl(var(--foreground)); font-size: clamp(24px, 3vw, 34px); letter-spacing: -0.035em; }
|
|
89
|
+
.portable-page-header p { max-width: 760px; margin: 0; color: var(--portable-muted); line-height: 1.6; }
|
|
90
|
+
.portable-eyebrow { color: var(--portable-accent); font-size: 11px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; }
|
|
91
|
+
.portable-page-grid { display: grid; gap: 18px; }
|
|
92
|
+
.portable-page-grid.grid-24 { grid-template-columns: repeat(24, minmax(0, 1fr)); grid-auto-rows: minmax(48px, auto); align-items: stretch; }
|
|
93
|
+
.portable-placement { min-width: 0; }
|
|
94
|
+
.portable-component { height: 100%; overflow: hidden; padding: 20px; border: 1px solid var(--portable-line); border-radius: var(--portable-radius); background: var(--portable-surface); color: hsl(var(--card-foreground)); box-shadow: 0 5px 18px rgb(0 0 0 / 0.045); transition: color 180ms ease, background 180ms ease, border-color 180ms ease; }
|
|
95
|
+
.dark .portable-component { box-shadow: 0 8px 24px rgb(0 0 0 / 0.22); }
|
|
96
|
+
.portable-type-Typography, .portable-type-Text, .portable-type-Title, .portable-type-Paragraph { padding: 0; border: 0; background: transparent; box-shadow: none; }
|
|
97
|
+
.portable-typography { margin: 0; line-height: 1.55; }
|
|
98
|
+
.portable-typography-title, .portable-typography-h1, .portable-typography-h2 { letter-spacing: -0.03em; }
|
|
99
|
+
.portable-section-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
|
|
100
|
+
.portable-section-heading h2 { margin: 0; color: hsl(var(--card-foreground)); font-size: 17px; }
|
|
101
|
+
.portable-section-heading p { margin: 5px 0 0; color: var(--portable-muted); font-size: 13px; }
|
|
102
|
+
.portable-stat-grid { display: grid; grid-template-columns: repeat(var(--stat-columns), minmax(0, 1fr)); gap: 14px; }
|
|
103
|
+
.portable-stat { min-width: 0; padding: 17px; border: 1px solid var(--portable-line); border-radius: 12px; background: hsl(var(--background)); }
|
|
104
|
+
.portable-stat-title { color: var(--portable-muted); font-size: 12px; font-weight: 600; }
|
|
105
|
+
.portable-stat-value { margin-top: 9px; color: hsl(var(--foreground)); font-size: 27px; font-weight: 760; letter-spacing: -0.04em; }
|
|
106
|
+
.portable-stat-trend { margin-top: 7px; color: #07855b; font-size: 12px; font-weight: 700; }
|
|
107
|
+
.portable-stat-trend.down { color: #d64545; }
|
|
108
|
+
.portable-stat-trend span { color: var(--portable-muted); font-weight: 400; }
|
|
109
|
+
.portable-table-wrap { max-width: 100%; overflow: auto; }
|
|
110
|
+
.portable-table-wrap table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
111
|
+
.portable-table-wrap th { padding: 11px 13px; color: var(--portable-muted); background: hsl(var(--muted)); text-align: left; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
112
|
+
.portable-table-wrap td { padding: 13px; border-top: 1px solid var(--portable-line); color: hsl(var(--card-foreground)); white-space: nowrap; }
|
|
113
|
+
.portable-table-wrap tr:hover td { background: hsl(var(--accent)); }
|
|
114
|
+
.portable-grid-search { margin-bottom: 14px; }
|
|
115
|
+
.portable-grid-search input { width: min(100%, 360px); padding: 10px 12px; border: 1px solid var(--portable-line); border-radius: 9px; color: hsl(var(--foreground)); background: hsl(var(--background)); }
|
|
116
|
+
.portable-card-grid { display: grid; gap: 10px; }
|
|
117
|
+
.portable-card-grid article { padding: 15px; border: 1px solid var(--portable-line); border-radius: 11px; background: hsl(var(--background)); }
|
|
118
|
+
.portable-card-grid header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
119
|
+
.portable-card-grid header strong { color: hsl(var(--foreground)); font-size: 14px; }
|
|
120
|
+
.portable-card-grid header p { margin: 4px 0 0; color: var(--portable-muted); font-size: 12px; }
|
|
121
|
+
.portable-card-grid header > span { color: var(--portable-muted); font-size: 22px; line-height: 1; }
|
|
122
|
+
.portable-card-grid dl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 11px 18px; margin: 14px 0 0; padding-top: 13px; border-top: 1px solid var(--portable-line); }
|
|
123
|
+
.portable-card-grid dl > div { min-width: 0; }
|
|
124
|
+
.portable-card-grid dt { color: var(--portable-muted); font-size: 10px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
125
|
+
.portable-card-grid dd { display: flex; align-items: center; gap: 7px; margin: 5px 0 0; color: hsl(var(--card-foreground)); font-size: 12px; }
|
|
126
|
+
.portable-progress { width: 72px; height: 6px; overflow: hidden; border-radius: 999px; background: hsl(var(--muted)); }
|
|
127
|
+
.portable-progress > span { display: block; height: 100%; border-radius: inherit; background: var(--portable-accent); }
|
|
128
|
+
.portable-tag { display: inline-flex; padding: 3px 7px; border-radius: 999px; color: hsl(var(--primary)); background: var(--portable-accent-soft); font-size: 11px; font-weight: 700; }
|
|
129
|
+
.portable-chart { width: 100%; overflow: hidden; }
|
|
130
|
+
.portable-chart svg { display: block; width: 100%; max-height: 330px; }
|
|
131
|
+
.portable-chart text { fill: var(--portable-muted); font-size: 11px; }
|
|
132
|
+
.portable-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 15px; }
|
|
133
|
+
.portable-form label { display: grid; gap: 7px; color: var(--portable-muted); font-size: 12px; font-weight: 650; }
|
|
134
|
+
.portable-form input, .portable-form textarea { width: 100%; padding: 10px 12px; border: 1px solid var(--portable-line); border-radius: 9px; color: hsl(var(--foreground)); background: hsl(var(--background)); outline: 0; }
|
|
135
|
+
.portable-form input:focus, .portable-form textarea:focus { border-color: var(--portable-accent); box-shadow: 0 0 0 3px var(--portable-accent-soft); }
|
|
136
|
+
.portable-form textarea { min-height: 92px; resize: vertical; }
|
|
137
|
+
.portable-form button { align-self: end; min-height: 40px; padding: 0 18px; border: 0; border-radius: 9px; color: hsl(var(--primary-foreground)); background: var(--portable-accent); font-weight: 700; }
|
|
138
|
+
.portable-task-input { display: grid; gap: 14px; }
|
|
139
|
+
.portable-task-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
140
|
+
.portable-task-fields label { display: grid; gap: 6px; color: var(--portable-muted); font-size: 12px; font-weight: 650; }
|
|
141
|
+
.portable-task-fields input { min-width: 0; padding: 10px 12px; border: 1px solid var(--portable-line); border-radius: 9px; color: hsl(var(--foreground)); background: hsl(var(--background)); }
|
|
142
|
+
.portable-file-drop { display: grid; min-height: 150px; place-items: center; align-content: center; gap: 6px; padding: 22px; border: 1px dashed hsl(var(--primary) / 0.5); border-radius: 12px; background: var(--portable-accent-soft); text-align: center; }
|
|
143
|
+
.portable-file-drop input { position: absolute; width: 1px; height: 1px; opacity: 0; }
|
|
144
|
+
.portable-file-drop strong { font-size: 13px; }
|
|
145
|
+
.portable-file-drop small { color: var(--portable-muted); font-size: 11px; font-weight: 400; }
|
|
146
|
+
.portable-file-icon { display: grid; width: 34px; height: 34px; place-items: center; border-radius: 999px; color: hsl(var(--primary-foreground)); background: var(--portable-accent); font-size: 19px; }
|
|
147
|
+
.portable-file-list { display: grid; gap: 7px; }
|
|
148
|
+
.portable-file-list > div { display: flex; justify-content: space-between; gap: 12px; padding: 9px 11px; border: 1px solid var(--portable-line); border-radius: 8px; background: hsl(var(--background)); font-size: 12px; }
|
|
149
|
+
.portable-file-list small { color: var(--portable-muted); }
|
|
150
|
+
.portable-task-submit { justify-self: end; min-height: 40px; padding: 0 18px; border: 0; border-radius: 9px; color: hsl(var(--primary-foreground)); background: var(--portable-accent); font-weight: 700; }
|
|
151
|
+
.portable-list { display: grid; gap: 0; }
|
|
152
|
+
.portable-list article { padding: 13px 2px; border-top: 1px solid var(--portable-line); }
|
|
153
|
+
.portable-list article:first-child { border-top: 0; }
|
|
154
|
+
.portable-list strong { font-size: 13px; }
|
|
155
|
+
.portable-list p { margin: 5px 0 0; color: var(--portable-muted); font-size: 12px; line-height: 1.5; }
|
|
156
|
+
.portable-tab-list { display: flex; gap: 5px; margin: -7px -7px 18px; padding: 6px; overflow-x: auto; border-radius: 10px; background: hsl(var(--muted)); }
|
|
157
|
+
.portable-tab-list button { padding: 8px 13px; border: 0; border-radius: 7px; color: var(--portable-muted); background: transparent; font-size: 12px; font-weight: 650; white-space: nowrap; }
|
|
158
|
+
.portable-tab-list button.active { color: hsl(var(--primary)); background: hsl(var(--card)); box-shadow: 0 2px 7px rgb(0 0 0 / 0.08); }
|
|
159
|
+
.portable-tab-panel, .portable-container { display: grid; gap: 14px; }
|
|
160
|
+
.portable-empty, .portable-unsupported { padding: 24px; color: var(--portable-muted); text-align: center; }
|
|
161
|
+
.portable-unsupported { border: 1px dashed #f0a8a8; border-radius: 9px; color: #b83a3a; background: #fff5f5; }
|
|
162
|
+
|
|
163
|
+
.portable-mobile-backdrop, .portable-mobile-drawer { display: none; }
|
|
164
|
+
|
|
165
|
+
@media (max-width: 1023px) {
|
|
166
|
+
.portable-shell { display: flex; min-height: 100dvh; flex-direction: column; }
|
|
167
|
+
.portable-sidebar { display: none; }
|
|
168
|
+
.portable-content, .sidebar-collapsed .portable-content { min-height: 0; flex: 1; padding-left: 0; }
|
|
169
|
+
.portable-mobile-header { position: sticky; top: 0; z-index: 30; display: flex; min-height: 60px; flex: 0 0 60px; align-items: center; gap: 10px; padding: 8px 12px; border-bottom: 1px solid hsl(var(--border)); background: hsl(var(--background) / 0.96); backdrop-filter: blur(12px); }
|
|
170
|
+
.portable-mobile-header > button, .portable-mobile-drawer-close button { display: grid; width: 40px; height: 40px; flex: 0 0 40px; place-items: center; border: 1px solid hsl(var(--border)); border-radius: 12px; background: hsl(var(--card)); color: hsl(var(--foreground)); }
|
|
171
|
+
.portable-mobile-header .portable-brand { flex: 1; }
|
|
172
|
+
.portable-mobile-header .portable-brand > span { width: 34px; height: 34px; flex-basis: 34px; }
|
|
173
|
+
.portable-mobile-header .portable-brand small { display: none; }
|
|
174
|
+
.portable-mobile-header .portable-controls { flex: 0 0 auto; }
|
|
175
|
+
.portable-mobile-nav { position: sticky; z-index: 30; bottom: 0; display: flex; min-height: 70px; flex: 0 0 auto; align-items: stretch; padding: 7px 5px max(env(safe-area-inset-bottom, 0px), 10px); border-top: 1px solid hsl(var(--border)); background: hsl(var(--background) / 0.98); backdrop-filter: blur(12px); }
|
|
176
|
+
.portable-mobile-nav button { display: flex; min-width: 0; flex: 1; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 5px 2px; border: 0; background: transparent; color: hsl(var(--muted-foreground)); }
|
|
177
|
+
.portable-mobile-nav button.active { color: hsl(var(--primary)); }
|
|
178
|
+
.portable-mobile-nav button .portable-icon { width: 25px; height: 25px; }
|
|
179
|
+
.portable-mobile-nav button span { width: 100%; overflow: hidden; text-align: center; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; font-weight: 600; }
|
|
180
|
+
.portable-mobile-backdrop { position: fixed; inset: 0; z-index: 300; display: block; background: rgb(10 10 10 / 0.5); backdrop-filter: blur(3px); }
|
|
181
|
+
.portable-mobile-drawer { position: fixed; inset: 0 auto 0 0; z-index: 400; display: flex; width: min(304px, 88vw); flex-direction: column; overflow: hidden; border-right: 1px solid hsl(var(--border)); border-radius: 0 18px 18px 0; background: hsl(var(--background) / 0.98); box-shadow: 0 16px 50px rgb(0 0 0 / 0.25); backdrop-filter: blur(14px); }
|
|
182
|
+
.portable-mobile-drawer-close { display: flex; justify-content: flex-end; padding: 10px 12px; border-bottom: 1px solid hsl(var(--border)); }
|
|
183
|
+
.portable-mobile-drawer .portable-sidebar-header { background: hsl(var(--muted)); }
|
|
184
|
+
.portable-page-grid.grid-24 { grid-template-columns: 1fr; }
|
|
185
|
+
.portable-page-grid.grid-24 > .portable-placement { grid-column: 1 !important; grid-row: auto !important; }
|
|
186
|
+
.portable-stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@media (max-width: 560px) {
|
|
190
|
+
.portable-mobile-header { gap: 8px; padding-inline: 10px; }
|
|
191
|
+
.portable-mobile-header .portable-brand strong { max-width: 150px; }
|
|
192
|
+
.portable-page { min-height: 0; padding: 20px 14px 30px; }
|
|
193
|
+
.portable-page-header { margin-bottom: 16px; }
|
|
194
|
+
.portable-page-header h1 { font-size: 25px; }
|
|
195
|
+
.portable-stat-grid, .portable-form, .portable-task-fields, .portable-card-grid dl { grid-template-columns: 1fr; }
|
|
196
|
+
.portable-component { padding: 15px; border-radius: 12px; }
|
|
197
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export declare const PORTABLE_WORKBENCH_COMPONENT_TYPES: readonly ["Typography", "Text", "Title", "Paragraph", "Statistic", "StatisticGroup", "Table", "EditableTable", "AnalyticsTable", "DataGridCard", "Chart", "EChartsChart", "RadarChart", "Form", "TaskInput", "TaskInputRenderer", "List", "Tabs", "Container", "Card", "CustomContent", "FilterPanel"];
|
|
2
|
+
export type PortableWorkbenchComponentType = typeof PORTABLE_WORKBENCH_COMPONENT_TYPES[number];
|
|
3
|
+
export type WorkbenchNavigationItem = {
|
|
4
|
+
key?: string;
|
|
5
|
+
title?: string | Record<string, string>;
|
|
6
|
+
icon?: string;
|
|
7
|
+
linkedPage?: string;
|
|
8
|
+
children?: WorkbenchNavigationItem[];
|
|
9
|
+
visibility?: {
|
|
10
|
+
devices?: Array<'desktop' | 'mobile'>;
|
|
11
|
+
};
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
};
|
|
14
|
+
export type WorkbenchComponentConfig = {
|
|
15
|
+
id: string;
|
|
16
|
+
type: PortableWorkbenchComponentType | string;
|
|
17
|
+
props?: Record<string, unknown>;
|
|
18
|
+
components?: WorkbenchComponentConfig[];
|
|
19
|
+
children?: WorkbenchComponentConfig[];
|
|
20
|
+
customStyles?: Record<string, unknown>;
|
|
21
|
+
mockData?: unknown[];
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
export type WorkbenchPageConfig = {
|
|
25
|
+
title?: string | Record<string, string>;
|
|
26
|
+
description?: string | Record<string, string>;
|
|
27
|
+
layout?: Record<string, unknown>;
|
|
28
|
+
components?: WorkbenchComponentConfig[];
|
|
29
|
+
customStyles?: Record<string, unknown>;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
export type WorkbenchAppConfig = {
|
|
33
|
+
appId?: string;
|
|
34
|
+
name?: string | Record<string, string>;
|
|
35
|
+
description?: string | Record<string, string>;
|
|
36
|
+
defaultPage?: string;
|
|
37
|
+
navigation?: {
|
|
38
|
+
items?: WorkbenchNavigationItem[];
|
|
39
|
+
};
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
};
|
|
42
|
+
export type WorkbenchConfig = {
|
|
43
|
+
schemaVersion?: number;
|
|
44
|
+
appConfig?: WorkbenchAppConfig;
|
|
45
|
+
pages?: Record<string, WorkbenchPageConfig>;
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable compatibility runtime for GeniApps exported from Workbench.
|
|
3
|
+
*
|
|
4
|
+
* Applications should import only this public entry. The implementation is
|
|
5
|
+
* deliberately independent from the private Workbench editor and API source.
|
|
6
|
+
*/
|
|
7
|
+
export { mountWorkbench } from './workbench/runtime';
|
|
8
|
+
export { PORTABLE_WORKBENCH_COMPONENT_TYPES, type PortableWorkbenchComponentType, type WorkbenchAppConfig, type WorkbenchComponentConfig, type WorkbenchConfig, type WorkbenchNavigationItem, type WorkbenchPageConfig, } from './workbench/types';
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
function ce() {
|
|
2
|
+
const s = {
|
|
3
|
+
sourceConfig: null,
|
|
4
|
+
config: null,
|
|
5
|
+
root: null,
|
|
6
|
+
activePage: null,
|
|
7
|
+
activeTabs: /* @__PURE__ */ new Map(),
|
|
8
|
+
locale: "en",
|
|
9
|
+
theme: "light",
|
|
10
|
+
collapsed: !1,
|
|
11
|
+
mobileDrawerOpen: !1,
|
|
12
|
+
allowedShellOrigins: /* @__PURE__ */ new Set()
|
|
13
|
+
}, n = (e) => String(e ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"), C = (e) => String(e || "").toLowerCase().startsWith("zh") ? "zh" : "en", x = (e) => e === "dark" ? "dark" : "light", y = (e) => e && typeof e == "object" && !Array.isArray(e), q = (e) => JSON.parse(JSON.stringify(e)), L = (e, t) => ["key", "dataIndex", "id", "value", "name"].map((r) => e?.[r]).find((r) => r != null && String(r).trim() !== "") ?? `__index_${t}`, A = (e, t) => {
|
|
14
|
+
if (Array.isArray(e) && Array.isArray(t)) {
|
|
15
|
+
const r = new Map(t.map((a, o) => [String(L(a, o)), a]));
|
|
16
|
+
return e.map((a, o) => {
|
|
17
|
+
const l = r.get(String(L(a, o)));
|
|
18
|
+
return y(a) && y(l) ? A(a, l) : a;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (y(e) && y(t)) {
|
|
22
|
+
const r = { ...e };
|
|
23
|
+
return Object.entries(t).forEach(([a, o]) => {
|
|
24
|
+
o !== void 0 && (r[a] = A(r[a], o));
|
|
25
|
+
}), r;
|
|
26
|
+
}
|
|
27
|
+
return t === void 0 ? e : t;
|
|
28
|
+
}, k = (e, t) => {
|
|
29
|
+
const r = e?.id ? t?.[e.id] : null, a = r ? A(e, r) : { ...e };
|
|
30
|
+
return ["components", "children"].forEach((o) => {
|
|
31
|
+
Array.isArray(a[o]) && (a[o] = a[o].map((l) => k(l, t)));
|
|
32
|
+
}), Array.isArray(a.props?.components) && (a.props = { ...a.props, components: a.props.components.map((o) => k(o, t)) }), Array.isArray(a.props?.items) && (a.props = {
|
|
33
|
+
...a.props,
|
|
34
|
+
items: a.props.items.map((o) => ({
|
|
35
|
+
...o,
|
|
36
|
+
...o.component ? { component: k(o.component, t) } : {},
|
|
37
|
+
...Array.isArray(o.components) ? { components: o.components.map((l) => k(l, t)) } : {}
|
|
38
|
+
}))
|
|
39
|
+
}), a;
|
|
40
|
+
}, E = (e, t) => {
|
|
41
|
+
const r = q(e || {}), a = r.metadata?.locales?.[t];
|
|
42
|
+
return a && (a.appConfig && (r.appConfig = A(r.appConfig || {}, a.appConfig)), Object.entries(a.pages || {}).forEach(([o, l]) => {
|
|
43
|
+
const i = r.pages?.[o];
|
|
44
|
+
if (!i) return;
|
|
45
|
+
const p = { ...i };
|
|
46
|
+
l.title !== void 0 && (p.title = l.title), l.description !== void 0 && (p.description = l.description), Array.isArray(p.components) && (p.components = p.components.map((d) => k(d, l.components || {}))), r.pages[o] = p;
|
|
47
|
+
})), r;
|
|
48
|
+
}, B = () => s.sourceConfig?.metadata?.locales?.[s.locale]?.labels || {}, O = (e) => {
|
|
49
|
+
const t = String(e ?? ""), r = B();
|
|
50
|
+
return r[t] ? r[t] : Object.keys(r).sort((a, o) => o.length - a.length).reduce((a, o) => o && a.includes(o) ? a.split(o).join(r[o]) : a, t);
|
|
51
|
+
}, c = (e) => {
|
|
52
|
+
if (e == null) return "";
|
|
53
|
+
if (y(e)) {
|
|
54
|
+
const t = e[s.locale] ?? e.zh ?? e.en;
|
|
55
|
+
return t === void 0 || y(t) ? "" : O(t);
|
|
56
|
+
}
|
|
57
|
+
return O(e);
|
|
58
|
+
}, G = (e) => e.replace(/[A-Z]/g, (t) => `-${t.toLowerCase()}`), M = (e) => Object.entries(e || {}).filter(([, t]) => t != null && t !== "").map(([t, r]) => `${G(t)}:${String(r)}`).join(";"), H = (e) => {
|
|
59
|
+
const t = String(e || "");
|
|
60
|
+
return /@import|javascript:|expression\s*\(|url\s*\(\s*['"]?data:text\/html/i.test(t) ? "" : t;
|
|
61
|
+
}, N = (e, t) => {
|
|
62
|
+
const r = e?.customStyles || e?.props?.customStyles;
|
|
63
|
+
if (!r) return "";
|
|
64
|
+
const a = [];
|
|
65
|
+
Object.entries(r.childStyles || {}).forEach(([l, i]) => a.push(`${t} ${l}{${M(i)}}`)), Object.entries(r.stateStyles || {}).forEach(([l, i]) => {
|
|
66
|
+
const p = l.startsWith(":") ? l : `:${l}`;
|
|
67
|
+
a.push(`${t}${p}{${M(i)}}`);
|
|
68
|
+
});
|
|
69
|
+
const o = H(r.customCss);
|
|
70
|
+
return o && a.push(o.replaceAll("&", t)), a.length ? `<style>${a.join(`
|
|
71
|
+
`)}</style>` : "";
|
|
72
|
+
}, $ = (e, t = "portable-icon") => {
|
|
73
|
+
const a = {
|
|
74
|
+
LayoutDashboard: '<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>',
|
|
75
|
+
Activity: '<path d="M3 12h4l3-8 4 16 3-8h4"/>',
|
|
76
|
+
ClipboardList: '<rect x="5" y="4" width="14" height="17" rx="2"/><path d="M9 4V2h6v2M9 10h6M9 14h6M9 18h4"/>',
|
|
77
|
+
Menu: '<path d="M4 7h16M4 12h16M4 17h16"/>',
|
|
78
|
+
X: '<path d="m6 6 12 12M18 6 6 18"/>',
|
|
79
|
+
ChevronLeft: '<path d="m15 18-6-6 6-6"/>',
|
|
80
|
+
ChevronRight: '<path d="m9 18 6-6-6-6"/>',
|
|
81
|
+
Languages: '<path d="M4 5h7M7.5 3v2c0 4-2 7-5 9M5 9c1 2 3 4 6 5M13 20l4-9 4 9M14.5 17h5"/>',
|
|
82
|
+
Sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/>',
|
|
83
|
+
Moon: '<path d="M20 15.5A8.5 8.5 0 0 1 8.5 4 8.5 8.5 0 1 0 20 15.5Z"/>'
|
|
84
|
+
}[e] || '<circle cx="12" cy="12" r="8"/><path d="M9 12h6"/>';
|
|
85
|
+
return `<svg class="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${a}</svg>`;
|
|
86
|
+
}, I = (e, t) => {
|
|
87
|
+
if (e == null) return "—";
|
|
88
|
+
if (t?.render === "currency") {
|
|
89
|
+
const r = Number(e);
|
|
90
|
+
return Number.isFinite(r) ? new Intl.NumberFormat(s.locale === "zh" ? "zh-CN" : "en-US", { style: "currency", currency: "USD" }).format(r) : e;
|
|
91
|
+
}
|
|
92
|
+
return typeof e == "boolean" ? e ? "Yes" : "No" : Array.isArray(e) ? e.map(c).join(", ") : typeof e == "object" ? JSON.stringify(e) : c(e);
|
|
93
|
+
}, f = (e, t) => e ? `<div class="portable-section-heading"><div><h2>${n(c(e))}</h2>${t ? `<p>${n(c(t))}</p>` : ""}</div></div>` : "", W = (e) => {
|
|
94
|
+
const t = e.props || {}, r = t.content ?? t.text ?? t.children ?? t.title ?? "", a = String(t.variant || "paragraph").toLowerCase(), o = a === "title" || a.startsWith("h") ? a.match(/^h[1-6]$/)?.[0] || "h2" : "p";
|
|
95
|
+
return `<${o} class="portable-typography portable-typography-${n(a)}">${n(c(r))}</${o}>`;
|
|
96
|
+
}, U = (e) => {
|
|
97
|
+
const t = e.props || {}, r = t.items || e.mockData || [];
|
|
98
|
+
return `<div class="portable-stat-grid" style="--stat-columns:${Math.max(1, Math.min(6, Number(t.grid?.cols || t.columns || r.length || 1)))}">${r.map((o) => {
|
|
99
|
+
const l = o.trend, i = l?.type === "down" ? "down" : "up", p = l ? `${i === "down" ? "↓" : "↑"} ${l.value ?? ""}${l.suffix ?? ""}` : "";
|
|
100
|
+
return `<article class="portable-stat"><div class="portable-stat-title">${n(c(o.title || o.label))}</div><div class="portable-stat-value">${n(o.prefix || "")}${n(o.value)}${n(o.suffix || "")}</div>${l ? `<div class="portable-stat-trend ${i}">${n(p)} <span>${n(c(l.description || ""))}</span></div>` : ""}</article>`;
|
|
101
|
+
}).join("")}</div>`;
|
|
102
|
+
}, V = (e) => {
|
|
103
|
+
const t = e.props || {}, r = e.mockData || t.data || t.rows || [], a = t.columns?.length ? t.columns : Object.keys(r[0] || {}).map((o) => ({ key: o, dataIndex: o, title: o }));
|
|
104
|
+
return `${f(t.title, t.description)}<div class="portable-table-wrap"><table><thead><tr>${a.map((o) => `<th>${n(c(o.title || o.label || o.key))}</th>`).join("")}</tr></thead><tbody>${r.map((o) => `<tr>${a.map((l) => `<td>${n(I(o[l.dataIndex || l.key], l))}</td>`).join("")}</tr>`).join("")}</tbody></table>${r.length === 0 ? '<div class="portable-empty">No data</div>' : ""}</div>`;
|
|
105
|
+
}, K = (e) => {
|
|
106
|
+
const t = e.props || {}, r = e.mockData || t.mockData || t.data || t.rows || [], a = t.columns || [], o = a.find((d) => d.primary) || a[0], l = a.find((d) => d.secondary) || a[1], i = a.filter((d) => d !== o && d !== l), p = (d, h) => {
|
|
107
|
+
const w = d?.[h?.dataIndex || h?.key], b = h?.render?.text?.[w] ?? w;
|
|
108
|
+
if (h?.render?.type === "Progress") {
|
|
109
|
+
const g = Math.max(0, Math.min(100, Number(w) || 0));
|
|
110
|
+
return `<span class="portable-progress"><span style="width:${g}%"></span></span><small>${n(`${g}%`)}</small>`;
|
|
111
|
+
}
|
|
112
|
+
return h?.render?.type === "Tag" ? `<span class="portable-tag">${n(c(b))}</span>` : n(I(b, h));
|
|
113
|
+
};
|
|
114
|
+
return `${f(t.title, t.description)}${t.showSearch ? `<div class="portable-grid-search"><input type="search" placeholder="${n(c(t.searchPlaceholder || "Search..."))}" /></div>` : ""}<div class="portable-card-grid">${r.map((d) => `<article><header><div><strong>${o ? p(d, o) : ""}</strong>${l ? `<p>${p(d, l)}</p>` : ""}</div><span aria-hidden="true">›</span></header>${i.length ? `<dl>${i.map((h) => `<div><dt>${n(c(h.title || h.label || h.key))}</dt><dd>${p(d, h)}</dd></div>`).join("")}</dl>` : ""}</article>`).join("")}${r.length === 0 ? '<div class="portable-empty">No data</div>' : ""}</div>`;
|
|
115
|
+
}, J = (e) => Object.entries(e || {}).filter(([, t]) => typeof t == "number"), Z = (e) => {
|
|
116
|
+
const t = e.props || {}, r = e.mockData || t.data || [], a = r.map((b) => J(b)[0]?.[1] || 0), o = r.map((b, g) => c(Object.values(b).find((m) => typeof m == "string") || g + 1)), l = Math.max(...a, 1), i = 720, p = Math.max(180, Number(t.height || 260)), d = String(t.chartType || t.type || "bar").toLowerCase();
|
|
117
|
+
let h = "";
|
|
118
|
+
if (d.includes("line")) {
|
|
119
|
+
const b = a.map((g, m) => {
|
|
120
|
+
const v = a.length === 1 ? i / 2 : 24 + m * ((i - 48) / Math.max(1, a.length - 1)), ie = p - 36 - g / l * (p - 72);
|
|
121
|
+
return `${v},${ie}`;
|
|
122
|
+
}).join(" ");
|
|
123
|
+
h = `<polyline points="${b}" fill="none" stroke="var(--portable-accent)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>${b.split(" ").map((g) => {
|
|
124
|
+
const [m, v] = g.split(",");
|
|
125
|
+
return `<circle cx="${m}" cy="${v}" r="5" fill="var(--portable-surface)" stroke="var(--portable-accent)" stroke-width="3"/>`;
|
|
126
|
+
}).join("")}`;
|
|
127
|
+
} else {
|
|
128
|
+
const b = (i - 48) / Math.max(1, a.length);
|
|
129
|
+
h = a.map((g, m) => {
|
|
130
|
+
const v = g / l * (p - 72);
|
|
131
|
+
return `<rect x="${24 + m * b + b * 0.16}" y="${p - 36 - v}" width="${b * 0.68}" height="${v}" rx="5" fill="var(--portable-accent)" opacity="${0.7 + m % 3 * 0.12}"/>`;
|
|
132
|
+
}).join("");
|
|
133
|
+
}
|
|
134
|
+
const w = o.map((b, g) => `<text x="${a.length === 1 ? i / 2 : 24 + g * ((i - 48) / Math.max(1, a.length - 1))}" y="${p - 10}" text-anchor="middle">${n(b)}</text>`).join("");
|
|
135
|
+
return `${f(t.title, t.description)}<div class="portable-chart"><svg viewBox="0 0 ${i} ${p}" role="img" aria-label="${n(c(t.title || "Chart"))}">${h}${w}</svg></div>`;
|
|
136
|
+
}, D = (e) => {
|
|
137
|
+
const t = e.props || {}, r = t.fields || t.items || [];
|
|
138
|
+
return `${f(t.title, t.description)}<form class="portable-form" onsubmit="return false">${r.map((a) => {
|
|
139
|
+
const l = (a.type === "textarea" ? "textarea" : "input") === "textarea" ? `<textarea placeholder="${n(c(a.placeholder || ""))}">${n(c(a.defaultValue || ""))}</textarea>` : `<input type="${n(a.type === "number" ? "number" : "text")}" value="${n(c(a.defaultValue || ""))}" placeholder="${n(c(a.placeholder || ""))}"/>`;
|
|
140
|
+
return `<label><span>${n(c(a.label || a.title || a.name))}</span>${l}</label>`;
|
|
141
|
+
}).join("")}<button type="button">${n(c(t.submitButtonText || t.submitText || "Submit"))}</button></form>`;
|
|
142
|
+
}, Y = (e) => {
|
|
143
|
+
const t = e.props || {}, r = t.title || e.mockTitle, a = t.description || e.mockDescription, o = t.mockFileData?.files || e.mockFileData?.files || [], l = t.fields || e.parameterConfig?.fields || [];
|
|
144
|
+
return `${f(t.showTitle === !1 ? "" : r, t.showDescription === !1 ? "" : a)}<div class="portable-task-input">${l.length ? `<div class="portable-task-fields">${l.map((i) => `<label><span>${n(c(i.label || i.title || i.name))}</span><input type="text" placeholder="${n(c(i.placeholder || ""))}" /></label>`).join("")}</div>` : ""}<label class="portable-file-drop"><input type="file" multiple /><span class="portable-file-icon">↑</span><strong>${n(c(t.uploadText || "Choose files or drop them here"))}</strong><small>${n(c(t.uploadHint || "Files remain local in this portable preview"))}</small></label>${o.length ? `<div class="portable-file-list">${o.map((i) => `<div><span>${n(i.name || "File")}</span><small>${n(i.type || "")}</small></div>`).join("")}</div>` : ""}<button type="button" class="portable-task-submit">${n(c(t.submitButtonText || "Run task"))}</button></div>`;
|
|
145
|
+
}, X = (e) => {
|
|
146
|
+
const t = e.props || {}, r = e.mockData || t.items || [];
|
|
147
|
+
return `${f(t.title, t.description)}<div class="portable-list">${r.map((a) => {
|
|
148
|
+
const o = typeof a == "object" ? a.title || a.name || a.label || Object.values(a)[0] : a, l = typeof a == "object" ? a.description || a.subtitle || Object.values(a)[1] : "";
|
|
149
|
+
return `<article><strong>${n(c(o))}</strong>${l ? `<p>${n(c(l))}</p>` : ""}</article>`;
|
|
150
|
+
}).join("")}</div>`;
|
|
151
|
+
}, Q = (e) => {
|
|
152
|
+
const t = e.props || {}, r = t.items || t.tabs || [], a = s.activeTabs.get(e.id) || r[0]?.key || r[0]?.id, o = r.find((i) => (i.key || i.id) === a) || r[0], l = o?.components || (o?.component ? [o.component] : []);
|
|
153
|
+
return `<div class="portable-tabs" data-tabs="${n(e.id)}"><div class="portable-tab-list">${r.map((i) => `<button type="button" data-tab-key="${n(i.key || i.id)}" class="${(i.key || i.id) === a ? "active" : ""}">${n(c(i.title || i.label))}</button>`).join("")}</div><div class="portable-tab-panel">${l.map(T).join("") || n(c(o?.content || ""))}</div></div>`;
|
|
154
|
+
}, ee = (e) => {
|
|
155
|
+
const t = e.props || {}, r = e.components || e.children || t.components || t.children;
|
|
156
|
+
return Array.isArray(r) ? `<div class="portable-container">${r.map(T).join("")}</div>` : `${f(t.title, t.subtitle)}${t.content ? `<p>${n(c(t.content))}</p>` : ""}`;
|
|
157
|
+
}, te = (e) => {
|
|
158
|
+
const t = document.createElement("template");
|
|
159
|
+
return t.innerHTML = String(e || ""), t.content.querySelectorAll("script,iframe,object,embed,link,meta").forEach((r) => r.remove()), t.content.querySelectorAll("*").forEach((r) => {
|
|
160
|
+
[...r.attributes].forEach((a) => {
|
|
161
|
+
(/^on/i.test(a.name) || /javascript:/i.test(a.value)) && r.removeAttribute(a.name);
|
|
162
|
+
});
|
|
163
|
+
}), t.innerHTML;
|
|
164
|
+
};
|
|
165
|
+
function T(e) {
|
|
166
|
+
const t = e?.props || {}, r = `portable-component-${String(e?.id || "anonymous").replace(/[^a-zA-Z0-9_-]/g, "-")}`, a = e?.customStyles?.rootStyles || t.customStyles?.rootStyles || {};
|
|
167
|
+
let o;
|
|
168
|
+
switch (e?.type) {
|
|
169
|
+
case "Typography":
|
|
170
|
+
case "Text":
|
|
171
|
+
case "Title":
|
|
172
|
+
case "Paragraph":
|
|
173
|
+
o = W(e);
|
|
174
|
+
break;
|
|
175
|
+
case "Statistic":
|
|
176
|
+
case "StatisticGroup":
|
|
177
|
+
o = U(e);
|
|
178
|
+
break;
|
|
179
|
+
case "Table":
|
|
180
|
+
case "EditableTable":
|
|
181
|
+
case "AnalyticsTable":
|
|
182
|
+
o = V(e);
|
|
183
|
+
break;
|
|
184
|
+
case "DataGridCard":
|
|
185
|
+
o = K(e);
|
|
186
|
+
break;
|
|
187
|
+
case "Chart":
|
|
188
|
+
case "EChartsChart":
|
|
189
|
+
case "RadarChart":
|
|
190
|
+
o = Z(e);
|
|
191
|
+
break;
|
|
192
|
+
case "Form":
|
|
193
|
+
o = D(e);
|
|
194
|
+
break;
|
|
195
|
+
case "TaskInput":
|
|
196
|
+
case "TaskInputRenderer":
|
|
197
|
+
o = Y(e);
|
|
198
|
+
break;
|
|
199
|
+
case "List":
|
|
200
|
+
o = X(e);
|
|
201
|
+
break;
|
|
202
|
+
case "Tabs":
|
|
203
|
+
o = Q(e);
|
|
204
|
+
break;
|
|
205
|
+
case "Container":
|
|
206
|
+
case "Card":
|
|
207
|
+
o = ee(e);
|
|
208
|
+
break;
|
|
209
|
+
case "CustomContent":
|
|
210
|
+
o = te(t.html || t.content || "");
|
|
211
|
+
break;
|
|
212
|
+
case "FilterPanel":
|
|
213
|
+
o = D({ ...e, props: { ...t, submitText: t.submitText || "Apply filters" } });
|
|
214
|
+
break;
|
|
215
|
+
default:
|
|
216
|
+
o = `<div class="portable-unsupported">Unsupported component: ${n(e?.type)}</div>`;
|
|
217
|
+
}
|
|
218
|
+
return `${N(e, `.${r}`)}<section class="portable-component ${r} portable-type-${n(e?.type || "unknown")}" style="${n(M(a))}" data-component-id="${n(e?.id)}">${o}</section>`;
|
|
219
|
+
}
|
|
220
|
+
const z = (e, t) => !e?.visibility?.devices?.length || e.visibility.devices.includes(t), R = (e, t) => {
|
|
221
|
+
if (!z(e, t)) return null;
|
|
222
|
+
if (e.linkedPage) return e.linkedPage;
|
|
223
|
+
for (const r of e.children || []) {
|
|
224
|
+
const a = R(r, t);
|
|
225
|
+
if (a) return a;
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}, _ = (e, t, r = 0) => (e || []).flatMap((a) => z(a, t) ? (a.linkedPage ? [{ ...a, depth: r }] : []).concat(_(a.children, t, r + 1)) : []), ae = (e) => (e || []).flatMap((t) => {
|
|
229
|
+
const r = R(t, "mobile");
|
|
230
|
+
return r ? [{ ...t, linkedPage: r }] : [];
|
|
231
|
+
}), F = (e, t) => _(e, t).map((r) => `
|
|
232
|
+
<button type="button" data-page="${n(r.linkedPage)}" class="portable-nav-item ${r.linkedPage === s.activePage ? "active" : ""}" style="--nav-depth:${r.depth}">
|
|
233
|
+
${$(r.icon)}<span>${n(c(r.title || r.key))}</span>
|
|
234
|
+
</button>`).join(""), j = (e = !1) => `<div class="portable-controls ${e ? "compact" : ""}">
|
|
235
|
+
<button type="button" data-locale-toggle aria-label="Change language">${$("Languages")}<span>${s.locale === "zh" ? "EN" : "ZH"}</span></button>
|
|
236
|
+
<button type="button" data-theme-toggle aria-label="Change color theme">${$(s.theme === "dark" ? "Sun" : "Moon")}<span>${s.theme === "dark" ? "Light" : "Dark"}</span></button>
|
|
237
|
+
</div>`, P = (e = !1) => {
|
|
238
|
+
const t = s.config.appConfig || {};
|
|
239
|
+
return `<div class="portable-brand ${e ? "collapsed" : ""}"><span>${n(c(t.name || "G").slice(0, 1))}</span>${e ? "" : `<div><strong>${n(c(t.name || "GeniApp"))}</strong><small>${n(c(t.description || "Exported from Workbench"))}</small></div>`}</div>`;
|
|
240
|
+
}, re = () => {
|
|
241
|
+
const e = s.config.pages?.[s.activePage] || Object.values(s.config.pages || {})[0], t = s.activePage || Object.keys(s.config.pages || {})[0];
|
|
242
|
+
if (!e) return '<main class="portable-page"><div class="portable-empty">No pages were exported.</div></main>';
|
|
243
|
+
const r = `.portable-page-${String(t).replace(/[^a-zA-Z0-9_-]/g, "-")}`, a = e.customStyles?.rootStyles || {}, l = (e.layout?.type === "grid-24" ? e.layout.components || [] : []).reduce((p, d) => (d?.id && (p[d.id] = d), p), e.layout?.placements || {}), i = (e.components || []).map((p) => {
|
|
244
|
+
const d = l[p.id];
|
|
245
|
+
return `<div class="portable-placement" style="${d ? `grid-column:${Number(d.colStart || 0) + 1} / span ${Number(d.colSpan || 24)};grid-row:${Number(d.rowStart || 0) + 1} / span ${Number(d.rowSpan || 1)};` : ""}">${T(p)}</div>`;
|
|
246
|
+
}).join("");
|
|
247
|
+
return `${N(e, r)}<main class="portable-page ${r}" style="${n(M(a))}"><header class="portable-page-header"><div><span class="portable-eyebrow">${n(c(s.config.appConfig?.name || ""))}</span><h1>${n(c(e.title || t))}</h1>${e.description ? `<p>${n(c(e.description))}</p>` : ""}</div></header><div class="portable-page-grid ${e.layout?.type === "grid-24" ? "grid-24" : ""}">${i}</div></main>`;
|
|
248
|
+
}, S = () => {
|
|
249
|
+
document.documentElement.lang = s.locale === "zh" ? "zh-CN" : "en", document.documentElement.classList.toggle("dark", s.theme === "dark"), document.documentElement.dataset.colorMode = s.theme, document.documentElement.style.colorScheme = s.theme;
|
|
250
|
+
}, oe = (e) => {
|
|
251
|
+
s.locale = C(e), s.config = E(s.sourceConfig, s.locale);
|
|
252
|
+
try {
|
|
253
|
+
localStorage.setItem("language", s.locale);
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
S(), u();
|
|
257
|
+
}, se = (e) => {
|
|
258
|
+
s.theme = x(e);
|
|
259
|
+
try {
|
|
260
|
+
localStorage.setItem("theme", s.theme);
|
|
261
|
+
} catch {
|
|
262
|
+
}
|
|
263
|
+
S(), u();
|
|
264
|
+
}, ne = (e) => {
|
|
265
|
+
s.config.pages?.[e] && (s.activePage = e, s.mobileDrawerOpen = !1, decodeURIComponent(window.location.hash.replace(/^#/, "")) !== e && (window.location.hash = encodeURIComponent(e)), u());
|
|
266
|
+
}, le = () => {
|
|
267
|
+
window.addEventListener("message", (e) => {
|
|
268
|
+
const t = e.data;
|
|
269
|
+
if (!t || t.v !== 1 || typeof t != "object") return;
|
|
270
|
+
const r = e.origin.replace(/\/$/, "");
|
|
271
|
+
if (t.type === "GENISPACE_SHELL_INIT") {
|
|
272
|
+
const a = t.payload || {}, o = [a.shellOrigin, ...Array.isArray(a.allowedShellOrigins) ? a.allowedShellOrigins : []].filter(Boolean).map((l) => String(l).replace(/\/$/, ""));
|
|
273
|
+
if (o.length && !o.includes(r)) return;
|
|
274
|
+
s.allowedShellOrigins = new Set(o.length ? o : [r]), a.locale && (s.locale = C(a.locale)), a.theme && (s.theme = x(a.theme)), s.config = E(s.sourceConfig, s.locale), S(), u(), window.parent.postMessage({ type: "GENISPACE_IFRAME_READY", v: 1, identifier: s.config.appConfig?.appId || "" }, e.origin);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
t.type === "GENISPACE_SHELL_UI" && s.allowedShellOrigins.has(r) && (t.locale && (s.locale = C(t.locale)), t.theme && (s.theme = x(t.theme)), s.config = E(s.sourceConfig, s.locale), S(), u());
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
function u() {
|
|
281
|
+
const e = s.root;
|
|
282
|
+
if (!e || !s.config) return;
|
|
283
|
+
const t = s.config.appConfig?.navigation?.items || [], r = ae(t);
|
|
284
|
+
e.innerHTML = `<div class="portable-shell ${s.collapsed ? "sidebar-collapsed" : ""}">
|
|
285
|
+
<aside class="portable-sidebar">
|
|
286
|
+
<div class="portable-sidebar-header">${P(s.collapsed)}</div>
|
|
287
|
+
<button type="button" class="portable-collapse" data-collapse aria-label="${s.collapsed ? "Expand sidebar" : "Collapse sidebar"}">${$(s.collapsed ? "ChevronRight" : "ChevronLeft")}</button>
|
|
288
|
+
<nav aria-label="Application navigation">${F(t, "desktop")}</nav>
|
|
289
|
+
<footer>${j(s.collapsed)}</footer>
|
|
290
|
+
</aside>
|
|
291
|
+
<header class="portable-mobile-header"><button type="button" data-mobile-drawer aria-label="Open navigation">${$("Menu")}</button>${P(!1)}${j(!0)}</header>
|
|
292
|
+
${s.mobileDrawerOpen ? `<div class="portable-mobile-backdrop" data-mobile-close></div><aside class="portable-mobile-drawer"><div class="portable-mobile-drawer-close"><button type="button" data-mobile-close aria-label="Close navigation">${$("X")}</button></div><div class="portable-sidebar-header">${P(!1)}</div><nav>${F(t, "mobile")}</nav><footer>${j(!1)}</footer></aside>` : ""}
|
|
293
|
+
<div class="portable-content">${re()}</div>
|
|
294
|
+
<nav class="portable-mobile-nav" aria-label="Workbench bottom navigation">${r.map((a) => `<button type="button" data-page="${n(a.linkedPage)}" class="${a.linkedPage === s.activePage ? "active" : ""}" aria-current="${a.linkedPage === s.activePage ? "page" : "false"}">${$(a.icon)}<span>${n(c(a.title || a.key))}</span></button>`).join("")}</nav>
|
|
295
|
+
</div>`, e.querySelectorAll("[data-page]").forEach((a) => a.addEventListener("click", () => ne(a.dataset.page))), e.querySelectorAll("[data-tabs] [data-tab-key]").forEach((a) => a.addEventListener("click", () => {
|
|
296
|
+
const o = a.closest("[data-tabs]");
|
|
297
|
+
s.activeTabs.set(o.dataset.tabs, a.dataset.tabKey), u();
|
|
298
|
+
})), e.querySelectorAll("[data-locale-toggle]").forEach((a) => a.addEventListener("click", () => oe(s.locale === "zh" ? "en" : "zh"))), e.querySelectorAll("[data-theme-toggle]").forEach((a) => a.addEventListener("click", () => se(s.theme === "dark" ? "light" : "dark"))), e.querySelector("[data-collapse]")?.addEventListener("click", () => {
|
|
299
|
+
s.collapsed = !s.collapsed;
|
|
300
|
+
try {
|
|
301
|
+
localStorage.setItem("portable_sidebar_collapsed", JSON.stringify(s.collapsed));
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
u();
|
|
305
|
+
}), e.querySelector("[data-mobile-drawer]")?.addEventListener("click", () => {
|
|
306
|
+
s.mobileDrawerOpen = !0, u();
|
|
307
|
+
}), e.querySelectorAll("[data-mobile-close]").forEach((a) => a.addEventListener("click", () => {
|
|
308
|
+
s.mobileDrawerOpen = !1, u();
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
return { mountWorkbench: (e, t) => {
|
|
312
|
+
if (!e) throw new Error("A root element is required.");
|
|
313
|
+
s.root = e, s.sourceConfig = t || {};
|
|
314
|
+
const r = new URLSearchParams(window.location.search);
|
|
315
|
+
let a = "", o = "", l = !1;
|
|
316
|
+
try {
|
|
317
|
+
a = localStorage.getItem("language") || "", o = localStorage.getItem("theme") || "", l = JSON.parse(localStorage.getItem("portable_sidebar_collapsed") || "false");
|
|
318
|
+
} catch {
|
|
319
|
+
}
|
|
320
|
+
s.locale = C(r.get("lng") || a || document.documentElement.lang || "en"), s.theme = x(r.get("theme") || o || (window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light")), s.collapsed = !!l, s.config = E(s.sourceConfig, s.locale);
|
|
321
|
+
const i = decodeURIComponent(window.location.hash.replace(/^#/, ""));
|
|
322
|
+
s.activePage = s.config.pages?.[i] ? i : s.config.appConfig?.defaultPage || Object.keys(s.config.pages || {})[0], s.allowedShellOrigins.add(window.location.origin.replace(/\/$/, "")), S(), le(), window.addEventListener("hashchange", () => {
|
|
323
|
+
const p = decodeURIComponent(window.location.hash.replace(/^#/, ""));
|
|
324
|
+
s.config.pages?.[p] && p !== s.activePage && (s.activePage = p, u());
|
|
325
|
+
}), u(), window.parent !== window && window.parent.postMessage({ type: "GENIAPP_READY", app: s.config.appConfig?.appId || "" }, "*");
|
|
326
|
+
} };
|
|
327
|
+
}
|
|
328
|
+
const pe = ce(), he = pe.mountWorkbench, be = [
|
|
329
|
+
"Typography",
|
|
330
|
+
"Text",
|
|
331
|
+
"Title",
|
|
332
|
+
"Paragraph",
|
|
333
|
+
"Statistic",
|
|
334
|
+
"StatisticGroup",
|
|
335
|
+
"Table",
|
|
336
|
+
"EditableTable",
|
|
337
|
+
"AnalyticsTable",
|
|
338
|
+
"DataGridCard",
|
|
339
|
+
"Chart",
|
|
340
|
+
"EChartsChart",
|
|
341
|
+
"RadarChart",
|
|
342
|
+
"Form",
|
|
343
|
+
"TaskInput",
|
|
344
|
+
"TaskInputRenderer",
|
|
345
|
+
"List",
|
|
346
|
+
"Tabs",
|
|
347
|
+
"Container",
|
|
348
|
+
"Card",
|
|
349
|
+
"CustomContent",
|
|
350
|
+
"FilterPanel"
|
|
351
|
+
];
|
|
352
|
+
export {
|
|
353
|
+
be as PORTABLE_WORKBENCH_COMPONENT_TYPES,
|
|
354
|
+
he as mountWorkbench
|
|
355
|
+
};
|
|
356
|
+
//# sourceMappingURL=workbench.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workbench.js","sources":["../src/workbench/runtime.ts","../src/workbench/types.ts"],"sourcesContent":["// @ts-nocheck -- The runtime intentionally accepts forward-compatible Workbench JSON.\nimport type { WorkbenchConfig } from './types';\n\nfunction createPortableRuntime() {\n const state = {\n sourceConfig: null,\n config: null,\n root: null,\n activePage: null,\n activeTabs: new Map(),\n locale: 'en',\n theme: 'light',\n collapsed: false,\n mobileDrawerOpen: false,\n allowedShellOrigins: new Set(),\n };\n\n const escapeHtml = (value) => String(value ?? '')\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n const normalizeLocale = (value) => String(value || '').toLowerCase().startsWith('zh') ? 'zh' : 'en';\n const normalizeTheme = (value) => value === 'dark' ? 'dark' : 'light';\n const isPlainObject = (value) => value && typeof value === 'object' && !Array.isArray(value);\n const clone = (value) => JSON.parse(JSON.stringify(value));\n const itemKey = (item, index) => ['key', 'dataIndex', 'id', 'value', 'name']\n .map((key) => item?.[key])\n .find((value) => value !== undefined && value !== null && String(value).trim() !== '') ?? `__index_${index}`;\n\n const mergeLocaleValue = (base, patch) => {\n if (Array.isArray(base) && Array.isArray(patch)) {\n const patches = new Map(patch.map((item, index) => [String(itemKey(item, index)), item]));\n return base.map((item, index) => {\n const match = patches.get(String(itemKey(item, index)));\n return isPlainObject(item) && isPlainObject(match) ? mergeLocaleValue(item, match) : item;\n });\n }\n if (isPlainObject(base) && isPlainObject(patch)) {\n const result = { ...base };\n Object.entries(patch).forEach(([key, value]) => {\n if (value !== undefined) result[key] = mergeLocaleValue(result[key], value);\n });\n return result;\n }\n return patch === undefined ? base : patch;\n };\n\n const localizeComponentTree = (component, patches) => {\n const ownPatch = component?.id ? patches?.[component.id] : null;\n const result = ownPatch ? mergeLocaleValue(component, ownPatch) : { ...component };\n ['components', 'children'].forEach((key) => {\n if (Array.isArray(result[key])) result[key] = result[key].map((child) => localizeComponentTree(child, patches));\n });\n if (Array.isArray(result.props?.components)) {\n result.props = { ...result.props, components: result.props.components.map((child) => localizeComponentTree(child, patches)) };\n }\n if (Array.isArray(result.props?.items)) {\n result.props = {\n ...result.props,\n items: result.props.items.map((item) => ({\n ...item,\n ...(item.component ? { component: localizeComponentTree(item.component, patches) } : {}),\n ...(Array.isArray(item.components) ? { components: item.components.map((child) => localizeComponentTree(child, patches)) } : {}),\n })),\n };\n }\n return result;\n };\n\n const applyLocale = (config, locale) => {\n const result = clone(config || {});\n const localePatch = result.metadata?.locales?.[locale];\n if (!localePatch) return result;\n if (localePatch.appConfig) result.appConfig = mergeLocaleValue(result.appConfig || {}, localePatch.appConfig);\n Object.entries(localePatch.pages || {}).forEach(([pageId, patch]) => {\n const page = result.pages?.[pageId];\n if (!page) return;\n const localized = { ...page };\n if (patch.title !== undefined) localized.title = patch.title;\n if (patch.description !== undefined) localized.description = patch.description;\n if (Array.isArray(localized.components)) {\n localized.components = localized.components.map((component) => localizeComponentTree(component, patch.components || {}));\n }\n result.pages[pageId] = localized;\n });\n return result;\n };\n\n const labelMap = () => state.sourceConfig?.metadata?.locales?.[state.locale]?.labels || {};\n const localizeLabel = (value) => {\n const raw = String(value ?? '');\n const labels = labelMap();\n if (labels[raw]) return labels[raw];\n return Object.keys(labels).sort((left, right) => right.length - left.length)\n .reduce((result, key) => key && result.includes(key) ? result.split(key).join(labels[key]) : result, raw);\n };\n const textValue = (value) => {\n if (value === null || value === undefined) return '';\n if (isPlainObject(value)) {\n const picked = value[state.locale] ?? value.zh ?? value.en;\n return picked === undefined || isPlainObject(picked) ? '' : localizeLabel(picked);\n }\n return localizeLabel(value);\n };\n\n const toKebab = (value) => value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n const styleText = (styles) => Object.entries(styles || {})\n .filter(([, value]) => value !== null && value !== undefined && value !== '')\n .map(([key, value]) => `${toKebab(key)}:${String(value)}`)\n .join(';');\n const safeCustomCss = (css) => {\n const source = String(css || '');\n if (/@import|javascript:|expression\\s*\\(|url\\s*\\(\\s*['\"]?data:text\\/html/i.test(source)) return '';\n return source;\n };\n const customStyleTag = (entity, scope) => {\n const customStyles = entity?.customStyles || entity?.props?.customStyles;\n if (!customStyles) return '';\n const rules = [];\n Object.entries(customStyles.childStyles || {}).forEach(([selector, styles]) => rules.push(`${scope} ${selector}{${styleText(styles)}}`));\n Object.entries(customStyles.stateStyles || {}).forEach(([selector, styles]) => {\n const normalized = selector.startsWith(':') ? selector : `:${selector}`;\n rules.push(`${scope}${normalized}{${styleText(styles)}}`);\n });\n const customCss = safeCustomCss(customStyles.customCss);\n if (customCss) rules.push(customCss.replaceAll('&', scope));\n return rules.length ? `<style>${rules.join('\\n')}</style>` : '';\n };\n\n const iconSvg = (name, className = 'portable-icon') => {\n const paths = {\n LayoutDashboard: '<rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"/>',\n Activity: '<path d=\"M3 12h4l3-8 4 16 3-8h4\"/>',\n ClipboardList: '<rect x=\"5\" y=\"4\" width=\"14\" height=\"17\" rx=\"2\"/><path d=\"M9 4V2h6v2M9 10h6M9 14h6M9 18h4\"/>',\n Menu: '<path d=\"M4 7h16M4 12h16M4 17h16\"/>',\n X: '<path d=\"m6 6 12 12M18 6 6 18\"/>',\n ChevronLeft: '<path d=\"m15 18-6-6 6-6\"/>',\n ChevronRight: '<path d=\"m9 18 6-6-6-6\"/>',\n Languages: '<path d=\"M4 5h7M7.5 3v2c0 4-2 7-5 9M5 9c1 2 3 4 6 5M13 20l4-9 4 9M14.5 17h5\"/>',\n Sun: '<circle cx=\"12\" cy=\"12\" r=\"4\"/><path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\"/>',\n Moon: '<path d=\"M20 15.5A8.5 8.5 0 0 1 8.5 4 8.5 8.5 0 1 0 20 15.5Z\"/>',\n };\n const body = paths[name] || '<circle cx=\"12\" cy=\"12\" r=\"8\"/><path d=\"M9 12h6\"/>';\n return `<svg class=\"${className}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${body}</svg>`;\n };\n\n const formatValue = (value, column) => {\n if (value === null || value === undefined) return '—';\n if (column?.render === 'currency') {\n const number = Number(value);\n return Number.isFinite(number) ? new Intl.NumberFormat(state.locale === 'zh' ? 'zh-CN' : 'en-US', { style: 'currency', currency: 'USD' }).format(number) : value;\n }\n if (typeof value === 'boolean') return value ? 'Yes' : 'No';\n if (Array.isArray(value)) return value.map(textValue).join(', ');\n if (typeof value === 'object') return JSON.stringify(value);\n return textValue(value);\n };\n const titleBlock = (title, subtitle) => title\n ? `<div class=\"portable-section-heading\"><div><h2>${escapeHtml(textValue(title))}</h2>${subtitle ? `<p>${escapeHtml(textValue(subtitle))}</p>` : ''}</div></div>`\n : '';\n const renderTypography = (component) => {\n const props = component.props || {};\n const text = props.content ?? props.text ?? props.children ?? props.title ?? '';\n const variant = String(props.variant || 'paragraph').toLowerCase();\n const tag = variant === 'title' || variant.startsWith('h') ? (variant.match(/^h[1-6]$/)?.[0] || 'h2') : 'p';\n return `<${tag} class=\"portable-typography portable-typography-${escapeHtml(variant)}\">${escapeHtml(textValue(text))}</${tag}>`;\n };\n const renderStatistics = (component) => {\n const props = component.props || {};\n const items = props.items || component.mockData || [];\n const columns = Math.max(1, Math.min(6, Number(props.grid?.cols || props.columns || items.length || 1)));\n return `<div class=\"portable-stat-grid\" style=\"--stat-columns:${columns}\">${items.map((item) => {\n const trend = item.trend;\n const direction = trend?.type === 'down' ? 'down' : 'up';\n const trendText = trend ? `${direction === 'down' ? '↓' : '↑'} ${trend.value ?? ''}${trend.suffix ?? ''}` : '';\n return `<article class=\"portable-stat\"><div class=\"portable-stat-title\">${escapeHtml(textValue(item.title || item.label))}</div><div class=\"portable-stat-value\">${escapeHtml(item.prefix || '')}${escapeHtml(item.value)}${escapeHtml(item.suffix || '')}</div>${trend ? `<div class=\"portable-stat-trend ${direction}\">${escapeHtml(trendText)} <span>${escapeHtml(textValue(trend.description || ''))}</span></div>` : ''}</article>`;\n }).join('')}</div>`;\n };\n const renderTable = (component) => {\n const props = component.props || {};\n const rows = component.mockData || props.data || props.rows || [];\n const columns = props.columns?.length ? props.columns : Object.keys(rows[0] || {}).map((key) => ({ key, dataIndex: key, title: key }));\n return `${titleBlock(props.title, props.description)}<div class=\"portable-table-wrap\"><table><thead><tr>${columns.map((column) => `<th>${escapeHtml(textValue(column.title || column.label || column.key))}</th>`).join('')}</tr></thead><tbody>${rows.map((row) => `<tr>${columns.map((column) => `<td>${escapeHtml(formatValue(row[column.dataIndex || column.key], column))}</td>`).join('')}</tr>`).join('')}</tbody></table>${rows.length === 0 ? '<div class=\"portable-empty\">No data</div>' : ''}</div>`;\n };\n const renderDataGridCard = (component) => {\n const props = component.props || {};\n const rows = component.mockData || props.mockData || props.data || props.rows || [];\n const columns = props.columns || [];\n const primary = columns.find((column) => column.primary) || columns[0];\n const secondary = columns.find((column) => column.secondary) || columns[1];\n const details = columns.filter((column) => column !== primary && column !== secondary);\n const gridValue = (row, column) => {\n const value = row?.[column?.dataIndex || column?.key];\n const mapped = column?.render?.text?.[value] ?? value;\n if (column?.render?.type === 'Progress') {\n const progress = Math.max(0, Math.min(100, Number(value) || 0));\n return `<span class=\"portable-progress\"><span style=\"width:${progress}%\"></span></span><small>${escapeHtml(`${progress}%`)}</small>`;\n }\n if (column?.render?.type === 'Tag') {\n return `<span class=\"portable-tag\">${escapeHtml(textValue(mapped))}</span>`;\n }\n return escapeHtml(formatValue(mapped, column));\n };\n return `${titleBlock(props.title, props.description)}${props.showSearch ? `<div class=\"portable-grid-search\"><input type=\"search\" placeholder=\"${escapeHtml(textValue(props.searchPlaceholder || 'Search...'))}\" /></div>` : ''}<div class=\"portable-card-grid\">${rows.map((row) => `<article><header><div><strong>${primary ? gridValue(row, primary) : ''}</strong>${secondary ? `<p>${gridValue(row, secondary)}</p>` : ''}</div><span aria-hidden=\"true\">›</span></header>${details.length ? `<dl>${details.map((column) => `<div><dt>${escapeHtml(textValue(column.title || column.label || column.key))}</dt><dd>${gridValue(row, column)}</dd></div>`).join('')}</dl>` : ''}</article>`).join('')}${rows.length === 0 ? '<div class=\"portable-empty\">No data</div>' : ''}</div>`;\n };\n const numericEntries = (row) => Object.entries(row || {}).filter(([, value]) => typeof value === 'number');\n const renderChart = (component) => {\n const props = component.props || {};\n const rows = component.mockData || props.data || [];\n const values = rows.map((row) => numericEntries(row)[0]?.[1] || 0);\n const labels = rows.map((row, index) => textValue(Object.values(row).find((value) => typeof value === 'string') || index + 1));\n const max = Math.max(...values, 1);\n const width = 720;\n const height = Math.max(180, Number(props.height || 260));\n const chartType = String(props.chartType || props.type || 'bar').toLowerCase();\n let graphic = '';\n if (chartType.includes('line')) {\n const points = values.map((value, index) => {\n const x = values.length === 1 ? width / 2 : 24 + index * ((width - 48) / Math.max(1, values.length - 1));\n const y = height - 36 - (value / max) * (height - 72);\n return `${x},${y}`;\n }).join(' ');\n graphic = `<polyline points=\"${points}\" fill=\"none\" stroke=\"var(--portable-accent)\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>${points.split(' ').map((point) => { const [x, y] = point.split(','); return `<circle cx=\"${x}\" cy=\"${y}\" r=\"5\" fill=\"var(--portable-surface)\" stroke=\"var(--portable-accent)\" stroke-width=\"3\"/>`; }).join('')}`;\n } else {\n const step = (width - 48) / Math.max(1, values.length);\n graphic = values.map((value, index) => {\n const barHeight = (value / max) * (height - 72);\n return `<rect x=\"${24 + index * step + step * 0.16}\" y=\"${height - 36 - barHeight}\" width=\"${step * 0.68}\" height=\"${barHeight}\" rx=\"5\" fill=\"var(--portable-accent)\" opacity=\"${0.7 + (index % 3) * 0.12}\"/>`;\n }).join('');\n }\n const axis = labels.map((label, index) => {\n const x = values.length === 1 ? width / 2 : 24 + index * ((width - 48) / Math.max(1, values.length - 1));\n return `<text x=\"${x}\" y=\"${height - 10}\" text-anchor=\"middle\">${escapeHtml(label)}</text>`;\n }).join('');\n return `${titleBlock(props.title, props.description)}<div class=\"portable-chart\"><svg viewBox=\"0 0 ${width} ${height}\" role=\"img\" aria-label=\"${escapeHtml(textValue(props.title || 'Chart'))}\">${graphic}${axis}</svg></div>`;\n };\n const renderForm = (component) => {\n const props = component.props || {};\n const fields = props.fields || props.items || [];\n return `${titleBlock(props.title, props.description)}<form class=\"portable-form\" onsubmit=\"return false\">${fields.map((field) => {\n const type = field.type === 'textarea' ? 'textarea' : 'input';\n const control = type === 'textarea'\n ? `<textarea placeholder=\"${escapeHtml(textValue(field.placeholder || ''))}\">${escapeHtml(textValue(field.defaultValue || ''))}</textarea>`\n : `<input type=\"${escapeHtml(field.type === 'number' ? 'number' : 'text')}\" value=\"${escapeHtml(textValue(field.defaultValue || ''))}\" placeholder=\"${escapeHtml(textValue(field.placeholder || ''))}\"/>`;\n return `<label><span>${escapeHtml(textValue(field.label || field.title || field.name))}</span>${control}</label>`;\n }).join('')}<button type=\"button\">${escapeHtml(textValue(props.submitButtonText || props.submitText || 'Submit'))}</button></form>`;\n };\n const renderTaskInput = (component) => {\n const props = component.props || {};\n const title = props.title || component.mockTitle;\n const description = props.description || component.mockDescription;\n const files = props.mockFileData?.files || component.mockFileData?.files || [];\n const fields = props.fields || component.parameterConfig?.fields || [];\n return `${titleBlock(props.showTitle === false ? '' : title, props.showDescription === false ? '' : description)}<div class=\"portable-task-input\">${fields.length ? `<div class=\"portable-task-fields\">${fields.map((field) => `<label><span>${escapeHtml(textValue(field.label || field.title || field.name))}</span><input type=\"text\" placeholder=\"${escapeHtml(textValue(field.placeholder || ''))}\" /></label>`).join('')}</div>` : ''}<label class=\"portable-file-drop\"><input type=\"file\" multiple /><span class=\"portable-file-icon\">↑</span><strong>${escapeHtml(textValue(props.uploadText || 'Choose files or drop them here'))}</strong><small>${escapeHtml(textValue(props.uploadHint || 'Files remain local in this portable preview'))}</small></label>${files.length ? `<div class=\"portable-file-list\">${files.map((file) => `<div><span>${escapeHtml(file.name || 'File')}</span><small>${escapeHtml(file.type || '')}</small></div>`).join('')}</div>` : ''}<button type=\"button\" class=\"portable-task-submit\">${escapeHtml(textValue(props.submitButtonText || 'Run task'))}</button></div>`;\n };\n const renderList = (component) => {\n const props = component.props || {};\n const rows = component.mockData || props.items || [];\n return `${titleBlock(props.title, props.description)}<div class=\"portable-list\">${rows.map((row) => {\n const title = typeof row === 'object' ? row.title || row.name || row.label || Object.values(row)[0] : row;\n const description = typeof row === 'object' ? row.description || row.subtitle || Object.values(row)[1] : '';\n return `<article><strong>${escapeHtml(textValue(title))}</strong>${description ? `<p>${escapeHtml(textValue(description))}</p>` : ''}</article>`;\n }).join('')}</div>`;\n };\n const renderTabs = (component) => {\n const props = component.props || {};\n const items = props.items || props.tabs || [];\n const activeKey = state.activeTabs.get(component.id) || items[0]?.key || items[0]?.id;\n const active = items.find((item) => (item.key || item.id) === activeKey) || items[0];\n const activeComponents = active?.components || (active?.component ? [active.component] : []);\n return `<div class=\"portable-tabs\" data-tabs=\"${escapeHtml(component.id)}\"><div class=\"portable-tab-list\">${items.map((item) => `<button type=\"button\" data-tab-key=\"${escapeHtml(item.key || item.id)}\" class=\"${(item.key || item.id) === activeKey ? 'active' : ''}\">${escapeHtml(textValue(item.title || item.label))}</button>`).join('')}</div><div class=\"portable-tab-panel\">${activeComponents.map(renderComponent).join('') || escapeHtml(textValue(active?.content || ''))}</div></div>`;\n };\n const renderContainer = (component) => {\n const props = component.props || {};\n const children = component.components || component.children || props.components || props.children;\n if (Array.isArray(children)) return `<div class=\"portable-container\">${children.map(renderComponent).join('')}</div>`;\n return `${titleBlock(props.title, props.subtitle)}${props.content ? `<p>${escapeHtml(textValue(props.content))}</p>` : ''}`;\n };\n const sanitizeHtml = (html) => {\n const template = document.createElement('template');\n template.innerHTML = String(html || '');\n template.content.querySelectorAll('script,iframe,object,embed,link,meta').forEach((node) => node.remove());\n template.content.querySelectorAll('*').forEach((node) => {\n [...node.attributes].forEach((attribute) => {\n if (/^on/i.test(attribute.name) || /javascript:/i.test(attribute.value)) node.removeAttribute(attribute.name);\n });\n });\n return template.innerHTML;\n };\n\n function renderComponent(component) {\n const props = component?.props || {};\n const scopeClass = `portable-component-${String(component?.id || 'anonymous').replace(/[^a-zA-Z0-9_-]/g, '-')}`;\n const rootStyles = component?.customStyles?.rootStyles || props.customStyles?.rootStyles || {};\n let content;\n switch (component?.type) {\n case 'Typography': case 'Text': case 'Title': case 'Paragraph': content = renderTypography(component); break;\n case 'Statistic': case 'StatisticGroup': content = renderStatistics(component); break;\n case 'Table': case 'EditableTable': case 'AnalyticsTable': content = renderTable(component); break;\n case 'DataGridCard': content = renderDataGridCard(component); break;\n case 'Chart': case 'EChartsChart': case 'RadarChart': content = renderChart(component); break;\n case 'Form': content = renderForm(component); break;\n case 'TaskInput': case 'TaskInputRenderer': content = renderTaskInput(component); break;\n case 'List': content = renderList(component); break;\n case 'Tabs': content = renderTabs(component); break;\n case 'Container': case 'Card': content = renderContainer(component); break;\n case 'CustomContent': content = sanitizeHtml(props.html || props.content || ''); break;\n case 'FilterPanel': content = renderForm({ ...component, props: { ...props, submitText: props.submitText || 'Apply filters' } }); break;\n default: content = `<div class=\"portable-unsupported\">Unsupported component: ${escapeHtml(component?.type)}</div>`;\n }\n return `${customStyleTag(component, `.${scopeClass}`)}<section class=\"portable-component ${scopeClass} portable-type-${escapeHtml(component?.type || 'unknown')}\" style=\"${escapeHtml(styleText(rootStyles))}\" data-component-id=\"${escapeHtml(component?.id)}\">${content}</section>`;\n }\n\n const isVisibleForDevice = (item, device) => !item?.visibility?.devices?.length || item.visibility.devices.includes(device);\n const firstPageForNavigation = (item, device) => {\n if (!isVisibleForDevice(item, device)) return null;\n if (item.linkedPage) return item.linkedPage;\n for (const child of item.children || []) {\n const page = firstPageForNavigation(child, device);\n if (page) return page;\n }\n return null;\n };\n const flattenNavigation = (items, device, depth = 0) => (items || []).flatMap((item) => {\n if (!isVisibleForDevice(item, device)) return [];\n const current = item.linkedPage ? [{ ...item, depth }] : [];\n return current.concat(flattenNavigation(item.children, device, depth + 1));\n });\n const mobileTabs = (items) => (items || []).flatMap((item) => {\n const page = firstPageForNavigation(item, 'mobile');\n return page ? [{ ...item, linkedPage: page }] : [];\n });\n const renderNavItems = (items, device) => flattenNavigation(items, device).map((item) => `\n <button type=\"button\" data-page=\"${escapeHtml(item.linkedPage)}\" class=\"portable-nav-item ${item.linkedPage === state.activePage ? 'active' : ''}\" style=\"--nav-depth:${item.depth}\">\n ${iconSvg(item.icon)}<span>${escapeHtml(textValue(item.title || item.key))}</span>\n </button>`).join('');\n const renderControls = (compact = false) => `<div class=\"portable-controls ${compact ? 'compact' : ''}\">\n <button type=\"button\" data-locale-toggle aria-label=\"Change language\">${iconSvg('Languages')}<span>${state.locale === 'zh' ? 'EN' : 'ZH'}</span></button>\n <button type=\"button\" data-theme-toggle aria-label=\"Change color theme\">${iconSvg(state.theme === 'dark' ? 'Sun' : 'Moon')}<span>${state.theme === 'dark' ? 'Light' : 'Dark'}</span></button>\n </div>`;\n const renderBrand = (collapsed = false) => {\n const appConfig = state.config.appConfig || {};\n return `<div class=\"portable-brand ${collapsed ? 'collapsed' : ''}\"><span>${escapeHtml(textValue(appConfig.name || 'G').slice(0, 1))}</span>${collapsed ? '' : `<div><strong>${escapeHtml(textValue(appConfig.name || 'GeniApp'))}</strong><small>${escapeHtml(textValue(appConfig.description || 'Exported from Workbench'))}</small></div>`}</div>`;\n };\n\n const renderPage = () => {\n const page = state.config.pages?.[state.activePage] || Object.values(state.config.pages || {})[0];\n const pageKey = state.activePage || Object.keys(state.config.pages || {})[0];\n if (!page) return '<main class=\"portable-page\"><div class=\"portable-empty\">No pages were exported.</div></main>';\n const pageScope = `.portable-page-${String(pageKey).replace(/[^a-zA-Z0-9_-]/g, '-')}`;\n const pageRoot = page.customStyles?.rootStyles || {};\n const placementList = page.layout?.type === 'grid-24' ? page.layout.components || [] : [];\n const placements = placementList.reduce((result, placement) => {\n if (placement?.id) result[placement.id] = placement;\n return result;\n }, page.layout?.placements || {});\n const components = (page.components || []).map((component) => {\n const placement = placements[component.id];\n const placementStyle = placement\n ? `grid-column:${Number(placement.colStart || 0) + 1} / span ${Number(placement.colSpan || 24)};grid-row:${Number(placement.rowStart || 0) + 1} / span ${Number(placement.rowSpan || 1)};`\n : '';\n return `<div class=\"portable-placement\" style=\"${placementStyle}\">${renderComponent(component)}</div>`;\n }).join('');\n return `${customStyleTag(page, pageScope)}<main class=\"portable-page ${pageScope}\" style=\"${escapeHtml(styleText(pageRoot))}\"><header class=\"portable-page-header\"><div><span class=\"portable-eyebrow\">${escapeHtml(textValue(state.config.appConfig?.name || ''))}</span><h1>${escapeHtml(textValue(page.title || pageKey))}</h1>${page.description ? `<p>${escapeHtml(textValue(page.description))}</p>` : ''}</div></header><div class=\"portable-page-grid ${page.layout?.type === 'grid-24' ? 'grid-24' : ''}\">${components}</div></main>`;\n };\n\n const applyDocumentUi = () => {\n document.documentElement.lang = state.locale === 'zh' ? 'zh-CN' : 'en';\n document.documentElement.classList.toggle('dark', state.theme === 'dark');\n document.documentElement.dataset.colorMode = state.theme;\n document.documentElement.style.colorScheme = state.theme;\n };\n const renderAndPersistLocale = (locale) => {\n state.locale = normalizeLocale(locale);\n state.config = applyLocale(state.sourceConfig, state.locale);\n try { localStorage.setItem('language', state.locale); } catch { /* ignore */ }\n applyDocumentUi();\n renderApp();\n };\n const renderAndPersistTheme = (theme) => {\n state.theme = normalizeTheme(theme);\n try { localStorage.setItem('theme', state.theme); } catch { /* ignore */ }\n applyDocumentUi();\n renderApp();\n };\n const navigatePage = (page) => {\n if (!state.config.pages?.[page]) return;\n state.activePage = page;\n state.mobileDrawerOpen = false;\n if (decodeURIComponent(window.location.hash.replace(/^#/, '')) !== page) window.location.hash = encodeURIComponent(page);\n renderApp();\n };\n\n const bindShellBridge = () => {\n window.addEventListener('message', (event) => {\n const message = event.data;\n if (!message || message.v !== 1 || typeof message !== 'object') return;\n const normalizedOrigin = event.origin.replace(/\\/$/, '');\n if (message.type === 'GENISPACE_SHELL_INIT') {\n const payload = message.payload || {};\n const origins = [payload.shellOrigin, ...(Array.isArray(payload.allowedShellOrigins) ? payload.allowedShellOrigins : [])]\n .filter(Boolean).map((origin) => String(origin).replace(/\\/$/, ''));\n if (origins.length && !origins.includes(normalizedOrigin)) return;\n state.allowedShellOrigins = new Set(origins.length ? origins : [normalizedOrigin]);\n if (payload.locale) state.locale = normalizeLocale(payload.locale);\n if (payload.theme) state.theme = normalizeTheme(payload.theme);\n state.config = applyLocale(state.sourceConfig, state.locale);\n applyDocumentUi();\n renderApp();\n window.parent.postMessage({ type: 'GENISPACE_IFRAME_READY', v: 1, identifier: state.config.appConfig?.appId || '' }, event.origin);\n return;\n }\n if (message.type === 'GENISPACE_SHELL_UI' && state.allowedShellOrigins.has(normalizedOrigin)) {\n if (message.locale) state.locale = normalizeLocale(message.locale);\n if (message.theme) state.theme = normalizeTheme(message.theme);\n state.config = applyLocale(state.sourceConfig, state.locale);\n applyDocumentUi();\n renderApp();\n }\n });\n };\n\n function renderApp() {\n const root = state.root;\n if (!root || !state.config) return;\n const navigation = state.config.appConfig?.navigation?.items || [];\n const mobileNavigation = mobileTabs(navigation);\n root.innerHTML = `<div class=\"portable-shell ${state.collapsed ? 'sidebar-collapsed' : ''}\">\n <aside class=\"portable-sidebar\">\n <div class=\"portable-sidebar-header\">${renderBrand(state.collapsed)}</div>\n <button type=\"button\" class=\"portable-collapse\" data-collapse aria-label=\"${state.collapsed ? 'Expand sidebar' : 'Collapse sidebar'}\">${iconSvg(state.collapsed ? 'ChevronRight' : 'ChevronLeft')}</button>\n <nav aria-label=\"Application navigation\">${renderNavItems(navigation, 'desktop')}</nav>\n <footer>${renderControls(state.collapsed)}</footer>\n </aside>\n <header class=\"portable-mobile-header\"><button type=\"button\" data-mobile-drawer aria-label=\"Open navigation\">${iconSvg('Menu')}</button>${renderBrand(false)}${renderControls(true)}</header>\n ${state.mobileDrawerOpen ? `<div class=\"portable-mobile-backdrop\" data-mobile-close></div><aside class=\"portable-mobile-drawer\"><div class=\"portable-mobile-drawer-close\"><button type=\"button\" data-mobile-close aria-label=\"Close navigation\">${iconSvg('X')}</button></div><div class=\"portable-sidebar-header\">${renderBrand(false)}</div><nav>${renderNavItems(navigation, 'mobile')}</nav><footer>${renderControls(false)}</footer></aside>` : ''}\n <div class=\"portable-content\">${renderPage()}</div>\n <nav class=\"portable-mobile-nav\" aria-label=\"Workbench bottom navigation\">${mobileNavigation.map((item) => `<button type=\"button\" data-page=\"${escapeHtml(item.linkedPage)}\" class=\"${item.linkedPage === state.activePage ? 'active' : ''}\" aria-current=\"${item.linkedPage === state.activePage ? 'page' : 'false'}\">${iconSvg(item.icon)}<span>${escapeHtml(textValue(item.title || item.key))}</span></button>`).join('')}</nav>\n </div>`;\n root.querySelectorAll('[data-page]').forEach((button) => button.addEventListener('click', () => navigatePage(button.dataset.page)));\n root.querySelectorAll('[data-tabs] [data-tab-key]').forEach((button) => button.addEventListener('click', () => {\n const tabs = button.closest('[data-tabs]');\n state.activeTabs.set(tabs.dataset.tabs, button.dataset.tabKey);\n renderApp();\n }));\n root.querySelectorAll('[data-locale-toggle]').forEach((button) => button.addEventListener('click', () => renderAndPersistLocale(state.locale === 'zh' ? 'en' : 'zh')));\n root.querySelectorAll('[data-theme-toggle]').forEach((button) => button.addEventListener('click', () => renderAndPersistTheme(state.theme === 'dark' ? 'light' : 'dark')));\n root.querySelector('[data-collapse]')?.addEventListener('click', () => {\n state.collapsed = !state.collapsed;\n try { localStorage.setItem('portable_sidebar_collapsed', JSON.stringify(state.collapsed)); } catch { /* ignore */ }\n renderApp();\n });\n root.querySelector('[data-mobile-drawer]')?.addEventListener('click', () => { state.mobileDrawerOpen = true; renderApp(); });\n root.querySelectorAll('[data-mobile-close]').forEach((button) => button.addEventListener('click', () => { state.mobileDrawerOpen = false; renderApp(); }));\n }\n\n const mountWorkbench = (root, config) => {\n if (!root) throw new Error('A root element is required.');\n state.root = root;\n state.sourceConfig = config || {};\n const search = new URLSearchParams(window.location.search);\n let savedLocale = '';\n let savedTheme = '';\n let savedCollapsed = false;\n try {\n savedLocale = localStorage.getItem('language') || '';\n savedTheme = localStorage.getItem('theme') || '';\n savedCollapsed = JSON.parse(localStorage.getItem('portable_sidebar_collapsed') || 'false');\n } catch { /* ignore */ }\n state.locale = normalizeLocale(search.get('lng') || savedLocale || document.documentElement.lang || 'en');\n state.theme = normalizeTheme(search.get('theme') || savedTheme || (window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'));\n state.collapsed = Boolean(savedCollapsed);\n state.config = applyLocale(state.sourceConfig, state.locale);\n const requestedPage = decodeURIComponent(window.location.hash.replace(/^#/, ''));\n state.activePage = state.config.pages?.[requestedPage]\n ? requestedPage\n : state.config.appConfig?.defaultPage || Object.keys(state.config.pages || {})[0];\n state.allowedShellOrigins.add(window.location.origin.replace(/\\/$/, ''));\n applyDocumentUi();\n bindShellBridge();\n window.addEventListener('hashchange', () => {\n const requested = decodeURIComponent(window.location.hash.replace(/^#/, ''));\n if (state.config.pages?.[requested] && requested !== state.activePage) {\n state.activePage = requested;\n renderApp();\n }\n });\n renderApp();\n if (window.parent !== window) window.parent.postMessage({ type: 'GENIAPP_READY', app: state.config.appConfig?.appId || '' }, '*');\n };\n\n return { mountWorkbench };\n}\n\n\nconst portableRuntime = createPortableRuntime();\n\nexport const mountWorkbench = portableRuntime.mountWorkbench as (\n root: HTMLElement,\n config: WorkbenchConfig,\n) => void;\n\n","export const PORTABLE_WORKBENCH_COMPONENT_TYPES = [\n 'Typography', 'Text', 'Title', 'Paragraph', 'Statistic', 'StatisticGroup',\n 'Table', 'EditableTable', 'AnalyticsTable', 'DataGridCard', 'Chart',\n 'EChartsChart', 'RadarChart', 'Form', 'TaskInput', 'TaskInputRenderer',\n 'List', 'Tabs', 'Container', 'Card', 'CustomContent', 'FilterPanel',\n] as const;\n\nexport type PortableWorkbenchComponentType = typeof PORTABLE_WORKBENCH_COMPONENT_TYPES[number];\n\nexport type WorkbenchNavigationItem = {\n key?: string;\n title?: string | Record<string, string>;\n icon?: string;\n linkedPage?: string;\n children?: WorkbenchNavigationItem[];\n visibility?: { devices?: Array<'desktop' | 'mobile'> };\n [key: string]: unknown;\n};\n\nexport type WorkbenchComponentConfig = {\n id: string;\n type: PortableWorkbenchComponentType | string;\n props?: Record<string, unknown>;\n components?: WorkbenchComponentConfig[];\n children?: WorkbenchComponentConfig[];\n customStyles?: Record<string, unknown>;\n mockData?: unknown[];\n [key: string]: unknown;\n};\n\nexport type WorkbenchPageConfig = {\n title?: string | Record<string, string>;\n description?: string | Record<string, string>;\n layout?: Record<string, unknown>;\n components?: WorkbenchComponentConfig[];\n customStyles?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport type WorkbenchAppConfig = {\n appId?: string;\n name?: string | Record<string, string>;\n description?: string | Record<string, string>;\n defaultPage?: string;\n navigation?: { items?: WorkbenchNavigationItem[] };\n [key: string]: unknown;\n};\n\nexport type WorkbenchConfig = {\n schemaVersion?: number;\n appConfig?: WorkbenchAppConfig;\n pages?: Record<string, WorkbenchPageConfig>;\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n};\n"],"names":["createPortableRuntime","state","escapeHtml","value","normalizeLocale","normalizeTheme","isPlainObject","clone","itemKey","item","index","key","mergeLocaleValue","base","patch","patches","match","result","localizeComponentTree","component","ownPatch","child","applyLocale","config","locale","localePatch","pageId","page","localized","labelMap","localizeLabel","raw","labels","left","right","textValue","picked","toKebab","letter","styleText","styles","safeCustomCss","css","source","customStyleTag","entity","scope","customStyles","rules","selector","normalized","customCss","iconSvg","name","className","body","formatValue","column","number","titleBlock","title","subtitle","renderTypography","props","text","variant","tag","renderStatistics","items","trend","direction","trendText","renderTable","rows","columns","row","renderDataGridCard","primary","secondary","details","gridValue","mapped","progress","numericEntries","renderChart","values","max","width","height","chartType","graphic","points","x","y","point","step","barHeight","axis","label","renderForm","fields","field","control","renderTaskInput","description","files","file","renderList","renderTabs","activeKey","active","activeComponents","renderComponent","renderContainer","children","sanitizeHtml","html","template","node","attribute","scopeClass","rootStyles","content","isVisibleForDevice","device","firstPageForNavigation","flattenNavigation","depth","mobileTabs","renderNavItems","renderControls","compact","renderBrand","collapsed","appConfig","renderPage","pageKey","pageScope","pageRoot","placements","placement","components","applyDocumentUi","renderAndPersistLocale","renderApp","renderAndPersistTheme","theme","navigatePage","bindShellBridge","event","message","normalizedOrigin","payload","origins","origin","root","navigation","mobileNavigation","button","tabs","search","savedLocale","savedTheme","savedCollapsed","requestedPage","requested","mountWorkbench","portableRuntime","PORTABLE_WORKBENCH_COMPONENT_TYPES"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genispace/geniapp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Public runtime, UI, Shell protocol and build contracts for GeniSpace applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -88,6 +88,11 @@
|
|
|
88
88
|
"types": "./dist/vite.d.ts",
|
|
89
89
|
"import": "./dist/vite.js"
|
|
90
90
|
},
|
|
91
|
+
"./workbench": {
|
|
92
|
+
"types": "./dist/workbench.d.ts",
|
|
93
|
+
"import": "./dist/workbench.js"
|
|
94
|
+
},
|
|
95
|
+
"./workbench/styles.css": "./dist/workbench/styles.css",
|
|
91
96
|
"./styles.css": "./dist/styles/base.css",
|
|
92
97
|
"./fonts.css": "./dist/fonts.css",
|
|
93
98
|
"./tailwind-preset": "./dist/styles/tailwind-preset.js"
|
|
@@ -96,6 +101,16 @@
|
|
|
96
101
|
"access": "public",
|
|
97
102
|
"provenance": true
|
|
98
103
|
},
|
|
104
|
+
"scripts": {
|
|
105
|
+
"clean": "rimraf dist",
|
|
106
|
+
"build": "pnpm clean && vite build && node scripts/copy-assets.mjs",
|
|
107
|
+
"type-check": "tsc --noEmit && tsc -p tsconfig.build.json --noEmit",
|
|
108
|
+
"test": "vitest run",
|
|
109
|
+
"test:coverage": "vitest run --coverage",
|
|
110
|
+
"check:sdk-version": "node scripts/check-sdk-version.mjs",
|
|
111
|
+
"pack:check": "pnpm check:sdk-version && pnpm build && pnpm pack --pack-destination .pack",
|
|
112
|
+
"prepublishOnly": "pnpm check:sdk-version && pnpm type-check && pnpm test && pnpm build"
|
|
113
|
+
},
|
|
99
114
|
"dependencies": {
|
|
100
115
|
"@fontsource/geist-mono": "^5.1.0",
|
|
101
116
|
"@fontsource/inter": "^5.1.0",
|
|
@@ -178,14 +193,5 @@
|
|
|
178
193
|
"engines": {
|
|
179
194
|
"node": ">=20"
|
|
180
195
|
},
|
|
181
|
-
"packageManager": "pnpm@8.15.0"
|
|
182
|
-
|
|
183
|
-
"clean": "rimraf dist",
|
|
184
|
-
"build": "pnpm clean && vite build && node scripts/copy-assets.mjs",
|
|
185
|
-
"type-check": "tsc --noEmit && tsc -p tsconfig.build.json --noEmit",
|
|
186
|
-
"test": "vitest run",
|
|
187
|
-
"test:coverage": "vitest run --coverage",
|
|
188
|
-
"check:sdk-version": "node scripts/check-sdk-version.mjs",
|
|
189
|
-
"pack:check": "pnpm check:sdk-version && pnpm build && pnpm pack --pack-destination .pack"
|
|
190
|
-
}
|
|
191
|
-
}
|
|
196
|
+
"packageManager": "pnpm@8.15.0"
|
|
197
|
+
}
|