anentrypoint-design 0.0.121 → 0.0.124

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.
Files changed (202) hide show
  1. package/README.md +253 -253
  2. package/app-shell.css +931 -594
  3. package/colors_and_type.css +226 -226
  4. package/community.css +817 -1222
  5. package/dist/247420.css +2202 -2084
  6. package/dist/247420.js +13 -13
  7. package/package.json +80 -80
  8. package/src/bootstrap.js +25 -25
  9. package/src/components/chat.js +199 -199
  10. package/src/components/community.js +190 -208
  11. package/src/components/content.js +269 -269
  12. package/src/components/editor-primitives.js +100 -0
  13. package/src/components/files-modals.js +107 -107
  14. package/src/components/files.js +118 -118
  15. package/src/components/freddie/helpers.js +50 -50
  16. package/src/components/freddie.js +33 -33
  17. package/src/components/shell.js +117 -117
  18. package/src/components/theme-toggle.js +70 -70
  19. package/src/components.js +59 -57
  20. package/src/debug.js +30 -30
  21. package/src/deck-stage.js +21 -21
  22. package/src/highlight.js +65 -32
  23. package/src/index.js +86 -86
  24. package/src/kits/os/about-app.js +52 -52
  25. package/src/kits/os/app-panes.css +152 -152
  26. package/src/kits/os/browser-app.js +58 -58
  27. package/src/kits/os/files-app.js +44 -44
  28. package/src/kits/os/freddie/helpers.js +59 -59
  29. package/src/kits/os/freddie/pages-chat.js +143 -143
  30. package/src/kits/os/freddie/pages-core.js +101 -101
  31. package/src/kits/os/freddie/pages-os.js +51 -51
  32. package/src/kits/os/freddie/pages-tools.js +183 -183
  33. package/src/kits/os/freddie/routes.js +24 -24
  34. package/src/kits/os/freddie-dashboard.css +51 -51
  35. package/src/kits/os/freddie-dashboard.js +101 -101
  36. package/src/kits/os/icons.js +17 -17
  37. package/src/kits/os/index.js +17 -17
  38. package/src/kits/os/launcher.css +61 -61
  39. package/src/kits/os/launcher.js +79 -79
  40. package/src/kits/os/monitor-app.js +34 -34
  41. package/src/kits/os/shell.js +214 -214
  42. package/src/kits/os/terminal-app.js +45 -45
  43. package/src/kits/os/theme.css +450 -450
  44. package/src/kits/os/validate.css +19 -19
  45. package/src/kits/os/validator-app.js +55 -55
  46. package/src/kits/os/wm.css +115 -115
  47. package/src/kits/os/wm.js +111 -111
  48. package/src/markdown.js +39 -39
  49. package/src/motion.js +35 -35
  50. package/src/page-html.js +196 -196
  51. package/src/styles.js +25 -25
  52. package/src/theme.js +99 -99
  53. package/src/web-components/ds-chat.js +116 -116
  54. package/dist/.nojekyll +0 -0
  55. package/dist/app-shell.css +0 -594
  56. package/dist/colors_and_type.css +0 -197
  57. package/dist/favicon.svg +0 -1
  58. package/dist/index.html +0 -308
  59. package/dist/preview/buttons.html +0 -28
  60. package/dist/preview/colors-core.html +0 -45
  61. package/dist/preview/colors-lore.html +0 -28
  62. package/dist/preview/colors-semantic.html +0 -34
  63. package/dist/preview/dateline.html +0 -19
  64. package/dist/preview/dropzone.html +0 -30
  65. package/dist/preview/file-grid.html +0 -19
  66. package/dist/preview/file-row.html +0 -20
  67. package/dist/preview/file-toolbar.html +0 -40
  68. package/dist/preview/file-viewer.html +0 -31
  69. package/dist/preview/header.html +0 -24
  70. package/dist/preview/icons-unicode.html +0 -26
  71. package/dist/preview/index-row.html +0 -25
  72. package/dist/preview/inputs.html +0 -22
  73. package/dist/preview/manifesto.html +0 -52
  74. package/dist/preview/motion-default.js +0 -106
  75. package/dist/preview/rules.html +0 -16
  76. package/dist/preview/spacing.html +0 -18
  77. package/dist/preview/stamps-lore.html +0 -20
  78. package/dist/preview/stamps.html +0 -14
  79. package/dist/preview/theme-ink.html +0 -15
  80. package/dist/preview/type-display.html +0 -16
  81. package/dist/preview/type-mono.html +0 -15
  82. package/dist/preview/type-prose.html +0 -11
  83. package/dist/preview/type-scale.html +0 -20
  84. package/dist/preview/wordmarks.html +0 -28
  85. package/dist/robots.txt +0 -8
  86. package/dist/site/content/globals/navigation.yaml +0 -5
  87. package/dist/site/content/globals/site.yaml +0 -16
  88. package/dist/site/content/pages/freddie.yaml +0 -88
  89. package/dist/site/content/pages/home.yaml +0 -190
  90. package/dist/site/theme.mjs +0 -368
  91. package/dist/sitemap.xml +0 -31
  92. package/dist/slides/deck-stage-overlay.js +0 -63
  93. package/dist/slides/deck-stage-state.js +0 -81
  94. package/dist/slides/deck-stage-style.js +0 -117
  95. package/dist/slides/deck-stage.js +0 -159
  96. package/dist/slides/index.html +0 -276
  97. package/dist/src/bootstrap.js +0 -25
  98. package/dist/src/components/chat.js +0 -199
  99. package/dist/src/components/community.js +0 -167
  100. package/dist/src/components/content.js +0 -213
  101. package/dist/src/components/files-modals.js +0 -107
  102. package/dist/src/components/files.js +0 -118
  103. package/dist/src/components/freddie/helpers.js +0 -50
  104. package/dist/src/components/freddie.js +0 -33
  105. package/dist/src/components/shell.js +0 -117
  106. package/dist/src/components/theme-toggle.js +0 -70
  107. package/dist/src/components.js +0 -52
  108. package/dist/src/debug.js +0 -30
  109. package/dist/src/deck-stage.js +0 -21
  110. package/dist/src/highlight.js +0 -32
  111. package/dist/src/index.js +0 -86
  112. package/dist/src/kits/os/about-app.js +0 -52
  113. package/dist/src/kits/os/app-panes.css +0 -152
  114. package/dist/src/kits/os/browser-app.js +0 -58
  115. package/dist/src/kits/os/files-app.js +0 -44
  116. package/dist/src/kits/os/freddie/helpers.js +0 -59
  117. package/dist/src/kits/os/freddie/pages-chat.js +0 -143
  118. package/dist/src/kits/os/freddie/pages-core.js +0 -101
  119. package/dist/src/kits/os/freddie/pages-os.js +0 -51
  120. package/dist/src/kits/os/freddie/pages-tools.js +0 -183
  121. package/dist/src/kits/os/freddie/routes.js +0 -24
  122. package/dist/src/kits/os/freddie-dashboard.css +0 -51
  123. package/dist/src/kits/os/freddie-dashboard.js +0 -101
  124. package/dist/src/kits/os/icons.js +0 -17
  125. package/dist/src/kits/os/index.js +0 -5
  126. package/dist/src/kits/os/launcher.css +0 -61
  127. package/dist/src/kits/os/launcher.js +0 -79
  128. package/dist/src/kits/os/monitor-app.js +0 -34
  129. package/dist/src/kits/os/shell.js +0 -214
  130. package/dist/src/kits/os/terminal-app.js +0 -45
  131. package/dist/src/kits/os/theme.css +0 -412
  132. package/dist/src/kits/os/validate.css +0 -19
  133. package/dist/src/kits/os/validator-app.js +0 -55
  134. package/dist/src/kits/os/wm.css +0 -115
  135. package/dist/src/kits/os/wm.js +0 -111
  136. package/dist/src/markdown.js +0 -39
  137. package/dist/src/motion.js +0 -35
  138. package/dist/src/page-html.js +0 -196
  139. package/dist/src/styles.js +0 -25
  140. package/dist/src/theme.js +0 -99
  141. package/dist/src/web-components/ds-chat.js +0 -45
  142. package/dist/ui_kits/aicat/README.md +0 -7
  143. package/dist/ui_kits/aicat/app.js +0 -156
  144. package/dist/ui_kits/aicat/index.html +0 -26
  145. package/dist/ui_kits/aicat/sample-square.png +0 -0
  146. package/dist/ui_kits/aicat/sample-svg.svg +0 -1
  147. package/dist/ui_kits/aicat/sample.pdf +0 -32
  148. package/dist/ui_kits/blog/README.md +0 -3
  149. package/dist/ui_kits/blog/index.html +0 -90
  150. package/dist/ui_kits/chat/README.md +0 -5
  151. package/dist/ui_kits/chat/app.js +0 -110
  152. package/dist/ui_kits/chat/index.html +0 -26
  153. package/dist/ui_kits/chat/sample-square.png +0 -0
  154. package/dist/ui_kits/chat/sample-svg.svg +0 -1
  155. package/dist/ui_kits/chat/sample.pdf +0 -32
  156. package/dist/ui_kits/community/app.js +0 -134
  157. package/dist/ui_kits/community/index.html +0 -24
  158. package/dist/ui_kits/dashboard/app.js +0 -92
  159. package/dist/ui_kits/dashboard/index.html +0 -26
  160. package/dist/ui_kits/docs/README.md +0 -3
  161. package/dist/ui_kits/docs/index.html +0 -123
  162. package/dist/ui_kits/error_404/app.js +0 -56
  163. package/dist/ui_kits/error_404/index.html +0 -26
  164. package/dist/ui_kits/file_browser/README.md +0 -48
  165. package/dist/ui_kits/file_browser/app.js +0 -231
  166. package/dist/ui_kits/file_browser/index.html +0 -33
  167. package/dist/ui_kits/gallery/app.js +0 -121
  168. package/dist/ui_kits/gallery/index.html +0 -26
  169. package/dist/ui_kits/homepage/README.md +0 -7
  170. package/dist/ui_kits/homepage/app.js +0 -167
  171. package/dist/ui_kits/homepage/index.html +0 -46
  172. package/dist/ui_kits/project_page/README.md +0 -3
  173. package/dist/ui_kits/project_page/app.js +0 -154
  174. package/dist/ui_kits/project_page/index.html +0 -45
  175. package/dist/ui_kits/search/app.js +0 -107
  176. package/dist/ui_kits/search/index.html +0 -26
  177. package/dist/ui_kits/settings/app.js +0 -133
  178. package/dist/ui_kits/settings/index.html +0 -26
  179. package/dist/ui_kits/signin/app.js +0 -115
  180. package/dist/ui_kits/signin/index.html +0 -26
  181. package/dist/ui_kits/slide_deck/app.js +0 -174
  182. package/dist/ui_kits/slide_deck/index.html +0 -26
  183. package/dist/ui_kits/system_primer/app.js +0 -152
  184. package/dist/ui_kits/system_primer/index.html +0 -26
  185. package/dist/ui_kits/terminal/app.js +0 -150
  186. package/dist/ui_kits/terminal/index.html +0 -26
  187. package/dist/vendor/webjsx/applyDiff.js +0 -182
  188. package/dist/vendor/webjsx/attributes.js +0 -154
  189. package/dist/vendor/webjsx/constants.js +0 -4
  190. package/dist/vendor/webjsx/createDOMElement.js +0 -52
  191. package/dist/vendor/webjsx/createElement.js +0 -75
  192. package/dist/vendor/webjsx/elementTags.js +0 -115
  193. package/dist/vendor/webjsx/factory.js +0 -6
  194. package/dist/vendor/webjsx/index.js +0 -6
  195. package/dist/vendor/webjsx/jsx-dev-runtime.js +0 -2
  196. package/dist/vendor/webjsx/jsx-runtime.js +0 -30
  197. package/dist/vendor/webjsx/jsx.js +0 -2
  198. package/dist/vendor/webjsx/package.json +0 -39
  199. package/dist/vendor/webjsx/renderSuspension.js +0 -25
  200. package/dist/vendor/webjsx/types.js +0 -5
  201. package/dist/vendor/webjsx/utils.js +0 -84
  202. package/src/components/overlays.js +0 -151
package/package.json CHANGED
@@ -1,80 +1,80 @@
1
- {
2
- "name": "anentrypoint-design",
3
- "version": "0.0.121",
4
- "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
- "type": "module",
6
- "main": "./dist/247420.js",
7
- "module": "./dist/247420.js",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/247420.js",
11
- "default": "./dist/247420.js"
12
- },
13
- "./css": "./dist/247420.css",
14
- "./kits/os": {
15
- "import": "./src/kits/os/index.js",
16
- "default": "./src/kits/os/index.js"
17
- },
18
- "./kits/os/theme.css": "./src/kits/os/theme.css",
19
- "./kits/os/wm.css": "./src/kits/os/wm.css",
20
- "./kits/os/wm.js": "./src/kits/os/wm.js",
21
- "./kits/os/launcher.js": "./src/kits/os/launcher.js",
22
- "./kits/os/launcher.css": "./src/kits/os/launcher.css",
23
- "./kits/os/validate.css": "./src/kits/os/validate.css",
24
- "./kits/os/icons.js": "./src/kits/os/icons.js",
25
- "./kits/os/shell.js": "./src/kits/os/shell.js",
26
- "./kits/os/freddie-dashboard.js": "./src/kits/os/freddie-dashboard.js",
27
- "./kits/os/freddie-dashboard.css": "./src/kits/os/freddie-dashboard.css",
28
- "./kits/os/files-app.js": "./src/kits/os/files-app.js",
29
- "./kits/os/monitor-app.js": "./src/kits/os/monitor-app.js",
30
- "./kits/os/about-app.js": "./src/kits/os/about-app.js",
31
- "./kits/os/terminal-app.js": "./src/kits/os/terminal-app.js",
32
- "./kits/os/browser-app.js": "./src/kits/os/browser-app.js",
33
- "./kits/os/validator-app.js": "./src/kits/os/validator-app.js",
34
- "./kits/os/app-panes.css": "./src/kits/os/app-panes.css",
35
- "./colors_and_type.css": "./colors_and_type.css",
36
- "./app-shell.css": "./app-shell.css",
37
- "./community.css": "./community.css",
38
- "./system.css": "./system.css",
39
- "./page-html": {
40
- "import": "./src/page-html.js",
41
- "default": "./src/page-html.js"
42
- },
43
- "./src/page-html.js": "./src/page-html.js",
44
- "./web-components/ds-chat.js": "./src/web-components/ds-chat.js",
45
- "./package.json": "./package.json"
46
- },
47
- "files": [
48
- "dist",
49
- "src",
50
- "vendor/webjsx",
51
- "colors_and_type.css",
52
- "app-shell.css",
53
- "community.css",
54
- "README.md"
55
- ],
56
- "scripts": {
57
- "build": "node scripts/build.mjs",
58
- "test": "node test.js"
59
- },
60
- "repository": {
61
- "type": "git",
62
- "url": "git+https://github.com/AnEntrypoint/Design.git"
63
- },
64
- "keywords": [
65
- "247420",
66
- "anentrypoint",
67
- "design-system",
68
- "webjsx",
69
- "rippleui"
70
- ],
71
- "license": "MIT",
72
- "publishConfig": {
73
- "access": "public"
74
- },
75
- "devDependencies": {
76
- "esbuild": "^0.28.0",
77
- "postcss": "^8.5.12",
78
- "postcss-prefix-selector": "^2.1.1"
79
- }
80
- }
1
+ {
2
+ "name": "anentrypoint-design",
3
+ "version": "0.0.124",
4
+ "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
+ "type": "module",
6
+ "main": "./dist/247420.js",
7
+ "module": "./dist/247420.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/247420.js",
11
+ "default": "./dist/247420.js"
12
+ },
13
+ "./css": "./dist/247420.css",
14
+ "./kits/os": {
15
+ "import": "./src/kits/os/index.js",
16
+ "default": "./src/kits/os/index.js"
17
+ },
18
+ "./kits/os/theme.css": "./src/kits/os/theme.css",
19
+ "./kits/os/wm.css": "./src/kits/os/wm.css",
20
+ "./kits/os/wm.js": "./src/kits/os/wm.js",
21
+ "./kits/os/launcher.js": "./src/kits/os/launcher.js",
22
+ "./kits/os/launcher.css": "./src/kits/os/launcher.css",
23
+ "./kits/os/validate.css": "./src/kits/os/validate.css",
24
+ "./kits/os/icons.js": "./src/kits/os/icons.js",
25
+ "./kits/os/shell.js": "./src/kits/os/shell.js",
26
+ "./kits/os/freddie-dashboard.js": "./src/kits/os/freddie-dashboard.js",
27
+ "./kits/os/freddie-dashboard.css": "./src/kits/os/freddie-dashboard.css",
28
+ "./kits/os/files-app.js": "./src/kits/os/files-app.js",
29
+ "./kits/os/monitor-app.js": "./src/kits/os/monitor-app.js",
30
+ "./kits/os/about-app.js": "./src/kits/os/about-app.js",
31
+ "./kits/os/terminal-app.js": "./src/kits/os/terminal-app.js",
32
+ "./kits/os/browser-app.js": "./src/kits/os/browser-app.js",
33
+ "./kits/os/validator-app.js": "./src/kits/os/validator-app.js",
34
+ "./kits/os/app-panes.css": "./src/kits/os/app-panes.css",
35
+ "./colors_and_type.css": "./colors_and_type.css",
36
+ "./app-shell.css": "./app-shell.css",
37
+ "./community.css": "./community.css",
38
+ "./system.css": "./system.css",
39
+ "./page-html": {
40
+ "import": "./src/page-html.js",
41
+ "default": "./src/page-html.js"
42
+ },
43
+ "./src/page-html.js": "./src/page-html.js",
44
+ "./web-components/ds-chat.js": "./src/web-components/ds-chat.js",
45
+ "./package.json": "./package.json"
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "src",
50
+ "vendor/webjsx",
51
+ "colors_and_type.css",
52
+ "app-shell.css",
53
+ "community.css",
54
+ "README.md"
55
+ ],
56
+ "scripts": {
57
+ "build": "node scripts/build.mjs",
58
+ "test": "node test.js"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/AnEntrypoint/Design.git"
63
+ },
64
+ "keywords": [
65
+ "247420",
66
+ "anentrypoint",
67
+ "design-system",
68
+ "webjsx",
69
+ "rippleui"
70
+ ],
71
+ "license": "MIT",
72
+ "publishConfig": {
73
+ "access": "public"
74
+ },
75
+ "devDependencies": {
76
+ "esbuild": "^0.28.0",
77
+ "postcss": "^8.5.12",
78
+ "postcss-prefix-selector": "^2.1.1"
79
+ }
80
+ }
package/src/bootstrap.js CHANGED
@@ -1,25 +1,25 @@
1
- // mountKit — single entry every ui_kit uses. Installs motion, runs
2
- // applyDiff, registers a debug snapshot.
3
-
4
- import * as webjsx from '../vendor/webjsx/index.js';
5
- import * as motion from './motion.js';
6
- import { register } from './debug.js';
7
-
8
- export function mountKit({ root, view, screen, animateOnMount = true } = {}) {
9
- if (!root) throw new Error('mountKit: root required');
10
- if (typeof view !== 'function') throw new Error('mountKit: view fn required');
11
- if (screen && typeof document !== 'undefined') document.body.dataset.screenLabel = screen;
12
- motion.installMotion();
13
- let scheduled = false;
14
- const render = () => {
15
- scheduled = false;
16
- webjsx.applyDiff(root, view());
17
- if (animateOnMount) requestAnimationFrame(() => motion.animateTree(root));
18
- };
19
- const schedule = () => { if (scheduled) return; scheduled = true; queueMicrotask(render); };
20
- register('bootstrap', () => ({ screen: screen || null, mounted: !!root.firstChild, root: root.id || root.tagName }));
21
- render();
22
- return { render, schedule };
23
- }
24
-
25
- export { webjsx };
1
+ // mountKit — single entry every ui_kit uses. Installs motion, runs
2
+ // applyDiff, registers a debug snapshot.
3
+
4
+ import * as webjsx from '../vendor/webjsx/index.js';
5
+ import * as motion from './motion.js';
6
+ import { register } from './debug.js';
7
+
8
+ export function mountKit({ root, view, screen, animateOnMount = true } = {}) {
9
+ if (!root) throw new Error('mountKit: root required');
10
+ if (typeof view !== 'function') throw new Error('mountKit: view fn required');
11
+ if (screen && typeof document !== 'undefined') document.body.dataset.screenLabel = screen;
12
+ motion.installMotion();
13
+ let scheduled = false;
14
+ const render = () => {
15
+ scheduled = false;
16
+ webjsx.applyDiff(root, view());
17
+ if (animateOnMount) requestAnimationFrame(() => motion.animateTree(root));
18
+ };
19
+ const schedule = () => { if (scheduled) return; scheduled = true; queueMicrotask(render); };
20
+ register('bootstrap', () => ({ screen: screen || null, mounted: !!root.firstChild, root: root.id || root.tagName }));
21
+ render();
22
+ return { render, schedule };
23
+ }
24
+
25
+ export { webjsx };
@@ -1,199 +1,199 @@
1
- // Chat surface — matches upstream signatures (parts, typing, reactions,
2
- // receipts, aicat). Pure factories — props in, vnode out.
3
- // Includes ChatMessage, ChatComposer, Chat, AICat, AICatPortrait.
4
-
5
- import * as webjsx from '../../vendor/webjsx/index.js';
6
- import { renderMarkdown, ensureReady as ensureMarkdownReady } from '../markdown.js';
7
- import { highlightAllUnder, ensurePrism } from '../highlight.js';
8
- import { register } from '../debug.js';
9
-
10
- const h = webjsx.createElement;
11
- let _stats = { messages: 0, lastKindCounts: {} };
12
-
13
- export function fmtBytes(n) {
14
- if (n == null) return '';
15
- if (n < 1024) return n + ' B';
16
- if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB';
17
- if (n < 1024 * 1024 * 1024) return (n / (1024 * 1024)).toFixed(1) + ' MB';
18
- return (n / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
19
- }
20
-
21
- // Inline-only markdown subset; safe for chat bubbles.
22
- export function renderInline(text) {
23
- if (text == null) return [];
24
- const out = [];
25
- const re = /(\*\*([^*]+)\*\*|\*([^*]+)\*|`([^`]+)`|\[([^\]]+)\]\(([^)]+)\))/g;
26
- let last = 0; let m; let i = 0;
27
- const push = (n) => out.push(n);
28
- while ((m = re.exec(text)) !== null) {
29
- if (m.index > last) push(h('span', { key: 's' + i + 'a' }, text.slice(last, m.index)));
30
- if (m[2] != null) push(h('strong', { key: 's' + i }, m[2]));
31
- else if (m[3] != null) push(h('em', { key: 's' + i }, m[3]));
32
- else if (m[4] != null) push(h('code', { key: 's' + i, class: 'chat-tick' }, m[4]));
33
- else if (m[5] != null) push(h('a', { key: 's' + i, href: m[6], target: '_blank', rel: 'noopener' }, m[5]));
34
- last = m.index + m[0].length; i += 1;
35
- }
36
- if (last < text.length) push(h('span', { key: 's' + i + 'a' }, text.slice(last)));
37
- return out;
38
- }
39
-
40
- const FILE_GLYPHS = { pdf: '▤', zip: '▦', tar: '▦', gz: '▦', mp4: '▶', mp3: '♪', wav: '♪', csv: '⊞', json: '{}', md: '§', txt: '§', default: '◫' };
41
- function fileGlyph(name) {
42
- const ext = String(name || '').split('.').pop().toLowerCase();
43
- return FILE_GLYPHS[ext] || FILE_GLYPHS.default;
44
- }
45
-
46
- function MdNode(p) {
47
- const refSink = (el) => {
48
- if (!el) return;
49
- if (el.dataset.mdSrc === p.text) return;
50
- el.dataset.mdSrc = p.text || '';
51
- ensureMarkdownReady().then(() => renderMarkdown(p.text || '')).then((html) => { el.innerHTML = html; });
52
- };
53
- return h('div', { class: 'chat-bubble chat-md', ref: refSink });
54
- }
55
-
56
- function CodeNode(p) {
57
- const refSink = (el) => {
58
- if (!el) return;
59
- if (el.dataset.codeKey === (p.lang || '') + '|' + (p.code || '').length) return;
60
- el.dataset.codeKey = (p.lang || '') + '|' + (p.code || '').length;
61
- ensurePrism().then(() => highlightAllUnder(el));
62
- };
63
- return h('div', { class: 'chat-bubble chat-code', ref: refSink },
64
- h('div', { class: 'chat-code-head' },
65
- h('span', { class: 'lang' }, p.lang || 'code'),
66
- p.filename ? h('span', { class: 'name' }, p.filename) : null
67
- ),
68
- h('pre', {}, h('code', { class: p.lang ? 'lang-' + p.lang + ' language-' + p.lang : '' }, p.code || ''))
69
- );
70
- }
71
-
72
- const PART_RENDERERS = {
73
- text: (p) => h('div', { class: 'chat-bubble' }, ...renderInline(p.text || '')),
74
- md: (p) => MdNode(p),
75
- code: (p) => CodeNode(p),
76
- image: (p) => h('a', { class: 'chat-image', href: p.href || p.src, target: '_blank', rel: 'noopener' },
77
- h('img', { src: p.src, alt: p.alt || '', loading: 'lazy' }),
78
- p.caption ? h('span', { class: 'cap' }, p.caption) : null),
79
- pdf: (p) => h('div', { class: 'chat-pdf' },
80
- h('div', { class: 'chat-pdf-head' },
81
- h('span', { class: 'glyph' }, '▤'),
82
- h('span', { class: 'name' }, p.name || 'document.pdf'),
83
- p.size != null ? h('span', { class: 'size' }, fmtBytes(p.size)) : null,
84
- h('a', { class: 'open', href: p.src, target: '_blank', rel: 'noopener' }, 'open ↗')
85
- ),
86
- h('embed', { src: p.src, type: 'application/pdf' })),
87
- file: (p) => h('a', { class: 'chat-file', href: p.src, target: '_blank', rel: 'noopener', download: p.name || true },
88
- h('span', { class: 'glyph' }, fileGlyph(p.name)),
89
- h('span', { class: 'meta' },
90
- h('span', { class: 'name' }, p.name || 'attachment'),
91
- h('span', { class: 'size' }, [p.kindLabel || (p.name || '').split('.').pop().toUpperCase(), p.size != null ? fmtBytes(p.size) : null].filter(Boolean).join(' · '))
92
- ),
93
- h('span', { class: 'go' }, '↓')),
94
- link: (p) => h('a', { class: 'chat-link', href: p.href, target: '_blank', rel: 'noopener' },
95
- p.thumb ? h('img', { class: 'thumb', src: p.thumb, alt: '' }) : null,
96
- h('span', { class: 'meta' },
97
- h('span', { class: 'host' }, p.host || (() => { try { return new URL(p.href).host; } catch { return ''; } })()),
98
- h('span', { class: 'title' }, p.title || p.href),
99
- p.desc ? h('span', { class: 'desc' }, p.desc) : null
100
- ))
101
- };
102
-
103
- function renderPart(p, key) {
104
- const fn = PART_RENDERERS[p.kind] || PART_RENDERERS.text;
105
- const node = fn(p);
106
- if (node && typeof node === 'object') node.props = { ...(node.props || {}), key: 'p' + key };
107
- _stats.lastKindCounts[p.kind] = (_stats.lastKindCounts[p.kind] || 0) + 1;
108
- return node;
109
- }
110
-
111
- export function ChatMessage({ who = 'them', avatar, text, parts, time, typing, key, aicat, reactions, receipt, name }) {
112
- _stats.messages += 1;
113
- const cls = 'chat-msg ' + who + (aicat && who === 'them' ? ' aicat' : '');
114
- const av = h('span', { class: 'chat-avatar' }, avatar || (who === 'you' ? 'u' : '?'));
115
- let bodyNodes;
116
- if (typing) bodyNodes = [h('span', { class: 'chat-typing', key: 'typ' }, h('span'), h('span'), h('span'))];
117
- else if (parts && parts.length) bodyNodes = parts.map((p, i) => renderPart(p, i));
118
- else bodyNodes = [h('div', { class: 'chat-bubble', key: 't' }, ...renderInline(text || ''))];
119
- const reactionRow = reactions && reactions.length
120
- ? h('div', { class: 'chat-reactions' },
121
- ...reactions.map((r, i) => h('span', { class: 'rxn' + (r.you ? ' you' : ''), key: 'r' + i },
122
- h('span', { class: 'e' }, r.emoji), h('span', { class: 'n' }, String(r.count)))))
123
- : null;
124
- const tickNode = who === 'you' && receipt
125
- ? h('span', { class: 'tick' + (receipt === 'read' ? ' read' : '') }, receipt === 'read' ? '✓✓' : '✓')
126
- : null;
127
- const metaItems = [];
128
- if (name && who === 'them') metaItems.push(h('span', { class: 'who', key: 'w' }, name));
129
- if (time) metaItems.push(h('span', { class: 't', key: 'ti' }, time));
130
- if (tickNode) metaItems.push(tickNode);
131
- const meta = metaItems.length ? h('div', { class: 'chat-meta' }, ...metaItems) : null;
132
- const stack = h('div', { class: 'chat-stack' }, ...bodyNodes, reactionRow, meta);
133
- return h('div', { key, class: cls }, who === 'you' ? stack : av, who === 'you' ? av : stack);
134
- }
135
-
136
- export function ChatComposer({ value, onInput, onSend, placeholder = 'message…', disabled }) {
137
- const send = () => {
138
- const v = (value || '').trim();
139
- if (!v || disabled) return;
140
- if (onSend) onSend(v);
141
- };
142
- return h('div', { class: 'chat-composer' },
143
- h('textarea', { value: value || '', placeholder, rows: 1,
144
- oninput: (e) => onInput && onInput(e.target.value),
145
- onkeydown: (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } } }),
146
- h('button', { class: 'send', disabled: disabled || !(value && value.trim()), onclick: send }, '↑')
147
- );
148
- }
149
-
150
- export function Chat({ title = 'chat', sub, messages = [], composer, header } = {}) {
151
- return h('div', { class: 'chat' },
152
- header || h('div', { class: 'chat-head' },
153
- h('span', { class: 'dot' }),
154
- h('span', {}, title),
155
- sub ? h('span', { class: 'sub' }, ' · ' + sub) : null,
156
- h('span', { class: 'spread' }),
157
- h('span', { class: 'sub' }, String(messages.length).padStart(2, '0') + ' msgs')
158
- ),
159
- h('div', { class: 'chat-thread' },
160
- ...messages.map((m, i) => ChatMessage({ ...m, key: m.key != null ? m.key : i }))
161
- ),
162
- composer || null
163
- );
164
- }
165
-
166
- export const AICAT_FACE = ` /\\_/\\\n( o.o )\n > ^ <`;
167
-
168
- export function AICatPortrait({ name = 'aicat', status = 'idle', face } = {}) {
169
- return h('div', { class: 'aicat-portrait' },
170
- h('pre', { class: 'aicat-face' }, face || AICAT_FACE),
171
- h('div', { class: 'aicat-meta' },
172
- h('span', { class: 'name' }, name),
173
- h('span', { class: 'status' }, h('span', { class: 'dot' }, '● '), status)
174
- )
175
- );
176
- }
177
-
178
- export function AICat({ name = 'aicat', messages = [], thinking, composer, status = 'online · purring' } = {}) {
179
- const annotated = messages.map((m) =>
180
- m.who === 'them' ? { ...m, aicat: true, avatar: m.avatar || '=^.^=' } : m);
181
- const all = thinking
182
- ? [...annotated, { who: 'them', aicat: true, avatar: '=^.^=', typing: true, key: '_thinking' }]
183
- : annotated;
184
- return h('div', { class: 'chat' },
185
- h('div', { class: 'chat-head' },
186
- h('span', { class: 'dot' }),
187
- h('span', {}, name),
188
- h('span', { class: 'sub' }, ' · ' + status),
189
- h('span', { class: 'spread' }),
190
- h('span', { class: 'sub' }, String(messages.length).padStart(2, '0') + ' turns')
191
- ),
192
- h('div', { class: 'chat-thread' },
193
- ...all.map((m, i) => ChatMessage({ ...m, key: m.key != null ? m.key : i }))
194
- ),
195
- composer || null
196
- );
197
- }
198
-
199
- register('chat', () => ({ messages: _stats.messages, lastKindCounts: { ..._stats.lastKindCounts } }));
1
+ // Chat surface — matches upstream signatures (parts, typing, reactions,
2
+ // receipts, aicat). Pure factories — props in, vnode out.
3
+ // Includes ChatMessage, ChatComposer, Chat, AICat, AICatPortrait.
4
+
5
+ import * as webjsx from '../../vendor/webjsx/index.js';
6
+ import { renderMarkdown, ensureReady as ensureMarkdownReady } from '../markdown.js';
7
+ import { highlightAllUnder, ensurePrism } from '../highlight.js';
8
+ import { register } from '../debug.js';
9
+
10
+ const h = webjsx.createElement;
11
+ let _stats = { messages: 0, lastKindCounts: {} };
12
+
13
+ export function fmtBytes(n) {
14
+ if (n == null) return '';
15
+ if (n < 1024) return n + ' B';
16
+ if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB';
17
+ if (n < 1024 * 1024 * 1024) return (n / (1024 * 1024)).toFixed(1) + ' MB';
18
+ return (n / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
19
+ }
20
+
21
+ // Inline-only markdown subset; safe for chat bubbles.
22
+ export function renderInline(text) {
23
+ if (text == null) return [];
24
+ const out = [];
25
+ const re = /(\*\*([^*]+)\*\*|\*([^*]+)\*|`([^`]+)`|\[([^\]]+)\]\(([^)]+)\))/g;
26
+ let last = 0; let m; let i = 0;
27
+ const push = (n) => out.push(n);
28
+ while ((m = re.exec(text)) !== null) {
29
+ if (m.index > last) push(h('span', { key: 's' + i + 'a' }, text.slice(last, m.index)));
30
+ if (m[2] != null) push(h('strong', { key: 's' + i }, m[2]));
31
+ else if (m[3] != null) push(h('em', { key: 's' + i }, m[3]));
32
+ else if (m[4] != null) push(h('code', { key: 's' + i, class: 'chat-tick' }, m[4]));
33
+ else if (m[5] != null) push(h('a', { key: 's' + i, href: m[6], target: '_blank', rel: 'noopener' }, m[5]));
34
+ last = m.index + m[0].length; i += 1;
35
+ }
36
+ if (last < text.length) push(h('span', { key: 's' + i + 'a' }, text.slice(last)));
37
+ return out;
38
+ }
39
+
40
+ const FILE_GLYPHS = { pdf: '▤', zip: '▦', tar: '▦', gz: '▦', mp4: '▶', mp3: '♪', wav: '♪', csv: '⊞', json: '{}', md: '§', txt: '§', default: '◫' };
41
+ function fileGlyph(name) {
42
+ const ext = String(name || '').split('.').pop().toLowerCase();
43
+ return FILE_GLYPHS[ext] || FILE_GLYPHS.default;
44
+ }
45
+
46
+ function MdNode(p) {
47
+ const refSink = (el) => {
48
+ if (!el) return;
49
+ if (el.dataset.mdSrc === p.text) return;
50
+ el.dataset.mdSrc = p.text || '';
51
+ ensureMarkdownReady().then(() => renderMarkdown(p.text || '')).then((html) => { el.innerHTML = html; });
52
+ };
53
+ return h('div', { class: 'chat-bubble chat-md', ref: refSink });
54
+ }
55
+
56
+ function CodeNode(p) {
57
+ const refSink = (el) => {
58
+ if (!el) return;
59
+ if (el.dataset.codeKey === (p.lang || '') + '|' + (p.code || '').length) return;
60
+ el.dataset.codeKey = (p.lang || '') + '|' + (p.code || '').length;
61
+ ensurePrism().then(() => highlightAllUnder(el));
62
+ };
63
+ return h('div', { class: 'chat-bubble chat-code', ref: refSink },
64
+ h('div', { class: 'chat-code-head' },
65
+ h('span', { class: 'lang' }, p.lang || 'code'),
66
+ p.filename ? h('span', { class: 'name' }, p.filename) : null
67
+ ),
68
+ h('pre', {}, h('code', { class: p.lang ? 'lang-' + p.lang + ' language-' + p.lang : '' }, p.code || ''))
69
+ );
70
+ }
71
+
72
+ const PART_RENDERERS = {
73
+ text: (p) => h('div', { class: 'chat-bubble' }, ...renderInline(p.text || '')),
74
+ md: (p) => MdNode(p),
75
+ code: (p) => CodeNode(p),
76
+ image: (p) => h('a', { class: 'chat-image', href: p.href || p.src, target: '_blank', rel: 'noopener' },
77
+ h('img', { src: p.src, alt: p.alt || '', loading: 'lazy' }),
78
+ p.caption ? h('span', { class: 'cap' }, p.caption) : null),
79
+ pdf: (p) => h('div', { class: 'chat-pdf' },
80
+ h('div', { class: 'chat-pdf-head' },
81
+ h('span', { class: 'glyph' }, '▤'),
82
+ h('span', { class: 'name' }, p.name || 'document.pdf'),
83
+ p.size != null ? h('span', { class: 'size' }, fmtBytes(p.size)) : null,
84
+ h('a', { class: 'open', href: p.src, target: '_blank', rel: 'noopener' }, 'open ↗')
85
+ ),
86
+ h('embed', { src: p.src, type: 'application/pdf' })),
87
+ file: (p) => h('a', { class: 'chat-file', href: p.src, target: '_blank', rel: 'noopener', download: p.name || true },
88
+ h('span', { class: 'glyph' }, fileGlyph(p.name)),
89
+ h('span', { class: 'meta' },
90
+ h('span', { class: 'name' }, p.name || 'attachment'),
91
+ h('span', { class: 'size' }, [p.kindLabel || (p.name || '').split('.').pop().toUpperCase(), p.size != null ? fmtBytes(p.size) : null].filter(Boolean).join(' · '))
92
+ ),
93
+ h('span', { class: 'go' }, '↓')),
94
+ link: (p) => h('a', { class: 'chat-link', href: p.href, target: '_blank', rel: 'noopener' },
95
+ p.thumb ? h('img', { class: 'thumb', src: p.thumb, alt: '' }) : null,
96
+ h('span', { class: 'meta' },
97
+ h('span', { class: 'host' }, p.host || (() => { try { return new URL(p.href).host; } catch { return ''; } })()),
98
+ h('span', { class: 'title' }, p.title || p.href),
99
+ p.desc ? h('span', { class: 'desc' }, p.desc) : null
100
+ ))
101
+ };
102
+
103
+ function renderPart(p, key) {
104
+ const fn = PART_RENDERERS[p.kind] || PART_RENDERERS.text;
105
+ const node = fn(p);
106
+ if (node && typeof node === 'object') node.props = { ...(node.props || {}), key: 'p' + key };
107
+ _stats.lastKindCounts[p.kind] = (_stats.lastKindCounts[p.kind] || 0) + 1;
108
+ return node;
109
+ }
110
+
111
+ export function ChatMessage({ who = 'them', avatar, text, parts, time, typing, key, aicat, reactions, receipt, name }) {
112
+ _stats.messages += 1;
113
+ const cls = 'chat-msg ' + who + (aicat && who === 'them' ? ' aicat' : '');
114
+ const av = h('span', { class: 'chat-avatar' }, avatar || (who === 'you' ? 'u' : '?'));
115
+ let bodyNodes;
116
+ if (typing) bodyNodes = [h('div', { class: 'chat-bubble', key: 'typb' }, h('span', { class: 'chat-typing' }, h('span'), h('span'), h('span')))];
117
+ else if (parts && parts.length) bodyNodes = parts.map((p, i) => renderPart(p, i));
118
+ else bodyNodes = [h('div', { class: 'chat-bubble', key: 't' }, ...renderInline(text || ''))];
119
+ const reactionRow = reactions && reactions.length
120
+ ? h('div', { class: 'chat-reactions' },
121
+ ...reactions.map((r, i) => h('span', { class: 'rxn' + (r.you ? ' you' : ''), key: 'r' + i },
122
+ h('span', { class: 'e' }, r.emoji), h('span', { class: 'n' }, String(r.count)))))
123
+ : null;
124
+ const tickNode = who === 'you' && receipt
125
+ ? h('span', { class: 'tick' + (receipt === 'read' ? ' read' : '') }, receipt === 'read' ? '✓✓' : '✓')
126
+ : null;
127
+ const metaItems = [];
128
+ if (name && who === 'them') metaItems.push(h('span', { class: 'who', key: 'w' }, name));
129
+ if (time) metaItems.push(h('span', { class: 't', key: 'ti' }, time));
130
+ if (tickNode) metaItems.push(tickNode);
131
+ const meta = metaItems.length ? h('div', { class: 'chat-meta' }, ...metaItems) : null;
132
+ const stack = h('div', { class: 'chat-stack' }, ...bodyNodes, reactionRow, meta);
133
+ return h('div', { key, class: cls }, who === 'you' ? stack : av, who === 'you' ? av : stack);
134
+ }
135
+
136
+ export function ChatComposer({ value, onInput, onSend, placeholder = 'message…', disabled }) {
137
+ const send = () => {
138
+ const v = (value || '').trim();
139
+ if (!v || disabled) return;
140
+ if (onSend) onSend(v);
141
+ };
142
+ return h('div', { class: 'chat-composer' },
143
+ h('textarea', { value: value || '', placeholder, rows: 1,
144
+ oninput: (e) => onInput && onInput(e.target.value),
145
+ onkeydown: (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } } }),
146
+ h('button', { class: 'send', disabled: disabled || !(value && value.trim()), onclick: send }, '↑')
147
+ );
148
+ }
149
+
150
+ export function Chat({ title = 'chat', sub, messages = [], composer, header } = {}) {
151
+ return h('div', { class: 'chat' },
152
+ header || h('div', { class: 'chat-head' },
153
+ h('span', { class: 'dot' }),
154
+ h('span', {}, title),
155
+ sub ? h('span', { class: 'sub' }, ' · ' + sub) : null,
156
+ h('span', { class: 'spread' }),
157
+ h('span', { class: 'sub' }, String(messages.length).padStart(2, '0') + ' msgs')
158
+ ),
159
+ h('div', { class: 'chat-thread' },
160
+ ...messages.map((m, i) => ChatMessage({ ...m, key: m.key != null ? m.key : i }))
161
+ ),
162
+ composer || null
163
+ );
164
+ }
165
+
166
+ export const AICAT_FACE = ` /\\_/\\\n( o.o )\n > ^ <`;
167
+
168
+ export function AICatPortrait({ name = 'aicat', status = 'idle', face } = {}) {
169
+ return h('div', { class: 'aicat-portrait' },
170
+ h('pre', { class: 'aicat-face' }, face || AICAT_FACE),
171
+ h('div', { class: 'aicat-meta' },
172
+ h('span', { class: 'name' }, name),
173
+ h('span', { class: 'status' }, h('span', { class: 'dot' }, '● '), status)
174
+ )
175
+ );
176
+ }
177
+
178
+ export function AICat({ name = 'aicat', messages = [], thinking, composer, status = 'online · purring' } = {}) {
179
+ const annotated = messages.map((m) =>
180
+ m.who === 'them' ? { ...m, aicat: true, avatar: m.avatar || '=^.^=' } : m);
181
+ const all = thinking
182
+ ? [...annotated, { who: 'them', aicat: true, avatar: '=^.^=', typing: true, key: '_thinking' }]
183
+ : annotated;
184
+ return h('div', { class: 'chat' },
185
+ h('div', { class: 'chat-head' },
186
+ h('span', { class: 'dot' }),
187
+ h('span', {}, name),
188
+ h('span', { class: 'sub' }, ' · ' + status),
189
+ h('span', { class: 'spread' }),
190
+ h('span', { class: 'sub' }, String(messages.length).padStart(2, '0') + ' turns')
191
+ ),
192
+ h('div', { class: 'chat-thread' },
193
+ ...all.map((m, i) => ChatMessage({ ...m, key: m.key != null ? m.key : i }))
194
+ ),
195
+ composer || null
196
+ );
197
+ }
198
+
199
+ register('chat', () => ({ messages: _stats.messages, lastKindCounts: { ..._stats.lastKindCounts } }));