anentrypoint-design 0.0.449 → 0.0.451

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.449",
3
+ "version": "0.0.451",
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",
@@ -46,7 +46,12 @@ import { EmojiPicker, CommandPalette, AuthModal, BootOverlay, SettingsPopover, V
46
46
 
47
47
  const h = webjsx.createElement;
48
48
 
49
- const CHANNEL_ICON = { voice: 'speaker', forum: 'forum', threaded: 'thread', announcement: 'megaphone', page: 'page', text: 'hash' };
49
+ // announcement previously used 'megaphone', whose two-arc speaker-cone SVG
50
+ // path reads as visually near-identical to the voice channel's 'speaker'
51
+ // icon at rail size (15px) -- easy to confuse a text-only broadcast channel
52
+ // for a live voice room. 'send' (paper-plane) reads distinctly as
53
+ // one-way/outbound at a glance and shares no silhouette with 'speaker'.
54
+ const CHANNEL_ICON = { voice: 'speaker', forum: 'forum', threaded: 'thread', announcement: 'send', page: 'page', text: 'hash' };
50
55
 
51
56
  export function mountCommunityApp(root, adapter = {}) {
52
57
  if (!root) throw new Error('mountCommunityApp: root required');
@@ -154,7 +159,18 @@ export function mountCommunityApp(root, adapter = {}) {
154
159
  const isYou = selfId && String(m.userId) === String(selfId);
155
160
  const reactions = Array.isArray(m.reactions) ? m.reactions.map(r => ({ emoji: r.emoji, count: r.count != null ? r.count : (r.users ? r.users.length : 1), you: !!(r.you || (r.users && selfId && r.users.includes(selfId))) })) : null;
156
161
  const msgActions = [
157
- { label: 'react', title: 'react to ' + username + '\'s message', icon: 'smile', onClick: () => A.reactToMessage && A.reactToMessage(m.id, m.userId) },
162
+ {
163
+ label: 'react', title: 'react to ' + username + '\'s message', icon: 'smile',
164
+ onClick: (e) => {
165
+ if (!A.reactToMessage) return;
166
+ const rect = e && e.currentTarget && e.currentTarget.getBoundingClientRect ? e.currentTarget.getBoundingClientRect() : null;
167
+ if (api.emojiPicker) {
168
+ api.emojiPicker.show(rect ? rect.left : 200, rect ? rect.bottom + 4 : 200, (em) => A.reactToMessage(m.id, m.userId, em));
169
+ } else {
170
+ A.reactToMessage(m.id, m.userId);
171
+ }
172
+ },
173
+ },
158
174
  { label: 'reply', title: 'reply to ' + username, icon: 'corner-up-left', onClick: () => A.startReply && A.startReply({ id: m.id, userId: m.userId, username, content: m.content }) },
159
175
  isYou ? { label: 'delete', title: 'delete message', icon: 'trash', onClick: () => A.deleteMessage && A.deleteMessage(m.id) } : null,
160
176
  ].filter(Boolean);
@@ -69,7 +69,12 @@ export function Chat({ title = 'chat', sub, messages = [], composer, header, sug
69
69
 
70
70
  export const AICAT_FACE = ` /\\_/\\\n( o.o )\n > ^ <`;
71
71
 
72
- export function AICatPortrait({ name = 'aicat', status = 'idle', face } = {}) {
72
+ // `status` is opt-in and omitted by default: this component renders IDENTITY
73
+ // (who you're talking to — name, avatar/face), not live conversation state.
74
+ // A caller that also renders a thread head with its own status (AICat below)
75
+ // should leave `status` unset here so there is exactly one place on the page
76
+ // showing dynamic state — passing it back in duplicates that source of truth.
77
+ export function AICatPortrait({ name = 'aicat', status, face } = {}) {
73
78
  return h('div', { class: 'aicat-portrait' },
74
79
  // role="img" collapses the ASCII art into a single named image for a
75
80
  // screen reader (otherwise the slashes and parens are read out
@@ -79,7 +84,9 @@ export function AICatPortrait({ name = 'aicat', status = 'idle', face } = {}) {
79
84
  h('pre', { class: 'aicat-face', role: 'img', 'aria-label': `${name} portrait` }, face || AICAT_FACE),
80
85
  h('div', { class: 'aicat-meta' },
81
86
  h('span', { class: 'name' }, name),
82
- h('span', { class: 'status', 'aria-label': `status: ${status}` }, h('span', { class: 'dot ds-dot ds-dot-on', 'aria-hidden': 'true' }), ' ', status)
87
+ status != null
88
+ ? h('span', { class: 'status', 'aria-label': `status: ${status}` }, h('span', { class: 'dot ds-dot ds-dot-on', 'aria-hidden': 'true' }), ' ', status)
89
+ : null
83
90
  )
84
91
  );
85
92
  }
@@ -1,16 +1,18 @@
1
- // Masthead blocks — the page-opening surfaces: Hero (the asymmetric
2
- // two-column grid), HeroFromPageData (the same shape driven by a parsed
3
- // page-data object), PageHeader (display and dense forms), Marquee (the
4
- // signature ticker) and Manifesto (long-form prose block).
1
+ // Masthead blocks — the page-opening surfaces: Hero (a left-aligned,
2
+ // left-inset single-column stack: oversized display title, body copy, then
3
+ // the badge/CTA cluster as a full-width card below — offset off the left
4
+ // edge rather than dead-centered), HeroFromPageData (the same shape driven
5
+ // by a parsed page-data object), PageHeader (display and dense forms),
6
+ // Marquee (the signature ticker) and Manifesto (long-form prose block).
5
7
 
6
8
  import * as webjsx from '../../../vendor/webjsx/index.js';
7
9
  const h = webjsx.createElement;
8
10
 
9
11
  export function Hero({ eyebrow, title, body, accent, actions, badges }) {
10
- // Eyebrow + title share the title grid-area so the named-area layout stays
11
- // intact; body occupies the wide left column, badges + actions stack in
12
- // the narrow right column so it carries real visual weight instead of
13
- // sitting empty beside the body copy.
12
+ // Eyebrow + title stack at the top of the single-column layout; badges +
13
+ // actions render into a full-width card BELOW the body copy (.ds-hero-aside)
14
+ // rather than a side column, so it still carries real visual weight instead
15
+ // of sitting empty beside the body copy.
14
16
  const badgeList = Array.isArray(badges) ? badges.filter(Boolean) : [];
15
17
  const badgeRow = badgeList.length
16
18
  ? h('div', { class: 'ds-hero-stats' }, ...badgeList.map((b, i) =>
@@ -8,21 +8,37 @@
8
8
  specific to the retired Acid Editorial identity. All child classes/markup
9
9
  are UNCHANGED (no JS component edit needed) -- only the grid arrangement
10
10
  and each part's own layout (aside becomes a full-width card below the body
11
- instead of a right-column card) changed. Centered text, capped measure. */
11
+ instead of a right-column card) changed. Centered text, capped measure.
12
+
13
+ DE-CENTERED 2026-07-31: the flex-stack architecture from the restyle above
14
+ is kept as-is (still a single-column stack, still the oversized display
15
+ lead, still the full-width aside card) -- this is NOT a revert to the old
16
+ two-column grid. What changed is alignment only: `align-items: center` /
17
+ `text-align: center` read as the textbook dead-centered "AI portfolio"
18
+ hero the moment the oversized display type is involved, regardless of
19
+ architecture. Swapping to flex-start + left text-align, plus a
20
+ --space-6 left inset inside the unchanged --stage-wide container, pushes
21
+ the whole block toward the left edge so the oversized title crops against
22
+ real whitespace on the right instead of sitting symmetric in the middle --
23
+ editorial tension from a one-axis asymmetry, no grid architecture
24
+ reintroduced. */
12
25
  .ds-hero {
13
26
  padding: var(--space-9) 0 var(--space-8);
14
- display: flex; flex-direction: column; align-items: center;
27
+ display: flex; flex-direction: column; align-items: flex-start;
15
28
  gap: var(--space-5);
16
29
  max-width: var(--stage-wide);
17
- text-align: center;
30
+ margin-inline-start: 0;
31
+ padding-inline-start: var(--space-6);
32
+ text-align: left;
18
33
  position: relative; isolation: isolate;
19
34
  }
20
- .ds-hero-head { display: grid; gap: var(--space-3); justify-items: center; }
21
- .ds-hero-body { margin-inline: auto; }
35
+ .ds-hero-head { display: grid; gap: var(--space-3); justify-items: start; }
36
+ .ds-hero-body { margin-inline: 0; }
22
37
  /* The stat/badge/CTA cluster now sits as a full-width card BELOW the body
23
- copy, centered, rather than a right-offset column -- still carries its own
24
- visual weight via the top accent bar (rotated from the former left spine)
25
- so it still reads as a deliberate block, not an afterthought. */
38
+ copy, left-aligned with the rest of the stack, rather than a right-offset
39
+ column -- still carries its own visual weight via the top accent bar
40
+ (rotated from the former left spine) so it still reads as a deliberate
41
+ block, not an afterthought. */
26
42
  .ds-hero-aside {
27
43
  position: relative; isolation: isolate;
28
44
  width: 100%; max-width: 46ch;
@@ -54,23 +70,23 @@
54
70
  Snapping to either changes the hero's whole optical weight. */
55
71
  font-size: clamp(40px, 9cqi, 116px);
56
72
  line-height: 0.96; letter-spacing: var(--tr-tighter);
57
- margin: 0 auto; max-width: 20ch; text-wrap: balance;
73
+ margin: 0; max-width: 20ch; text-wrap: balance;
58
74
  }
59
75
  .ds-hero-body {
60
76
  font-family: var(--ff-body); font-size: var(--fs-xl);
61
- line-height: 1.45; margin: 0 auto; max-width: 46ch;
77
+ line-height: 1.45; margin: 0; max-width: 46ch;
62
78
  color: var(--fg-2);
63
79
  }
64
80
  /* The lead phrase in the title — printed in the electric lead, not glowing. */
65
81
  .ds-hero-accent { color: var(--accent-ink); font-weight: 700; }
66
82
  .ds-hero-actions {
67
83
  display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
68
- justify-content: center; margin-top: var(--space-hair, 4px);
84
+ justify-content: flex-start; margin-top: var(--space-hair, 4px);
69
85
  }
70
86
  /* Below this width the aside card's own internal rhythm (stat rows still
71
87
  stacked vertically at full width) is already correct for a narrow column —
72
88
  no separate breakpoint override needed now that .ds-hero is always a
73
- single-column centered stack at every width. */
89
+ single-column left-aligned stack at every width. */
74
90
  @container (max-width: 900px) {
75
91
  .ds-hero { padding: var(--space-7) 0 var(--space-6); }
76
92
  }
@@ -80,6 +96,21 @@
80
96
  Section grouping
81
97
  ============================================================ */
82
98
  .ds-section { margin: var(--space-8) 0; }
99
+ /* A .ds-section's own margin-top exists so a BARE first section (no element
100
+ above it inside .app-main/.ds-app-surface) still gets the --space-8 lead
101
+ from something. But .app-main and .ds-tier are flex/grid containers, where
102
+ sibling margins never collapse -- so once ANY preceding sibling supplies
103
+ its own trailing space (a .panel's --space-4 bottom margin, or a prior
104
+ .ds-section's own --space-8 bottom margin), that top margin stacks ON TOP
105
+ of it instead of coordinating into one gap: measured live, two adjacent
106
+ .ds-section elements sat 192px apart (96 + 96) instead of 96, and a .panel
107
+ followed by a .ds-section sat ~136px apart instead of the intended single
108
+ gap. Zeroing the top margin on every NON-first .ds-section collapses the
109
+ pair back to one coordinated gap, supplied by whichever side already
110
+ carries it (the preceding sibling's own bottom margin, or the .ds-section's
111
+ trailing margin below) -- same "gap is owned by one side only" pattern as
112
+ .ds-panel-gap + .ds-panel-gap / .row + .row elsewhere in this file. */
113
+ * + .ds-section { margin-top: 0; }
83
114
  /* Compact section (e.g. a PageHeader used as a page's first element): no large
84
115
  leading margin, modest trailing margin — top-aligns without consumer overrides. */
85
116
  .ds-section-compact { margin-top: 0; margin-bottom: var(--space-4); }
@@ -638,7 +638,21 @@
638
638
  it leaves a lone thread column growing to 1400px+ with no other use of
639
639
  the extra width. This wrapper adds a persistent "thread info" rail once
640
640
  there is room to spare, instead of just widening the message column. */
641
- .ds-chat-layout { display: flex; flex-direction: column; flex: 1; min-height: 0; gap: var(--space-3); }
641
+ /* min-height is a floor, not the intended size — .chat-kit-page's flex-column
642
+ splits leftover height between this (flex:1 1 0%, "leftover") and the
643
+ pattern-notes panel below it (flex:0 1 auto, i.e. sized to its own content
644
+ first). On a short viewport the panel's natural content height can consume
645
+ the entire column budget, squeezing this flex-basis:0% sibling to a real,
646
+ rendered, fully-populated-with-messages 0px — the thread is never empty,
647
+ it is invisible. Inside .chat itself, .chat-head and .chat-composer are
648
+ also flex:0-ish naturally-sized siblings of .chat-thread (flex:1 1 0%,
649
+ chat-polish.css), so the floor has to clear their combined natural height
650
+ (~55px head + ~78px composer, chrome + gap) with real room left for the
651
+ thread to still show at least a couple of message bubbles rather than
652
+ collapsing to a sliver between them — 30vh was not enough on a short
653
+ viewport. It still grows past this floor via flex:1 whenever the column
654
+ has room. */
655
+ .ds-chat-layout { display: flex; flex-direction: column; flex: 1; min-height: max(30vh, 420px); gap: var(--space-3); }
642
656
  .ds-chat-layout > .chat { min-width: 0; }
643
657
  .ds-chat-detail { display: none; }
644
658
  @media (min-width: 1100px) {
@@ -874,6 +888,67 @@
874
888
  }
875
889
  .ds-pattern-notes strong { color: var(--fg); font-weight: 600; }
876
890
 
891
+ /* .panel.panel-docs — documentation/annotation chrome, visibly different from
892
+ the plain .panel the real interface renders in. aicat stacks its "about
893
+ this kit" caption directly under the live chat surface; identical card
894
+ chrome on both made the meta-explanation read as part of the product
895
+ instead of a caption about it. Dashed border reuses the .ds-dropzone
896
+ affordance vocabulary (a dashed edge already reads as "not solid content"
897
+ in this system) and the tint is a quiet, low-saturation wash rather than
898
+ an accent color, so it never competes with real accent-toned UI state. */
899
+ .panel.panel-docs {
900
+ border-style: dashed;
901
+ border-color: var(--rule-strong);
902
+ background: color-mix(in oklab, var(--fg) 4%, var(--bg-2));
903
+ box-shadow: none;
904
+ }
905
+ .panel.panel-docs .panel-title {
906
+ color: var(--fg-3);
907
+ font-family: var(--ff-mono);
908
+ font-size: var(--fs-xs);
909
+ letter-spacing: 0.02em;
910
+ text-transform: uppercase;
911
+ }
912
+ .panel.panel-docs .panel-title::before {
913
+ content: 'docs · ';
914
+ color: var(--fg-3);
915
+ }
916
+
917
+ /* .ds-kit-controls — collapsed-by-default dev/demo toggle drawer. Reference
918
+ state-toggle pills (ready/loading/empty/error and similar) are scaffolding
919
+ for exercising a kit's other states, not live content; sitting exposed in
920
+ the flow next to real content made them read as leftover dev debris. A
921
+ native <details>/<summary> disclosure needs no bespoke open/close state or
922
+ JS and is keyboard/AT-operable for free — closed by default, opens on
923
+ click or Enter/Space on the summary. */
924
+ .ds-kit-controls {
925
+ border: var(--bw-hair) dashed var(--rule);
926
+ border-radius: var(--r-2);
927
+ margin: 0 0 var(--space-4);
928
+ background: var(--bg);
929
+ }
930
+ .ds-kit-controls summary {
931
+ cursor: pointer;
932
+ padding: var(--space-2) var(--space-3);
933
+ font-family: var(--ff-mono);
934
+ font-size: var(--fs-xs);
935
+ color: var(--fg-3);
936
+ list-style: none;
937
+ }
938
+ .ds-kit-controls summary::-webkit-details-marker { display: none; }
939
+ .ds-kit-controls summary::before { content: '[+] '; }
940
+ .ds-kit-controls[open] summary::before { content: '[-] '; }
941
+ .ds-kit-controls summary:focus-visible {
942
+ outline: var(--focus-w) solid var(--focus-color);
943
+ outline-offset: var(--focus-offset);
944
+ }
945
+ .ds-kit-controls-body {
946
+ padding: 0 var(--space-3) var(--space-3);
947
+ display: flex;
948
+ flex-direction: column;
949
+ gap: var(--space-2);
950
+ }
951
+
877
952
  /* Swatch cell wrapper (system_primer pairs it with .ds-swatch-col, which owns
878
953
  the column/gap). This adds only what the wrapper itself needs: a minimum-zero
879
954
  track so long token names ellipsize inside the grid instead of widening it. */
@@ -180,30 +180,46 @@ a.row:hover .meta, .row[role="button"]:hover .meta { color: var(--accent-ink); t
180
180
  /* A row with no leading code/index drops the empty first column so the title
181
181
  takes the full width instead of wrapping in the narrow code gutter. */
182
182
  .row.row-nocode { grid-template-columns: minmax(0, 1fr) auto; }
183
- /* Template-rendered index/example rows (site/theme.mjs "why design" +
184
- "live examples" panels, via panelNode()/examplesNode() in
185
- src/page-html/client-script.js) never emit a leading ".code" span for
186
- these entries (no `code` field on the "features" items), so their actual
187
- children are title + an inline ".meta.dim" description + a trailing
188
- ".ds-row-arrow" — three items, but with no ".code" as the first child the
189
- base 3-track .row grid (minmax(80px,12ch) / minmax(0,1fr) / auto) still
190
- places the FIRST item (the title) into the narrow 12ch leading track
191
- meant for a code index, not the 1fr track. ".ds-row-arrow" also had no
192
- rule at all, and ".meta" is nowrap by default, so on longer descriptions
193
- ("…never borders", "…--fs-* tokens") the un-wrapped text overflows its
194
- cramped column straight into the arrow's box. Rows carrying both a dim
195
- meta description and an arrow get their own two-row template instead:
196
- title + arrow share row 1, the description drops to its own full-width
197
- row 2 and wraps normally — matching how every other multi-line row
198
- pattern in this file (.ds-row-detail) already gets a dedicated line. */
183
+ /* Template-rendered index/example rows (site/theme.mjs panels, via
184
+ panelNode()/examplesNode() in src/page-html/client-script.js) share one
185
+ row template across every panel-driven section on the homepage — "ui
186
+ kits", "previews", "file browser", "web components", "public api", "why
187
+ design", "live examples". Every one of those rows carries an inline
188
+ ".meta.dim" description and a trailing ".ds-row-arrow"; some ALSO carry a
189
+ leading ".code" span (file_browser/web_components/api_exports items have
190
+ a `code` field, "why design"/"live examples" items do not) — the
191
+ selector below has to handle both shapes as ONE template, not two.
192
+ Un-augmented, the base 3-track .row grid (minmax(80px,12ch) /
193
+ minmax(0,1fr) / auto) either crams the title into the narrow 12ch code
194
+ gutter (no-code rows) or, worse, auto-places an EXPLICIT-grid orphan:
195
+ once .title/.ds-row-arrow/.meta.dim below are pinned to explicit
196
+ grid-column/grid-row, a .code span left on `auto` placement can't share
197
+ row 1 with .title (already occupying column 1) and gets pushed into a
198
+ phantom row 3, rendering as a stray floating "fb"/"wc"/"api" line under
199
+ the description — the exact bug this rule exists to prevent, previously
200
+ left unfixed for the has-code case. Rows carrying a dim meta description
201
+ and an arrow always get the two-row template: code + title + arrow share
202
+ row 1 (code first, in its own narrow track), the description drops to
203
+ its own full-width row 2 and wraps normally — matching how every other
204
+ multi-line row pattern in this file (.ds-row-detail) already gets a
205
+ dedicated line. */
199
206
  .row:has(.meta.dim):has(.ds-row-arrow) {
200
- grid-template-columns: minmax(0, 1fr) auto;
207
+ grid-template-columns: minmax(80px, 12ch) minmax(0, 1fr) auto;
201
208
  grid-template-rows: auto auto;
202
209
  row-gap: var(--space-1);
203
210
  }
204
- .row:has(.meta.dim):has(.ds-row-arrow) .title { grid-column: 1; grid-row: 1; }
205
- .row:has(.meta.dim):has(.ds-row-arrow) .ds-row-arrow { grid-column: 2; grid-row: 1; }
211
+ .row:has(.meta.dim):has(.ds-row-arrow) .code { grid-column: 1; grid-row: 1; }
212
+ .row:has(.meta.dim):has(.ds-row-arrow) .title { grid-column: 2; grid-row: 1; }
213
+ .row:has(.meta.dim):has(.ds-row-arrow) .ds-row-arrow { grid-column: 3; grid-row: 1; }
206
214
  .row:has(.meta.dim):has(.ds-row-arrow) .meta.dim { grid-column: 1 / -1; grid-row: 2; }
215
+ /* No-code rows ("why design", "live examples") drop the empty leading
216
+ gutter so the title starts flush left instead of leaving a dead 12ch
217
+ column — same fix .row-nocode already applies to the base template. */
218
+ .row:has(.meta.dim):has(.ds-row-arrow):not(:has(.code)) {
219
+ grid-template-columns: minmax(0, 1fr) auto;
220
+ }
221
+ .row:has(.meta.dim):has(.ds-row-arrow):not(:has(.code)) .title { grid-column: 1; }
222
+ .row:has(.meta.dim):has(.ds-row-arrow):not(:has(.code)) .ds-row-arrow { grid-column: 2; }
207
223
  .row .meta.dim {
208
224
  white-space: normal;
209
225
  min-width: 0;
@@ -907,8 +907,7 @@ export declare const AICAT_FACE: any;
907
907
  export interface AICatPortraitProps {
908
908
  /** @default 'aicat' */
909
909
  name?: string;
910
- /** @default 'idle' */
911
- status?: string;
910
+ status?: any;
912
911
  face?: any;
913
912
  }
914
913
  export declare function AICatPortrait(props?: AICatPortraitProps): VNode;