anentrypoint-design 0.0.77 → 0.0.79

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.77",
3
+ "version": "0.0.79",
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",
@@ -26,6 +26,9 @@
26
26
  "./desktop/shell.js": "./src/desktop/shell.js",
27
27
  "./desktop/freddie-dashboard.js": "./src/desktop/freddie-dashboard.js",
28
28
  "./desktop/freddie-dashboard.css": "./src/desktop/freddie-dashboard.css",
29
+ "./desktop/files-app.js": "./src/desktop/files-app.js",
30
+ "./desktop/monitor-app.js": "./src/desktop/monitor-app.js",
31
+ "./desktop/about-app.js": "./src/desktop/about-app.js",
29
32
  "./colors_and_type.css": "./colors_and_type.css",
30
33
  "./app-shell.css": "./app-shell.css",
31
34
  "./page-html": {
@@ -0,0 +1,52 @@
1
+ // About-app paint surface — static info card, bible classes.
2
+ // renderAboutApp({brand, tagline, bullets, links}) -> {node, dispose}.
3
+ // Consumer provides content; module owns layout + classes.
4
+
5
+ export function renderAboutApp(opts = {}) {
6
+ const {
7
+ brand = 'thebird / web os',
8
+ tagline = 'browser-native web OS. multi-instance, per-instance fs / worker / shell / browser. no server.',
9
+ bullets = [
10
+ 'POSIX terminal · IndexedDB filesystem',
11
+ 'OffscreenCanvas worker per instance',
12
+ 'CDP-shaped browser pane',
13
+ 'libsql via sql.js · freddie host',
14
+ 'responsive: phone / tablet / desktop',
15
+ ],
16
+ footer = 'open <code>validator</code> to run isolation harness · click apps menu for more.',
17
+ links = [
18
+ { href: 'https://github.com/AnEntrypoint/thebird', text: 'source' },
19
+ { href: './validate.html', text: 'validate' },
20
+ ],
21
+ } = opts;
22
+
23
+ const node = document.createElement('div');
24
+ node.className = 'app-pane';
25
+ node.dataset.component = 'about-app';
26
+
27
+ const h2 = document.createElement('h2');
28
+ h2.textContent = brand;
29
+ const p = document.createElement('p');
30
+ p.textContent = tagline;
31
+ const ul = document.createElement('ul');
32
+ for (const b of bullets) {
33
+ const li = document.createElement('li');
34
+ li.textContent = b;
35
+ ul.appendChild(li);
36
+ }
37
+ const foot = document.createElement('p');
38
+ foot.innerHTML = footer;
39
+ const meta = document.createElement('p');
40
+ meta.className = 'meta';
41
+ links.forEach((l, i) => {
42
+ const a = document.createElement('a');
43
+ a.href = l.href;
44
+ a.textContent = l.text;
45
+ meta.appendChild(a);
46
+ if (i < links.length - 1) meta.appendChild(document.createTextNode(' · '));
47
+ });
48
+
49
+ node.append(h2, p, ul, foot, meta);
50
+
51
+ return { node, dispose() {} };
52
+ }
@@ -0,0 +1,44 @@
1
+ // Files-app paint surface — bible classes, pure DOM. Consumer provides callbacks.
2
+ // renderFilesApp({list, readFile}) -> {node, refresh, dispose}.
3
+ // list() -> Promise<string[]>; readFile(path) -> Promise<string|Uint8Array>.
4
+ // Header text comes from {label} (consumer assembles "<id> — N files").
5
+
6
+ export function renderFilesApp(opts = {}) {
7
+ const { list, readFile, label = '', pollMs = 2000 } = opts;
8
+ const node = document.createElement('div');
9
+ node.className = 'app-pane mono';
10
+ node.dataset.component = 'files-app';
11
+
12
+ let preview = null;
13
+ async function refresh() {
14
+ const items = await list();
15
+ node.innerHTML = '';
16
+ const head = document.createElement('div');
17
+ head.className = 'head';
18
+ head.textContent = (label ? label + ' — ' : '') + items.length + ' files';
19
+ node.appendChild(head);
20
+ for (const p of items) {
21
+ const row = document.createElement('div');
22
+ row.className = 'row';
23
+ row.textContent = p;
24
+ row.addEventListener('click', async () => {
25
+ const body = await readFile(p);
26
+ if (preview) preview.remove();
27
+ preview = document.createElement('pre');
28
+ preview.textContent = String(body);
29
+ node.appendChild(preview);
30
+ });
31
+ node.appendChild(row);
32
+ }
33
+ }
34
+
35
+ let timer = null;
36
+ refresh().catch(() => {});
37
+ if (pollMs > 0) timer = setInterval(() => refresh().catch(() => {}), pollMs);
38
+
39
+ return {
40
+ node,
41
+ refresh,
42
+ dispose() { if (timer) clearInterval(timer); },
43
+ };
44
+ }
@@ -0,0 +1,34 @@
1
+ // Monitor-app paint surface — bible classes, pure DOM. Consumer supplies getStats().
2
+ // getStats() -> Promise<{instanceId, frames, shells, windows, appsRegistered, jsHeapMb, jsHeapLimitMb, time}>.
3
+ // Field names map directly to displayed lines so consumer controls labels by value, not template.
4
+
5
+ export function renderMonitorApp(opts = {}) {
6
+ const { getStats, pollMs = 1000 } = opts;
7
+ const node = document.createElement('div');
8
+ node.className = 'app-pane mono';
9
+ node.dataset.component = 'monitor-app';
10
+
11
+ async function tick() {
12
+ const s = (await Promise.resolve(getStats())) || {};
13
+ const heap = (s.jsHeapMb != null && s.jsHeapLimitMb != null)
14
+ ? `js heap: ${Number(s.jsHeapMb).toFixed(1)} MB / ${Number(s.jsHeapLimitMb).toFixed(0)} MB`
15
+ : 'js heap: n/a';
16
+ node.textContent = [
17
+ `instance: ${s.instanceId ?? ''}`,
18
+ `worker frames: ${s.frames ?? 0}`,
19
+ `shells: ${s.shells ?? 0}`,
20
+ `windows: ${s.windows ?? 0}`,
21
+ `apps registered: ${s.appsRegistered ?? 0}`,
22
+ heap,
23
+ `now: ${s.time ?? new Date().toLocaleTimeString()}`,
24
+ ].join('\n');
25
+ }
26
+
27
+ tick().catch(() => {});
28
+ const timer = setInterval(() => tick().catch(() => {}), pollMs);
29
+ return {
30
+ node,
31
+ tick,
32
+ dispose() { clearInterval(timer); },
33
+ };
34
+ }
@@ -140,11 +140,23 @@ export function createDesktopShell({ root = document.body, wm, registry, brand =
140
140
  const clockTimer = setInterval(tickClock, 30000);
141
141
 
142
142
  let activeContext = null;
143
+ let activeInstanceId = null;
143
144
  function setContext(ctx) { activeContext = ctx; }
144
145
 
146
+ function applyInstanceFilter() {
147
+ if (!activeInstanceId) return;
148
+ for (const wEl of document.querySelectorAll('.wm-win[data-instance-id]')) {
149
+ const wInst = wEl.dataset.instanceId;
150
+ wEl.style.display = (wInst === activeInstanceId) ? '' : 'none';
151
+ }
152
+ }
153
+
145
154
  function refreshTaskbar() {
146
155
  taskbar.innerHTML = '';
147
156
  for (const w of wm.list()) {
157
+ const wEl = document.querySelector('.wm-win[data-id="' + w.id + '"]');
158
+ const wInst = wEl && wEl.dataset.instanceId;
159
+ if (activeInstanceId && wInst && wInst !== activeInstanceId) continue;
148
160
  const t = document.createElement('button');
149
161
  t.className = 'os-task' + (w.focused ? ' focused' : '');
150
162
  t.type = 'button';
@@ -155,6 +167,15 @@ export function createDesktopShell({ root = document.body, wm, registry, brand =
155
167
  }
156
168
  }
157
169
 
170
+ function setActiveInstance(id) {
171
+ activeInstanceId = id;
172
+ for (const btn of instSwitch.querySelectorAll('.os-btn')) {
173
+ btn.classList.toggle('active', btn.dataset.instanceId === id);
174
+ }
175
+ applyInstanceFilter();
176
+ refreshTaskbar();
177
+ }
178
+
158
179
  function openApp(appId) {
159
180
  const app = (typeof registry.get === 'function') ? registry.get(appId) : registry[appId];
160
181
  if (!app) throw new Error('unknown app: ' + appId);
@@ -165,6 +186,11 @@ export function createDesktopShell({ root = document.body, wm, registry, brand =
165
186
  const titlePrefix = (activeContext && activeContext.titlePrefix) ? activeContext.titlePrefix + ' · ' : '';
166
187
  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 });
167
188
  win._app = { id: appId, dispose: r.dispose };
189
+ if (activeInstanceId && win.el) {
190
+ win.el.dataset.instanceId = activeInstanceId;
191
+ win.instanceId = activeInstanceId;
192
+ }
193
+ win.appId = appId;
168
194
  refreshTaskbar();
169
195
  return win;
170
196
  };
@@ -176,8 +202,9 @@ export function createDesktopShell({ root = document.body, wm, registry, brand =
176
202
  const taskTimer = setInterval(refreshTaskbar, 500);
177
203
 
178
204
  const api = {
179
- wm, registry, openApp, setContext, refreshTaskbar,
205
+ wm, registry, openApp, setContext, refreshTaskbar, setActiveInstance,
180
206
  openDrawer, closeDrawer, openMenu, closeMenu,
207
+ get activeInstanceId() { return activeInstanceId; },
181
208
  elements: { osRoot, menubar, taskbar, appsMenu, sideRail, drawer, instSwitch, homeBtn, appsBtn },
182
209
  dispose() { clearInterval(clockTimer); clearInterval(taskTimer); osRoot.remove(); sideRail.remove(); drawer.remove(); },
183
210
  };
@@ -308,7 +308,10 @@ html, body {
308
308
 
309
309
  .os-spacer { flex: 1 1 auto; }
310
310
  .os-tray { display: flex; align-items: center; gap: 6px; }
311
- .os-instances { display: flex; gap: 6px; margin-left: 8px; }
311
+ .os-instances { display: flex; gap: 4px; margin-left: 8px; max-width: 280px; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; padding: 0 4px; }
312
+ .os-instances::-webkit-scrollbar { height: 4px; }
313
+ .os-instances .os-btn { flex: 0 0 auto; min-width: 36px; padding: 2px 8px; font-family: var(--os-mono); font-size: 11px; }
314
+ .os-instances .os-btn.active { background: var(--panel-select, var(--os-accent-soft)); color: var(--os-fg); border-color: var(--panel-accent, var(--os-accent)); box-shadow: inset 0 0 0 1px var(--panel-accent, var(--os-accent)); }
312
315
  .os-menubar [data-role="home"] { display: none; }
313
316
  .os-root { position: fixed; inset: 0; display: flex; flex-direction: column; pointer-events: none; z-index: 8000; }
314
317
  .os-menubar, .os-taskbar { pointer-events: auto; flex: 0 0 auto; }