anentrypoint-design 0.0.340 → 0.0.342
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/chat.css +14 -0
- package/dist/247420.css +27 -0
- package/dist/247420.js +21 -21
- package/package.json +3 -1
- package/src/components/chat.js +10 -1
- package/src/components/content.js +12 -0
- package/src/components/files.js +2 -2
- package/src/components/sessions.js +39 -16
- package/src/components/shell.js +56 -20
- package/src/components.js +1 -1
- package/src/css/app-shell/kits-appended.css +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anentrypoint-design",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.342",
|
|
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",
|
|
@@ -84,6 +84,8 @@
|
|
|
84
84
|
"lint:ui-kits": "node scripts/generate-ui-kit-scaffolds.mjs --check",
|
|
85
85
|
"tokens": "node scripts/generate-tokens-json.mjs",
|
|
86
86
|
"tokens:doc": "node scripts/generate-tokens-json.mjs && node scripts/generate-theme-tokens-doc.mjs",
|
|
87
|
+
"docs:components": "node scripts/generate-component-docs.mjs",
|
|
88
|
+
"lint:component-docs": "node scripts/generate-component-docs.mjs --check",
|
|
87
89
|
"generate:ui-kits": "node scripts/generate-ui-kit-scaffolds.mjs",
|
|
88
90
|
"generate:preview-index": "node scripts/generate-preview-index.mjs",
|
|
89
91
|
"a11y": "node scripts/a11y-audit.mjs",
|
package/src/components/chat.js
CHANGED
|
@@ -97,7 +97,7 @@ function renderPart(p, key) {
|
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typing, key, aicat, reactions, receipt, name, streaming, actions, incomplete, stopped, flat }) {
|
|
100
|
+
export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typing, key, aicat, reactions, receipt, name, streaming, actions, incomplete, stopped, flat, error, onRetry }) {
|
|
101
101
|
_stats.messages += 1;
|
|
102
102
|
// Support legacy 'who' prop, prefer 'role' with mapping:
|
|
103
103
|
// 'user' -> 'you' (right-aligned, accent bubble)
|
|
@@ -144,6 +144,15 @@ export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typ
|
|
|
144
144
|
typeof stopped === 'string' ? stopped : 'stopped — this turn was cancelled before it finished')];
|
|
145
145
|
if (incomplete) bodyNodes = [...bodyNodes, h('div', { key: '_incomplete', class: 'chat-msg-notice is-incomplete', role: 'status' },
|
|
146
146
|
typeof incomplete === 'string' ? incomplete : 'connection dropped mid-turn — the response may be incomplete')];
|
|
147
|
+
// Inline per-turn error: unlike a global toast, this pins the failure to
|
|
148
|
+
// the specific turn that failed (docstudio pattern) with a retry action
|
|
149
|
+
// right there instead of forcing the user to hunt for what broke.
|
|
150
|
+
if (error) bodyNodes = [...bodyNodes, h('div', { key: '_error', class: 'chat-msg-notice is-error', role: 'alert' },
|
|
151
|
+
h('span', {}, typeof error === 'string' ? error : 'this turn failed'),
|
|
152
|
+
onRetry ? h('button', {
|
|
153
|
+
type: 'button', class: 'chat-msg-retry-btn',
|
|
154
|
+
onclick: (e) => { e.preventDefault(); onRetry(e); },
|
|
155
|
+
}, 'retry') : null)];
|
|
147
156
|
const reactionRow = reactions && reactions.length
|
|
148
157
|
? h('div', { class: 'chat-reactions' },
|
|
149
158
|
...reactions.map((r, i) => h('span', { class: 'rxn' + (r.you ? ' you' : ''), key: 'r' + i, 'aria-label': `${r.emoji} reaction (${String(r.count)} ${String(r.count) === '1' ? 'reaction' : 'reactions'})${r.you ? ' - you reacted' : ''}` },
|
|
@@ -6,6 +6,18 @@ import * as webjsx from '../../vendor/webjsx/index.js';
|
|
|
6
6
|
import { Btn, Heading, Lede, Dot, Icon } from './shell.js';
|
|
7
7
|
const h = webjsx.createElement;
|
|
8
8
|
|
|
9
|
+
// Avatar — generic identity disc: an image when `src` resolves, else a
|
|
10
|
+
// letter fallback derived from `name`/`fallback`. Kit previously only had
|
|
11
|
+
// scoped one-offs (chat.js `.chat-avatar`, community.js `.cm-user-avatar`)
|
|
12
|
+
// duplicating this same letter-fallback logic; this is the reusable version.
|
|
13
|
+
export function Avatar({ name, src, fallback, size = 'md', key } = {}) {
|
|
14
|
+
const letter = fallback != null ? fallback
|
|
15
|
+
: (name ? String(name).trim().charAt(0).toUpperCase() || '?' : '?');
|
|
16
|
+
const cls = 'ds-avatar ds-avatar-' + size;
|
|
17
|
+
if (src) return h('img', { key, class: cls, src, alt: name || '', loading: 'lazy' });
|
|
18
|
+
return h('span', { key, class: cls, 'aria-hidden': !!name, role: name ? 'img' : undefined, 'aria-label': name || undefined }, letter);
|
|
19
|
+
}
|
|
20
|
+
|
|
9
21
|
export function Panel({ title, count, right, style = '', class: className = '', children, kind, id }) {
|
|
10
22
|
const cls = 'panel' + (kind ? ' panel-' + kind : '') + (className ? ' ' + className : '');
|
|
11
23
|
return h('div', { class: cls, style, id: id || null },
|
package/src/components/files.js
CHANGED
|
@@ -147,8 +147,8 @@ export function FileRow({ name, type = 'other', size, modified, code, onOpen, on
|
|
|
147
147
|
// grid does not flash from a bare spinner to a full list (predictable perceived
|
|
148
148
|
// perf, the file-manager feel). `rows` controls how many ghost rows render.
|
|
149
149
|
export function FileSkeleton({ rows = 12 } = {}) {
|
|
150
|
-
return h('div', { class: 'ds-file-grid ds-file-skeleton', 'aria-
|
|
151
|
-
...Array.from({ length: Math.max(1, rows) }, (_, i) => h('div', { key: 'sk' + i, class: 'ds-file-row ds-file-row-skeleton' },
|
|
150
|
+
return h('div', { class: 'ds-file-grid ds-file-skeleton', role: 'status', 'aria-busy': 'true', 'aria-label': 'loading files' },
|
|
151
|
+
...Array.from({ length: Math.max(1, rows) }, (_, i) => h('div', { key: 'sk' + i, class: 'ds-file-row ds-file-row-skeleton', 'aria-hidden': 'true' },
|
|
152
152
|
h('span', { class: 'ds-skel ds-skel-icon' }),
|
|
153
153
|
h('span', { class: 'ds-skel ds-skel-title' }),
|
|
154
154
|
h('span', { class: 'ds-skel ds-skel-meta' })))
|
|
@@ -37,17 +37,24 @@ export function fmtDuration(ms) {
|
|
|
37
37
|
return hrs + 'h ' + (m % 60) + 'm';
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The Claude-Desktop "Chats" column. Sessions grouped by a caller-supplied
|
|
42
|
+
* group label, each row showing title/project, relative time, agent badge,
|
|
43
|
+
* and a running/new-event indicator. Selecting a row switches the active
|
|
44
|
+
* conversation.
|
|
45
|
+
*
|
|
46
|
+
* @param {Object} [props]
|
|
47
|
+
* @param {Array<{sid:*, title?:string, project?:string, agent?:string, time?:string, running?:boolean, unread?:boolean, rail?:string}>} [props.sessions=[]]
|
|
48
|
+
* @param {*} [props.selected] - the active sid.
|
|
49
|
+
* @param {Array<{label:string, sids:Array<*>}>} [props.groups] - OPTIONAL buckets for the rows; else one flat list.
|
|
50
|
+
* @param {{value:string, onInput:Function, placeholder?:string}} [props.search] - inline filter (optional).
|
|
51
|
+
* @param {Function} [props.onSelect] - onSelect(session).
|
|
52
|
+
* @param {Function} [props.onNew] - onNew().
|
|
53
|
+
* @param {string} [props.emptyText='No conversations yet']
|
|
54
|
+
* @param {boolean} [props.loading=false]
|
|
55
|
+
* @param {*} [props.error=null]
|
|
56
|
+
* @returns {*} webjsx vnode
|
|
57
|
+
*/
|
|
51
58
|
export function ConversationList({ sessions = [], selected, groups, search, caption,
|
|
52
59
|
onSelect, onNew, newLabel = 'New chat',
|
|
53
60
|
emptyText = 'No conversations yet', loading = false, error = null,
|
|
@@ -304,11 +311,27 @@ const STREAM_WORD = {
|
|
|
304
311
|
lost: 'live stream offline — retrying…',
|
|
305
312
|
};
|
|
306
313
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
314
|
+
/**
|
|
315
|
+
* The live multi-session command center ("Live" dashboard).
|
|
316
|
+
*
|
|
317
|
+
* The stop-all / stop-selected danger buttons are two-step (host-driven, the
|
|
318
|
+
* kit is stateless): the first click fires onArmStop* so the host flips
|
|
319
|
+
* confirming* true and re-renders; the armed button reads 'stop N sessions -
|
|
320
|
+
* press again' and only THAT click fires the real onStopAll/onStopSelected.
|
|
321
|
+
* Hosts that wire no onArmStop* keep the old single-click behavior.
|
|
322
|
+
*
|
|
323
|
+
* @param {Object} [props]
|
|
324
|
+
* @param {Array<Object>} [props.sessions=[]] - session shape: `{ sid, realSid, title, agent, model, cwd, elapsedMs, counter, lastActivity, currentTool, status, stopping, external, isNew, cost, tokens }`.
|
|
325
|
+
* @param {Function} [props.onStop] - onStop(session).
|
|
326
|
+
* @param {Function} [props.onOpen] - onOpen(session).
|
|
327
|
+
* @param {Function} [props.onView] - onView(session).
|
|
328
|
+
* @param {Function} [props.onStopAll]
|
|
329
|
+
* @param {Function} [props.onStopSelected]
|
|
330
|
+
* @param {boolean} [props.confirmingStopAll=false]
|
|
331
|
+
* @param {boolean} [props.confirmingStopSelected=false]
|
|
332
|
+
* @param {'connected'|'connecting'|'lost'|'offline'} [props.streamState]
|
|
333
|
+
* @returns {*} webjsx vnode
|
|
334
|
+
*/
|
|
312
335
|
export function SessionDashboard({ sessions = [], onStop, onOpen, onView, onStopAll, onStopSelected,
|
|
313
336
|
confirmingStopAll = false, confirmingStopSelected = false,
|
|
314
337
|
onArmStopAll, onArmStopSelected,
|
package/src/components/shell.js
CHANGED
|
@@ -6,19 +6,54 @@ import * as webjsx from '../../vendor/webjsx/index.js';
|
|
|
6
6
|
import { trapTab } from './overlay-primitives.js';
|
|
7
7
|
const h = webjsx.createElement;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* The wordmark used in Topbar/AppShell headers.
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} [props]
|
|
13
|
+
* @param {string} [props.name='247420'] - the brand text.
|
|
14
|
+
* @param {*} [props.leaf] - optional trailing breadcrumb-style leaf, rendered after a " / " separator.
|
|
15
|
+
* @returns {*} webjsx vnode
|
|
16
|
+
*/
|
|
9
17
|
export function Brand({ name = '247420', leaf } = {}) {
|
|
10
18
|
return h('span', { class: 'brand' }, name,
|
|
11
19
|
leaf ? h('span', { class: 'slash' }, ' / ') : null,
|
|
12
20
|
leaf || null);
|
|
13
21
|
}
|
|
14
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A small pill/tag label.
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} props
|
|
27
|
+
* @param {string} [props.tone=''] - semantic color tone (empty = neutral).
|
|
28
|
+
* @param {'sm'|'md'|'lg'} [props.size='md']
|
|
29
|
+
* @param {boolean} [props.tag=false] - true renders a rectangular sentence-case variant for dense data (drops the all-caps pill styling). Orthogonal to tone.
|
|
30
|
+
* @param {*} props.children
|
|
31
|
+
* @returns {*} webjsx vnode
|
|
32
|
+
*/
|
|
15
33
|
export function Chip({ tone = '', size = 'md', tag = false, children }) {
|
|
16
|
-
// size: 'sm' | 'md' | 'lg'; tag=true -> rectangular sentence-case variant
|
|
17
|
-
// for dense data (drops the all-caps pill). Both are orthogonal to tone.
|
|
18
34
|
const sizeCls = size === 'sm' ? ' chip--sm' : (size === 'lg' ? ' chip--lg' : '');
|
|
19
35
|
return h('span', { class: 'chip' + sizeCls + (tag ? ' chip--tag' : '') + (tone ? ' tone-' + tone : '') }, children);
|
|
20
36
|
}
|
|
21
37
|
|
|
38
|
+
/**
|
|
39
|
+
* The standard button/link factory. Renders an `<a>` when `href` is given,
|
|
40
|
+
* otherwise a `<button>`.
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} props
|
|
43
|
+
* @param {string} [props.href] - if present, renders as a link instead of a button.
|
|
44
|
+
* @param {'default'|'primary'|'ghost'|'danger'} [props.variant='default']
|
|
45
|
+
* @param {'sm'|'md'|'lg'} [props.size='md']
|
|
46
|
+
* @param {*} props.children
|
|
47
|
+
* @param {Function} [props.onClick]
|
|
48
|
+
* @param {string} [props['aria-label']]
|
|
49
|
+
* @param {boolean} [props.primary] - legacy alias for variant:'primary', kept for backward compatibility.
|
|
50
|
+
* @param {boolean} [props.ghost] - legacy alias for variant:'ghost'.
|
|
51
|
+
* @param {boolean} [props.danger] - legacy alias for variant:'danger'.
|
|
52
|
+
* @param {boolean} [props.disabled]
|
|
53
|
+
* @param {string} [props.class] - extra class name(s) appended to the generated class list.
|
|
54
|
+
* @param {*} [props.key]
|
|
55
|
+
* @returns {*} webjsx vnode
|
|
56
|
+
*/
|
|
22
57
|
export function Btn({ href, variant = 'default', size = 'md', children, onClick, 'aria-label': ariaLabel, primary, ghost, danger, disabled, class: className, key }) {
|
|
23
58
|
// Support legacy primary/ghost props for backward compatibility, but prefer variant
|
|
24
59
|
const resolvedVariant = variant !== 'default' ? variant : (primary ? 'primary' : (ghost ? 'ghost' : (danger ? 'danger' : 'default')));
|
|
@@ -576,24 +611,25 @@ function wsCollapsed(which, fallback) {
|
|
|
576
611
|
return !!fallback;
|
|
577
612
|
}
|
|
578
613
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
614
|
+
/**
|
|
615
|
+
* A Claude-Desktop / cowork three-(or four-)column app shell.
|
|
616
|
+
*
|
|
617
|
+
* Pure stateless chrome (props in, vnode out). Collapse is DOM-class + a
|
|
618
|
+
* persisted flag, so the host does not have to thread collapse state through
|
|
619
|
+
* its own store. Visual styling lives in app-shell.css (.ws-*).
|
|
620
|
+
*
|
|
621
|
+
* @param {Object} props
|
|
622
|
+
* @param {*} props.rail - the persistent left workspace nav (icon+label items, collapsible to icon-only). Pass the result of WorkspaceRail() or any vnode.
|
|
623
|
+
* @param {*} props.sessions - an OPTIONAL second column (a conversation/session list) shown between the rail and the main content. Null hides it.
|
|
624
|
+
* @param {*} props.main - the primary content column (chat thread, files view, dashboard...).
|
|
625
|
+
* @param {*} props.pane - an OPTIONAL right context pane (per-conversation context, file preview...). Null hides it; collapsible when present.
|
|
626
|
+
* @param {*} props.crumb - an optional thin top chrome bar (breadcrumb + status), spanning the content area only (the rail has its own header).
|
|
627
|
+
* @param {*} props.status - an optional footer.
|
|
628
|
+
* @param {boolean} props.narrow - caller's isNarrow() — drives the mobile single-column collapse.
|
|
629
|
+
* @param {boolean} props.railCollapsed - initial rail collapse (persisted state wins).
|
|
630
|
+
* @param {boolean} props.paneCollapsed - initial pane collapse (persisted state wins).
|
|
631
|
+
* @returns {*} webjsx vnode
|
|
632
|
+
*/
|
|
597
633
|
export function WorkspaceShell({ rail, sessions, main, pane, crumb, status, narrow,
|
|
598
634
|
railCollapsed = false, paneCollapsed = false,
|
|
599
635
|
railLabel = 'workspace navigation',
|
package/src/components.js
CHANGED
|
@@ -16,7 +16,7 @@ export {
|
|
|
16
16
|
WorksList, WritingList, Manifesto, Section, PageHeader,
|
|
17
17
|
Kpi, Sparkline, BarChart, Table, SearchInput, TextField, Select, EventList,
|
|
18
18
|
HomeView, ProjectView, Form,
|
|
19
|
-
Spinner, Skeleton, Alert, FilterPills
|
|
19
|
+
Spinner, Skeleton, Alert, FilterPills, Avatar
|
|
20
20
|
} from './components/content.js';
|
|
21
21
|
|
|
22
22
|
export {
|
|
@@ -372,3 +372,16 @@
|
|
|
372
372
|
.ds-chat-layout { display: grid; grid-template-columns: minmax(0, 1fr) 280px; align-items: start; gap: var(--space-4); }
|
|
373
373
|
.ds-chat-detail { display: block; position: sticky; top: 0; }
|
|
374
374
|
}
|
|
375
|
+
|
|
376
|
+
/* Avatar — generic identity disc primitive (content.js Avatar). Sized
|
|
377
|
+
variants mirror the existing chat-avatar/community-avatar footprints so
|
|
378
|
+
any consumer gets a consistent disc without duplicating the CSS. */
|
|
379
|
+
.ds-avatar {
|
|
380
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
381
|
+
border-radius: 50%; background: var(--bg-3); color: var(--fg);
|
|
382
|
+
font-family: var(--ff-mono); font-weight: 600; text-transform: lowercase;
|
|
383
|
+
letter-spacing: 0.02em; user-select: none; flex-shrink: 0; object-fit: cover;
|
|
384
|
+
}
|
|
385
|
+
.ds-avatar-sm { width: 24px; height: 24px; font-size: 10px; }
|
|
386
|
+
.ds-avatar-md { width: 36px; height: 36px; font-size: 12px; }
|
|
387
|
+
.ds-avatar-lg { width: 48px; height: 48px; font-size: 15px; }
|