anentrypoint-design 0.0.42 → 0.0.44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
5
  "type": "module",
6
6
  "main": "./dist/247420.js",
@@ -12,6 +12,18 @@
12
12
  },
13
13
  "./app": "./dist/247420.app.js",
14
14
  "./css": "./dist/247420.css",
15
+ "./desktop": {
16
+ "import": "./src/desktop/index.js",
17
+ "default": "./src/desktop/index.js"
18
+ },
19
+ "./desktop/theme.css": "./src/desktop/theme.css",
20
+ "./desktop/icons.js": "./src/desktop/icons.js",
21
+ "./desktop/shell.js": "./src/desktop/shell.js",
22
+ "./page-html": {
23
+ "import": "./src/page-html.js",
24
+ "default": "./src/page-html.js"
25
+ },
26
+ "./src/page-html.js": "./src/page-html.js",
15
27
  "./package.json": "./package.json"
16
28
  },
17
29
  "files": [
@@ -123,6 +123,25 @@ export function Manifesto({ paragraphs = [], maxWidth = 820 }) {
123
123
  });
124
124
  }
125
125
 
126
+ export function Kpi({ items = [] }) {
127
+ return h('div', { class: 'kpi' }, ...items.map(([n, l]) =>
128
+ h('div', { class: 'kpi-card' },
129
+ h('div', { class: 'num' }, String(n)),
130
+ h('div', { class: 'lbl' }, l))));
131
+ }
132
+
133
+ export function Table({ headers = [], rows = [], onRowClick, emptyText = 'no rows' }) {
134
+ if (!rows || rows.length === 0) {
135
+ return h('div', { class: 'empty' }, emptyText);
136
+ }
137
+ return h('table', {},
138
+ h('thead', {}, h('tr', {}, ...headers.map(hd => h('th', {}, hd)))),
139
+ h('tbody', {}, ...rows.map((row, i) => h('tr', {
140
+ class: onRowClick ? 'clickable' : '',
141
+ onclick: onRowClick ? () => onRowClick(i) : null
142
+ }, ...row.map(c => h('td', {}, c == null ? '' : String(c)))))));
143
+ }
144
+
126
145
  export function Section({ title, children }) {
127
146
  return h('div', { class: 'ds-section' },
128
147
  title ? h('h3', {}, title) : null,
package/src/components.js CHANGED
@@ -11,6 +11,7 @@ export {
11
11
  Panel, Row, RowLink,
12
12
  Hero, Install, Receipt, Changelog,
13
13
  WorksList, WritingList, Manifesto, Section,
14
+ Kpi, Table,
14
15
  HomeView, ProjectView
15
16
  } from './components/content.js';
16
17
 
@@ -0,0 +1,11 @@
1
+ export const icons = {
2
+ terminal: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg>',
3
+ browser: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 010 18M12 3a14 14 0 000 18"/></svg>',
4
+ canvas: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="14" rx="2"/><path d="M3 17l6-5 4 3 5-4 3 2"/></svg>',
5
+ files: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6a2 2 0 012-2h4l2 2h8a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2z"/></svg>',
6
+ monitor: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12l4-8 4 14 4-10 4 8 2-3"/></svg>',
7
+ validator: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l4 4L19 6"/></svg>',
8
+ about: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v.01M11 12h1v5h1"/></svg>',
9
+ apps: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg>',
10
+ plus: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>',
11
+ };
@@ -0,0 +1,3 @@
1
+ export { icons } from './icons.js';
2
+ export { createDesktopShell } from './shell.js';
3
+ export const themeUrl = new URL('./theme.css', import.meta.url).href;
@@ -0,0 +1,180 @@
1
+ import { icons } from './icons.js';
2
+
3
+ const THEME_CSS_URL = new URL('./theme.css', import.meta.url).href;
4
+
5
+ function ensureCss() {
6
+ if (document.querySelector('link[data-os-theme]')) return;
7
+ const l = document.createElement('link');
8
+ l.rel = 'stylesheet';
9
+ l.href = THEME_CSS_URL;
10
+ l.dataset.osTheme = '1';
11
+ document.head.appendChild(l);
12
+ }
13
+
14
+ function ic(svg) {
15
+ const s = document.createElement('span');
16
+ s.className = 'ic';
17
+ s.innerHTML = svg;
18
+ return s;
19
+ }
20
+
21
+ function makeBtn(svg, label, role) {
22
+ const b = document.createElement('button');
23
+ b.className = 'os-btn';
24
+ if (role) b.dataset.role = role;
25
+ if (svg) b.append(ic(svg));
26
+ if (label) b.append(Object.assign(document.createElement('span'), { textContent: label }));
27
+ return b;
28
+ }
29
+
30
+ export function createDesktopShell({ root = document.body, wm, registry, brand = 'desktop', themeUrl, onNewInstance, autoBoot = false } = {}) {
31
+ if (!wm) throw new Error('createDesktopShell: wm is required');
32
+ if (!registry) throw new Error('createDesktopShell: registry is required');
33
+ if (themeUrl) {
34
+ if (!document.querySelector('link[data-os-theme]')) {
35
+ const l = document.createElement('link');
36
+ l.rel = 'stylesheet';
37
+ l.href = themeUrl;
38
+ l.dataset.osTheme = '1';
39
+ document.head.appendChild(l);
40
+ }
41
+ } else {
42
+ ensureCss();
43
+ }
44
+
45
+ const osRoot = document.createElement('div');
46
+ osRoot.className = 'os-root';
47
+ osRoot.style.cssText = 'position:fixed;inset:0;display:flex;flex-direction:column;pointer-events:none;z-index:8000';
48
+ root.appendChild(osRoot);
49
+
50
+ const menubar = document.createElement('div');
51
+ menubar.className = 'os-menubar';
52
+
53
+ const brandEl = document.createElement('span');
54
+ brandEl.className = 'os-brand';
55
+ brandEl.textContent = brand;
56
+
57
+ const appsBtn = makeBtn(icons.apps, 'apps', 'apps');
58
+ const newInstBtn = onNewInstance ? makeBtn(icons.plus, 'instance', 'add') : null;
59
+
60
+ const instSwitch = document.createElement('div');
61
+ instSwitch.className = 'os-instances';
62
+ instSwitch.style.cssText = 'display:flex;gap:6px;margin-left:8px';
63
+
64
+ const spacer = document.createElement('div');
65
+ spacer.style.cssText = 'flex:1';
66
+
67
+ const tray = document.createElement('div');
68
+ tray.style.cssText = 'display:flex;align-items:center;gap:6px';
69
+ const clock = document.createElement('span');
70
+ clock.className = 'os-clock';
71
+ tray.appendChild(clock);
72
+
73
+ menubar.append(brandEl, appsBtn);
74
+ if (newInstBtn) menubar.append(newInstBtn);
75
+ menubar.append(instSwitch, spacer, tray);
76
+
77
+ const appsMenu = document.createElement('div');
78
+ appsMenu.className = 'os-menu';
79
+ appsMenu.style.cssText = 'position:absolute;display:none;flex-direction:column;pointer-events:auto';
80
+
81
+ const sideRail = document.createElement('div');
82
+ sideRail.className = 'os-side-rail';
83
+
84
+ const sheet = document.createElement('div');
85
+ sheet.className = 'os-mobile-sheet';
86
+ const sheetHandle = document.createElement('div');
87
+ sheetHandle.className = 'os-mobile-handle';
88
+ const sheetGrid = document.createElement('div');
89
+ sheetGrid.className = 'os-mobile-grid';
90
+ sheet.append(sheetHandle, sheetGrid);
91
+ sheet.addEventListener('click', e => {
92
+ if (e.target === sheet || e.target === sheetHandle) sheet.classList.toggle('open');
93
+ });
94
+
95
+ const apps = typeof registry.list === 'function' ? registry.list() : [...registry.values()];
96
+
97
+ for (const app of apps) {
98
+ const iconSvg = app.icon || icons[app.id] || '';
99
+ const menuBtn = makeBtn(iconSvg, app.name);
100
+ menuBtn.addEventListener('click', () => { appsMenu.style.display = 'none'; openApp(app.id); });
101
+ appsMenu.appendChild(menuBtn);
102
+
103
+ const railBtn = document.createElement('button');
104
+ railBtn.className = 'os-rail-btn';
105
+ railBtn.title = app.name;
106
+ railBtn.append(ic(iconSvg));
107
+ railBtn.addEventListener('click', () => openApp(app.id));
108
+ sideRail.appendChild(railBtn);
109
+
110
+ const tile = document.createElement('button');
111
+ tile.className = 'os-mobile-tile';
112
+ tile.append(ic(iconSvg), Object.assign(document.createElement('span'), { className: 'lbl', textContent: app.name }));
113
+ tile.addEventListener('click', () => { sheet.classList.remove('open'); openApp(app.id); });
114
+ sheetGrid.appendChild(tile);
115
+ }
116
+
117
+ const taskbar = document.createElement('div');
118
+ taskbar.className = 'os-taskbar';
119
+ taskbar.style.cssText = 'margin-top:auto;display:flex;align-items:center;gap:6px;flex-wrap:wrap';
120
+
121
+ osRoot.append(menubar, appsMenu, taskbar);
122
+ document.body.appendChild(sideRail);
123
+ document.body.appendChild(sheet);
124
+
125
+ appsBtn.addEventListener('click', e => {
126
+ e.stopPropagation();
127
+ appsMenu.style.display = appsMenu.style.display === 'flex' ? 'none' : 'flex';
128
+ });
129
+ document.addEventListener('click', e => {
130
+ if (!appsMenu.contains(e.target) && !appsBtn.contains(e.target)) appsMenu.style.display = 'none';
131
+ });
132
+
133
+ function tickClock() { clock.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }
134
+ tickClock();
135
+ const clockTimer = setInterval(tickClock, 30000);
136
+
137
+ let activeContext = null;
138
+ function setContext(ctx) { activeContext = ctx; }
139
+
140
+ function refreshTaskbar() {
141
+ taskbar.innerHTML = '';
142
+ for (const w of wm.list()) {
143
+ const t = document.createElement('button');
144
+ t.className = 'os-task' + (w.focused ? ' focused' : '');
145
+ t.textContent = w.title;
146
+ t.addEventListener('click', () => wm.focus(w.id));
147
+ taskbar.appendChild(t);
148
+ }
149
+ }
150
+
151
+ function openApp(appId) {
152
+ const app = (typeof registry.get === 'function') ? registry.get(appId) : registry[appId];
153
+ if (!app) throw new Error('unknown app: ' + appId);
154
+ const ctx = { ...(activeContext || {}), registry, openApp, wm };
155
+ const result = app.factory(ctx);
156
+ const finish = (r) => {
157
+ const sz = app.defaultSize || { w: 520, h: 360 };
158
+ const titlePrefix = (activeContext && activeContext.titlePrefix) ? activeContext.titlePrefix + ' · ' : '';
159
+ const win = wm.open({ title: titlePrefix + app.name, body: r.node, kind: appId, width: sz.w, height: sz.h, x: 100 + (wm.count * 28) % 240, y: 80 + (wm.count * 22) % 180 });
160
+ win._app = { id: appId, dispose: r.dispose };
161
+ refreshTaskbar();
162
+ return win;
163
+ };
164
+ return (result && typeof result.then === 'function') ? result.then(finish) : finish(result);
165
+ }
166
+
167
+ if (newInstBtn) newInstBtn.addEventListener('click', () => onNewInstance && onNewInstance({ instSwitch, setContext, openApp }));
168
+
169
+ const taskTimer = setInterval(refreshTaskbar, 500);
170
+
171
+ const api = {
172
+ wm, registry, openApp, setContext, refreshTaskbar,
173
+ toggleSheet() { sheet.classList.toggle('open'); },
174
+ elements: { osRoot, menubar, taskbar, appsMenu, sideRail, sheet, instSwitch },
175
+ dispose() { clearInterval(clockTimer); clearInterval(taskTimer); osRoot.remove(); sideRail.remove(); sheet.remove(); },
176
+ };
177
+
178
+ if (autoBoot && typeof autoBoot === 'string') openApp(autoBoot);
179
+ return api;
180
+ }
@@ -0,0 +1,297 @@
1
+ :root {
2
+ --os-accent: #3FA93A;
3
+ --os-accent-2: #79e872;
4
+ --os-accent-soft: rgba(63, 169, 58, 0.16);
5
+ --os-bg-0: #0b0d10;
6
+ --os-bg-1: #14181d;
7
+ --os-bg-2: #1a1f26;
8
+ --os-bg-3: #222831;
9
+ --os-fg: #e7ecf2;
10
+ --os-fg-2: #93a0ad;
11
+ --os-fg-3: #5a6571;
12
+ --os-red: #d04444;
13
+ --os-amber: #c0a02f;
14
+ --os-green: #3FA93A;
15
+ --os-radius: 6px;
16
+ --os-radius-sm: 4px;
17
+ --os-bar-h: 40px;
18
+ --os-bar-h-mobile: 48px;
19
+ --os-rail-w: 64px;
20
+ --os-tap: 44px;
21
+ --os-font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
22
+ --os-mono: "SF Mono", ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;
23
+ }
24
+
25
+ html, body {
26
+ background: var(--os-bg-0);
27
+ color: var(--os-fg);
28
+ font-family: var(--os-font);
29
+ -webkit-font-smoothing: antialiased;
30
+ text-rendering: optimizeLegibility;
31
+ }
32
+
33
+ .os-menubar, .os-taskbar {
34
+ background: var(--os-bg-1);
35
+ border: none;
36
+ color: var(--os-fg);
37
+ font: 13px var(--os-font);
38
+ height: var(--os-bar-h);
39
+ padding: 0 12px;
40
+ gap: 6px;
41
+ box-shadow: none;
42
+ }
43
+ .os-menubar { border-bottom: 1px solid var(--os-bg-3); }
44
+ .os-taskbar { border-top: 1px solid var(--os-bg-3); }
45
+
46
+ .os-brand {
47
+ color: var(--os-fg);
48
+ font-weight: 600;
49
+ letter-spacing: 0.01em;
50
+ margin-right: 14px;
51
+ display: inline-flex;
52
+ align-items: center;
53
+ gap: 8px;
54
+ }
55
+ .os-brand::before {
56
+ content: '';
57
+ display: inline-block;
58
+ width: 8px; height: 8px;
59
+ border-radius: 50%;
60
+ background: var(--os-accent);
61
+ }
62
+
63
+ .os-btn {
64
+ background: transparent;
65
+ color: var(--os-fg);
66
+ border: none;
67
+ padding: 6px 12px;
68
+ cursor: pointer;
69
+ font: inherit;
70
+ border-radius: var(--os-radius-sm);
71
+ transition: background 100ms ease, color 100ms ease;
72
+ display: inline-flex;
73
+ align-items: center;
74
+ gap: 6px;
75
+ outline: none;
76
+ }
77
+ .os-btn:hover { background: var(--os-bg-2); color: var(--os-accent-2); }
78
+ .os-btn.active, .os-btn[aria-pressed="true"] { background: var(--os-accent-soft); color: var(--os-accent-2); }
79
+ .os-btn:focus-visible { background: var(--os-bg-2); }
80
+ .os-btn .ic { color: var(--os-accent); display: inline-flex; width: 16px; height: 16px; }
81
+ .os-btn .ic svg { width: 16px; height: 16px; display: block; fill: none; stroke: currentColor; }
82
+
83
+ .os-menu {
84
+ background: var(--os-bg-1);
85
+ border: 1px solid var(--os-bg-3);
86
+ border-radius: var(--os-radius);
87
+ box-shadow: none;
88
+ padding: 6px;
89
+ min-width: 220px;
90
+ top: calc(var(--os-bar-h) + 4px);
91
+ left: 8px;
92
+ z-index: 9500;
93
+ }
94
+ .os-menu .os-btn {
95
+ width: 100%;
96
+ text-align: left;
97
+ border-radius: var(--os-radius-sm);
98
+ padding: 8px 10px;
99
+ color: var(--os-fg);
100
+ justify-content: flex-start;
101
+ }
102
+ .os-menu .os-btn:hover { background: var(--os-bg-2); color: var(--os-accent-2); }
103
+
104
+ .os-clock {
105
+ color: var(--os-fg-2);
106
+ font-variant-numeric: tabular-nums;
107
+ padding: 0 10px;
108
+ font-size: 12px;
109
+ }
110
+
111
+ .os-task {
112
+ border: none;
113
+ background: var(--os-bg-2);
114
+ color: var(--os-fg);
115
+ border-radius: var(--os-radius-sm);
116
+ padding: 6px 10px;
117
+ font-size: 12px;
118
+ transition: background 100ms ease, color 100ms ease;
119
+ max-width: 200px;
120
+ cursor: pointer;
121
+ outline: none;
122
+ }
123
+ .os-task:hover { background: var(--os-bg-3); }
124
+ .os-task.focused {
125
+ background: var(--os-accent-soft);
126
+ color: var(--os-accent-2);
127
+ }
128
+
129
+ .wm-win {
130
+ background: var(--os-bg-1) !important;
131
+ border: 1px solid var(--os-bg-3) !important;
132
+ border-radius: var(--os-radius) !important;
133
+ box-shadow: none !important;
134
+ overflow: hidden;
135
+ }
136
+ .wm-win.wm-focused {
137
+ border-color: var(--os-accent) !important;
138
+ box-shadow: none !important;
139
+ }
140
+
141
+ .wm-bar {
142
+ background: var(--os-bg-2) !important;
143
+ border-bottom: 1px solid var(--os-bg-3) !important;
144
+ padding: 8px 12px !important;
145
+ gap: 10px !important;
146
+ }
147
+ .wm-title {
148
+ font: 12px var(--os-font) !important;
149
+ color: var(--os-fg-2) !important;
150
+ letter-spacing: 0.02em;
151
+ text-align: center;
152
+ }
153
+ .wm-btns { gap: 6px !important; order: -1; }
154
+ .wm-btn {
155
+ width: 12px !important;
156
+ height: 12px !important;
157
+ border-radius: 50% !important;
158
+ border: none !important;
159
+ padding: 0 !important;
160
+ cursor: pointer;
161
+ font-size: 0 !important;
162
+ transition: opacity 100ms ease;
163
+ }
164
+ .wm-btn:hover { opacity: 0.75; }
165
+ .wm-btns .wm-btn:nth-child(1) { background: var(--os-amber) !important; }
166
+ .wm-btns .wm-btn:nth-child(2) { background: var(--os-green) !important; }
167
+ .wm-btns .wm-btn:nth-child(3) { background: var(--os-red) !important; }
168
+
169
+ .wm-resize {
170
+ background: var(--os-bg-3) !important;
171
+ width: 14px !important;
172
+ height: 14px !important;
173
+ clip-path: polygon(100% 0, 100% 100%, 0 100%);
174
+ }
175
+ .wm-body { background: var(--os-bg-1) !important; }
176
+
177
+ .os-side-rail {
178
+ position: fixed;
179
+ left: 0; top: 0; bottom: 0;
180
+ width: var(--os-rail-w);
181
+ background: var(--os-bg-1);
182
+ border-right: 1px solid var(--os-bg-3);
183
+ display: none;
184
+ flex-direction: column;
185
+ align-items: center;
186
+ padding: 12px 0;
187
+ gap: 6px;
188
+ z-index: 9100;
189
+ pointer-events: auto;
190
+ }
191
+ .os-rail-btn {
192
+ width: 48px; height: 48px;
193
+ border-radius: var(--os-radius-sm);
194
+ background: transparent;
195
+ border: none;
196
+ color: var(--os-fg);
197
+ cursor: pointer;
198
+ display: flex; align-items: center; justify-content: center;
199
+ transition: background 100ms ease;
200
+ padding: 0;
201
+ outline: none;
202
+ }
203
+ .os-rail-btn:hover { background: var(--os-bg-2); }
204
+ .os-rail-btn:active { background: var(--os-bg-3); }
205
+ .os-rail-btn .ic { color: var(--os-accent); display: inline-flex; }
206
+ .os-rail-btn .ic svg { width: 22px; height: 22px; fill: none; stroke: currentColor; }
207
+
208
+ .os-mobile-sheet {
209
+ position: fixed;
210
+ left: 0; right: 0; bottom: 0;
211
+ background: var(--os-bg-1);
212
+ border-top: 1px solid var(--os-bg-3);
213
+ border-radius: 14px 14px 0 0;
214
+ padding: 8px 12px env(safe-area-inset-bottom, 12px);
215
+ transform: translateY(calc(100% - 56px));
216
+ transition: transform 220ms cubic-bezier(0.22, 0.8, 0.34, 1.0);
217
+ z-index: 9700;
218
+ pointer-events: auto;
219
+ display: none;
220
+ flex-direction: column;
221
+ gap: 8px;
222
+ max-height: 70vh;
223
+ box-shadow: none;
224
+ }
225
+ .os-mobile-sheet.open { transform: translateY(0); }
226
+ .os-mobile-handle {
227
+ width: 44px; height: 4px;
228
+ border-radius: 999px;
229
+ background: var(--os-bg-3);
230
+ margin: 6px auto 4px;
231
+ }
232
+ .os-mobile-grid {
233
+ display: grid;
234
+ grid-template-columns: repeat(4, 1fr);
235
+ gap: 8px;
236
+ overflow-y: auto;
237
+ padding: 6px 4px 12px;
238
+ }
239
+ .os-mobile-tile {
240
+ display: flex; flex-direction: column; align-items: center; gap: 6px;
241
+ padding: 12px 6px;
242
+ border-radius: var(--os-radius);
243
+ background: var(--os-bg-2);
244
+ border: none;
245
+ color: var(--os-fg);
246
+ font: 11px var(--os-font);
247
+ min-height: var(--os-tap);
248
+ cursor: pointer;
249
+ transition: background 100ms ease;
250
+ outline: none;
251
+ }
252
+ .os-mobile-tile:active { background: var(--os-accent-soft); }
253
+ .os-mobile-tile .ic { color: var(--os-accent); display: inline-flex; width: 28px; height: 28px; }
254
+ .os-mobile-tile .ic svg { width: 28px; height: 28px; fill: none; stroke: currentColor; }
255
+ .os-mobile-tile .lbl { color: var(--os-fg-2); }
256
+
257
+ .app-pane { padding: 14px; font: 13px var(--os-font); color: var(--os-fg); line-height: 1.55; overflow: auto; height: 100%; box-sizing: border-box; }
258
+ .app-pane h2 { margin: 0 0 10px 0; color: var(--os-fg); font-size: 16px; font-weight: 600; }
259
+ .app-pane p { margin: 0 0 10px 0; color: var(--os-fg-2); }
260
+ .app-pane ul { padding-left: 18px; margin: 6px 0 12px; color: var(--os-fg-2); }
261
+ .app-pane li { padding: 2px 0; }
262
+ .app-pane code { font: 12px var(--os-mono); background: var(--os-bg-2); padding: 1px 5px; border-radius: 3px; color: var(--os-fg); }
263
+ .app-pane a { color: var(--os-accent); text-decoration: none; }
264
+ .app-pane a:hover { color: var(--os-accent-2); }
265
+ .app-pane .meta { color: var(--os-fg-3); font-size: 12px; }
266
+ .app-pane.mono { font: 12px var(--os-mono); padding: 10px; }
267
+ .app-pane.mono .row { padding: 4px 6px; cursor: pointer; border-radius: 3px; }
268
+ .app-pane.mono .row:hover { background: var(--os-bg-2); }
269
+ .app-pane.mono .head { color: var(--os-accent); margin-bottom: 8px; padding-bottom: 4px; border-bottom: 1px solid var(--os-bg-3); font-weight: 600; }
270
+ .app-pane.mono pre { background: var(--os-bg-2); padding: 8px; margin: 8px 0 0 0; max-height: 200px; overflow: auto; white-space: pre-wrap; font: 11px var(--os-mono); border-radius: 3px; color: var(--os-fg); border: none; }
271
+ .app-canvas { width: 100%; height: 100%; background: var(--os-bg-0); }
272
+ .app-frame { width: 100%; height: 100%; border: 0; background: var(--os-bg-0); }
273
+ @media (max-width: 1023px) and (min-width: 768px) {
274
+ .os-side-rail { display: flex; }
275
+ .wm-root { left: var(--os-rail-w) !important; }
276
+ .os-menubar { padding-left: calc(var(--os-rail-w) + 8px); }
277
+ .os-taskbar { padding-left: calc(var(--os-rail-w) + 8px); }
278
+ .os-menubar .os-instances { display: flex; }
279
+ .os-menu { left: calc(var(--os-rail-w) + 8px); }
280
+ }
281
+
282
+ @media (max-width: 767px) {
283
+ :root { --os-bar-h: var(--os-bar-h-mobile); }
284
+ .os-mobile-sheet { display: flex; }
285
+ .os-menubar { font-size: 14px; padding: 0 8px; }
286
+ .os-menubar .os-btn { min-height: var(--os-tap); padding: 8px 10px; }
287
+ .os-menubar [data-role="apps"] { display: none; }
288
+ .os-menubar [data-role="add"] { min-width: var(--os-tap); }
289
+ .os-menubar .os-instances { gap: 4px; }
290
+ .os-clock { display: none; }
291
+ .os-taskbar { padding: 4px 8px 64px; gap: 4px; overflow-x: auto; flex-wrap: nowrap; }
292
+ .os-task { flex: 0 0 auto; min-height: 36px; max-width: 140px; padding: 8px 10px; }
293
+ .wm-win { border-radius: 0 !important; }
294
+ .wm-bar { padding: 10px 12px !important; }
295
+ .wm-btn { width: 16px !important; height: 16px !important; }
296
+ .os-menu { left: 8px; right: 8px; min-width: 0; }
297
+ }
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ import * as motion from './motion.js';
6
6
  import * as debug from './debug.js';
7
7
  import { renderMarkdown, ensureReady as ensureMarkdownReady } from './markdown.js';
8
8
  import { ensurePrism, highlightAllUnder } from './highlight.js';
9
+ import { renderPageHtml } from './page-html.js';
9
10
  import { mountKit } from './bootstrap.js';
10
11
  import { registerChatElement } from './web-components/ds-chat.js';
11
12
 
@@ -43,12 +44,13 @@ export {
43
44
  components, motion, debug, mountKit,
44
45
  renderMarkdown, ensureMarkdownReady,
45
46
  ensurePrism, highlightAllUnder,
46
- registerChatElement
47
+ registerChatElement,
48
+ renderPageHtml
47
49
  };
48
50
  export const h = webjsx.createElement;
49
51
  export const applyDiff = webjsx.applyDiff;
50
52
  export default {
51
53
  webjsx, loadCss, scope, installStyles, mount, h, applyDiff,
52
54
  registerDeckStage, getDeckStage, components, motion, debug, mountKit,
53
- renderMarkdown, ensurePrism, registerChatElement
55
+ renderMarkdown, ensurePrism, registerChatElement, renderPageHtml
54
56
  };