anentrypoint-design 0.0.244 → 0.0.246

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/dist/index.html CHANGED
@@ -2,7 +2,7 @@
2
2
  <html lang="en" class="ds-247420" data-theme="auto">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <title>design — 247420 design system</title>
7
7
  <meta name="description" content="the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface." />
8
8
  <meta name="keywords" content="design-system, tokens, 247420, anentrypoint" />
@@ -42,19 +42,27 @@
42
42
  <meta name="twitter:creator" content="@AnEntrypoint" />
43
43
  <meta name="twitter:image" content="https://anentrypoint.github.io/design/og-card.png" />
44
44
  <meta name="twitter:image:alt" content="design" />
45
- <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%E2%97%B0%3C/text%3E%3C/svg%3E" />
46
- <link rel="apple-touch-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%E2%97%B0%3C/text%3E%3C/svg%3E" />
45
+ <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%C2%B7%3C/text%3E%3C/svg%3E" />
46
+ <link rel="apple-touch-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%C2%B7%3C/text%3E%3C/svg%3E" />
47
47
  <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"design","url":"https://anentrypoint.github.io/design","description":"the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface.","inLanguage":"en","publisher":{"@type":"Organization","name":"247420 / AnEntrypoint","url":"https://247420.xyz"}}</script>
48
48
  <script type="importmap">{"imports":{"anentrypoint-design":"https://unpkg.com/anentrypoint-design@latest/dist/247420.js"}}</script>
49
49
  <link rel="stylesheet" href="https://unpkg.com/anentrypoint-design@latest/dist/247420.css">
50
50
  <link rel="preconnect" href="https://unpkg.com" crossorigin>
51
51
  <link rel="dns-prefetch" href="https://unpkg.com">
52
- <style>html,body{margin:0;padding:0}body{background:var(--app-bg,#FBF6EB);color:var(--ink,#1F1B16);font-family:var(--ff-ui,'Nunito',system-ui,sans-serif)}html:not(.ds-ready) body{visibility:hidden}html.ds-ready body{visibility:visible;animation:ds-fade-in .18s ease-out both}@keyframes ds-fade-in{from{opacity:0}to{opacity:1}}</style>
52
+ <style>html,body{margin:0;padding:0}body{background:var(--bg,#F6F5F1);color:var(--fg,#131318);font-family:var(--ff-body,system-ui,sans-serif)}html:not(.ds-ready) body{visibility:hidden}html.ds-ready body{visibility:visible;animation:ds-fade-in .18s ease-out both}@keyframes ds-fade-in{from{opacity:0}to{opacity:1}}</style>
53
53
  <noscript><style>html body{visibility:visible !important}</style></noscript>
54
54
  </head>
55
55
  <body>
56
56
  <div id="app"></div>
57
- <script type="application/json" id="__site__">{"site":{"title":"design","tagline":"247420 design system","description":"the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface.","repo":"https://github.com/AnEntrypoint/design","url":"https://anentrypoint.github.io/design","year":2026,"keywords":["design-system","tokens","247420","anentrypoint"],"accent_from":"#56d364","accent_to":"#79c0ff","glyph":"◰","code":"072","category":"web"},"nav":{"links":[{"label":247420,"href":"https://247420.xyz"},{"label":"GitHub","href":"https://github.com/AnEntrypoint"}]},"home":{"id":"home","title":"Home","hero":{"heading":"design","subheading":"247420 design system","body":"the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface.","badges":[{"label":"design-system"},{"label":"tokens"},{"label":"web"}],"ctas":[{"label":"GitHub","href":"https://github.com/AnEntrypoint/design","primary":true},{"label":"247420","href":"https://247420.xyz"}]},"sidebar":{"fab":{"label":"open","glyph":"✦","href":"./ui_kits/homepage/"},"bins":[{"glyph":"▣","label":"everything","href":"#all","count":23,"active":true},{"glyph":"★","label":"starred","href":"#starred","count":5},{"glyph":"◐","label":"shipped","href":"#shipped","count":12},{"glyph":"◌","label":"drafts","href":"#drafts","count":6}],"labels_group":"labels","labels":[{"glyph":"●","label":"ui kits","href":"#kits","count":4,"color":"var(--panel-accent)"},{"glyph":"●","label":"decks","href":"#decks","count":1,"color":"var(--mascot,#e0a200)"},{"glyph":"●","label":"previews","href":"#previews","count":20,"color":"var(--purple,#8856b3)"},{"glyph":"●","label":"docs","href":"#docs","count":3,"color":"var(--panel-text-3)"}],"more_group":"more","more":[{"glyph":"§","label":"readme","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"glyph":"§","label":"skill","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"glyph":"⌘","label":"tokens","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"glyph":"↗","label":"source","href":"https://github.com/AnEntrypoint/design"}]},"tabs":[{"glyph":"▣","label":"everything","href":"#all","active":true},{"glyph":"◎","label":"kits","href":"#kits"},{"glyph":"▰","label":"decks","href":"#decks"},{"glyph":"§","label":"previews","href":"#previews"}],"kits":{"heading":"ui kits","count":"14 surfaces","items":[{"code":"01","title":"homepage","sub":"marquee + works grid","desc":"editorial banner over a quiet shell","href":"./ui_kits/homepage/"},{"code":"02","title":"project page","sub":"hero · receipt · install · changelog","desc":"shippable case-study template","href":"./ui_kits/project_page/"},{"code":"03","title":"docs","sub":"long-form prose chrome","desc":"sidebar nav, mono headings, code blocks","href":"./ui_kits/docs/"},{"code":"04","title":"blog","sub":"dated index + reading view","desc":"typographic, no clutter","href":"./ui_kits/blog/"},{"code":"05","title":"chat","sub":"message thread + composer","desc":"pill bubbles, monospace timestamps, room sidebar","href":"./ui_kits/chat/"},{"code":"06","title":"aicat","sub":"ai assistant with cat persona","desc":"ascii portrait, thinking dots, mood-swapping face","href":"./ui_kits/aicat/"},{"code":"07","title":"file browser","sub":"rails by file type · drop · preview","desc":"static demo wired to fsbrowse — every file-row primitive in one surface","href":"./ui_kits/file_browser/"},{"code":"08","title":"dashboard","sub":"kpis · tables · receipts · changelog","desc":"every content primitive in one operations surface","href":"./ui_kits/dashboard/"},{"code":"09","title":"terminal","sub":"cli prompt · command lines · log view","desc":"five line kinds — cmt cmd out ok warn — over a tonal panel","href":"./ui_kits/terminal/"},{"code":"10","title":"settings","sub":"sectioned forms · toggles · save bar","desc":"every input primitive — fields, segmented buttons, danger panel","href":"./ui_kits/settings/"},{"code":"11","title":"signin","sub":"auth · providers · magic link","desc":"narrow shell + tone-on-tone form, no shadows, no spinners","href":"./ui_kits/signin/"},{"code":"12","title":"search","sub":"topbar query · faceted filters · rows","desc":"ranked results reuse the same RowLink primitive every list does","href":"./ui_kits/search/"},{"code":"13","title":"404","sub":"empty-state hero · suggested routes","desc":"narrow shell, oversized mono code, three CTAs","href":"./ui_kits/error_404/"},{"code":"14","title":"gallery","sub":"visual grid · tonal cards · lightbox","desc":"tiles share the panel tokens; lightbox reuses the same surface","href":"./ui_kits/gallery/"}]},"decks":{"heading":"decks","items":[{"code":"01","title":"deck template","sub":"16:9 stage with auto-fit","desc":"title, lede, code, comparison, manifesto","href":"./slides/"}]},"docs":{"heading":"docs","items":[{"code":"md","title":"readme","sub":"overview, manifesto, conventions","desc":"start here","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"code":"md","title":"skill","sub":"authoring rules for the agent","desc":"editorial · zine · surface modes","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"code":"css","title":"tokens","sub":"colors, type, panel surface tokens","desc":"canonical source of truth","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"}]},"previews":{"heading":"previews","base":"./preview/","items":["buttons","colors-core","colors-lore","colors-semantic","dateline","dropzone","file-grid","file-row","file-toolbar","file-viewer","header","icons-unicode","index-row","inputs","manifesto","rules","spacing","stamps","stamps-lore","theme-ink","type-display","type-mono","type-prose","type-scale","wordmarks"]},"file_browser":{"heading":"file browser","count":"primitives","items":[{"code":"fb","title":"file_browser kit","sub":"drop, list, preview, dialogs","desc":"the full surface, working with mock data","href":"./ui_kits/file_browser/","cta":"open kit ↗"},{"code":"fb","title":"FileRow","sub":"rail · icon · name · meta","desc":"data-file-type drives the rail color — never apply rail-* manually","href":"./preview/file-row.html","cta":"preview ↗"},{"code":"fb","title":"FileGrid","sub":"stack of rows in a panel","desc":"directories sort first; selected row gets the mint .active tone","href":"./preview/file-grid.html","cta":"preview ↗"},{"code":"fb","title":"DropZone","sub":"tonal upload target","desc":"swap to --panel-select on dragover; preventDefault on document, not just zone","href":"./preview/dropzone.html","cta":"preview ↗"},{"code":"fb","title":"FileViewer","sub":"modal preview · keyed head","desc":"head + body both carry data-file-type so rails propagate inside the modal","href":"./preview/file-viewer.html","cta":"preview ↗"},{"code":"fb","title":"FileToolbar","sub":"actions · breadcrumb · upload","desc":"left-aligned actions, right-aligned count; UploadProgress sits underneath","href":"./preview/file-toolbar.html","cta":"preview ↗"},{"code":"fb","title":"fsbrowse","sub":"Express + busboy backend","desc":"canonical real-world wiring — same SDK, real filesystem operations","href":"https://github.com/AnEntrypoint/fsbrowse","cta":"source ↗"}]},"quickstart":{"heading":"quick start","lines":[{"kind":"cmt","text":"# install via importmap (no bundler)"},{"kind":"cmd","text":"\u003cscript type='importmap'\u003e{\"imports\":{\"anentrypoint-design\":\"https://unpkg.com/anentrypoint-design@latest/dist/247420.js\"}}\u003c/script\u003e"},{"kind":"cmt","text":"# or clone the source"},{"kind":"cmd","text":"git clone https://github.com/AnEntrypoint/design.git"}]},"desktop_os":{"heading":"desktop os shell","count":"in-page wm","items":[{"code":"os","title":"createDesktopShell","sub":"menubar · apps launcher · taskbar · window manager","desc":"in-page desktop OS chrome — mount any app registry into a draggable wm","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/shell.js","cta":"shell.js ↗"},{"code":"os","title":"icons set","sub":"svg glyphs for menubar + taskbar","desc":"home, apps, search, settings — used by the shell and exposed for apps","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/icons.js","cta":"icons.js ↗"},{"code":"os","title":"theme.css","sub":"os chrome tokens · menubar · launcher · wm","desc":"scoped css module loaded by the shell — keeps desktop visuals isolated","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/theme.css","cta":"theme.css ↗"},{"code":"os","title":"import path","sub":"anentrypoint-design/desktop","desc":"subpath export; no bundler needed — pulls icons + createDesktopShell","href":"https://github.com/AnEntrypoint/design/blob/main/package.json","cta":"exports ↗"}]},"web_components":{"heading":"web components","count":"1 element","items":[{"code":"wc","title":"\u003cds-chat\u003e","sub":"auto-registers when the sdk loads in a browser","desc":"set el.messages = [...] or pass json via attribute; listen for 'send' event","href":"https://github.com/AnEntrypoint/design/blob/main/src/web-components/ds-chat.js","cta":"ds-chat.js ↗"},{"code":"wc","title":"registerChatElement","sub":"manual register helper","desc":"exported from the sdk root for ssr / late-mount when customElements is gated","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js","cta":"source ↗"}]},"api_exports":{"heading":"public api","count":"sdk surface","items":[{"code":"api","title":"h / applyDiff","sub":"webjsx createElement + diff","desc":"build vnodes with h(), render with applyDiff(root, [vnode]) — no jsx pragma needed","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js","cta":"index.js ↗"},{"code":"api","title":"installStyles / scope","sub":"ds-247420 css scope + bootstrap","desc":"installStyles() injects the prefixed css; scope = '.ds-247420' for selector composition","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js","cta":"styles.js ↗"},{"code":"api","title":"loadCss","sub":"fetch the bundled css string","desc":"useful for shadow roots or custom style injection paths","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js","cta":"styles.js ↗"},{"code":"api","title":"mount / mountKit","sub":"ds shell + ui_kit bootstrap","desc":"mount(root, viewFn) wires applyDiff + motion; mountKit({root,view,screen}) wires a kit","href":"https://github.com/AnEntrypoint/design/blob/main/src/bootstrap.js","cta":"bootstrap.js ↗"},{"code":"api","title":"registerDeckStage / getDeckStage","sub":"16:9 deck stage api","desc":"register custom deck stages and fetch the active stage for slide transitions","href":"https://github.com/AnEntrypoint/design/blob/main/src/deck-stage.js","cta":"deck-stage.js ↗"},{"code":"api","title":"renderMarkdown","sub":"marked v15 + dompurify lazy stack","desc":"lazy-loads marked + dompurify from jsdelivr; only xss gate for chat html","href":"https://github.com/AnEntrypoint/design/blob/main/src/markdown.js","cta":"markdown.js ↗"},{"code":"api","title":"ensurePrism / highlightAllUnder","sub":"prism core + per-language","desc":"injects prism on first use; CodeNode ref-callback highlights inside any subtree","href":"https://github.com/AnEntrypoint/design/blob/main/src/highlight.js","cta":"highlight.js ↗"},{"code":"api","title":"renderPageHtml","sub":"static page html template","desc":"shared head/body wrapper for kit pages — meta, importmap, ds-247420 scope","href":"https://github.com/AnEntrypoint/design/blob/main/src/page-html.js","cta":"page-html.js ↗"},{"code":"api","title":"components / motion / debug","sub":"namespaces from the default export","desc":"components.* are the C.* primitives; motion.animateTree, debug.window.__debug registry","href":"https://github.com/AnEntrypoint/design/blob/main/src/components.js","cta":"components.js ↗"}]},"features":{"heading":"why design","items":[{"name":"layered surfaces","desc":"panel-on-panel rhythm; loud content sits inside quiet chrome."},{"name":"monospace labels","desc":"mono only for codes/labels/CLI; sans for everything legible."},{"name":"indicator rails","desc":"color-coded inset rails for category separation, never borders."},{"name":"tokens-only","desc":"every surface, type ramp, accent driven by --panel-* / --fs-* tokens."}]},"examples":{"heading":"live examples","items":[{"name":"index shell","desc":"full navigation shell with tabs, filters, and row interactions.","href":"./index.html","cta":"open index"},{"name":"homepage kit","desc":"hero + works layout and updated readable type scale.","href":"./ui_kits/homepage/","cta":"open kit"},{"name":"project page kit","desc":"overview, install, receipt, and changelog template.","href":"./ui_kits/project_page/","cta":"open kit"},{"name":"docs kit","desc":"technical documentation layout with sidebar and prose.","href":"./ui_kits/docs/","cta":"open docs"},{"name":"blog kit","desc":"long-form writing layout tuned for readability.","href":"./ui_kits/blog/","cta":"open writing"},{"name":"chat kit","desc":"message thread + composer with pill bubbles and room sidebar.","href":"./ui_kits/chat/","cta":"open chat"},{"name":"aicat kit","desc":"ai assistant with cat persona — ascii portrait + mood face.","href":"./ui_kits/aicat/","cta":"open aicat"},{"name":"slide deck","desc":"16:9 deck stage with improved presenter controls text.","href":"./slides/","cta":"open slides"},{"name":"dashboard kit","desc":"kpis, tables, receipts, changelog — operations surface.","href":"./ui_kits/dashboard/","cta":"open dashboard"},{"name":"terminal kit","desc":"cli prompt, command lines, log viewer.","href":"./ui_kits/terminal/","cta":"open terminal"},{"name":"settings kit","desc":"sectioned forms, toggles, segmented buttons, save bar.","href":"./ui_kits/settings/","cta":"open settings"},{"name":"signin kit","desc":"auth panel, providers, magic link.","href":"./ui_kits/signin/","cta":"open signin"},{"name":"search kit","desc":"query bar, faceted filters, ranked results.","href":"./ui_kits/search/","cta":"open search"},{"name":"404 kit","desc":"empty-state hero with suggested routes.","href":"./ui_kits/error_404/","cta":"open 404"},{"name":"gallery kit","desc":"visual grid + lightbox over tonal cards.","href":"./ui_kits/gallery/","cta":"open gallery"},{"name":"preview samples","desc":"design previews and component samples.","href":"./preview/buttons.html","cta":"open previews"}]},"status_left":["main","• utf-8","• lf"],"status_right":["247420 / mmxxvi","• probably emerging"]}}</script>
57
+ <noscript>
58
+ <main class="ds-prose">
59
+ <h1>design — 247420 design system</h1>
60
+ <p>the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface.</p>
61
+ <nav><a href="https://247420.xyz">247420</a>
62
+ <a href="https://github.com/AnEntrypoint">GitHub</a></nav>
63
+ </main>
64
+ </noscript>
65
+ <script type="application/json" id="__site__">{"site":{"title":"design","tagline":"247420 design system","description":"the visual paradigm. layered surfaces, monospace labels, loud content inside quiet chrome. consumed by every 247420 surface.","repo":"https://github.com/AnEntrypoint/design","url":"https://anentrypoint.github.io/design","year":2026,"keywords":["design-system","tokens","247420","anentrypoint"],"accent_from":"#247420","accent_to":"#3A9A34","glyph":"·","code":"072","category":"web"},"nav":{"links":[{"label":247420,"href":"https://247420.xyz"},{"label":"GitHub","href":"https://github.com/AnEntrypoint"}]},"home":{"id":"home","title":"Home","hero":{"heading":"design","subheading":"the 247420 design system","body":"acid editorial. oversized display type, one electric green, print texture over glow. every 247420 surface runs on it.","badges":[{"label":"design-system"},{"label":"tokens"},{"label":"web"}],"ctas":[{"label":"GitHub","href":"https://github.com/AnEntrypoint/design","primary":true},{"label":"247420","href":"https://247420.xyz"}]},"sidebar":{"fab":{"label":"open","glyph":"+","href":"./ui_kits/homepage/"},"bins":[{"label":"everything","href":"#all","count":23,"active":true},{"label":"pinned","href":"#kits","count":5},{"label":"shipped","href":"#previews","count":12},{"label":"drafts","href":"#decks","count":6}],"labels_group":"labels","labels":[{"label":"ui kits","href":"#kits","count":4,"color":"var(--panel-accent)"},{"label":"decks","href":"#decks","count":1,"color":"var(--mascot,#E84B8A)"},{"label":"previews","href":"#previews","count":20,"color":"var(--purple,#420247)"},{"label":"docs","href":"#docs","count":3,"color":"var(--panel-text-3)"}],"more_group":"more","more":[{"label":"readme","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"label":"skill","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"label":"tokens","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"label":"source","href":"https://github.com/AnEntrypoint/design"}]},"tabs":[{"label":"everything","href":"#all","active":true},{"label":"kits","href":"#kits"},{"label":"decks","href":"#decks"},{"label":"previews","href":"#previews"}],"kits":{"heading":"ui kits","count":"14 surfaces","items":[{"code":"01","title":"homepage","sub":"marquee + works grid","desc":"editorial banner over a quiet shell","href":"./ui_kits/homepage/"},{"code":"02","title":"project page","sub":"hero receipt install changelog","desc":"shippable case-study template","href":"./ui_kits/project_page/"},{"code":"03","title":"docs","sub":"long-form prose chrome","desc":"sidebar nav, mono headings, code blocks","href":"./ui_kits/docs/"},{"code":"04","title":"blog","sub":"dated index + reading view","desc":"typographic, no clutter","href":"./ui_kits/blog/"},{"code":"05","title":"chat","sub":"message thread + composer","desc":"pill bubbles, monospace timestamps, room sidebar","href":"./ui_kits/chat/"},{"code":"06","title":"aicat","sub":"ai assistant with cat persona","desc":"ascii portrait, thinking dots, mood-swapping face","href":"./ui_kits/aicat/"},{"code":"07","title":"file browser","sub":"rails by file type drop preview","desc":"static demo wired to fsbrowse — every file-row primitive in one surface","href":"./ui_kits/file_browser/"},{"code":"08","title":"dashboard","sub":"kpis tables receipts changelog","desc":"every content primitive in one operations surface","href":"./ui_kits/dashboard/"},{"code":"09","title":"terminal","sub":"cli prompt command lines log view","desc":"five line kinds (cmt cmd out ok warn) over a tonal panel","href":"./ui_kits/terminal/"},{"code":"10","title":"settings","sub":"sectioned forms toggles save bar","desc":"every input primitive — fields, segmented buttons, danger panel","href":"./ui_kits/settings/"},{"code":"11","title":"signin","sub":"auth providers magic link","desc":"narrow shell + tone-on-tone form, no shadows, no spinners","href":"./ui_kits/signin/"},{"code":"12","title":"search","sub":"topbar query faceted filters rows","desc":"ranked results reuse the same RowLink primitive every list does","href":"./ui_kits/search/"},{"code":"13","title":"404","sub":"empty-state hero suggested routes","desc":"narrow shell, oversized mono code, three CTAs","href":"./ui_kits/error_404/"},{"code":"14","title":"gallery","sub":"visual grid tonal cards lightbox","desc":"tiles share the panel tokens; lightbox reuses the same surface","href":"./ui_kits/gallery/"}]},"decks":{"heading":"decks","items":[{"code":"01","title":"deck template","sub":"16:9 stage with auto-fit","desc":"title, lede, code, comparison, manifesto","href":"./slides/"}]},"docs":{"heading":"docs","items":[{"code":"md","title":"readme","sub":"overview, manifesto, conventions","desc":"start here","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"code":"md","title":"skill","sub":"authoring rules for the agent","desc":"editorial zine surface modes","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"code":"css","title":"tokens","sub":"colors, type, panel surface tokens","desc":"canonical source of truth","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"}]},"previews":{"heading":"previews","base":"./preview/","items":["buttons","colors-core","colors-lore","colors-semantic","dateline","dropzone","file-grid","file-row","file-toolbar","file-viewer","header","icons-unicode","index-row","inputs","manifesto","rules","spacing","stamps","stamps-lore","theme-ink","type-display","type-mono","type-prose","type-scale","wordmarks"]},"file_browser":{"heading":"file browser","count":"primitives","items":[{"code":"fb","title":"file_browser kit","sub":"drop, list, preview, dialogs","desc":"the full surface, working with mock data","href":"./ui_kits/file_browser/","cta":"open kit"},{"code":"fb","title":"FileRow","sub":"rail icon name meta","desc":"data-file-type drives the rail color — never apply rail-* manually","href":"./preview/file-row.html","cta":"preview"},{"code":"fb","title":"FileGrid","sub":"stack of rows in a panel","desc":"directories sort first; selected row gets the mint .active tone","href":"./preview/file-grid.html","cta":"preview"},{"code":"fb","title":"DropZone","sub":"tonal upload target","desc":"swap to --panel-select on dragover; preventDefault on document, not just zone","href":"./preview/dropzone.html","cta":"preview"},{"code":"fb","title":"FileViewer","sub":"modal preview keyed head","desc":"head + body both carry data-file-type so rails propagate inside the modal","href":"./preview/file-viewer.html","cta":"preview"},{"code":"fb","title":"FileToolbar","sub":"actions breadcrumb upload","desc":"left-aligned actions, right-aligned count; UploadProgress sits underneath","href":"./preview/file-toolbar.html","cta":"preview"},{"code":"fb","title":"fsbrowse","sub":"Express + busboy backend","desc":"canonical real-world wiring — same SDK, real filesystem operations","href":"https://github.com/AnEntrypoint/fsbrowse","cta":"source"}]},"quickstart":{"heading":"quick start","lines":[{"kind":"cmt","text":"# install via importmap (no bundler)"},{"kind":"cmd","text":"\u003cscript type='importmap'\u003e{\"imports\":{\"anentrypoint-design\":\"https://unpkg.com/anentrypoint-design@latest/dist/247420.js\"}}\u003c/script\u003e"},{"kind":"cmt","text":"# or clone the source"},{"kind":"cmd","text":"git clone https://github.com/AnEntrypoint/design.git"}]},"desktop_os":{"heading":"desktop os shell","count":"in-page wm","items":[{"code":"os","title":"createDesktopShell","sub":"menubar apps launcher taskbar window manager","desc":"in-page desktop OS chrome — mount any app registry into a draggable wm","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/shell.js","cta":"shell.js"},{"code":"os","title":"icons set","sub":"svg glyphs for menubar + taskbar","desc":"home, apps, search, settings — used by the shell and exposed for apps","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/icons.js","cta":"icons.js"},{"code":"os","title":"theme.css","sub":"os chrome tokens menubar launcher wm","desc":"scoped css module loaded by the shell — keeps desktop visuals isolated","href":"https://github.com/AnEntrypoint/design/blob/main/src/desktop/theme.css","cta":"theme.css"},{"code":"os","title":"import path","sub":"anentrypoint-design/desktop","desc":"subpath export; no bundler needed — pulls icons + createDesktopShell","href":"https://github.com/AnEntrypoint/design/blob/main/package.json","cta":"exports"}]},"web_components":{"heading":"web components","count":"1 element","items":[{"code":"wc","title":"\u003cds-chat\u003e","sub":"auto-registers when the sdk loads in a browser","desc":"set el.messages = [...] or pass json via attribute; listen for 'send' event","href":"https://github.com/AnEntrypoint/design/blob/main/src/web-components/ds-chat.js","cta":"ds-chat.js"},{"code":"wc","title":"registerChatElement","sub":"manual register helper","desc":"exported from the sdk root for ssr / late-mount when customElements is gated","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js","cta":"source"}]},"api_exports":{"heading":"public api","count":"sdk surface","items":[{"code":"api","title":"h / applyDiff","sub":"webjsx createElement + diff","desc":"build vnodes with h(), render with applyDiff(root, [vnode]) — no jsx pragma needed","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js","cta":"index.js"},{"code":"api","title":"installStyles / scope","sub":"ds-247420 css scope + bootstrap","desc":"installStyles() injects the prefixed css; scope = '.ds-247420' for selector composition","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js","cta":"styles.js"},{"code":"api","title":"loadCss","sub":"fetch the bundled css string","desc":"useful for shadow roots or custom style injection paths","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js","cta":"styles.js"},{"code":"api","title":"mount / mountKit","sub":"ds shell + ui_kit bootstrap","desc":"mount(root, viewFn) wires applyDiff + motion; mountKit({root,view,screen}) wires a kit","href":"https://github.com/AnEntrypoint/design/blob/main/src/bootstrap.js","cta":"bootstrap.js"},{"code":"api","title":"registerDeckStage / getDeckStage","sub":"16:9 deck stage api","desc":"register custom deck stages and fetch the active stage for slide transitions","href":"https://github.com/AnEntrypoint/design/blob/main/src/deck-stage.js","cta":"deck-stage.js"},{"code":"api","title":"renderMarkdown","sub":"marked v15 + dompurify lazy stack","desc":"lazy-loads marked + dompurify from jsdelivr; only xss gate for chat html","href":"https://github.com/AnEntrypoint/design/blob/main/src/markdown.js","cta":"markdown.js"},{"code":"api","title":"ensurePrism / highlightAllUnder","sub":"prism core + per-language","desc":"injects prism on first use; CodeNode ref-callback highlights inside any subtree","href":"https://github.com/AnEntrypoint/design/blob/main/src/highlight.js","cta":"highlight.js"},{"code":"api","title":"renderPageHtml","sub":"static page html template","desc":"shared head/body wrapper for kit pages — meta, importmap, ds-247420 scope","href":"https://github.com/AnEntrypoint/design/blob/main/src/page-html.js","cta":"page-html.js"},{"code":"api","title":"components / motion / debug","sub":"namespaces from the default export","desc":"components.* are the C.* primitives; motion.animateTree, debug.window.__debug registry","href":"https://github.com/AnEntrypoint/design/blob/main/src/components.js","cta":"components.js"}]},"features":{"heading":"why design","items":[{"name":"layered surfaces","desc":"panel-on-panel rhythm; loud content sits inside quiet chrome."},{"name":"monospace labels","desc":"mono only for codes/labels/CLI; sans for everything legible."},{"name":"indicator rails","desc":"color-coded inset rails for category separation, never borders."},{"name":"tokens-only","desc":"every surface, type ramp, accent driven by --panel-* / --fs-* tokens."}]},"examples":{"heading":"live examples","items":[{"name":"index shell","desc":"full navigation shell with tabs, filters, and row interactions.","href":"./index.html","cta":"open index"},{"name":"homepage kit","desc":"hero + works layout and updated readable type scale.","href":"./ui_kits/homepage/","cta":"open kit"},{"name":"project page kit","desc":"overview, install, receipt, and changelog template.","href":"./ui_kits/project_page/","cta":"open kit"},{"name":"docs kit","desc":"technical documentation layout with sidebar and prose.","href":"./ui_kits/docs/","cta":"open docs"},{"name":"blog kit","desc":"long-form writing layout tuned for readability.","href":"./ui_kits/blog/","cta":"open writing"},{"name":"chat kit","desc":"message thread + composer with pill bubbles and room sidebar.","href":"./ui_kits/chat/","cta":"open chat"},{"name":"aicat kit","desc":"ai assistant with cat persona — ascii portrait + mood face.","href":"./ui_kits/aicat/","cta":"open aicat"},{"name":"slide deck","desc":"16:9 deck stage with improved presenter controls text.","href":"./slides/","cta":"open slides"},{"name":"dashboard kit","desc":"kpis, tables, receipts, changelog — operations surface.","href":"./ui_kits/dashboard/","cta":"open dashboard"},{"name":"terminal kit","desc":"cli prompt, command lines, log viewer.","href":"./ui_kits/terminal/","cta":"open terminal"},{"name":"settings kit","desc":"sectioned forms, toggles, segmented buttons, save bar.","href":"./ui_kits/settings/","cta":"open settings"},{"name":"signin kit","desc":"auth panel, providers, magic link.","href":"./ui_kits/signin/","cta":"open signin"},{"name":"search kit","desc":"query bar, faceted filters, ranked results.","href":"./ui_kits/search/","cta":"open search"},{"name":"404 kit","desc":"empty-state hero with suggested routes.","href":"./ui_kits/error_404/","cta":"open 404"},{"name":"gallery kit","desc":"visual grid + lightbox over tonal cards.","href":"./ui_kits/gallery/","cta":"open gallery"},{"name":"preview samples","desc":"design previews and component samples.","href":"./preview/buttons.html","cta":"open previews"}]},"status_left":["main","utf-8","lf"],"status_right":["247420 · mmxxvi","probably emerging"]}}</script>
58
66
  <script type="module">
59
67
  import { h, applyDiff, installStyles, components as C, initTheme } from 'anentrypoint-design';
60
68
  installStyles();
@@ -73,20 +81,18 @@ const { site, nav, home } = data;
73
81
  function Hero() {
74
82
  if (!home || !home.hero) return null;
75
83
  const hero = home.hero;
76
- return C.Panel({
77
- style: 'margin:8px',
78
- children: h('div', { style: 'padding:24px 22px' },
79
- C.Heading({ level: 1, style: 'margin:0 0 8px 0', children: hero.heading || site.title }),
80
- hero.subheading ? C.Lede({ children: hero.subheading }) : null,
81
- hero.body ? h('p', { style: 'margin:8px 0 16px 0;color:var(--panel-text-2);max-width:64ch' }, hero.body) : null,
82
- (hero.badges && hero.badges.length) ? h('div', { style: 'display:flex;gap:6px;flex-wrap:wrap;margin:0 0 12px 0' },
83
- ...hero.badges.map((b, i) => C.Chip({ key: 'b' + i, children: b.label }))
84
- ) : null,
85
- (hero.ctas && hero.ctas.length) ? h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap' },
86
- ...hero.ctas.map((c, i) => C.Btn({ key: 'c' + i, href: c.href, primary: c.primary, children: c.label }))
87
- ) : null
88
- )
89
- });
84
+ const actions = (hero.ctas && hero.ctas.length)
85
+ ? hero.ctas.map((c, i) => C.Btn({ key: 'c' + i, href: c.href, primary: c.primary, children: c.label }))
86
+ : null;
87
+ // Editorial Hero oversized display, asymmetric grid, print grain.
88
+ return h('div', { class: 'ds-grain ds-home-hero-wrap' },
89
+ C.Hero({
90
+ eyebrow: hero.subheading || site.tagline || null,
91
+ title: hero.heading || site.title,
92
+ body: hero.body || '',
93
+ actions
94
+ })
95
+ );
90
96
  }
91
97
 
92
98
  function rowsFromItems(items, prefix) {
@@ -95,7 +101,7 @@ function rowsFromItems(items, prefix) {
95
101
  code: it.code || String(i + 1).padStart(2, '0'),
96
102
  title: it.title || it.name,
97
103
  sub: it.sub || it.desc || '',
98
- meta: it.cta || it.meta || 'open ',
104
+ meta: it.cta || it.meta || 'open ->',
99
105
  href: it.href || '#'
100
106
  }));
101
107
  }
@@ -103,9 +109,10 @@ function rowsFromItems(items, prefix) {
103
109
  function Kits() {
104
110
  if (!home.kits || !home.kits.items || !home.kits.items.length) return null;
105
111
  return C.Panel({
112
+ id: 'kits',
106
113
  title: home.kits.heading || 'ui kits',
107
114
  count: home.kits.count || home.kits.items.length,
108
- style: 'margin:8px',
115
+ class: 'ds-home-panel',
109
116
  children: rowsFromItems(home.kits.items, 'k')
110
117
  });
111
118
  }
@@ -113,8 +120,9 @@ function Kits() {
113
120
  function Decks() {
114
121
  if (!home.decks || !home.decks.items || !home.decks.items.length) return null;
115
122
  return C.Panel({
123
+ id: 'decks',
116
124
  title: home.decks.heading || 'decks',
117
- style: 'margin:8px',
125
+ class: 'ds-home-panel',
118
126
  children: rowsFromItems(home.decks.items, 'd')
119
127
  });
120
128
  }
@@ -124,7 +132,7 @@ function FileBrowser() {
124
132
  return C.Panel({
125
133
  title: home.file_browser.heading || 'file browser',
126
134
  count: home.file_browser.count || home.file_browser.items.length,
127
- style: 'margin:8px',
135
+ class: 'ds-home-panel',
128
136
  children: rowsFromItems(home.file_browser.items, 'fb')
129
137
  });
130
138
  }
@@ -132,8 +140,9 @@ function FileBrowser() {
132
140
  function Docs() {
133
141
  if (!home.docs || !home.docs.items || !home.docs.items.length) return null;
134
142
  return C.Panel({
143
+ id: 'docs',
135
144
  title: home.docs.heading || 'docs',
136
- style: 'margin:8px',
145
+ class: 'ds-home-panel',
137
146
  children: rowsFromItems(home.docs.items, 'doc')
138
147
  });
139
148
  }
@@ -146,13 +155,14 @@ function Previews() {
146
155
  code: String(i + 1).padStart(2, '0'),
147
156
  title: String(name).replace(/-/g, ' '),
148
157
  sub: 'preview · ' + name + '.html',
149
- meta: 'open ',
158
+ meta: 'open ->',
150
159
  href: base + name + '.html'
151
160
  }));
152
161
  return C.Panel({
162
+ id: 'previews',
153
163
  title: home.previews.heading || 'previews',
154
164
  count: rows.length,
155
- style: 'margin:8px',
165
+ class: 'ds-home-panel',
156
166
  children: rows
157
167
  });
158
168
  }
@@ -169,7 +179,7 @@ function Features() {
169
179
  }));
170
180
  return C.Panel({
171
181
  title: home.features.heading || 'why design',
172
- style: 'margin:8px',
182
+ class: 'ds-home-panel',
173
183
  children: rows
174
184
  });
175
185
  }
@@ -182,8 +192,8 @@ function Quickstart() {
182
192
  ));
183
193
  return C.Panel({
184
194
  title: home.quickstart.heading || 'quick start',
185
- style: 'margin:8px',
186
- children: h('div', { style: 'padding:16px 22px;display:flex;flex-direction:column;gap:6px' }, ...lineNodes)
195
+ class: 'ds-home-panel',
196
+ children: h('div', { class: 'ds-quickstart' }, ...lineNodes)
187
197
  });
188
198
  }
189
199
 
@@ -192,7 +202,7 @@ function DesktopOS() {
192
202
  return C.Panel({
193
203
  title: home.desktop_os.heading || 'desktop os shell',
194
204
  count: home.desktop_os.count || home.desktop_os.items.length,
195
- style: 'margin:8px',
205
+ class: 'ds-home-panel',
196
206
  children: rowsFromItems(home.desktop_os.items, 'os')
197
207
  });
198
208
  }
@@ -202,7 +212,7 @@ function WebComponents() {
202
212
  return C.Panel({
203
213
  title: home.web_components.heading || 'web components',
204
214
  count: home.web_components.count || home.web_components.items.length,
205
- style: 'margin:8px',
215
+ class: 'ds-home-panel',
206
216
  children: rowsFromItems(home.web_components.items, 'wc')
207
217
  });
208
218
  }
@@ -212,7 +222,7 @@ function ApiExports() {
212
222
  return C.Panel({
213
223
  title: home.api_exports.heading || 'public api',
214
224
  count: home.api_exports.count || home.api_exports.items.length,
215
- style: 'margin:8px',
225
+ class: 'ds-home-panel',
216
226
  children: rowsFromItems(home.api_exports.items, 'api')
217
227
  });
218
228
  }
@@ -222,7 +232,7 @@ function Examples() {
222
232
  return C.Panel({
223
233
  title: home.examples.heading || 'live examples',
224
234
  count: home.examples.items.length,
225
- style: 'margin:8px',
235
+ class: 'ds-home-panel',
226
236
  children: rowsFromItems(home.examples.items, 'e')
227
237
  });
228
238
  }
@@ -233,7 +243,7 @@ function buildSide() {
233
243
  if (sb.fab) {
234
244
  sections.push({
235
245
  group: 'open',
236
- items: [{ glyph: sb.fab.glyph || '', label: sb.fab.label || 'open', href: sb.fab.href || '#' }]
246
+ items: [{ glyph: sb.fab.glyph || '+', label: sb.fab.label || 'open', href: sb.fab.href || '#' }]
237
247
  });
238
248
  }
239
249
  if (sb.bins && sb.bins.length) {
@@ -250,7 +260,7 @@ function buildSide() {
250
260
 
251
261
  function Tabs() {
252
262
  if (!home.tabs || !home.tabs.length) return null;
253
- return h('div', { class: 'tabs', role: 'tablist', style: 'margin:8px' },
263
+ return h('div', { class: 'tabs ds-home-panel', role: 'tablist' },
254
264
  ...home.tabs.map((t, i) => h('a', {
255
265
  key: 't' + i,
256
266
  href: t.href || '#',
@@ -265,8 +275,8 @@ function Tabs() {
265
275
 
266
276
  const navItems = (nav && nav.links ? nav.links : []).map(l => [String(l.label || ''), l.href]);
267
277
 
268
- const statusLeft = home.status_left || ['main', ' utf-8', ' lf'];
269
- const statusRight = home.status_right || ['247420 / mmxxvi', ' probably emerging'];
278
+ const statusLeft = home.status_left || ['main', '- utf-8', '- lf'];
279
+ const statusRight = home.status_right || ['247420 · mmxxvi', '- probably emerging'];
270
280
 
271
281
  const App = C.AppShell({
272
282
  topbar: C.Topbar({
@@ -276,8 +286,9 @@ const App = C.AppShell({
276
286
  }),
277
287
  crumb: C.Crumb({ trail: ['247420'], leaf: site.title || 'design' }),
278
288
  side: buildSide(),
279
- main: h('div', {},
289
+ main: h('div', { id: 'all' },
280
290
  Hero(),
291
+ C.Marquee({ items: ['always open', '24 7 420', 'the creative department', 'shipping in public'], sep: '/' }),
281
292
  Tabs(),
282
293
  Kits(),
283
294
  FileBrowser(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.244",
3
+ "version": "0.0.246",
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",
@@ -120,6 +120,32 @@ export function RowLink({ code, title, sub, meta, href = '#', key, target }) {
120
120
  return Row({ code, title, sub, meta, href, kind: 'link', key, target });
121
121
  }
122
122
 
123
+ // PanelFromItems — the shared 'items[] -> RowLink wrapped in Panel' mapper
124
+ // every portfolio consumer theme.mjs (zellous/wireweave/thebird/247420) had
125
+ // hand-rolled identically: items.map((it,i) => RowLink({code, title, sub,
126
+ // meta, href})) inside a titled Panel. `keyPrefix` seeds each row's stable
127
+ // key (`${keyPrefix}${i}`), matching the consumer convention of a
128
+ // one-letter-per-section prefix (e.g. 'f' for features, 'm' for modules).
129
+ // Field aliasing mirrors the union of shapes actually hand-rolled downstream:
130
+ // title reads `title` then `name`; sub reads `sub` then `desc`; code falls
131
+ // back to a zero-padded 1-based index when the item carries none. `heading`/
132
+ // `count`/`style`/`kind` pass through to Panel unchanged.
133
+ export function PanelFromItems({ heading, items = [], keyPrefix = 'i', count, style, kind, emptyText } = {}) {
134
+ if (!items || !items.length) return emptyText != null ? h('div', { class: 'empty' }, emptyText) : null;
135
+ const rows = items.map((it, i) => {
136
+ const codeVal = it.code != null ? it.code : (it.rank != null ? it.rank : String(i + 1).padStart(2, '0'));
137
+ return RowLink({
138
+ key: keyPrefix + i,
139
+ code: codeVal,
140
+ title: it.title != null ? it.title : it.name,
141
+ sub: it.sub != null ? it.sub : (it.desc != null ? it.desc : ''),
142
+ meta: it.meta != null ? it.meta : '',
143
+ href: it.href || '#'
144
+ });
145
+ });
146
+ return Panel({ title: heading, count, style, kind, children: rows });
147
+ }
148
+
123
149
  export function Section({ title, eyebrow, children, id }) {
124
150
  return h('section', { class: 'ds-section', id: id || null },
125
151
  eyebrow ? h('span', { class: 'eyebrow' }, eyebrow) : null,
@@ -144,6 +170,66 @@ export function Hero({ eyebrow, title, body, accent, actions }) {
144
170
  );
145
171
  }
146
172
 
173
+ // HeroFromPageData — a single factory for the "hero block driven by a page-data
174
+ // object" shape that recurs, independently hand-rolled, across every flatspace
175
+ // consumer theme.mjs (heading/subheading/body/badges/ctas/install all read off
176
+ // a `hero` object parsed from the `__site__` JSON script tag). Consumers differ
177
+ // only in which fields their content YAML populates; this factory renders every
178
+ // field it is given and omits what is absent, so it is a drop-in for the
179
+ // narrowest (heading+body only) or richest (badges+ctas+install) hero shape
180
+ // alike. Returns null on a falsy `hero` so callers can write
181
+ // `HeroFromPageData(page.hero)` unconditionally, matching the existing
182
+ // `!home.hero ? null : ...` guard every hand-rolled version repeats.
183
+ //
184
+ // Shape: { heading, title, subheading, body, accent, badges, ctas, install }
185
+ // heading/title — hero <h1> text (heading wins if both given)
186
+ // subheading — a Lede-style standalone line above `body`
187
+ // body — the hero paragraph
188
+ // accent — a muted trailing aside appended to `body`
189
+ // badges — [{label, desc}] or [string], rendered as a stat strip
190
+ // ctas — [{label, href, primary}], rendered as Btn-equivalent links
191
+ // install — a single install command string, rendered as a `.cli` block
192
+ export function HeroFromPageData(hero) {
193
+ if (!hero) return null;
194
+ const heading = hero.heading || hero.title || '';
195
+ const badges = Array.isArray(hero.badges) ? hero.badges.filter(Boolean) : [];
196
+ const ctas = Array.isArray(hero.ctas) ? hero.ctas.filter(Boolean) : [];
197
+ const badgeRow = badges.length
198
+ ? h('div', { class: 'ds-hero-stats' }, ...badges.map((b, i) =>
199
+ h('span', { key: 'hb' + i, class: 'ds-hero-stat' },
200
+ h('strong', { class: 'ds-hero-stat-n' }, String(b && b.label != null ? b.label : b)),
201
+ (b && b.desc) ? h('span', { class: 'ds-hero-stat-l' }, String(b.desc)) : null,
202
+ )))
203
+ : null;
204
+ const ctaRow = ctas.length
205
+ ? h('div', { class: 'ds-hero-actions' }, ...ctas.map((c, i) =>
206
+ h('a', {
207
+ key: 'hc' + i,
208
+ class: (c.primary || i === 0) ? 'btn btn-accent' : 'btn btn-ghost',
209
+ href: c.href || '#',
210
+ }, c.label || c.cta || 'go')))
211
+ : null;
212
+ const installRow = hero.install
213
+ ? h('div', { class: 'cli' },
214
+ h('span', { class: 'prompt' }, '$'),
215
+ h('span', { class: 'cmd' }, hero.install))
216
+ : null;
217
+ return h('div', { class: 'ds-hero' },
218
+ h('div', { class: 'ds-hero-head' },
219
+ hero.eyebrow ? h('span', { class: 'eyebrow' }, hero.eyebrow) : null,
220
+ h('h1', { class: 'ds-hero-title' }, heading)
221
+ ),
222
+ hero.subheading ? h('p', { class: 'ds-hero-body lede' }, hero.subheading) : null,
223
+ hero.body ? h('p', { class: 'ds-hero-body' },
224
+ hero.body,
225
+ hero.accent ? h('span', { class: 'ds-hero-accent' }, ' ' + hero.accent) : null,
226
+ ) : null,
227
+ installRow,
228
+ ctaRow,
229
+ badgeRow,
230
+ );
231
+ }
232
+
147
233
  export function Marquee({ items = [], sep = '/' }) {
148
234
  // No items -> no ticker: an empty marquee still paints its border-block
149
235
  // rules as an unexplained full-width stripe.
@@ -168,6 +254,32 @@ export function Install({ cmd, copied, onCopy }) {
168
254
  );
169
255
  }
170
256
 
257
+ // CliBlock — the shared 'quickstart.lines[] -> stacked CLI block' renderer
258
+ // every portfolio consumer theme.mjs (zellous/wireweave/247420) had hand-rolled
259
+ // identically: lines.map((l,i) => a div per line holding a prompt span ('$' or
260
+ // '#' for a comment line) and a cmd span, all wrapped in a Panel. This factory
261
+ // targets the multi-line `.cli` contract already defined in app-shell.css and
262
+ // gm-prose.css (`.cli` holding `.ds-cli-row` rows — each a prompt+cmd pair —
263
+ // and `.ds-cli-comment` comment rows). `lines` is [{kind, text}] where kind: 'cmt' renders a
264
+ // comment-only row (no prompt glyph); any other kind (or omitted) renders a
265
+ // command row prefixed '$'. `heading` titles the wrapping Panel ('quick start'
266
+ // default, matching every hand-rolled instance); pass `heading: null` to
267
+ // render the bare `.cli` block with no Panel chrome.
268
+ export function CliBlock({ lines = [], heading = 'quick start', className = '' } = {}) {
269
+ if (!lines || !lines.length) return null;
270
+ const rows = lines.map((l, i) => {
271
+ const isComment = l && l.kind === 'cmt';
272
+ const text = l && l.text != null ? l.text : '';
273
+ return isComment
274
+ ? h('div', { key: 'q' + i, class: 'ds-cli-comment' }, text)
275
+ : h('div', { key: 'q' + i, class: 'ds-cli-row' },
276
+ h('span', { class: 'prompt' }, '$'),
277
+ h('span', { class: 'cmd' }, text));
278
+ });
279
+ const body = h('div', { class: 'cli' + (className ? ' ' + className : '') }, ...rows);
280
+ return heading == null ? body : Panel({ title: heading, children: body });
281
+ }
282
+
171
283
  export function Receipt({ rows = [], emptyText = 'nothing here yet' }) {
172
284
  if (!rows.length) return h('div', { class: 'empty' }, emptyText);
173
285
  return h('table', { class: 'kv' },
package/src/components.js CHANGED
@@ -11,8 +11,8 @@ export {
11
11
  } from './components/shell.js';
12
12
 
13
13
  export {
14
- Panel, Card, Row, RowLink,
15
- Hero, Marquee, Install, Receipt, Changelog,
14
+ Panel, Card, Row, RowLink, PanelFromItems,
15
+ Hero, HeroFromPageData, Marquee, Install, CliBlock, Receipt, Changelog,
16
16
  WorksList, WritingList, Manifesto, Section, PageHeader,
17
17
  Kpi, Table, SearchInput, TextField, Select, EventList,
18
18
  HomeView, ProjectView, Form,
@@ -0,0 +1,31 @@
1
+ // Single source of HTML/JSON escaping for the whole SDK and every static-site
2
+ // consumer that embeds SDK-produced markup or JSON into an HTML document.
3
+ // Exported from the SDK root so consumer theme.mjs files (this repo's own
4
+ // site/theme.mjs included) import these instead of pasting their own copy.
5
+
6
+ // Full HTML-entity escape (incl. quotes), safe in both text and attribute
7
+ // contexts.
8
+ export function escapeHtml(s) {
9
+ return String(s ?? '').replace(/[&<>"']/g, (c) => ({
10
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
11
+ })[c]);
12
+ }
13
+
14
+ // U+2028 LINE SEPARATOR / U+2029 PARAGRAPH SEPARATOR are valid JSON string
15
+ // contents but invalid raw JS string-literal contents, so they must be
16
+ // entity-escaped too before this can be safely embedded in an inline
17
+ // <script> block. Built from character codes rather than a literal
18
+ // character or bare regex literal so no raw U+2028/U+2029 byte has to
19
+ // survive on disk (some toolchains mangle/strip it), and so it never risks
20
+ // being parsed as a source-level line terminator.
21
+ const LINE_SEP_RE = new RegExp(String.fromCharCode(0x2028), 'g');
22
+ const PARA_SEP_RE = new RegExp(String.fromCharCode(0x2029), 'g');
23
+
24
+ // Safe to embed the result of JSON.stringify inside a <script type="...">
25
+ // block: escapes </script>-breaking sequences and the two line-terminator
26
+ // code points that are valid JSON but invalid raw JS string literals.
27
+ export function escapeJson(obj) {
28
+ return JSON.stringify(obj)
29
+ .replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026')
30
+ .replace(LINE_SEP_RE, '\\u2028').replace(PARA_SEP_RE, '\\u2029');
31
+ }
package/src/index.js CHANGED
@@ -10,8 +10,11 @@ import * as components from './components.js';
10
10
  import * as motion from './motion.js';
11
11
  import * as debug from './debug.js';
12
12
  import { renderMarkdown, ensureReady as ensureMarkdownReady } from './markdown.js';
13
+ import { escapeHtml, escapeJson } from './html-escape.js';
13
14
  import { ensurePrism, highlightAllUnder } from './highlight.js';
14
15
  import { renderPageHtml } from './page-html.js';
16
+ import { HeroFromPageData } from './components/content.js';
17
+ import { ThemeToggle } from './components/theme-toggle.js';
15
18
  import { mountKit } from './bootstrap.js';
16
19
  import * as theme from './theme.js';
17
20
  import { registerChatElement, DsChat } from './web-components/ds-chat.js';
@@ -68,8 +71,9 @@ export {
68
71
  ensurePrism, highlightAllUnder,
69
72
  registerChatElement, DsChat,
70
73
  registerFreddieChatElement, FreddieChat,
71
- renderPageHtml,
72
- theme
74
+ renderPageHtml, HeroFromPageData,
75
+ escapeHtml, escapeJson,
76
+ theme, ThemeToggle
73
77
  };
74
78
  export { applyTheme, getTheme, resolvedTheme, onThemeChange, initTheme,
75
79
  applyAccent, getAccent, applyDensity, getDensity } from './theme.js';
@@ -94,5 +98,6 @@ export default {
94
98
  webjsx, loadCss, scope, installStyles, mount, h, applyDiff,
95
99
  registerDeckStage, getDeckStage, Router, createRouter,
96
100
  components, motion, debug, mountKit,
97
- renderMarkdown, ensurePrism, registerChatElement, renderPageHtml
101
+ renderMarkdown, ensurePrism, registerChatElement, renderPageHtml, HeroFromPageData,
102
+ escapeHtml, escapeJson
98
103
  };
package/src/markdown.js CHANGED
@@ -2,6 +2,8 @@
2
2
  // if loading fails, we fall back to a simple escape-and-linebreak pass so
3
3
  // the chat doesn't go blank.
4
4
 
5
+ import { escapeHtml } from './html-escape.js';
6
+
5
7
  let _ready = null;
6
8
  let _marked = null;
7
9
  let _purify = null;
@@ -44,13 +46,11 @@ export async function ensureReady() {
44
46
  return _ready;
45
47
  }
46
48
 
47
- // The single HTML-entity escape for the whole SDK (full set incl. quotes, so it
48
- // is safe in attribute contexts too). page-html.js re-exports this as `escape`.
49
- export function escapeHtml(s) {
50
- return String(s).replace(/[&<>"']/g, (c) => ({
51
- '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
52
- })[c]);
53
- }
49
+ // The single HTML-entity escape for the whole SDK now lives in html-escape.js
50
+ // (full set incl. quotes, so it is safe in attribute contexts too).
51
+ // Re-exported here for backward compatibility with existing importers of
52
+ // escapeHtml from this module. page-html.js re-exports this as `escape`.
53
+ export { escapeHtml };
54
54
 
55
55
  export async function renderMarkdown(src) {
56
56
  const ok = await ensureReady();