anentrypoint-design 0.0.102 → 0.0.104

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 (78) hide show
  1. package/app-shell.css +464 -2005
  2. package/colors_and_type.css +148 -619
  3. package/dist/247420.css +592 -2748
  4. package/dist/247420.js +23 -62
  5. package/package.json +22 -23
  6. package/src/bootstrap.js +5 -18
  7. package/src/components/chat.js +15 -15
  8. package/src/components/community.js +9 -7
  9. package/src/components/content.js +71 -54
  10. package/src/components/files-modals.js +4 -2
  11. package/src/components/files.js +6 -14
  12. package/src/components/freddie/helpers.js +38 -77
  13. package/src/components/freddie.js +32 -16
  14. package/src/components/shell.js +22 -15
  15. package/src/components.js +7 -3
  16. package/src/debug.js +21 -30
  17. package/src/deck-stage.js +10 -6
  18. package/src/highlight.js +25 -11
  19. package/src/index.js +31 -7
  20. package/src/{desktop → kits/os}/freddie/helpers.js +1 -1
  21. package/src/{desktop → kits/os}/freddie/pages-chat.js +2 -2
  22. package/src/{desktop → kits/os}/freddie/pages-core.js +2 -2
  23. package/src/{desktop → kits/os}/freddie/pages-os.js +1 -1
  24. package/src/{desktop → kits/os}/freddie/pages-tools.js +2 -2
  25. package/src/{desktop → kits/os}/freddie-dashboard.js +2 -2
  26. package/src/markdown.js +27 -49
  27. package/src/motion.js +30 -17
  28. package/src/page-html.js +18 -116
  29. package/src/styles.js +14 -22
  30. package/src/web-components/ds-chat.js +26 -56
  31. package/dist/247420.app.js +0 -5
  32. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTT0zRp8A.ttf +0 -0
  33. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTT6jRp8A.ttf +0 -0
  34. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTBjNp8A.ttf +0 -0
  35. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTNDNp8A.ttf +0 -0
  36. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTnTRp8A.ttf +0 -0
  37. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTtDRp8A.ttf +0 -0
  38. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhv8laKpA.ttf +0 -0
  39. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhvHlGKpA.ttf +0 -0
  40. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhvLFGKpA.ttf +0 -0
  41. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhvy1aKpA.ttf +0 -0
  42. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8-qxjPQ.ttf +0 -0
  43. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8FqtjPQ.ttf +0 -0
  44. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8L6tjPQ.ttf +0 -0
  45. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxjPQ.ttf +0 -0
  46. package/dist/fonts/jetbrainsmono_v24_tDba2o-flEEny0FZhsfKu5WU4xD-IQ-PuZJJXxfpAO-LflOQ.ttf +0 -0
  47. package/dist/fonts/jetbrainsmono_v24_tDba2o-flEEny0FZhsfKu5WU4xD-IQ-PuZJJXxfpAO9seVOQ.ttf +0 -0
  48. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj42Vksj.ttf +0 -0
  49. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj4PVksj.ttf +0 -0
  50. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7aUUsj.ttf +0 -0
  51. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7oUUsj.ttf +0 -0
  52. package/src/app.js +0 -156
  53. package/src/components/freddie/pages-chains.js +0 -168
  54. package/src/components/freddie/pages-chat.js +0 -122
  55. package/src/components/freddie/pages-config-edit.js +0 -174
  56. package/src/components/freddie/pages-config.js +0 -193
  57. package/src/components/freddie/pages-core.js +0 -170
  58. package/src/components/freddie/pages-runtime.js +0 -69
  59. package/src/components/freddie/pages-voice.js +0 -109
  60. package/src/web-components/freddie-chat.js +0 -34
  61. /package/src/{desktop → kits/os}/about-app.js +0 -0
  62. /package/src/{desktop → kits/os}/app-panes.css +0 -0
  63. /package/src/{desktop → kits/os}/browser-app.js +0 -0
  64. /package/src/{desktop → kits/os}/files-app.js +0 -0
  65. /package/src/{desktop → kits/os}/freddie/routes.js +0 -0
  66. /package/src/{desktop → kits/os}/freddie-dashboard.css +0 -0
  67. /package/src/{desktop → kits/os}/icons.js +0 -0
  68. /package/src/{desktop → kits/os}/index.js +0 -0
  69. /package/src/{desktop → kits/os}/launcher.css +0 -0
  70. /package/src/{desktop → kits/os}/launcher.js +0 -0
  71. /package/src/{desktop → kits/os}/monitor-app.js +0 -0
  72. /package/src/{desktop → kits/os}/shell.js +0 -0
  73. /package/src/{desktop → kits/os}/terminal-app.js +0 -0
  74. /package/src/{desktop → kits/os}/theme.css +0 -0
  75. /package/src/{desktop → kits/os}/validate.css +0 -0
  76. /package/src/{desktop → kits/os}/validator-app.js +0 -0
  77. /package/src/{desktop → kits/os}/wm.css +0 -0
  78. /package/src/{desktop → kits/os}/wm.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.102",
3
+ "version": "0.0.104",
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",
@@ -10,38 +10,37 @@
10
10
  "import": "./dist/247420.js",
11
11
  "default": "./dist/247420.js"
12
12
  },
13
- "./app": "./dist/247420.app.js",
14
13
  "./css": "./dist/247420.css",
15
- "./desktop": {
16
- "import": "./src/desktop/index.js",
17
- "default": "./src/desktop/index.js"
14
+ "./kits/os": {
15
+ "import": "./src/kits/os/index.js",
16
+ "default": "./src/kits/os/index.js"
18
17
  },
19
- "./desktop/theme.css": "./src/desktop/theme.css",
20
- "./desktop/wm.css": "./src/desktop/wm.css",
21
- "./desktop/wm.js": "./src/desktop/wm.js",
22
- "./desktop/launcher.js": "./src/desktop/launcher.js",
23
- "./desktop/launcher.css": "./src/desktop/launcher.css",
24
- "./desktop/validate.css": "./src/desktop/validate.css",
25
- "./desktop/icons.js": "./src/desktop/icons.js",
26
- "./desktop/shell.js": "./src/desktop/shell.js",
27
- "./desktop/freddie-dashboard.js": "./src/desktop/freddie-dashboard.js",
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",
32
- "./desktop/terminal-app.js": "./src/desktop/terminal-app.js",
33
- "./desktop/browser-app.js": "./src/desktop/browser-app.js",
34
- "./desktop/validator-app.js": "./src/desktop/validator-app.js",
35
- "./desktop/app-panes.css": "./src/desktop/app-panes.css",
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",
36
35
  "./colors_and_type.css": "./colors_and_type.css",
37
36
  "./app-shell.css": "./app-shell.css",
37
+ "./system.css": "./system.css",
38
38
  "./page-html": {
39
39
  "import": "./src/page-html.js",
40
40
  "default": "./src/page-html.js"
41
41
  },
42
42
  "./src/page-html.js": "./src/page-html.js",
43
43
  "./web-components/ds-chat.js": "./src/web-components/ds-chat.js",
44
- "./web-components/freddie-chat.js": "./src/web-components/freddie-chat.js",
45
44
  "./package.json": "./package.json"
46
45
  },
47
46
  "files": [
package/src/bootstrap.js CHANGED
@@ -1,28 +1,15 @@
1
+ // mountKit — single entry every ui_kit uses. Installs motion, runs
2
+ // applyDiff, registers a debug snapshot.
3
+
1
4
  import * as webjsx from '../vendor/webjsx/index.js';
2
5
  import * as motion from './motion.js';
3
6
  import { register } from './debug.js';
4
7
 
5
- const ANIMATE_HREF = 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css';
6
- const PRISM_CSS = 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/themes/prism-tomorrow.min.css';
7
-
8
- export function ensureCdnLink(id, href) {
9
- if (document.getElementById(id)) return;
10
- const link = document.createElement('link');
11
- link.id = id;
12
- link.rel = 'stylesheet';
13
- link.href = href;
14
- document.head.appendChild(link);
15
- }
16
-
17
- export function ensureMotionCss() { ensureCdnLink('animate-style-cdn', ANIMATE_HREF); }
18
- export function ensurePrismCss() { ensureCdnLink('prism-style-cdn', PRISM_CSS); }
19
-
20
8
  export function mountKit({ root, view, screen, animateOnMount = true } = {}) {
21
9
  if (!root) throw new Error('mountKit: root required');
22
10
  if (typeof view !== 'function') throw new Error('mountKit: view fn required');
23
- if (screen) document.body.dataset.screenLabel = screen;
24
- ensureMotionCss();
25
- ensurePrismCss();
11
+ if (screen && typeof document !== 'undefined') document.body.dataset.screenLabel = screen;
12
+ motion.installMotion();
26
13
  let scheduled = false;
27
14
  const render = () => {
28
15
  scheduled = false;
@@ -1,10 +1,13 @@
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
+
1
5
  import * as webjsx from '../../vendor/webjsx/index.js';
2
6
  import { renderMarkdown, ensureReady as ensureMarkdownReady } from '../markdown.js';
3
7
  import { highlightAllUnder, ensurePrism } from '../highlight.js';
4
8
  import { register } from '../debug.js';
5
9
 
6
10
  const h = webjsx.createElement;
7
-
8
11
  let _stats = { messages: 0, lastKindCounts: {} };
9
12
 
10
13
  export function fmtBytes(n) {
@@ -15,6 +18,7 @@ export function fmtBytes(n) {
15
18
  return (n / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
16
19
  }
17
20
 
21
+ // Inline-only markdown subset; safe for chat bubbles.
18
22
  export function renderInline(text) {
19
23
  if (text == null) return [];
20
24
  const out = [];
@@ -66,38 +70,34 @@ function CodeNode(p) {
66
70
  }
67
71
 
68
72
  const PART_RENDERERS = {
69
- text: (p) => h('div', { class: 'chat-bubble' }, ...renderInline(p.text || '')),
70
- md: (p) => MdNode(p),
71
- code: (p) => CodeNode(p),
73
+ text: (p) => h('div', { class: 'chat-bubble' }, ...renderInline(p.text || '')),
74
+ md: (p) => MdNode(p),
75
+ code: (p) => CodeNode(p),
72
76
  image: (p) => h('a', { class: 'chat-image', href: p.href || p.src, target: '_blank', rel: 'noopener' },
73
77
  h('img', { src: p.src, alt: p.alt || '', loading: 'lazy' }),
74
- p.caption ? h('span', { class: 'cap' }, p.caption) : null
75
- ),
76
- pdf: (p) => h('div', { class: 'chat-pdf' },
78
+ p.caption ? h('span', { class: 'cap' }, p.caption) : null),
79
+ pdf: (p) => h('div', { class: 'chat-pdf' },
77
80
  h('div', { class: 'chat-pdf-head' },
78
81
  h('span', { class: 'glyph' }, '▤'),
79
82
  h('span', { class: 'name' }, p.name || 'document.pdf'),
80
83
  p.size != null ? h('span', { class: 'size' }, fmtBytes(p.size)) : null,
81
84
  h('a', { class: 'open', href: p.src, target: '_blank', rel: 'noopener' }, 'open ↗')
82
85
  ),
83
- h('embed', { src: p.src, type: 'application/pdf' })
84
- ),
85
- file: (p) => h('a', { class: 'chat-file', href: p.src, target: '_blank', rel: 'noopener', download: p.name || true },
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 },
86
88
  h('span', { class: 'glyph' }, fileGlyph(p.name)),
87
89
  h('span', { class: 'meta' },
88
90
  h('span', { class: 'name' }, p.name || 'attachment'),
89
91
  h('span', { class: 'size' }, [p.kindLabel || (p.name || '').split('.').pop().toUpperCase(), p.size != null ? fmtBytes(p.size) : null].filter(Boolean).join(' · '))
90
92
  ),
91
- h('span', { class: 'go' }, '↓')
92
- ),
93
- link: (p) => h('a', { class: 'chat-link', href: p.href, target: '_blank', rel: 'noopener' },
93
+ h('span', { class: 'go' }, '↓')),
94
+ link: (p) => h('a', { class: 'chat-link', href: p.href, target: '_blank', rel: 'noopener' },
94
95
  p.thumb ? h('img', { class: 'thumb', src: p.thumb, alt: '' }) : null,
95
96
  h('span', { class: 'meta' },
96
97
  h('span', { class: 'host' }, p.host || (() => { try { return new URL(p.href).host; } catch { return ''; } })()),
97
98
  h('span', { class: 'title' }, p.title || p.href),
98
99
  p.desc ? h('span', { class: 'desc' }, p.desc) : null
99
- )
100
- )
100
+ ))
101
101
  };
102
102
 
103
103
  function renderPart(p, key) {
@@ -1,3 +1,5 @@
1
+ // Community surface — matches upstream signatures.
2
+
1
3
  import * as webjsx from '../../vendor/webjsx/index.js';
2
4
  const h = webjsx.createElement;
3
5
 
@@ -14,7 +16,7 @@ export function ServerRail({ servers = [], activeId, onSelect, onAdd } = {}) {
14
16
  return h('div', { class: 'cm-server-rail' },
15
17
  h('a', { class: 'cm-server-back', href: '../', title: 'Back' }, '◰'),
16
18
  h('div', { class: 'cm-server-sep' }),
17
- ...servers.map(s => ServerIcon({ ...s, active: s.id === activeId, onClick: () => onSelect?.(s.id) })),
19
+ ...servers.map(s => ServerIcon({ ...s, active: s.id === activeId, onClick: () => onSelect && onSelect(s.id) })),
18
20
  onAdd ? h('button', { class: 'cm-server-add', onclick: onAdd, title: 'Add server' }, '+') : null
19
21
  );
20
22
  }
@@ -25,7 +27,7 @@ export function ChannelItem({ id, name, type = 'text', active, voiceActive, onCl
25
27
  class: 'cm-channel-item' + (active ? ' active' : '') + (voiceActive ? ' voice-active' : ''),
26
28
  'data-id': id,
27
29
  onclick: onClick,
28
- oncontextmenu: (e) => { e.preventDefault(); onContext?.(id, e.clientX, e.clientY); }
30
+ oncontextmenu: (e) => { e.preventDefault(); onContext && onContext(id, e.clientX, e.clientY); }
29
31
  },
30
32
  h('span', { class: 'cm-ch-icon' }, icon),
31
33
  h('span', { class: 'cm-ch-name' }, name)
@@ -36,7 +38,7 @@ export function ChannelCategory({ id, name, channels = [], collapsed, activeId,
36
38
  return h('div', { class: 'cm-channel-category' },
37
39
  h('div', {
38
40
  class: 'cm-category-header' + (collapsed ? ' collapsed' : ''),
39
- onclick: () => onToggle?.(id)
41
+ onclick: () => onToggle && onToggle(id)
40
42
  },
41
43
  h('svg', { class: 'cm-cat-arrow', viewBox: '0 0 24 24' }, h('path', { d: 'M7 10l5 5 5-5z' })),
42
44
  h('span', { class: 'cm-cat-name' }, name),
@@ -46,7 +48,7 @@ export function ChannelCategory({ id, name, channels = [], collapsed, activeId,
46
48
  ...channels.map(c => ChannelItem({
47
49
  ...c,
48
50
  active: c.id === activeId,
49
- onClick: () => onChannelClick?.(c),
51
+ onClick: () => onChannelClick && onChannelClick(c),
50
52
  onContext: onChannelContext
51
53
  }))
52
54
  )
@@ -80,10 +82,10 @@ export function UserPanel({ name, tag, color, muted, deafened, onMute, onDeafen,
80
82
  );
81
83
  }
82
84
 
83
- export function ChannelSidebar({ serverName, channels = [], categories = [], activeId, collapsedCats = new Set(), onChannelClick, onCategoryToggle, onAddChannel, onChannelContext, userPanelProps } = {}) {
85
+ export function ChannelSidebar({ serverName, channels = [], categories = [], activeId, collapsedCats, onChannelClick, onCategoryToggle, onAddChannel, onChannelContext, userPanelProps } = {}) {
86
+ const collapsed = collapsedCats || new Set();
84
87
  const uncategorized = channels.filter(c => !c.categoryId || !categories.find(cat => cat.id === c.categoryId));
85
88
  const sorted = [...categories].sort((a, b) => (a.position || 0) - (b.position || 0));
86
-
87
89
  return h('div', { class: 'cm-channel-sidebar' },
88
90
  h('div', { class: 'cm-server-header' },
89
91
  h('span', { class: 'cm-server-header-name' }, serverName || 'Server'),
@@ -93,7 +95,7 @@ export function ChannelSidebar({ serverName, channels = [], categories = [], act
93
95
  id: cat.id,
94
96
  name: cat.name,
95
97
  channels: channels.filter(c => c.categoryId === cat.id).sort((a, b) => (a.position || 0) - (b.position || 0)),
96
- collapsed: collapsedCats.has(cat.id),
98
+ collapsed: collapsed.has && collapsed.has(cat.id),
97
99
  activeId,
98
100
  onToggle: onCategoryToggle,
99
101
  onAddChannel,
@@ -1,5 +1,9 @@
1
+ // Content blocks: Panel, Row, RowLink, Section, Hero, Install, Receipt,
2
+ // Changelog, WorksList, WritingList, Manifesto, Kpi, Table, HomeView,
3
+ // ProjectView, Form. Pure factories.
4
+
1
5
  import * as webjsx from '../../vendor/webjsx/index.js';
2
- import { Btn, Heading, Lede } from './shell.js';
6
+ import { Btn, Heading, Lede, Dot } from './shell.js';
3
7
  const h = webjsx.createElement;
4
8
 
5
9
  export function Panel({ title, count, right, style = '', children, kind }) {
@@ -29,13 +33,23 @@ export function RowLink({ code, title, sub, meta, href = '#', key, target }) {
29
33
  return Row({ code, title, sub, meta, href, kind: 'link', key, target });
30
34
  }
31
35
 
32
- export function Hero({ title, body, accent, badge, badgeCount }) {
36
+ export function Section({ title, eyebrow, children }) {
37
+ return h('section', { class: 'ds-section' },
38
+ eyebrow ? h('span', { class: 'eyebrow' }, eyebrow) : null,
39
+ title ? h('h3', {}, title) : null,
40
+ ...(Array.isArray(children) ? children : [children])
41
+ );
42
+ }
43
+
44
+ export function Hero({ eyebrow, title, body, accent, badge, badgeCount, actions }) {
33
45
  return h('div', { class: 'ds-hero' },
46
+ eyebrow ? h('span', { class: 'eyebrow' }, eyebrow) : null,
34
47
  h('h1', { class: 'ds-hero-title' }, title),
35
48
  body ? h('p', { class: 'ds-hero-body' },
36
49
  body,
37
50
  accent ? h('span', { class: 'ds-hero-accent' }, ' ' + accent) : null
38
51
  ) : null,
52
+ actions ? h('div', { class: 'ds-hero-actions', style: 'display:flex;gap:10px;flex-wrap:wrap;margin-top:8px' }, ...(Array.isArray(actions) ? actions : [actions])) : null,
39
53
  badge ? Panel({ title: badge, count: badgeCount, kind: 'inline', children: [] }) : null
40
54
  );
41
55
  }
@@ -71,21 +85,17 @@ export function Changelog({ entries = [] }) {
71
85
 
72
86
  export function WorksList({ works = [], openedIndex = -1, onToggle }) {
73
87
  return Panel({
74
- title: `works · ${String(works.length).padStart(2, '0')} of ~${works.length}`,
75
- right: h('a', { class: 'ds-link-accent', href: 'https://github.com/AnEntrypoint' }, 'all repos ↗'),
76
88
  children: works.map((w, i) => {
77
89
  const isOpen = openedIndex === i;
78
90
  return h('div', { key: i },
79
91
  Row({
80
- code: w.code, title: w.title, sub: w.sub,
92
+ code: w.code,
93
+ title: w.title, sub: w.sub,
81
94
  meta: w.meta + ' ' + (isOpen ? '−' : '+'),
82
95
  active: isOpen,
83
96
  onClick: () => onToggle && onToggle(isOpen ? -1 : i)
84
97
  }),
85
- isOpen ? h('div', {
86
- class: 'work-detail',
87
- 'data-work-index': String(i)
88
- },
98
+ isOpen ? h('div', { class: 'work-detail', 'data-work-index': String(i) },
89
99
  h('div', { class: 'ds-prose' },
90
100
  h('p', { class: 'ds-work-body' }, w.body)
91
101
  ),
@@ -102,7 +112,7 @@ export function WorksList({ works = [], openedIndex = -1, onToggle }) {
102
112
  export function WritingList({ posts = [] }) {
103
113
  return Panel({
104
114
  children: posts.map((p, i) =>
105
- RowLink({ key: i, code: p.date, title: p.title, meta: '§ ' + p.tag, href: p.href || '#' })
115
+ RowLink({ key: i, code: p.date, title: p.title, meta: p.tag, href: p.href || '#' })
106
116
  )
107
117
  });
108
118
  }
@@ -120,77 +130,84 @@ export function Manifesto({ paragraphs = [], maxWidth }) {
120
130
  }
121
131
 
122
132
  export function Kpi({ items = [] }) {
123
- return h('div', { class: 'kpi' }, ...items.map(([n, l]) =>
124
- h('div', { class: 'kpi-card' },
133
+ return h('div', { class: 'kpi' }, ...items.map(([n, l], i) =>
134
+ h('div', { key: i, class: 'kpi-card' },
125
135
  h('div', { class: 'num' }, String(n)),
126
136
  h('div', { class: 'lbl' }, l))));
127
137
  }
128
138
 
129
- export function Table({ headers = [], rows = [], onRowClick, emptyText = 'no rows' }) {
130
- if (!rows || rows.length === 0) {
131
- return h('div', { class: 'empty' }, emptyText);
132
- }
139
+ export function Table({ headers = [], rows = [], onRowClick, emptyText = 'nothing here yet' }) {
140
+ if (!rows || rows.length === 0) return h('div', { class: 'empty' }, emptyText);
133
141
  return h('table', {},
134
- h('thead', {}, h('tr', {}, ...headers.map(hd => h('th', {}, hd)))),
142
+ h('thead', {}, h('tr', {}, ...headers.map((hd, i) => h('th', { key: i }, hd)))),
135
143
  h('tbody', {}, ...rows.map((row, i) => h('tr', {
144
+ key: i,
136
145
  class: onRowClick ? 'clickable' : '',
137
146
  onclick: onRowClick ? () => onRowClick(i) : null
138
- }, ...row.map(c => h('td', {}, c == null ? '' : (typeof c === 'object' ? c : String(c))))))));
147
+ }, ...row.map((c, j) => h('td', { key: j }, c == null ? '' : (typeof c === 'object' ? c : String(c))))))));
139
148
  }
140
149
 
141
- export function Section({ title, children }) {
142
- return h('div', { class: 'ds-section' },
143
- title ? h('h3', {}, title) : null,
144
- ...(Array.isArray(children) ? children : [children])
145
- );
146
- }
147
-
148
- export function HomeView({ state, onNav, onToggleWork, works, posts, manifesto, currentlyShipping }) {
150
+ export function HomeView({ state = {}, onNav, onToggleWork, works = [], posts = [], manifesto = [], currentlyShipping } = {}) {
149
151
  return [
150
152
  Hero({
151
- title: 'the creative department of the internet.',
152
- body: '247420 is a collective of mercurials. we ship fast, break things on purpose, and document honestly.',
153
- accent: 'humor is load-bearing.'
153
+ eyebrow: 'an entrypoint',
154
+ title: 'Small, weird, useful tools built in public.',
155
+ body: '247420 is a creative collective of eight, scattered across three timezones. We have been shipping open-source tools for the web since 2018.',
156
+ accent: 'Some become the future. Most don\'t. That\'s the deal.'
154
157
  }),
155
- currentlyShipping ? h('div', { class: 'ds-section' },
156
- Panel({
157
- title: 'currently shipping',
158
- count: currentlyShipping.length,
159
- kind: 'inline',
158
+ currentlyShipping ? Section({
159
+ eyebrow: 'currently shipping',
160
+ children: Panel({
161
+ kind: 'wide',
160
162
  children: currentlyShipping.map((row, i) =>
161
163
  Row({
162
164
  key: i,
163
- code: h('span', { class: row.live ? 'ds-dot-live' : 'ds-dot-idle' }, row.live ? '●' : '○'),
165
+ code: Dot({ tone: row.live ? 'live' : 'idle' }),
164
166
  title: row.title, sub: row.sub, meta: row.meta
165
167
  })
166
168
  )
167
169
  })
168
- ) : null,
169
- Section({ title: '// works', children: WorksList({ works, openedIndex: state.opened, onToggle: onToggleWork }) }),
170
- Section({ title: '// recent writing', children: WritingList({ posts }) }),
171
- Section({ title: '// manifesto · rough draft', children: Manifesto({ paragraphs: manifesto }) })
172
- ];
173
- }
174
-
175
- export function ProjectView({ project, copied, onCopy }) {
170
+ }) : null,
171
+ works.length ? Section({
172
+ eyebrow: 'works', title: 'Everything else.',
173
+ children: WorksList({ works, openedIndex: state.opened ?? -1, onToggle: onToggleWork })
174
+ }) : null,
175
+ posts.length ? Section({
176
+ eyebrow: 'writing', title: 'When we have something to say.',
177
+ children: WritingList({ posts })
178
+ }) : null,
179
+ manifesto.length ? Section({
180
+ eyebrow: 'who\'s here', title: 'Eight people, three timezones, one ongoing conversation.',
181
+ children: Manifesto({ paragraphs: manifesto })
182
+ }) : null
183
+ ].filter(Boolean);
184
+ }
185
+
186
+ export function ProjectView({ project = {}, copied, onCopy } = {}) {
176
187
  return [
177
188
  h('div', { class: 'ds-prose' },
178
189
  Heading({ level: 1, children: project.name }),
179
190
  Lede({ children: project.tagline })
180
191
  ),
181
- Heading({ level: 3, children: 'install' }),
182
- Install({ cmd: project.install, copied, onCopy }),
183
- Heading({ level: 3, children: 'receipt' }),
184
- Receipt({ rows: project.receipt }),
185
- Heading({ level: 3, children: 'changelog' }),
186
- Changelog({ entries: project.changelog })
187
- ];
192
+ project.install ? [
193
+ Heading({ level: 3, children: 'install' }),
194
+ Install({ cmd: project.install, copied, onCopy }),
195
+ ] : null,
196
+ project.receipt ? [
197
+ Heading({ level: 3, children: 'by the numbers' }),
198
+ Receipt({ rows: project.receipt }),
199
+ ] : null,
200
+ project.changelog ? [
201
+ Heading({ level: 3, children: 'recent releases' }),
202
+ Changelog({ entries: project.changelog })
203
+ ] : null
204
+ ].filter(Boolean).flat();
188
205
  }
189
206
 
190
207
  export function Form({ fields = [], submit = 'submit', onSubmit }) {
191
- return h('form', { class: 'row-form', onsubmit: ev => { ev.preventDefault(); onSubmit && onSubmit(ev); } },
192
- ...fields.map(f => f.kind === 'textarea'
193
- ? h('textarea', { name: f.name, placeholder: f.placeholder || '', rows: f.rows || 4 })
194
- : h('input', { name: f.name, type: f.type || 'text', placeholder: f.placeholder || '', value: f.value || '', required: f.required ? 'true' : null })),
208
+ return h('form', { class: 'row-form', onsubmit: (ev) => { ev.preventDefault(); onSubmit && onSubmit(ev); } },
209
+ ...fields.map((f, i) => f.kind === 'textarea'
210
+ ? h('textarea', { key: i, name: f.name, placeholder: f.placeholder || '', rows: f.rows || 4 })
211
+ : h('input', { key: i, name: f.name, type: f.type || 'text', placeholder: f.placeholder || '', value: f.value || '', required: f.required ? 'true' : null })),
195
212
  h('button', { type: 'submit', class: 'btn-primary' }, submit));
196
213
  }
@@ -1,3 +1,5 @@
1
+ // File modals — matches upstream signatures + class names.
2
+
1
3
  import * as webjsx from '../../vendor/webjsx/index.js';
2
4
  import { Btn } from './shell.js';
3
5
  import { fileGlyph, fmtFileSize } from './files.js';
@@ -22,7 +24,7 @@ export function ConfirmDialog({ title = 'confirm', message, confirmLabel = 'conf
22
24
  h('div', { class: 'ds-modal-actions' },
23
25
  Btn({ onClick: onCancel, children: cancelLabel }),
24
26
  h('button', {
25
- class: destructive ? 'btn-stamp flame' : 'btn-stamp green',
27
+ class: destructive ? 'btn-primary danger' : 'btn-primary',
26
28
  onclick: onConfirm
27
29
  }, confirmLabel)
28
30
  )
@@ -52,7 +54,7 @@ export function PromptDialog({ title = 'name', value = '', placeholder = '', con
52
54
  ),
53
55
  h('div', { class: 'ds-modal-actions' },
54
56
  Btn({ onClick: onCancel, children: cancelLabel }),
55
- h('button', { class: 'btn-stamp green', onclick: () => onConfirm && onConfirm(value) }, confirmLabel)
57
+ h('button', { class: 'btn-primary', onclick: () => onConfirm && onConfirm(value) }, confirmLabel)
56
58
  )
57
59
  ]
58
60
  });
@@ -1,5 +1,7 @@
1
+ // File primitives — matches upstream signatures.
2
+
1
3
  import * as webjsx from '../../vendor/webjsx/index.js';
2
- import { Btn, Glyph } from './shell.js';
4
+ import { Btn } from './shell.js';
3
5
  const h = webjsx.createElement;
4
6
 
5
7
  const FILE_TYPES = ['dir', 'image', 'video', 'audio', 'code', 'text', 'archive', 'document', 'symlink', 'other'];
@@ -49,12 +51,7 @@ export function FileGrid({ files = [], onOpen, onAction, emptyText = 'no files h
49
51
  return h('div', { class: 'ds-file-grid' },
50
52
  ...files.map((f, i) => FileRow({
51
53
  key: f.path || f.name + i,
52
- name: f.name,
53
- type: f.type,
54
- size: f.size,
55
- modified: f.modified,
56
- code: f.code,
57
- active: f.active,
54
+ name: f.name, type: f.type, size: f.size, modified: f.modified, code: f.code, active: f.active,
58
55
  onOpen: onOpen ? () => onOpen(f) : null,
59
56
  onAction: onAction ? (act) => onAction(act, f) : null
60
57
  }))
@@ -93,10 +90,7 @@ export function UploadProgress({ items = [] } = {}) {
93
90
  },
94
91
  h('span', { class: 'ds-upload-name' }, it.name),
95
92
  h('span', { class: 'ds-upload-bar' },
96
- h('span', {
97
- class: 'ds-upload-fill',
98
- 'data-pct': String(Math.max(0, Math.min(100, it.pct || 0)))
99
- })
93
+ h('span', { class: 'ds-upload-fill', 'data-pct': String(Math.max(0, Math.min(100, it.pct || 0))) })
100
94
  ),
101
95
  h('span', { class: 'ds-upload-pct' }, (it.error ? 'err' : (it.done ? 'ok' : (it.pct || 0) + '%')))
102
96
  ))
@@ -111,9 +105,7 @@ export function EmptyState({ text = 'nothing here', glyph = '◌' } = {}) {
111
105
  }
112
106
 
113
107
  export function BreadcrumbPath({ segments = [], onNav, root = 'root' } = {}) {
114
- const parts = [
115
- h('button', { key: 'root', class: 'ds-crumb-seg', onclick: () => onNav && onNav(0) }, root)
116
- ];
108
+ const parts = [h('button', { key: 'root', class: 'ds-crumb-seg', onclick: () => onNav && onNav(0) }, root)];
117
109
  segments.forEach((seg, i) => {
118
110
  parts.push(h('span', { key: 'sep' + i, class: 'ds-crumb-sep' }, '›'));
119
111
  parts.push(h('button', {