anentrypoint-design 0.0.385 → 0.0.387

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 (71) hide show
  1. package/dist/247420.css +33 -0
  2. package/dist/247420.js +53 -51
  3. package/package.json +1 -1
  4. package/src/components/agent-chat/controls.js +143 -0
  5. package/src/components/agent-chat/empty-state.js +63 -0
  6. package/src/components/agent-chat/message-rows.js +141 -0
  7. package/src/components/agent-chat/surface.js +206 -0
  8. package/src/components/agent-chat/thread-behaviour.js +50 -0
  9. package/src/components/agent-chat.js +6 -546
  10. package/src/components/chat/composer-affordances.js +109 -0
  11. package/src/components/chat/composer.js +256 -0
  12. package/src/components/chat/threads.js +105 -0
  13. package/src/components/chat-message-parts/agent-nodes.js +103 -0
  14. package/src/components/chat-message-parts/inline.js +106 -0
  15. package/src/components/chat-message-parts/prose-nodes.js +133 -0
  16. package/src/components/chat-message-parts/renderers.js +89 -0
  17. package/src/components/chat-message-parts.js +12 -408
  18. package/src/components/chat-minimap/minimap.js +167 -0
  19. package/src/components/chat-minimap/paint.js +73 -0
  20. package/src/components/chat-minimap/preview.js +41 -0
  21. package/src/components/chat-minimap.js +7 -263
  22. package/src/components/chat.js +20 -628
  23. package/src/components/community/chrome.js +63 -0
  24. package/src/components/community/navigation.js +167 -0
  25. package/src/components/community/presence.js +106 -0
  26. package/src/components/community/shell.js +17 -0
  27. package/src/components/community/views.js +131 -0
  28. package/src/components/community.js +18 -447
  29. package/src/components/files/chrome.js +140 -0
  30. package/src/components/files/entries.js +156 -0
  31. package/src/components/files/grid-controls.js +63 -0
  32. package/src/components/files/grid.js +177 -0
  33. package/src/components/files/types.js +69 -0
  34. package/src/components/files-modals/dialogs.js +118 -0
  35. package/src/components/files-modals/modal-shell.js +153 -0
  36. package/src/components/files-modals/preview-bodies.js +129 -0
  37. package/src/components/files-modals/preview-containers.js +96 -0
  38. package/src/components/files-modals.js +14 -475
  39. package/src/components/files.js +15 -564
  40. package/src/components/freddie/pages-config.js +3 -94
  41. package/src/components/freddie/pages-models.js +97 -0
  42. package/src/components/freddie.js +2 -1
  43. package/src/components/interaction-primitives/mobile.js +25 -0
  44. package/src/components/interaction-primitives/pointer.js +214 -0
  45. package/src/components/interaction-primitives/reorderable.js +47 -0
  46. package/src/components/interaction-primitives/shortcuts.js +119 -0
  47. package/src/components/interaction-primitives.js +16 -388
  48. package/src/components/sessions/conversation-list.js +230 -0
  49. package/src/components/sessions/dashboard.js +202 -0
  50. package/src/components/sessions/detail-bits.js +49 -0
  51. package/src/components/sessions/format.js +42 -0
  52. package/src/components/sessions/session-card.js +92 -0
  53. package/src/components/sessions.js +16 -579
  54. package/src/components/voice/audio-cue.js +39 -0
  55. package/src/components/voice/capture.js +90 -0
  56. package/src/components/voice/playback.js +75 -0
  57. package/src/components/voice/settings-modal.js +104 -0
  58. package/src/components/voice.js +16 -293
  59. package/src/css/app-shell/base.css +23 -0
  60. package/src/css/app-shell/states-interactions.css +10 -0
  61. package/src/kits/os/freddie/chat-protocol.js +32 -0
  62. package/src/kits/os/freddie/chat-transport.js +178 -0
  63. package/src/kits/os/freddie/pages-chat.js +10 -180
  64. package/src/kits/os/shell-chrome.js +163 -0
  65. package/src/kits/os/shell-geometry.js +59 -0
  66. package/src/kits/os/shell.js +178 -335
  67. package/src/page-html/client-script.js +151 -0
  68. package/src/page-html/head-tags.js +59 -0
  69. package/src/page-html/markdown.js +68 -0
  70. package/src/page-html/page-styles.js +44 -0
  71. package/src/page-html.js +14 -291
package/src/page-html.js CHANGED
@@ -15,114 +15,18 @@
15
15
  // theme: 'auto' | 'light' | 'ink',
16
16
  // cssHref, headExtra,
17
17
  // })
18
+ //
19
+ // This module is a barrel over ./page-html/: the server-side markdown+href
20
+ // helpers, the <head> tag builders, the inline <style> block, and the client
21
+ // mount script string. The public export surface here is unchanged — no
22
+ // consumer import needs to move.
18
23
 
19
- // Single source of HTML escaping lives in markdown.js (full entity set). Kept
20
- // the `escape` export name for backward compatibility with any consumer.
21
- import { escapeHtml } from './markdown.js';
22
- export const escape = escapeHtml;
23
-
24
- export function inlineMd(s) {
25
- return s
26
- .replace(/`([^`]+)`/g, '<code>$1</code>')
27
- .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
28
- .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
29
- }
30
-
31
- // GitHub-flavored heading slug: lowercase, strip non-word/non-space/non-hyphen,
32
- // collapse whitespace to hyphens. Matches the fallback anchor target a hero/nav
33
- // CTA's `#slug` href expects to resolve against a `## slug text` body heading.
34
- export function slugify(s) {
35
- return String(s || '').trim().toLowerCase()
36
- .replace(/[^\w\s-]/g, '')
37
- .replace(/\s+/g, '-');
38
- }
39
-
40
- // Raw-HTML passthrough block, opt-in via ```html fences. Distinct from a
41
- // plain ``` code fence (which still escapes+<pre>-wraps its contents) — this
42
- // is for SSR call sites that are trusted, repo-authored content (a theme.mjs
43
- // page body sourced from the project's own YAML, never end-user input) and
44
- // need to emit real markup (e.g. an <iframe> demo embed) that must NOT be
45
- // escaped. There is no sanitization here by design: the caller owns trust.
46
- // A consumer rendering untrusted content must not route it through this
47
- // path — use markdown.js's DOMPurify-backed renderMarkdown for that instead.
48
- export function renderMarkdown(md) {
49
- const lines = String(md || '').split('\n');
50
- const out = [];
51
- let inCode = false, inList = false, inRawHtml = false;
52
- for (const line of lines) {
53
- if (line.trim() === '```html') { if (!inCode) { inRawHtml = true; continue; } }
54
- if (line.startsWith('```')) {
55
- if (inRawHtml) { inRawHtml = false; continue; }
56
- if (inCode) { out.push('</pre>'); inCode = false; } else { out.push('<pre>'); inCode = true; }
57
- continue;
58
- }
59
- if (inRawHtml) { out.push(line); continue; }
60
- if (inCode) { out.push(escape(line)); continue; }
61
- if (line.startsWith('# ')) { const t = line.slice(2); out.push(`<h1 id="${slugify(t)}">${escape(t)}</h1>`); }
62
- else if (line.startsWith('## ')) { const t = line.slice(3); out.push(`<h2 id="${slugify(t)}">${escape(t)}</h2>`); }
63
- else if (line.startsWith('### ')) { const t = line.slice(4); out.push(`<h3 id="${slugify(t)}">${escape(t)}</h3>`); }
64
- else if (line.startsWith('- ')) { if (!inList) { out.push('<ul>'); inList = true; } out.push(`<li>${inlineMd(escape(line.slice(2)))}</li>`); }
65
- else { if (inList) { out.push('</ul>'); inList = false; } if (line.trim()) out.push(`<p>${inlineMd(escape(line))}</p>`); }
66
- }
67
- if (inList) out.push('</ul>');
68
- if (inCode) out.push('</pre>');
69
- return out.join('\n');
70
- }
24
+ import { escape, inlineMd, slugify, renderMarkdown, joinHref } from './page-html/markdown.js';
25
+ import { renderSeoTags, renderFaviconTags, renderCssLink } from './page-html/head-tags.js';
26
+ import { PAGE_INLINE_STYLES } from './page-html/page-styles.js';
27
+ import { CLIENT_SCRIPT } from './page-html/client-script.js';
71
28
 
72
- // Join a basePath prefix to a nav href. Absolute URLs and hash links pass
73
- // through unchanged; leading-slash paths get the prefix.
74
- function joinHref(basePath, href) {
75
- if (!href) return '#';
76
- const h = String(href);
77
- if (/^([a-z]+:|#|\/\/)/i.test(h)) return h;
78
- if (!basePath) return h;
79
- const base = basePath.replace(/\/+$/, '');
80
- if (h.startsWith('/')) return base + h;
81
- return base + '/' + h.replace(/^\.?\//, '');
82
- }
83
-
84
- // Full SEO/OG/twitter/schema.org meta block, extracted so renderPageHtml
85
- // consumers (design's own marketing site, thebird's landing) can opt in
86
- // instead of hand-rolling ~40 lines of <meta> tags per theme.mjs.
87
- function renderSeoTags({ title, siteName, seo }) {
88
- const desc = escape(seo.description || '');
89
- const lang = escape(seo.lang || 'en');
90
- const url = escape(seo.url || '');
91
- const image = escape(seo.image || '');
92
- const author = escape(seo.author || siteName);
93
- const twitter = escape(seo.twitter || '');
94
- const locale = escape(seo.locale || 'en_US');
95
- const keywords = escape(Array.isArray(seo.keywords) ? seo.keywords.join(', ') : (seo.keywords || ''));
96
- const ogTitle = escape(title);
97
- const ogDesc = escape(seo.description || siteName);
98
- let out = `
99
- <meta name="description" content="${desc}">
100
- ${keywords ? `<meta name="keywords" content="${keywords}">` : ''}
101
- <meta name="author" content="${author}">
102
- <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1">
103
- <meta name="generator" content="anentrypoint-design">
104
- ${url ? `<link rel="canonical" href="${url}">` : ''}
105
- <meta property="og:type" content="website">
106
- <meta property="og:title" content="${ogTitle}">
107
- <meta property="og:description" content="${ogDesc}">
108
- ${url ? `<meta property="og:url" content="${url}">` : ''}
109
- <meta property="og:site_name" content="${escape(siteName)}">
110
- <meta property="og:locale" content="${locale}">
111
- ${image ? `<meta property="og:image" content="${image}">` : ''}
112
- <meta name="twitter:card" content="summary_large_image">
113
- <meta name="twitter:title" content="${ogTitle}">
114
- <meta name="twitter:description" content="${ogDesc}">
115
- ${twitter ? `<meta name="twitter:site" content="${twitter}">` : ''}
116
- ${image ? `<meta name="twitter:image" content="${image}">` : ''}`;
117
- if (seo.ldJson !== false && (seo.description || url)) {
118
- const ld = JSON.stringify({
119
- '@context': 'https://schema.org', '@type': 'WebSite',
120
- name: title, url: seo.url || '', description: seo.description || '', inLanguage: seo.lang || 'en',
121
- }).replace(/</g, '\\u003c');
122
- out += `\n<script type="application/ld+json">${ld}</script>`;
123
- }
124
- return out;
125
- }
29
+ export { escape, inlineMd, slugify, renderMarkdown };
126
30
 
127
31
  export function renderPageHtml({
128
32
  title = '247420', slug = 'index', siteName = '247420',
@@ -147,9 +51,7 @@ export function renderPageHtml({
147
51
  // instead of @latest (e.g. '0.0.320'); omitted -> default @latest behavior.
148
52
  } = {}) {
149
53
  const pkgVersion = version || 'latest';
150
- const cssLink = cssHref
151
- ? `<link rel="stylesheet" href="${cssHref}">`
152
- : `<link rel="stylesheet" href="https://unpkg.com/anentrypoint-design@${pkgVersion}/dist/247420.css">`;
54
+ const cssLink = renderCssLink({ cssHref, pkgVersion });
153
55
 
154
56
  // Resolve nav hrefs server-side against basePath. Client receives final URLs.
155
57
  const navResolved = (Array.isArray(navItems) ? navItems : []).map(([label, href]) =>
@@ -173,11 +75,7 @@ export function renderPageHtml({
173
75
  };
174
76
 
175
77
  const seoTags = seo ? renderSeoTags({ title, siteName, seo }) : '';
176
- const faviconTags = faviconHref
177
- ? `<link rel="icon" href="${escape(faviconHref)}">`
178
- : (faviconGlyph
179
- ? `<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ctext y='26' font-size='26'%3E${encodeURIComponent(faviconGlyph)}%3C/text%3E%3C/svg%3E">`
180
- : '');
78
+ const faviconTags = renderFaviconTags({ faviconHref, faviconGlyph });
181
79
 
182
80
  // Theme attribute co-location is CORRECT here: dist/247420.css keys every
183
81
  // theme block off the COMPOUND selector `.ds-247420[data-theme="X"]`
@@ -201,42 +99,7 @@ ${cssLink}
201
99
  { "imports": { "anentrypoint-design": "https://unpkg.com/anentrypoint-design@${pkgVersion}/dist/247420.js" } }
202
100
  </script>
203
101
  <style>
204
- .app-stage { width: 100%; max-width: var(--stage-wide, min(96vw, 1440px)); margin-inline: auto; padding: var(--space-6, 48px) var(--space-4, 24px) var(--space-8, 96px); display: grid; gap: var(--space-6, 48px); box-sizing: border-box }
205
- @media (max-width: 768px) { .app-stage { padding: var(--space-4, 24px) var(--space-3, 16px) var(--space-6, 48px); gap: var(--space-5, 32px) } }
206
- .page-body > :first-child { margin-top: 0 }
207
- .page-body h1 { margin-top: 0 } .page-body h2 { margin-top: var(--space-5, 32px) } .page-body h3 { margin-top: var(--space-4, 24px) }
208
- .page-body > * + * { margin-top: var(--space-3, 16px) }
209
- .page-body pre { margin: var(--space-3, 16px) 0; background: var(--panel-2); padding: var(--space-3, 16px); border-radius: var(--r-1, 10px); overflow-x: auto }
210
- /* .app-stage owns inter-block rhythm via grid gap; sections/hero must not double it.
211
- These selectors carry !important because this inline block loads before the
212
- unpkg CSS bundle, which would otherwise win on load-order for equal specificity. */
213
- .ds-247420 .app-stage > .ds-hero { margin: 0 !important; padding: var(--space-4, 24px) 0 0 !important; max-width: none !important; gap: var(--space-4, 24px) !important }
214
- .ds-247420 .app-stage > .ds-section { margin: 0 !important }
215
- .app-stage .row + .row { margin-top: var(--space-1, 4px) }
216
- .app-stage .ds-section .row { margin-top: var(--space-2, 8px) }
217
- .app-stage .ds-section > p.ds-lede { margin: 0 0 var(--space-3, 16px); max-width: var(--measure, 68ch); color: var(--fg-2) }
218
- .row-benefit { font-style: italic; color: var(--fg-3); font-size: var(--fs-sm); margin-top: var(--space-1, 4px) }
219
- .ds-row-arrow { margin-left: auto; opacity: .5; transition: opacity var(--dur-snap, 80ms) var(--ease) }
220
- a.row:hover .ds-row-arrow { opacity: 1 }
221
- /* hero stat strip — all badges as a wrapping inline rhythm, not one empty panel */
222
- .ds-hero-stats { display: flex; flex-wrap: wrap; gap: var(--space-3, 16px) var(--space-5, 32px); margin-top: var(--space-2, 8px) }
223
- .ds-hero-stat { display: flex; align-items: baseline; gap: var(--space-2, 8px) }
224
- .ds-hero-stat-n { font-family: var(--ff-body); font-weight: 700; font-size: var(--fs-lg, 18px); color: var(--fg) }
225
- .ds-hero-stat-l { font-size: var(--fs-sm, 15px); color: var(--fg-3) }
226
- /* accent sits on its own line, muted, so it reads as a distinct aside instead
227
- of running on from the hero body sentence. */
228
- .ds-hero-accent { display: block; margin-top: var(--space-2, 8px); color: var(--fg-3) }
229
- /* feature rows — single-column stack (the dashboard .row grid forces a 3-col
230
- code/title/meta layout that mangles title+desc+benefit) */
231
- /* background uses a theme-neutral panel token (resolves per data-theme) so dark
232
- mode doesn't flash a literal white card before/independent of the bundle.
233
- Flat tonal fill only — no border-left rail accent (house style: no bespoke
234
- tile chrome, no shadows, no borders; see ui_kits/gallery/app.js). */
235
- .ds-feature { padding: var(--space-3, 16px) var(--space-4, 24px); background: var(--panel-1, var(--bg)); border-radius: var(--r-2, 14px); display: grid; gap: var(--space-1, 4px) }
236
- .ds-feature + .ds-feature { margin-top: var(--space-2, 8px) }
237
- .ds-feature-title { font-weight: 600; font-size: var(--fs-lg, 18px); color: var(--fg) }
238
- .ds-feature-desc { font-size: var(--fs-sm, 15px); color: var(--fg-2); line-height: 1.5; overflow-wrap: anywhere }
239
- .ds-feature-benefit { font-style: italic; font-size: var(--fs-sm, 15px); color: var(--fg-3); margin-top: var(--space-1, 4px) }
102
+ ${PAGE_INLINE_STYLES}
240
103
  </style>
241
104
  <script id="__site__" type="application/json">${JSON.stringify(pageData).replace(/</g, '\\u003c')}</script>
242
105
  ${headExtra}
@@ -244,147 +107,7 @@ ${headExtra}
244
107
  <body>
245
108
  <div id="app"></div>
246
109
  <script type="module">
247
- import { mount, components as C, h } from 'anentrypoint-design';
248
- const data = JSON.parse(document.getElementById('__site__').textContent);
249
-
250
- function heroNode(hero) {
251
- if (!hero) return null;
252
- const badges = Array.isArray(hero.badges) ? hero.badges.filter(Boolean) : [];
253
- const badgeRow = badges.length
254
- ? h('div', { class: 'ds-hero-stats' }, ...badges.map((b, i) =>
255
- h('span', { key: i, class: 'ds-hero-stat' },
256
- h('strong', { class: 'ds-hero-stat-n' }, String(b.label != null ? b.label : b)),
257
- b.desc ? h('span', { class: 'ds-hero-stat-l' }, String(b.desc)) : null,
258
- )))
259
- : null;
260
- return h('div', { class: 'ds-hero' },
261
- hero.eyebrow ? h('span', { class: 'eyebrow' }, hero.eyebrow) : null,
262
- h('h1', { class: 'ds-hero-title' }, hero.heading || hero.title || data.title),
263
- (hero.body || hero.subheading) ? h('p', { class: 'ds-hero-body' },
264
- hero.body || hero.subheading,
265
- hero.accent ? h('span', { class: 'ds-hero-accent' }, ' ' + hero.accent) : null,
266
- ) : null,
267
- Array.isArray(hero.ctas) && hero.ctas.length
268
- ? h('div', { class: 'ds-hero-actions' }, ...hero.ctas.map((c, i) =>
269
- h('a', { key: i, class: i === 0 ? 'btn btn-accent' : 'btn btn-ghost', href: c.href || '#' }, c.label || c.cta || 'go')))
270
- : null,
271
- badgeRow,
272
- );
273
- }
274
-
275
- function sectionNode(sec, idx) {
276
- const features = sec.features || sec.items || [];
277
- const rows = features.map((f, i) => {
278
- const kids = [h('div', { key: 't', class: 'ds-feature-title' }, String(f.name || ''))];
279
- if (f.desc) kids.push(h('div', { key: 'd', class: 'ds-feature-desc', innerHTML: String(f.desc).replace(/\`([^\`]+)\`/g, '<code>$1</code>') }));
280
- if (f.benefit) kids.push(h('div', { key: 'b', class: 'ds-feature-benefit' }, String(f.benefit)));
281
- return h('div', { key: i, class: 'ds-feature' }, ...kids);
282
- });
283
- return C.Section({
284
- id: sec.id || null,
285
- title: sec.name || sec.title || sec.id,
286
- children: [
287
- sec.lede ? h('p', { class: 'ds-lede' }, sec.lede) : null,
288
- ...rows,
289
- sec.body && String(sec.body).trim() ? h('div', { class: 'page-body', innerHTML: __md(sec.body) }) : null,
290
- ].filter(Boolean),
291
- });
292
- }
293
-
294
- function examplesNode(examples) {
295
- if (!examples || !examples.length) return null;
296
- return C.Section({
297
- title: 'explore',
298
- children: examples.map((e, i) => {
299
- const kids = [
300
- h('span', { key: 'c', class: 'code' }, String(i + 1).padStart(2, '0')),
301
- h('span', { key: 't', class: 'title' }, String(e.label || e.name || e.href || '')),
302
- ];
303
- if (e.desc) kids.push(h('span', { key: 'm', class: 'meta dim' }, ' — ' + e.desc));
304
- kids.push(h('span', { key: 'a', class: 'ds-row-arrow' }, '->'));
305
- return h('a', { key: i, class: 'row', href: e.href || '#' }, ...kids);
306
- }),
307
- });
308
- }
309
-
310
- function panelNode(panel, idx) {
311
- const items = Array.isArray(panel.items) ? panel.items : [];
312
- if (!items.length) return null;
313
- const rows = items.map((it, i) => {
314
- const kids = [
315
- h('span', { key: 'c', class: 'code' }, String(it.code || String(i + 1).padStart(2, '0'))),
316
- h('span', { key: 't', class: 'title' }, String(it.title || it.name || '')),
317
- ];
318
- if (it.sub || it.desc) kids.push(h('span', { key: 'm', class: 'meta dim' }, ' — ' + (it.sub || it.desc)));
319
- kids.push(h('span', { key: 'a', class: 'ds-row-arrow' }, it.meta || '->'));
320
- return h('a', { key: i, class: 'row', href: it.href || '#' }, ...kids);
321
- });
322
- return C.Panel({ id: panel.id || null, title: panel.title || panel.name || '', count: panel.count || items.length, children: rows });
323
- }
324
-
325
- function marqueeNode(marquee) {
326
- if (!marquee || !Array.isArray(marquee.items) || !marquee.items.length) return null;
327
- return C.Marquee ? C.Marquee({ items: marquee.items, sep: marquee.sep || '/' }) : null;
328
- }
329
-
330
- function quickstartNode(quickstart) {
331
- if (!quickstart || !Array.isArray(quickstart.lines) || !quickstart.lines.length) return null;
332
- const lineNodes = quickstart.lines.map((l, i) => h('div', { key: 'q' + i, class: 'cli' },
333
- h('span', { class: 'prompt' }, l.kind === 'cmt' ? '#' : '$'),
334
- h('span', { class: 'cmd' }, l.text)
335
- ));
336
- return C.Panel({ title: quickstart.heading || 'quick start', children: h('div', { class: 'ds-quickstart' }, ...lineNodes) });
337
- }
338
-
339
- function sideNode(sidebar) {
340
- if (!sidebar || !Array.isArray(sidebar.sections) || !sidebar.sections.length || !C.Side) return null;
341
- return C.Side({ sections: sidebar.sections });
342
- }
343
-
344
- // minimal client-side markdown renderer matching server-side renderer (idempotent for already-html bodies)
345
- function __slug(s) { return String(s || '').trim().toLowerCase().replace(/[^\\w\\s-]/g, '').replace(/\\s+/g, '-'); }
346
- function __md(md) {
347
- const lines = String(md || '').split('\\n');
348
- const out = []; let inCode = false, inList = false;
349
- const esc = (s) => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
350
- const inl = (s) => s.replace(/\`([^\`]+)\`/g, '<code>$1</code>').replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>').replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href="$2">$1</a>');
351
- for (const line of lines) {
352
- if (line.startsWith('\`\`\`')) { if (inCode) { out.push('</pre>'); inCode = false; } else { out.push('<pre>'); inCode = true; } continue; }
353
- if (inCode) { out.push(esc(line)); continue; }
354
- if (line.startsWith('# ')) { const t = line.slice(2); out.push('<h1 id="' + __slug(t) + '">' + esc(t) + '</h1>'); }
355
- else if (line.startsWith('## ')) { const t = line.slice(3); out.push('<h2 id="' + __slug(t) + '">' + esc(t) + '</h2>'); }
356
- else if (line.startsWith('### ')) { const t = line.slice(4); out.push('<h3 id="' + __slug(t) + '">' + esc(t) + '</h3>'); }
357
- else if (line.startsWith('- ')) { if (!inList) { out.push('<ul>'); inList = true; } out.push('<li>' + inl(esc(line.slice(2))) + '</li>'); }
358
- else { if (inList) { out.push('</ul>'); inList = false; } if (line.trim()) out.push('<p>' + inl(esc(line)) + '</p>'); }
359
- }
360
- if (inList) out.push('</ul>');
361
- if (inCode) out.push('</pre>');
362
- return out.join('\\n');
363
- }
364
-
365
- const bodyNode = data.bodyHtml ? C.Section({ children: h('div', { class: 'page-body', innerHTML: data.bodyHtml }) }) : null;
366
-
367
- const mainChildren = [
368
- heroNode(data.hero),
369
- marqueeNode(data.marquee),
370
- ...data.sections.map(sectionNode),
371
- ...(data.panels || []).map(panelNode),
372
- quickstartNode(data.quickstart),
373
- examplesNode(data.examples),
374
- bodyNode,
375
- ].filter(Boolean);
376
-
377
- mount(document.getElementById('app'), () => C.AppShell({
378
- topbar: C.Topbar({ brand: data.siteName, items: data.navItems, active: data.title }),
379
- crumb: C.Crumb({ leaf: data.title }),
380
- side: sideNode(data.sidebar),
381
- main: h('div', { class: 'app-stage' }, ...mainChildren),
382
- status: C.Status({
383
- left: data.statusLeft || [data.siteName.toLowerCase(), data.slug],
384
- right: data.statusRight || ['live'],
385
- }),
386
- }));
387
- ${clientScriptExtra}
110
+ ${CLIENT_SCRIPT}${clientScriptExtra}
388
111
  </script>
389
112
  </body>
390
113
  </html>`;