anentrypoint-design 1.0.9 → 1.0.11
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/README.md +2 -1
- package/dist/247420.css +179 -8
- package/dist/247420.js +56 -30
- package/dist/index.html +29 -3
- package/package.json +1 -1
- package/src/components/chat/message.js +1 -1
- package/src/components/content/charts.js +26 -5
- package/src/components/shell/atoms.js +3 -2
- package/src/components/shell/icons.js +13 -1
- package/src/components/theme-toggle.js +18 -0
- package/src/css/app-shell/chat-polish.css +18 -0
- package/src/css/app-shell/hero-content.css +38 -5
- package/src/css/app-shell/kits-appended.css +56 -2
- package/src/css/app-shell/primitives.css +4 -0
- package/src/css/app-shell/row-print.css +13 -0
- package/src/css/app-shell/sidebar-misc.css +15 -0
- package/src/css/app-shell/topbar.css +35 -1
- package/src/kits/os/freddie/pages-core.js +13 -3
- package/src/kits/os/freddie/pages-os.js +2 -2
- package/src/kits/os/freddie-dashboard.js +16 -5
- package/src/kits/os/theme.css +47 -6
- package/src/page-html/client-script.js +18 -2
- package/src/page-html/page-styles.js +10 -0
- package/types/components.d.ts +1 -1
package/dist/index.html
CHANGED
|
@@ -131,6 +131,16 @@ a.row:hover .ds-row-arrow { opacity: 1 }
|
|
|
131
131
|
letter-spacing: 0.06em; color: var(--fg-3, #6b6b6b);
|
|
132
132
|
}
|
|
133
133
|
.ds-showcase-row { display: flex; flex-wrap: wrap; gap: var(--space-2, 8px); align-items: center; }
|
|
134
|
+
/* Sets Danger apart from Primary/Default/Ghost in the button showcase row: an
|
|
135
|
+
extra left margin beyond the row's own gap, plus a hairline divider, so a
|
|
136
|
+
danger action never reads as just one more same-weight choice beside the
|
|
137
|
+
primary action. */
|
|
138
|
+
.ds-showcase-btn-danger-group {
|
|
139
|
+
display: inline-flex; align-items: center;
|
|
140
|
+
margin-left: var(--space-3, 16px);
|
|
141
|
+
padding-left: var(--space-3, 16px);
|
|
142
|
+
border-left: 1px solid var(--rule, rgba(0,0,0,.12));
|
|
143
|
+
}
|
|
134
144
|
/* Card-grid layout (panel.layout === 'cards'): a browsable gallery of tiles
|
|
135
145
|
instead of a dense text-row list, opt-in per panel via home.yaml's
|
|
136
146
|
kits.layout: cards. */
|
|
@@ -158,7 +168,7 @@ a.row:hover .ds-row-arrow { opacity: 1 }
|
|
|
158
168
|
color: var(--fg-3, #6b6b6b); font-size: var(--fs-sm, 15px);
|
|
159
169
|
}
|
|
160
170
|
</style>
|
|
161
|
-
<script id="__site__" type="application/json">{"title":"design","slug":"index","siteName":"design","navItems":[["247420","https://247420.xyz"],["AnEntrypoint ->","https://github.com/AnEntrypoint"]],"theme":"auto","hero":{"heading":"Design","subheading":"The 247420 design system","body":"A complete, tokens-driven component system for building consistent, accessible interfaces fast: 15 ready-to-ship kit surfaces, 25 live previews, a slide deck, and a full desktop-shell demo — plus a web component and an SDK. Every panel, row, and form control reads its color, radius, and spacing from one shared token file, so a single theme change updates every surface built on it at once. WCAG AA verified across all 21 kits, zero JavaScript bundler required.","badges":[{"label":"Design system"},{"label":"Design tokens"},{"label":"WCAG AA"}],"ctas":[{"label":"GitHub","href":"https://github.com/AnEntrypoint/design","primary":true},{"label":"247420","href":"https://247420.xyz"}]},"sections":[],"examples":[],"bodyHtml":"","sidebar":{"sections":[{"group":"open","items":[{"glyph":"+","label":"open","href":"./ui_kits/homepage/"}]},{"group":"bins","items":[{"label":"Everything","href":"#all","active":true,"count":48},{"label":"Pinned","href":"#kits","count":15},{"label":"Shipped","href":"#previews","count":25},{"label":"Drafts","href":"#decks","count":1}]},{"group":"Labels","items":[{"label":"UI kits","href":"#kits","count":15},{"label":"Decks","href":"#decks","count":1},{"label":"Previews","href":"#previews","count":25},{"label":"Docs","href":"#docs","count":7}]},{"group":"More","items":[{"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"},{"label":"MIT license","href":"https://github.com/AnEntrypoint/design/blob/main/LICENSE"}]}]},"marquee":{"items":["Open source","Design tokens","WCAG AA verified","No bundler required"],"sep":"/"},"showcase":{"heading":"Live components","lede":"Not a screenshot — the same Btn, Chip, Badge, and Table components every kit page imports, rendered right here from the SDK you'd actually install."},"panels":[{"id":"kits","title":"UI kits","count":"15 surfaces","items":[{"code":"","title":"Homepage","sub":"Marquee and works grid","meta":"open ->","href":"./ui_kits/homepage/"},{"code":"","title":"Project page","sub":"Hero, receipt, install, changelog","meta":"open ->","href":"./ui_kits/project_page/"},{"code":"","title":"Docs","sub":"Long-form prose chrome","meta":"open ->","href":"./ui_kits/docs/"},{"code":"","title":"Blog","sub":"Dated index and reading view","meta":"open ->","href":"./ui_kits/blog/"},{"code":"","title":"Chat","sub":"Message thread and composer","meta":"open ->","href":"./ui_kits/chat/"},{"code":"","title":"AICat","sub":"AI assistant with a cat persona","meta":"open ->","href":"./ui_kits/aicat/"},{"code":"","title":"File browser","sub":"Type-aware rails, drop zone, preview","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"","title":"Dashboard","sub":"KPIs, tables, receipts, changelog","meta":"open ->","href":"./ui_kits/dashboard/"},{"code":"","title":"Terminal","sub":"CLI prompt, command lines, log view","meta":"open ->","href":"./ui_kits/terminal/"},{"code":"","title":"Settings","sub":"Sectioned forms, toggles, save bar","meta":"open ->","href":"./ui_kits/settings/"},{"code":"","title":"Sign in","sub":"Auth providers and magic link","meta":"open ->","href":"./ui_kits/signin/"},{"code":"","title":"Search","sub":"Topbar query, faceted filters, rows","meta":"open ->","href":"./ui_kits/search/"},{"code":"","title":"404","sub":"Empty-state hero, suggested routes","meta":"open ->","href":"./ui_kits/error_404/"},{"code":"","title":"Gallery","sub":"Visual grid, tonal cards, lightbox","meta":"open ->","href":"./ui_kits/gallery/"},{"code":"","title":"OS shell","sub":"Menubar, window manager, taskbar","meta":"open ->","href":"./ui_kits/os/"}],"layout":"cards"},{"id":"file_browser","title":"File browser","count":"primitives","items":[{"code":"fb","title":"file_browser kit","sub":"Drop, list, preview, dialogs","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"fb","title":"FileRow","sub":"Rail, icon, name, meta","meta":"open ->","href":"./preview/file-row.html"},{"code":"fb","title":"FileGrid","sub":"A stack of rows in a panel","meta":"open ->","href":"./preview/file-grid.html"},{"code":"fb","title":"DropZone","sub":"Tonal upload target","meta":"open ->","href":"./preview/dropzone.html"},{"code":"fb","title":"FileViewer","sub":"Modal preview, keyed head","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"fb","title":"FileToolbar","sub":"Actions, breadcrumb, upload","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"fb","title":"fsbrowse","sub":"Express + busboy backend","meta":"source","href":"https://github.com/AnEntrypoint/fsbrowse"}],"layout":null},{"id":"desktop_os","title":"Desktop OS shell","count":"in-page window manager","items":[{"code":"os","title":"Live demo","sub":"menubar, apps drawer, side rail, taskbar, floating windows","meta":"open ->","href":"./ui_kits/os/"},{"code":"os","title":"createDesktopShell","sub":"menubar, apps launcher, taskbar, window manager","meta":"shell.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/shell.js"},{"code":"os","title":"renderWindow / renderDock","sub":"pure paint-surface primitives","meta":"wm.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/wm.js"},{"code":"os","title":"Icon set","sub":"SVG glyphs for menubar and taskbar","meta":"icons.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/icons.js"},{"code":"os","title":"theme.css","sub":"OS chrome tokens: menubar, launcher, window manager","meta":"theme.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/theme.css"},{"code":"os","title":"Import path","sub":"anentrypoint-design/kits/os","meta":"exports","href":"https://github.com/AnEntrypoint/design/blob/main/package.json"}],"layout":null},{"id":"web_components","title":"Web components","count":"1 element","items":[{"code":"wc","title":"\u003cds-chat>","sub":"Auto-registers when the SDK loads in a browser","meta":"ds-chat.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/web-components/ds-chat.js"},{"code":"wc","title":"registerChatElement","sub":"Manual register helper","meta":"source","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"}],"layout":null},{"id":"api_exports","title":"Public API","count":"SDK surface","items":[{"code":"api","title":"h / applyDiff","sub":"webjsx createElement and diff","meta":"index.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"},{"code":"api","title":"installStyles / scope","sub":"ds-247420 CSS scope and bootstrap","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"loadCss","sub":"Fetch the bundled CSS string","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"mount / mountKit","sub":"Shell and ui_kit bootstrap","meta":"bootstrap.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/bootstrap.js"},{"code":"api","title":"registerDeckStage / getDeckStage","sub":"16:9 deck stage API","meta":"deck-stage.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/deck-stage.js"},{"code":"api","title":"renderMarkdown","sub":"marked v15 + DOMPurify, lazy-loaded","meta":"markdown.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/markdown.js"},{"code":"api","title":"ensurePrism / highlightAllUnder","sub":"Prism core plus per-language","meta":"highlight.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/highlight.js"},{"code":"api","title":"renderPageHtml","sub":"Static page HTML template","meta":"page-html.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/page-html.js"},{"code":"api","title":"components / motion / debug","sub":"Namespaces from the default export","meta":"components.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/components.js"}],"layout":null},{"id":"decks","title":"Decks","count":1,"items":[{"code":"","title":"Deck template","sub":"16:9 stage with auto-fit","meta":"open ->","href":"./slides/"}],"layout":null},{"id":"docs","title":"Docs","count":7,"items":[{"code":"md","title":"Readme","sub":"Overview, manifesto, conventions","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"code":"md","title":"Skill","sub":"Authoring rules for the agent","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"code":"css","title":"Tokens","sub":"Colors, type, panel surface tokens","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"md","title":"Component props","sub":"Generated prop reference","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/component-props.md"},{"code":"md","title":"Changelog","sub":"Release history","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/CHANGELOG.md"},{"code":"md","title":"Accessibility","sub":"WCAG AA compliance, keyboard navigation","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/accessibility.md"},{"code":"md","title":"Responsive breakpoints","sub":"The documented breakpoint scale in use","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/responsive.md"}],"layout":null},{"id":"features","title":"Why teams choose 247420","count":5,"items":[{"code":"","title":"Clear visual hierarchy","sub":"Panel-on-panel layering keeps dense dashboards scannable — important content stays legible even in complex, data-heavy screens.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css"},{"code":"","title":"Readable at a glance","sub":"A disciplined type system reserves monospace for codes and labels and sans-serif for everything meant to be read, so interfaces stay legible under real workloads.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"","title":"Instant status recognition","sub":"Color-coded indicator rails let users scan for status and category at a glance, without relying on borders that add visual noise.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css#L126"},{"code":"","title":"Rebrand in minutes, not sprints","sub":"Every surface, type scale, and accent color is driven entirely by design tokens — retheme an entire product by editing one file, with zero component code changes.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"","title":"Accessible by default","sub":"Every kit is WCAG AA verified (0 blocking violations across all 21 surfaces), with shared focus-visible tokens, skip links, and correct ARIA roles built into every component.","meta":"a11y-report.md","href":"https://github.com/AnEntrypoint/design/blob/main/docs/a11y-report.md"}],"layout":null},{"id":"previews","title":"Previews","count":25,"items":[{"code":"","title":"buttons","sub":"preview · buttons.html","meta":"open ->","href":"./preview/buttons.html"},{"code":"","title":"colors core","sub":"preview · colors-core.html","meta":"open ->","href":"./preview/colors-core.html"},{"code":"","title":"colors lore","sub":"preview · colors-lore.html","meta":"open ->","href":"./preview/colors-lore.html"},{"code":"","title":"colors semantic","sub":"preview · colors-semantic.html","meta":"open ->","href":"./preview/colors-semantic.html"},{"code":"","title":"dateline","sub":"preview · dateline.html","meta":"open ->","href":"./preview/dateline.html"},{"code":"","title":"dropzone","sub":"preview · dropzone.html","meta":"open ->","href":"./preview/dropzone.html"},{"code":"","title":"file grid","sub":"preview · file-grid.html","meta":"open ->","href":"./preview/file-grid.html"},{"code":"","title":"file row","sub":"preview · file-row.html","meta":"open ->","href":"./preview/file-row.html"},{"code":"","title":"file toolbar","sub":"preview · file-toolbar.html","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"","title":"file viewer","sub":"preview · file-viewer.html","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"","title":"header","sub":"preview · header.html","meta":"open ->","href":"./preview/header.html"},{"code":"","title":"icons unicode","sub":"preview · icons-unicode.html","meta":"open ->","href":"./preview/icons-unicode.html"},{"code":"","title":"index row","sub":"preview · index-row.html","meta":"open ->","href":"./preview/index-row.html"},{"code":"","title":"inputs","sub":"preview · inputs.html","meta":"open ->","href":"./preview/inputs.html"},{"code":"","title":"manifesto","sub":"preview · manifesto.html","meta":"open ->","href":"./preview/manifesto.html"},{"code":"","title":"rules","sub":"preview · rules.html","meta":"open ->","href":"./preview/rules.html"},{"code":"","title":"spacing","sub":"preview · spacing.html","meta":"open ->","href":"./preview/spacing.html"},{"code":"","title":"stamps","sub":"preview · stamps.html","meta":"open ->","href":"./preview/stamps.html"},{"code":"","title":"stamps lore","sub":"preview · stamps-lore.html","meta":"open ->","href":"./preview/stamps-lore.html"},{"code":"","title":"theme ink","sub":"preview · theme-ink.html","meta":"open ->","href":"./preview/theme-ink.html"},{"code":"","title":"type display","sub":"preview · type-display.html","meta":"open ->","href":"./preview/type-display.html"},{"code":"","title":"type mono","sub":"preview · type-mono.html","meta":"open ->","href":"./preview/type-mono.html"},{"code":"","title":"type prose","sub":"preview · type-prose.html","meta":"open ->","href":"./preview/type-prose.html"},{"code":"","title":"type scale","sub":"preview · type-scale.html","meta":"open ->","href":"./preview/type-scale.html"},{"code":"","title":"wordmarks","sub":"preview · wordmarks.html","meta":"open ->","href":"./preview/wordmarks.html"}]}],"quickstart":{"heading":"Quick start","lines":[{"kind":"cmt","text":"# Install via importmap (no bundler)"},{"kind":"cmd","text":"\u003cscript type='importmap'>{\"imports\":{\"anentrypoint-design\":\"https://unpkg.com/anentrypoint-design@latest/dist/247420.js\"}}\u003c/script>"},{"kind":"cmt","text":"# Or clone the source"},{"kind":"cmd","text":"git clone https://github.com/AnEntrypoint/design.git"}]},"statusLeft":["main","utf-8","lf"],"statusRight":["anentrypoint-design@latest","15 kits"],"seoAuthor":"247420 · a design system by AnEntrypoint"}</script>
|
|
171
|
+
<script id="__site__" type="application/json">{"title":"design","slug":"index","siteName":"design","navItems":[["247420","https://247420.xyz"],["AnEntrypoint ->","https://github.com/AnEntrypoint"]],"theme":"auto","hero":{"heading":"Design","subheading":"The 247420 design system","body":"A complete, tokens-driven component system for building consistent, accessible interfaces fast: 15 ready-to-ship kit surfaces, 25 live previews, a slide deck, and a full desktop-shell demo — plus a web component and an SDK. Every panel, row, and form control reads its color, radius, and spacing from one shared token file, so a single theme change updates every surface built on it at once. WCAG AA verified across all 15 kits, zero JavaScript bundler required.","badges":[{"label":"Design system"},{"label":"Design tokens"},{"label":"WCAG AA"}],"ctas":[{"label":"GitHub","href":"https://github.com/AnEntrypoint/design","primary":true},{"label":"247420","href":"https://247420.xyz"}]},"sections":[],"examples":[],"bodyHtml":"","sidebar":{"sections":[{"group":"open","items":[{"glyph":"+","label":"open","href":"./ui_kits/homepage/"}]},{"group":"bins","items":[{"label":"Everything","href":"#all","active":true,"count":49},{"label":"Pinned","href":"#kits","count":15},{"label":"Shipped","href":"#previews","count":25},{"label":"Drafts","href":"#decks","count":1}]},{"group":"Labels","items":[{"label":"UI kits","href":"#kits","count":15},{"label":"Decks","href":"#decks","count":1},{"label":"Previews","href":"#previews","count":25},{"label":"Docs","href":"#docs","count":8}]},{"group":"More","items":[{"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"},{"label":"MIT license","href":"https://github.com/AnEntrypoint/design/blob/main/LICENSE"}]}]},"marquee":{"items":["Open source","Design tokens","WCAG AA verified","No bundler required"],"sep":"/"},"showcase":{"heading":"Live components","lede":"Not a screenshot — the same Btn, Chip, Badge, and Table components every kit page imports, rendered right here from the SDK you'd actually install."},"panels":[{"id":"kits","title":"UI kits","count":"15 surfaces","items":[{"code":"","title":"Homepage","sub":"Marquee and works grid","meta":"open ->","href":"./ui_kits/homepage/"},{"code":"","title":"Project page","sub":"Hero, receipt, install, changelog","meta":"open ->","href":"./ui_kits/project_page/"},{"code":"","title":"Docs","sub":"Long-form prose chrome","meta":"open ->","href":"./ui_kits/docs/"},{"code":"","title":"Blog","sub":"Dated index and reading view","meta":"open ->","href":"./ui_kits/blog/"},{"code":"","title":"Chat","sub":"Message thread and composer","meta":"open ->","href":"./ui_kits/chat/"},{"code":"","title":"AICat","sub":"AI assistant with a cat persona","meta":"open ->","href":"./ui_kits/aicat/"},{"code":"","title":"File browser","sub":"Type-aware rails, drop zone, preview","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"","title":"Dashboard","sub":"KPIs, tables, receipts, changelog","meta":"open ->","href":"./ui_kits/dashboard/"},{"code":"","title":"Terminal","sub":"CLI prompt, command lines, log view","meta":"open ->","href":"./ui_kits/terminal/"},{"code":"","title":"Settings","sub":"Sectioned forms, toggles, save bar","meta":"open ->","href":"./ui_kits/settings/"},{"code":"","title":"Sign in","sub":"Auth providers and magic link","meta":"open ->","href":"./ui_kits/signin/"},{"code":"","title":"Search","sub":"Topbar query, faceted filters, rows","meta":"open ->","href":"./ui_kits/search/"},{"code":"","title":"404","sub":"Empty-state hero, suggested routes","meta":"open ->","href":"./ui_kits/error_404/"},{"code":"","title":"Gallery","sub":"Visual grid, tonal cards, lightbox","meta":"open ->","href":"./ui_kits/gallery/"},{"code":"","title":"OS shell","sub":"Menubar, window manager, taskbar","meta":"open ->","href":"./ui_kits/os/"}],"layout":"cards"},{"id":"file_browser","title":"File browser","count":"primitives","items":[{"code":"fb","title":"file_browser kit","sub":"Drop, list, preview, dialogs","meta":"open ->","href":"./ui_kits/file_browser/"},{"code":"fb","title":"FileRow","sub":"Rail, icon, name, meta","meta":"open ->","href":"./preview/file-row.html"},{"code":"fb","title":"FileGrid","sub":"A stack of rows in a panel","meta":"open ->","href":"./preview/file-grid.html"},{"code":"fb","title":"DropZone","sub":"Tonal upload target","meta":"open ->","href":"./preview/dropzone.html"},{"code":"fb","title":"FileViewer","sub":"Modal preview, keyed head","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"fb","title":"FileToolbar","sub":"Actions, breadcrumb, upload","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"fb","title":"fsbrowse","sub":"Express + busboy backend","meta":"source","href":"https://github.com/AnEntrypoint/fsbrowse"}],"layout":null},{"id":"desktop_os","title":"Desktop OS shell","count":"in-page window manager","items":[{"code":"os","title":"Live demo","sub":"menubar, apps drawer, side rail, taskbar, floating windows","meta":"open ->","href":"./ui_kits/os/"},{"code":"os","title":"createDesktopShell","sub":"menubar, apps launcher, taskbar, window manager","meta":"shell.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/shell.js"},{"code":"os","title":"renderWindow / renderDock","sub":"pure paint-surface primitives","meta":"wm.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/wm.js"},{"code":"os","title":"Icon set","sub":"SVG glyphs for menubar and taskbar","meta":"icons.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/icons.js"},{"code":"os","title":"theme.css","sub":"OS chrome tokens: menubar, launcher, window manager","meta":"theme.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/kits/os/theme.css"},{"code":"os","title":"Import path","sub":"anentrypoint-design/kits/os","meta":"exports","href":"https://github.com/AnEntrypoint/design/blob/main/package.json"}],"layout":null},{"id":"web_components","title":"Web components","count":"1 element","items":[{"code":"wc","title":"\u003cds-chat>","sub":"Auto-registers when the SDK loads in a browser","meta":"ds-chat.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/web-components/ds-chat.js"},{"code":"wc","title":"registerChatElement","sub":"Manual register helper","meta":"source","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"}],"layout":null},{"id":"api_exports","title":"Public API","count":"SDK surface","items":[{"code":"api","title":"h / applyDiff","sub":"webjsx createElement and diff","meta":"index.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/index.js"},{"code":"api","title":"installStyles / scope","sub":"ds-247420 CSS scope and bootstrap","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"loadCss","sub":"Fetch the bundled CSS string","meta":"styles.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/styles.js"},{"code":"api","title":"mount / mountKit","sub":"Shell and ui_kit bootstrap","meta":"bootstrap.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/bootstrap.js"},{"code":"api","title":"registerDeckStage / getDeckStage","sub":"16:9 deck stage API","meta":"deck-stage.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/deck-stage.js"},{"code":"api","title":"renderMarkdown","sub":"marked v15 + DOMPurify, lazy-loaded","meta":"markdown.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/markdown.js"},{"code":"api","title":"ensurePrism / highlightAllUnder","sub":"Prism core plus per-language","meta":"highlight.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/highlight.js"},{"code":"api","title":"renderPageHtml","sub":"Static page HTML template","meta":"page-html.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/page-html.js"},{"code":"api","title":"components / motion / debug","sub":"Namespaces from the default export","meta":"components.js","href":"https://github.com/AnEntrypoint/design/blob/main/src/components.js"}],"layout":null},{"id":"decks","title":"Decks","count":1,"items":[{"code":"","title":"Deck template","sub":"16:9 stage with auto-fit","meta":"open ->","href":"./slides/"}],"layout":null},{"id":"docs","title":"Docs","count":8,"items":[{"code":"md","title":"Readme","sub":"Overview, manifesto, conventions","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/README.md"},{"code":"md","title":"Skill","sub":"Authoring rules for the agent","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/SKILL.md"},{"code":"css","title":"Tokens","sub":"Colors, type, panel surface tokens","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"md","title":"Component props","sub":"Generated prop reference","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/component-props.md"},{"code":"live","title":"Component explorer","sub":"Interactive, searchable, live-rendered","meta":"open ->","href":"./ui_kits/component_explorer/"},{"code":"md","title":"Changelog","sub":"Release history","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/CHANGELOG.md"},{"code":"md","title":"Accessibility","sub":"WCAG AA compliance, keyboard navigation","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/accessibility.md"},{"code":"md","title":"Responsive breakpoints","sub":"The documented breakpoint scale in use","meta":"open ->","href":"https://github.com/AnEntrypoint/design/blob/main/docs/responsive.md"}],"layout":null},{"id":"features","title":"Why teams choose 247420","count":5,"items":[{"code":"","title":"Clear visual hierarchy","sub":"Panel-on-panel layering keeps dense dashboards scannable — important content stays legible even in complex, data-heavy screens.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css"},{"code":"","title":"Readable at a glance","sub":"A disciplined type system reserves monospace for codes and labels and sans-serif for everything meant to be read, so interfaces stay legible under real workloads.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"","title":"Instant status recognition","sub":"Color-coded indicator rails let users scan for status and category at a glance, without relying on borders that add visual noise.","meta":"panel-row.css","href":"https://github.com/AnEntrypoint/design/blob/main/src/css/app-shell/panel-row.css#L126"},{"code":"","title":"Rebrand in minutes, not sprints","sub":"Every surface, type scale, and accent color is driven entirely by design tokens — retheme an entire product by editing one file, with zero component code changes.","meta":"colors_and_type.css","href":"https://github.com/AnEntrypoint/design/blob/main/colors_and_type.css"},{"code":"","title":"Accessible by default","sub":"Every kit is WCAG AA verified (0 blocking violations across all 15 surfaces), with shared focus-visible tokens, skip links, and correct ARIA roles built into every component.","meta":"a11y-report.md","href":"https://github.com/AnEntrypoint/design/blob/main/docs/a11y-report.md"}],"layout":null},{"id":"previews","title":"Previews","count":25,"items":[{"code":"","title":"buttons","sub":"preview · buttons.html","meta":"open ->","href":"./preview/buttons.html"},{"code":"","title":"colors core","sub":"preview · colors-core.html","meta":"open ->","href":"./preview/colors-core.html"},{"code":"","title":"colors lore","sub":"preview · colors-lore.html","meta":"open ->","href":"./preview/colors-lore.html"},{"code":"","title":"colors semantic","sub":"preview · colors-semantic.html","meta":"open ->","href":"./preview/colors-semantic.html"},{"code":"","title":"dateline","sub":"preview · dateline.html","meta":"open ->","href":"./preview/dateline.html"},{"code":"","title":"dropzone","sub":"preview · dropzone.html","meta":"open ->","href":"./preview/dropzone.html"},{"code":"","title":"file grid","sub":"preview · file-grid.html","meta":"open ->","href":"./preview/file-grid.html"},{"code":"","title":"file row","sub":"preview · file-row.html","meta":"open ->","href":"./preview/file-row.html"},{"code":"","title":"file toolbar","sub":"preview · file-toolbar.html","meta":"open ->","href":"./preview/file-toolbar.html"},{"code":"","title":"file viewer","sub":"preview · file-viewer.html","meta":"open ->","href":"./preview/file-viewer.html"},{"code":"","title":"header","sub":"preview · header.html","meta":"open ->","href":"./preview/header.html"},{"code":"","title":"icons unicode","sub":"preview · icons-unicode.html","meta":"open ->","href":"./preview/icons-unicode.html"},{"code":"","title":"index row","sub":"preview · index-row.html","meta":"open ->","href":"./preview/index-row.html"},{"code":"","title":"inputs","sub":"preview · inputs.html","meta":"open ->","href":"./preview/inputs.html"},{"code":"","title":"manifesto","sub":"preview · manifesto.html","meta":"open ->","href":"./preview/manifesto.html"},{"code":"","title":"rules","sub":"preview · rules.html","meta":"open ->","href":"./preview/rules.html"},{"code":"","title":"spacing","sub":"preview · spacing.html","meta":"open ->","href":"./preview/spacing.html"},{"code":"","title":"stamps","sub":"preview · stamps.html","meta":"open ->","href":"./preview/stamps.html"},{"code":"","title":"stamps lore","sub":"preview · stamps-lore.html","meta":"open ->","href":"./preview/stamps-lore.html"},{"code":"","title":"theme ink","sub":"preview · theme-ink.html","meta":"open ->","href":"./preview/theme-ink.html"},{"code":"","title":"type display","sub":"preview · type-display.html","meta":"open ->","href":"./preview/type-display.html"},{"code":"","title":"type mono","sub":"preview · type-mono.html","meta":"open ->","href":"./preview/type-mono.html"},{"code":"","title":"type prose","sub":"preview · type-prose.html","meta":"open ->","href":"./preview/type-prose.html"},{"code":"","title":"type scale","sub":"preview · type-scale.html","meta":"open ->","href":"./preview/type-scale.html"},{"code":"","title":"wordmarks","sub":"preview · wordmarks.html","meta":"open ->","href":"./preview/wordmarks.html"}]}],"quickstart":{"heading":"Quick start","lines":[{"kind":"cmt","text":"# Install via importmap (no bundler)"},{"kind":"cmd","text":"\u003cscript type='importmap'>{\"imports\":{\"anentrypoint-design\":\"https://unpkg.com/anentrypoint-design@latest/dist/247420.js\"}}\u003c/script>"},{"kind":"cmt","text":"# Or clone the source"},{"kind":"cmd","text":"git clone https://github.com/AnEntrypoint/design.git"}]},"statusLeft":["main","utf-8","lf"],"statusRight":["anentrypoint-design@latest","15 kits"],"seoAuthor":"247420 · a design system by AnEntrypoint"}</script>
|
|
162
172
|
<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)}</style>
|
|
163
173
|
</head>
|
|
164
174
|
<body>
|
|
@@ -191,9 +201,15 @@ function heroNode(hero) {
|
|
|
191
201
|
hero.body || hero.subheading,
|
|
192
202
|
hero.accent ? h('span', { class: 'ds-hero-accent' }, ' ' + hero.accent) : null,
|
|
193
203
|
) : null,
|
|
204
|
+
// Every hero CTA is a plain <a href> that navigates away from this page
|
|
205
|
+
// (GitHub, the portfolio site, ...), never an in-page action -- so the
|
|
206
|
+
// trailing arrow is appended here once, at the render layer, rather than
|
|
207
|
+
// hand-typed per label in content yaml where it could drift out of sync
|
|
208
|
+
// with the "navigates away = arrow" rule used elsewhere (row ctas,
|
|
209
|
+
// signin's in-page submit buttons).
|
|
194
210
|
Array.isArray(hero.ctas) && hero.ctas.length
|
|
195
211
|
? h('div', { class: 'ds-hero-actions' }, ...hero.ctas.map((c, i) =>
|
|
196
|
-
h('a', { key: i, class: i === 0 ? 'btn btn-accent' : 'btn btn-ghost', href: c.href || '#' }, c.label || c.cta || 'go')))
|
|
212
|
+
h('a', { key: i, class: i === 0 ? 'btn btn-accent' : 'btn btn-ghost', href: c.href || '#' }, (c.label || c.cta || 'go') + ' ->')))
|
|
197
213
|
: null,
|
|
198
214
|
badgeRow,
|
|
199
215
|
);
|
|
@@ -212,8 +228,18 @@ function showcaseNode(showcase) {
|
|
|
212
228
|
C.Btn({ key: 'b1', variant: 'primary', children: 'Primary' }),
|
|
213
229
|
C.Btn({ key: 'b2', variant: 'default', children: 'Default' }),
|
|
214
230
|
C.Btn({ key: 'b3', variant: 'ghost', children: 'Ghost' }),
|
|
215
|
-
|
|
231
|
+
// .ds-showcase-btn-danger-group gives Danger its own visually separated
|
|
232
|
+
// cluster (extra leading gap + a hairline divider) instead of sitting in
|
|
233
|
+
// the same uniform-gap row as Primary -- two similarly-weighted filled
|
|
234
|
+
// buttons side by side otherwise compete for "the one action to take"
|
|
235
|
+
// with nothing marking Danger as the deliberately-set-apart one.
|
|
236
|
+
h('span', { key: 'b4-group', class: 'ds-showcase-btn-danger-group' },
|
|
237
|
+
C.Btn({ key: 'b4', variant: 'danger', children: 'Danger' })),
|
|
216
238
|
);
|
|
239
|
+
// Hue documents STATUS, not decoration: green = shipping/live, blue = pre-
|
|
240
|
+
// release/in-flux, purple = newly added. Badge (not a bespoke pill) carries
|
|
241
|
+
// the '0 violations' count so every status indicator in this row is one of
|
|
242
|
+
// the two real chip-family components, never a one-off styled span.
|
|
217
243
|
const chipRow = h('div', { class: 'ds-showcase-row' },
|
|
218
244
|
C.Chip({ key: 'c1', tone: 'green', children: 'Live' }),
|
|
219
245
|
C.Chip({ key: 'c2', tone: 'blue', children: 'Beta' }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anentrypoint-design",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
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",
|
|
@@ -38,7 +38,7 @@ export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typ
|
|
|
38
38
|
: (resolvedWho === 'you' ? 'u' : avatarInitial(name));
|
|
39
39
|
const av = h('span', { class: 'chat-avatar' }, fallbackAvatar);
|
|
40
40
|
let bodyNodes;
|
|
41
|
-
if (typing) bodyNodes = [h('div', { class: 'chat-bubble', key: 'typb' }, h('span', { class: 'chat-typing' }, h('span'), h('span'), h('span')))];
|
|
41
|
+
if (typing) bodyNodes = [h('div', { class: 'chat-bubble chat-bubble-typing', key: 'typb' }, h('span', { class: 'chat-typing' }, h('span'), h('span'), h('span')))];
|
|
42
42
|
else if (parts && parts.length) bodyNodes = parts.map((p, i) => renderPart(p, i));
|
|
43
43
|
else bodyNodes = [h('div', { class: 'chat-bubble', key: 't' }, ...renderInline(text || ''))];
|
|
44
44
|
// A blinking caret at the stream head: while an assistant turn is streaming
|
|
@@ -23,16 +23,30 @@ export function Kpi({ items = [], emptyText = 'no metrics yet' }) {
|
|
|
23
23
|
return h('div', { class: 'kpi' }, ...items.map(([n, l, meta], i) => {
|
|
24
24
|
const isUp = meta && meta.tone !== 'down';
|
|
25
25
|
const good = meta && meta.invert ? !isUp : isUp;
|
|
26
|
+
// Colour + arrow direction alone is not enough for colorblind/
|
|
27
|
+
// low-vision readers to tell "this movement is good" from "this
|
|
28
|
+
// movement is bad" -- the same up-arrow means opposite things for a
|
|
29
|
+
// normal metric vs an `invert` one (see the invert doc above). An
|
|
30
|
+
// sr-only word carries the actual verdict as text, independent of
|
|
31
|
+
// hue or glyph shape, reusing the same `good` boolean the color
|
|
32
|
+
// class already keys off so the two can never disagree.
|
|
33
|
+
const worseBetter = good ? 'better' : 'worse';
|
|
26
34
|
return h('div', { key: i, class: 'kpi-card' },
|
|
27
35
|
meta && meta.glyph ? h('div', { class: 'kpi-glyph' }, Icon(meta.glyph, { size: 16 })) : null,
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
// Fixed-alignment number+caption stack: a shared flex column with
|
|
37
|
+
// an explicit start alignment means a short one-line caption and
|
|
38
|
+
// a long wrapping caption both anchor their number at the same
|
|
39
|
+
// top position instead of drifting per tile height.
|
|
40
|
+
h('div', { class: 'kpi-stack' },
|
|
41
|
+
h('div', { class: 'num' }, String(n)),
|
|
42
|
+
h('div', { class: 'lbl' }, l)),
|
|
30
43
|
meta && (meta.delta != null || meta.spark)
|
|
31
44
|
? h('div', { class: 'kpi-foot' },
|
|
32
45
|
meta.delta != null
|
|
33
46
|
? h('span', { class: 'kpi-delta kpi-delta-' + (good ? 'up' : 'down') },
|
|
34
47
|
Icon(isUp ? 'arrow-up' : 'arrow-down', { size: 12 }),
|
|
35
|
-
String(meta.delta)
|
|
48
|
+
String(meta.delta),
|
|
49
|
+
h('span', { class: 'sr-only' }, ' (' + worseBetter + ')'))
|
|
36
50
|
: null,
|
|
37
51
|
meta.spark ? Sparkline({ values: meta.spark, tone: good ? 'up' : 'down' }) : null)
|
|
38
52
|
: null);
|
|
@@ -40,6 +54,10 @@ export function Kpi({ items = [], emptyText = 'no metrics yet' }) {
|
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
// Minimal inline SVG trend line — token-stroke only, no raw color literals.
|
|
57
|
+
// `title` (native <title> element, not the `title` attribute — SVG scopes
|
|
58
|
+
// tooltip text to the element it's nested in) gives every point a lightweight
|
|
59
|
+
// hover tooltip showing its value; no custom tooltip machinery, just the
|
|
60
|
+
// browser's own affordance, so this stays a "minimal inline SVG" primitive.
|
|
43
61
|
export function Sparkline({ values = [], width = 72, height = 24, tone }) {
|
|
44
62
|
if (!values.length) return null;
|
|
45
63
|
const max = Math.max(...values), min = Math.min(...values);
|
|
@@ -47,8 +65,11 @@ export function Sparkline({ values = [], width = 72, height = 24, tone }) {
|
|
|
47
65
|
const step = width / (values.length - 1 || 1);
|
|
48
66
|
const points = values.map((v, i) => [i * step, height - ((v - min) / span) * height]);
|
|
49
67
|
const d = points.map(([x, y], i) => (i === 0 ? 'M' : 'L') + x.toFixed(1) + ',' + y.toFixed(1)).join(' ');
|
|
50
|
-
return h('svg', { class: 'ds-sparkline ds-sparkline-' + (tone === 'down' ? 'down' : 'up'), viewBox: '0 0 ' + width + ' ' + height, width, height, 'aria-
|
|
51
|
-
h('
|
|
68
|
+
return h('svg', { class: 'ds-sparkline ds-sparkline-' + (tone === 'down' ? 'down' : 'up'), viewBox: '0 0 ' + width + ' ' + height, width, height, role: 'img', 'aria-label': 'trend: ' + values.join(', ') },
|
|
69
|
+
h('title', {}, values.join(', ')),
|
|
70
|
+
h('path', { d, fill: 'none', 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }),
|
|
71
|
+
...points.map(([x, y], i) => h('circle', { key: i, cx: x.toFixed(1), cy: y.toFixed(1), r: 6, fill: 'transparent', stroke: 'none' },
|
|
72
|
+
h('title', {}, String(values[i])))));
|
|
52
73
|
}
|
|
53
74
|
|
|
54
75
|
// Horizontal token-only bar breakdown — e.g. revenue by channel, traffic by source.
|
|
@@ -158,8 +158,9 @@ export function Dot({ tone = 'on' }) {
|
|
|
158
158
|
// top of ds-dot-on so a live-broadcast indicator is never visually
|
|
159
159
|
// identical to a plain "this thing is on" status dot — same split
|
|
160
160
|
// rationale as .chip.tone-live / .ds-badge.tone-live.
|
|
161
|
-
const
|
|
162
|
-
const
|
|
161
|
+
const modifierCls = tone === 'live' ? ' ds-dot-live' : (tone === 'warn' ? ' ds-dot-warn' : '');
|
|
162
|
+
const cls = 'ds-dot ' + (tone === 'warn' ? 'ds-dot-off' : (isOn ? 'ds-dot-on' : 'ds-dot-off')) + modifierCls;
|
|
163
|
+
const statusLabel = tone === 'live' ? 'live status indicator' : (tone === 'warn' ? 'warning status indicator' : (isOn ? 'on status indicator' : 'off status indicator'));
|
|
163
164
|
// Drawn as a CSS circle (.ds-dot) — no decorative text glyph.
|
|
164
165
|
return h('span', { class: cls, role: 'img', 'aria-label': statusLabel });
|
|
165
166
|
}
|
|
@@ -92,7 +92,19 @@ export const ICON_PATHS = {
|
|
|
92
92
|
cursor: '<path d="M5 3l14 8-6.5 1.5L11 20z"/>',
|
|
93
93
|
// Password-visibility toggle — eye / eye-off pair.
|
|
94
94
|
eye: '<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/>',
|
|
95
|
-
'eye-off': '<path d="M2 12s3.5-7 10-7c1.7 0 3.2.4 4.5 1.1M22 12s-3.5 7-10 7c-1.7 0-3.2-.4-4.5-1.1"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/><path d="m4 4 16 16"/>'
|
|
95
|
+
'eye-off': '<path d="M2 12s3.5-7 10-7c1.7 0 3.2.4 4.5 1.1M22 12s-3.5 7-10 7c-1.7 0-3.2-.4-4.5-1.1"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/><path d="m4 4 16 16"/>',
|
|
96
|
+
// Auth-provider glyphs for the signin kit — generic provider-neutral
|
|
97
|
+
// shapes (not trademarked logo reproductions), so a real icon renders
|
|
98
|
+
// instead of a text-letter abbreviation per AGENTS.md icon policy.
|
|
99
|
+
// github: a rounded body + one circular "eye", a widely-recognized
|
|
100
|
+
// silhouette-family shape without tracing the actual brand mark.
|
|
101
|
+
github: '<path d="M12 3a8 8 0 0 0-2.5 15.6c.4.1.5-.2.5-.4v-1.7c-2.2.4-2.7-1-2.9-1.6-.1-.3-.5-1-1-1.2-.3-.1-.6-.4 0-.5.9-.1 1.5.8 1.7 1.1.7 1.1 1.7.8 2.1.6.1-.5.3-.8.6-1-2.2-.3-3.4-1.4-3.4-3.4 0-.8.3-1.5.7-2-.1-.3-.3-1.1.1-2.2 0 0 .8-.2 2.5.9a8 8 0 0 1 4.5 0c1.7-1.1 2.5-.9 2.5-.9.4 1.1.2 1.9.1 2.2.5.5.7 1.2.7 2 0 2-1.2 3.1-3.4 3.4.3.3.6.8.6 1.5v2.1c0 .2.1.5.5.4A8 8 0 0 0 12 3z"/>',
|
|
102
|
+
// google: provider-neutral "G-circle" — a plain ring with a break and a
|
|
103
|
+
// short spoke, evoking the four-color pinwheel mark's silhouette only.
|
|
104
|
+
google: '<circle cx="12" cy="12" r="8"/><path d="M12 12h6"/><path d="M12 8v4"/>',
|
|
105
|
+
// sso: shield-check, a common auth/identity glyph for a generic
|
|
106
|
+
// single-sign-on entry point.
|
|
107
|
+
sso: '<path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6z"/><path d="M9 12l2 2 4-4"/>'
|
|
96
108
|
};
|
|
97
109
|
|
|
98
110
|
// The single SVG attribute contract (viewBox/stroke/linecap…) shared by both
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import * as webjsx from '../../vendor/webjsx/index.js';
|
|
12
12
|
import { applyTheme, getTheme, resolvedTheme, onThemeChange } from '../theme.js';
|
|
13
|
+
import { Icon, iconMarkup } from './shell/icons.js';
|
|
13
14
|
|
|
14
15
|
const h = webjsx.createElement;
|
|
15
16
|
|
|
@@ -19,6 +20,12 @@ const MODES = [
|
|
|
19
20
|
['ink', 'dark'],
|
|
20
21
|
];
|
|
21
22
|
|
|
23
|
+
// Sun/moon/contrast line-icon per mode (ICON_PATHS already carries these —
|
|
24
|
+
// see icons.js's "theme-toggle icons" entry) so the control reads at a
|
|
25
|
+
// glance even before the text label is parsed, not just via the CSS-drawn
|
|
26
|
+
// disc (which is icon-rail-only; the compact button keeps its text label).
|
|
27
|
+
const ICON_FOR_MODE = { auto: 'contrast', paper: 'sun', ink: 'moon' };
|
|
28
|
+
|
|
22
29
|
// Both variants render from `getTheme()` at the moment their vnode is built,
|
|
23
30
|
// but nothing re-renders this control when the theme changes: a host kit's view
|
|
24
31
|
// is not subscribed to the theme, and applyTheme() only touches <html> and the
|
|
@@ -69,6 +76,12 @@ export function ThemeToggle({ compact = false, onChange } = {}) {
|
|
|
69
76
|
if (lab) lab.textContent = labelFor(now);
|
|
70
77
|
const disc = el.querySelector('.ds-theme-disc');
|
|
71
78
|
if (disc) disc.setAttribute('data-mode', now);
|
|
79
|
+
// Repaint via raw markup (not a webjsx re-render — this ref
|
|
80
|
+
// runs outside any applyDiff pass), same pattern as icons.js's
|
|
81
|
+
// iconMarkup() is meant for: raw-DOM consumers with no
|
|
82
|
+
// webjsx render scope at hand.
|
|
83
|
+
const icon = el.querySelector('.ds-theme-toggle-icon');
|
|
84
|
+
if (icon) icon.innerHTML = iconMarkup(ICON_FOR_MODE[now] || 'contrast', { size: 14 });
|
|
72
85
|
})
|
|
73
86
|
},
|
|
74
87
|
// CSS-drawn disc so the control still reads as the theme switch when
|
|
@@ -77,6 +90,11 @@ export function ThemeToggle({ compact = false, onChange } = {}) {
|
|
|
77
90
|
// so the icon itself — not just the title tooltip — shows current
|
|
78
91
|
// state at a glance.
|
|
79
92
|
h('span', { class: 'ds-theme-disc', 'data-mode': current, 'aria-hidden': 'true' }),
|
|
93
|
+
// Sun/moon/contrast glyph alongside the text label — was text-only
|
|
94
|
+
// ("theme: auto"), so the control carried no visual cue of the
|
|
95
|
+
// current mode beyond the tiny CSS disc. Kept minimal: one small
|
|
96
|
+
// line-icon, no extra chrome.
|
|
97
|
+
h('span', { class: 'ds-theme-toggle-icon' }, Icon(ICON_FOR_MODE[current] || 'contrast', { size: 14 })),
|
|
80
98
|
h('span', { class: 'ds-theme-toggle-label' }, labelFor(current)));
|
|
81
99
|
}
|
|
82
100
|
|
|
@@ -393,6 +393,24 @@
|
|
|
393
393
|
.chat-reactions .rxn .n { font-family: var(--ff-mono); font-weight: 600; font-size: var(--fs-nano); color: var(--fg-2); }
|
|
394
394
|
.chat-reactions .rxn.you .n { color: var(--accent-ink); }
|
|
395
395
|
|
|
396
|
+
/* Typing indicator renders through the same .chat-bubble container as a real
|
|
397
|
+
message, but must never read as a bubble holding actual content — no
|
|
398
|
+
border, no hover-lift shadow, no tail-corner cut; just a pill-shaped
|
|
399
|
+
borderless dot cluster, visually lighter than any card/bubble on the page. */
|
|
400
|
+
/* Double-class selector (.chat-bubble.chat-bubble-typing) deliberately, not
|
|
401
|
+
bare .chat-bubble-typing: chat.css (loaded after app-shell.css on every
|
|
402
|
+
kit that links both) still carries a plain `.chat-bubble { background:
|
|
403
|
+
var(--bg-2) }` rule at the same (0,1,0) specificity, and cascade order
|
|
404
|
+
would let that later rule win over an equal-specificity selector here. */
|
|
405
|
+
.chat-bubble.chat-bubble-typing {
|
|
406
|
+
background: transparent;
|
|
407
|
+
padding: var(--space-2) var(--space-1);
|
|
408
|
+
border-radius: var(--r-pill);
|
|
409
|
+
}
|
|
410
|
+
.chat-msg:hover .chat-bubble.chat-bubble-typing { transform: none; box-shadow: none; }
|
|
411
|
+
.chat-msg:not(.you) .chat-bubble.chat-bubble-typing,
|
|
412
|
+
.chat-msg.you .chat-bubble.chat-bubble-typing { border-bottom-left-radius: var(--r-pill); border-bottom-right-radius: var(--r-pill); }
|
|
413
|
+
|
|
396
414
|
.chat-typing { display: inline-flex; gap: var(--space-1); align-items: center; }
|
|
397
415
|
.chat-typing span {
|
|
398
416
|
width: 8px; height: 8px; border-radius: 50%; background: var(--fg-3);
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
.ds-hero-accent { color: var(--accent-ink); font-weight: 700; }
|
|
93
93
|
.ds-hero-actions {
|
|
94
94
|
display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
|
|
95
|
-
justify-content: flex-start; margin-top: var(--space-
|
|
95
|
+
justify-content: flex-start; margin-top: var(--space-4);
|
|
96
96
|
}
|
|
97
97
|
/* Hero CTA labels are content-driven (e.g. "GitHub", proper nouns from
|
|
98
98
|
home.yaml) and the site's voice is deliberately all-lowercase everywhere
|
|
@@ -435,7 +435,7 @@ table td.is-num, table th.is-num { text-align: right; font-variant-numeric: tabu
|
|
|
435
435
|
/* live is a distinct hue from a plain "on" dot — see .chip.tone-live's
|
|
436
436
|
comment for the success-vs-live rationale. */
|
|
437
437
|
.ds-dot-live { color: var(--sky); }
|
|
438
|
-
.ds-dot-
|
|
438
|
+
.ds-dot-warn { color: var(--amber); }
|
|
439
439
|
.ds-dot-idle { color: var(--fg-3); }
|
|
440
440
|
|
|
441
441
|
/* ============================================================
|
|
@@ -465,6 +465,17 @@ table td.is-num, table th.is-num { text-align: right; font-variant-numeric: tabu
|
|
|
465
465
|
transform: translateY(-1px);
|
|
466
466
|
box-shadow: var(--shadow-1, 0 2px 8px rgba(0,0,0,.12));
|
|
467
467
|
}
|
|
468
|
+
/* Number+caption stack, isolated from .kpi-foot below it. Previously the
|
|
469
|
+
number and label were plain block children of .kpi-card with the label's
|
|
470
|
+
own margin-top providing the gap — visually fine for a single card, but
|
|
471
|
+
across a row of four the caption's WRAPPED height (one line vs two, e.g.
|
|
472
|
+
"requests · 24h" vs "error rate · 5xx+4xx") pushed .kpi-foot down by a
|
|
473
|
+
different amount per card, so the deltas/sparklines never lined up on one
|
|
474
|
+
shared baseline. A dedicated flex column groups exactly the two elements
|
|
475
|
+
that must stay glued together, independent of whatever sits below. */
|
|
476
|
+
.kpi-stack {
|
|
477
|
+
display: flex; flex-direction: column; align-items: flex-start;
|
|
478
|
+
}
|
|
468
479
|
.kpi-glyph {
|
|
469
480
|
position: absolute;
|
|
470
481
|
top: var(--space-2);
|
|
@@ -551,14 +562,36 @@ table td.is-num, table th.is-num { text-align: right; font-variant-numeric: tabu
|
|
|
551
562
|
padding: var(--space-5);
|
|
552
563
|
background: var(--bg-2);
|
|
553
564
|
border-radius: var(--r-3);
|
|
554
|
-
|
|
565
|
+
/* Grid's default justify-items:stretch was silently stretching the submit
|
|
566
|
+
* button (a direct grid child, same as every input) to the full column
|
|
567
|
+
* width -- other primary buttons elsewhere (e.g. session-ui's "new
|
|
568
|
+
* session") are inline/compact by contrast, since they're not grid
|
|
569
|
+
* children. justify-self:start keeps inputs/textareas at their natural
|
|
570
|
+
* grid-stretched width (a form field SHOULD fill its column) while the
|
|
571
|
+
* submit button sizes to its own content, matching the compact convention
|
|
572
|
+
* used everywhere else primary buttons appear. */
|
|
573
|
+
}
|
|
574
|
+
.row-form > button[type="submit"] { justify-self: start; }
|
|
555
575
|
.row-form input,
|
|
556
576
|
.row-form textarea {
|
|
557
577
|
font-family: inherit; font-size: var(--fs-sm);
|
|
558
578
|
padding: 12px 16px;
|
|
559
|
-
|
|
579
|
+
/* --bg here previously resolved to the SAME color as .row-form's own
|
|
580
|
+
* --bg-2 background in the dark theme, leaving only a 14%-opacity
|
|
581
|
+
* currentColor ring (var(--rule)) as the sole edge between an input and
|
|
582
|
+
* the panel behind it -- effectively invisible. --bg-3 (one step darker
|
|
583
|
+
* than the panel) plus a stronger border restores a real, panel-distinct
|
|
584
|
+
* field surface.
|
|
585
|
+
* LOAD-BEARING !important: `.row-form input` and states-interactions.css's
|
|
586
|
+
* bare `input[type="text"]:where(...)` rule are both (0,1,1) specificity
|
|
587
|
+
* (the :where() wrapper there is intentionally zero-specificity) --
|
|
588
|
+
* states-interactions.css @imports AFTER this file in app-shell.css, so on
|
|
589
|
+
* this exact tie it wins by source order and silently discarded these two
|
|
590
|
+
* declarations. Only !important beats that without restructuring the
|
|
591
|
+
* shared bare-input rule's own selector, which many other consumers rely on. */
|
|
592
|
+
background: var(--bg-3) !important; color: var(--fg);
|
|
560
593
|
border: 0; border-radius: var(--r-2);
|
|
561
|
-
box-shadow: inset 0 0 0 1px
|
|
594
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, currentColor 28%, transparent) !important;
|
|
562
595
|
}
|
|
563
596
|
.row-form input:focus-visible,
|
|
564
597
|
.row-form textarea:focus-visible { box-shadow: var(--focus-ring-inset); }
|
|
@@ -507,6 +507,14 @@
|
|
|
507
507
|
justify-content: flex-end; gap: var(--space-2); flex-wrap: wrap;
|
|
508
508
|
padding: calc(var(--space-2-75) * var(--density)) calc(var(--space-3) * var(--density));
|
|
509
509
|
background: var(--panel-2); border-radius: var(--r-1);
|
|
510
|
+
/* --panel-1 (this bar's parent .panel surface) and --panel-2 are adjacent
|
|
511
|
+
lightness steps that measure only ~1.1-1.5:1 apart (both themes) -- too
|
|
512
|
+
close to read as a distinct nesting depth by background tone alone.
|
|
513
|
+
A hairline border is the same edge-definition device .panel itself
|
|
514
|
+
already uses (see the top of this file) rather than a token-lightness
|
|
515
|
+
change, which would risk the fg-3-on-panel-2 text contrast that is
|
|
516
|
+
already right at its AA floor in the dark theme. */
|
|
517
|
+
border: var(--bw-hair) solid var(--rule);
|
|
510
518
|
margin: calc(var(--space-5) * var(--density)) 0 var(--space-2);
|
|
511
519
|
box-shadow: var(--shadow-2, var(--shadow-1));
|
|
512
520
|
}
|
|
@@ -552,13 +560,37 @@
|
|
|
552
560
|
/* .ds-auth-field-label joins the kit small-label voice above, no overrides. */
|
|
553
561
|
.ds-auth-field-input-row { position: relative; display: flex; align-items: center; }
|
|
554
562
|
/* Reserves room for the absolutely-positioned toggle: its --space-1 inset plus
|
|
555
|
-
the --ds-icon-btn-sm 26px box, so the input text never sits under it.
|
|
563
|
+
the --ds-icon-btn-sm 26px box, so the input text never sits under it. This
|
|
564
|
+
only holds at the pointer:fine 26px box size, though -- the coarse-pointer
|
|
565
|
+
touch-floor rule (states-interactions.css) grows .ds-icon-btn-sm to a
|
|
566
|
+
min-width/height of 44px without this padding following it, so on a
|
|
567
|
+
touchscreen the enlarged hit target actually overlapped 14px into the
|
|
568
|
+
typed password text (44 + 4 inset > 34 reserved). Reserve for the coarse
|
|
569
|
+
floor too, gated behind the same media query, so clearance holds at both
|
|
570
|
+
sizes instead of only the desktop one. */
|
|
556
571
|
.ds-auth-field-input-row .input { flex: 1 1 auto; padding-right: calc(26px + var(--space-2)); }
|
|
572
|
+
@media (pointer: coarse) {
|
|
573
|
+
.ds-auth-field-input-row .input { padding-right: calc(44px + var(--space-2)); }
|
|
574
|
+
}
|
|
557
575
|
.ds-auth-pw-toggle { position: absolute; right: var(--space-1); }
|
|
558
576
|
.ds-auth-row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
|
|
559
577
|
.ds-auth-remember { display: flex; align-items: center; gap: var(--space-1-75); cursor: pointer; }
|
|
578
|
+
/* The native checkbox is already re-tinted site-wide via `accent-color:
|
|
579
|
+
var(--accent-ink)` in states-interactions.css (that rule's own comment
|
|
580
|
+
names this exact control) -- reused here rather than hand-drawing a new
|
|
581
|
+
checkbox component. What that global rule doesn't cover is size: the UA
|
|
582
|
+
default box renders at ~13px, which is under the 24px comfortable-tap
|
|
583
|
+
floor other controls in this row (the link text, the input fields) sit
|
|
584
|
+
above. Sized up on the existing --space-2-5 token, no new primitive. */
|
|
585
|
+
.ds-auth-remember input[type="checkbox"] { width: var(--space-2-5); height: var(--space-2-5); margin: 0; }
|
|
560
586
|
.ds-auth-remember-text { color: var(--panel-text-2); font-size: var(--fs-tiny); }
|
|
561
|
-
|
|
587
|
+
/* --accent-ink, not --accent, per the design system's text-vs-fill split
|
|
588
|
+
(AGENTS.md): --accent is a background/border-color lead only, --accent-ink
|
|
589
|
+
is the tone actually verified for text contrast. The link was previously
|
|
590
|
+
unstyled prose color at --fs-tiny, reading as inert grey next to the
|
|
591
|
+
checkbox label it shares a row with. */
|
|
592
|
+
.ds-auth-forgot { font-size: var(--fs-tiny); color: var(--accent-ink); font-weight: 500; }
|
|
593
|
+
.ds-auth-forgot:hover { text-decoration: underline; }
|
|
562
594
|
/* Error and status share layout but not color: a color-only distinction
|
|
563
595
|
between role="alert" (something is wrong) and role="status" (informational)
|
|
564
596
|
fails WCAG 1.4.1, so each also carries a distinct ASCII marker via ::before —
|
|
@@ -568,6 +600,28 @@
|
|
|
568
600
|
.ds-auth-error::before { content: '[!]'; flex: none; }
|
|
569
601
|
.ds-auth-status { color: var(--panel-text-2); }
|
|
570
602
|
.ds-auth-status::before { content: '[i]'; flex: none; }
|
|
603
|
+
/* The shared Divider() label defaults to --fs-tiny/--panel-text-3 (editor-
|
|
604
|
+
primitives.css), tuned for a dense editor toolbar rule -- inside the auth
|
|
605
|
+
form it sat at the same weight as fine print two rows below it and read
|
|
606
|
+
as barely-there rather than a section break between the password form and
|
|
607
|
+
the OAuth row. Scoped to this form only (never edit the shared component
|
|
608
|
+
sheet for one consumer): borrows the kit small-label voice above (mono,
|
|
609
|
+
--fs-nano, --tr-label, uppercase) at --panel-text-2 instead of the
|
|
610
|
+
dimmer -3 tier, plus the ::before/::after rule lines pushed to full
|
|
611
|
+
--panel-text opacity so the break itself, not just the label, is visible. */
|
|
612
|
+
.ds-auth-form .ds-ep-divider-labeled { margin: var(--space-1) 0; }
|
|
613
|
+
.ds-auth-form .ds-ep-divider-labeled::before,
|
|
614
|
+
.ds-auth-form .ds-ep-divider-labeled::after {
|
|
615
|
+
border-top-color: var(--panel-text-3);
|
|
616
|
+
}
|
|
617
|
+
.ds-auth-form .ds-ep-divider-label {
|
|
618
|
+
font-family: var(--ff-mono);
|
|
619
|
+
font-size: var(--fs-nano);
|
|
620
|
+
font-weight: 600;
|
|
621
|
+
letter-spacing: var(--tr-label);
|
|
622
|
+
text-transform: uppercase;
|
|
623
|
+
color: var(--panel-text-2);
|
|
624
|
+
}
|
|
571
625
|
.ds-auth-providers { display: flex; gap: var(--space-2); flex-wrap: wrap; }
|
|
572
626
|
.ds-auth-provider-btn { flex: 1 1 100px; min-width: 0; display: flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-2-5); }
|
|
573
627
|
.ds-auth-provider-btn--loading { opacity: 0.7; pointer-events: none; }
|
|
@@ -171,6 +171,10 @@
|
|
|
171
171
|
.chip.tone-flame, .chip.tone-error, .chip.tone-miss {
|
|
172
172
|
background: var(--flame); color: var(--on-color);
|
|
173
173
|
}
|
|
174
|
+
.chip.tone-warn {
|
|
175
|
+
background: color-mix(in oklab, var(--amber) 22%, var(--bg));
|
|
176
|
+
color: var(--amber);
|
|
177
|
+
}
|
|
174
178
|
.chip.tone-wip, .chip.tone-neutral {
|
|
175
179
|
background: var(--bg-3); color: var(--fg-2);
|
|
176
180
|
}
|
|
@@ -31,6 +31,19 @@
|
|
|
31
31
|
.ds-filter-pill.active { background: var(--accent-tint); color: var(--fg); border-color: var(--accent); }
|
|
32
32
|
.ds-filter-pill:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
33
33
|
|
|
34
|
+
.ds-filter-pill[class*="tone-"]::before {
|
|
35
|
+
content: '';
|
|
36
|
+
display: inline-block; width: 7px; height: 7px; border-radius: 50%;
|
|
37
|
+
margin-right: var(--space-1);
|
|
38
|
+
background: currentColor;
|
|
39
|
+
}
|
|
40
|
+
.ds-filter-pill.tone-accent { color: var(--accent-ink); }
|
|
41
|
+
.ds-filter-pill.tone-warn { color: var(--amber); }
|
|
42
|
+
.ds-filter-pill.tone-live { color: var(--sky); }
|
|
43
|
+
.ds-filter-pill.tone-sun { color: var(--sun); }
|
|
44
|
+
.ds-filter-pill.tone-success { color: var(--green-deep); }
|
|
45
|
+
.ds-filter-pill.tone-dim { color: var(--fg-3); }
|
|
46
|
+
|
|
34
47
|
/* Touch floor for the new small controls. */
|
|
35
48
|
@media (pointer: coarse) {
|
|
36
49
|
.row-act, .ds-filter-pill { min-height: 44px; }
|
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
Sidebar polish: hide zero-count badges; tonal active state;
|
|
3
3
|
monospace count chips.
|
|
4
4
|
============================================================ */
|
|
5
|
+
/* Rail row rhythm: the sidebar rows (bins/labels) previously packed at
|
|
6
|
+
--space-hair (2px) margin-bottom while the main content column reads at
|
|
7
|
+
the --space-5/--space-3 outer/inner rhythm (AGENTS.md "panel rhythm").
|
|
8
|
+
Bumping the inter-row gap to --space-1-5 (5px) — still a tight, dense-app
|
|
9
|
+
value, but enough that adjacent rows no longer read as glued together —
|
|
10
|
+
and making it density-aware via [data-density] mirrors the existing
|
|
11
|
+
compact-density override pattern in files.css (.ds-file-grid[data-density]).
|
|
12
|
+
[data-density="compact"] keeps the old tighter feel for long rail lists;
|
|
13
|
+
[data-density="spacious"] opens it further. */
|
|
14
|
+
.app-side a { margin-bottom: var(--space-1-5); }
|
|
15
|
+
.app-side[data-density="compact"] a,
|
|
16
|
+
.app-side-shell[data-density="compact"] .app-side a { margin-bottom: var(--space-hair); }
|
|
17
|
+
.app-side[data-density="spacious"] a,
|
|
18
|
+
.app-side-shell[data-density="spacious"] .app-side a { margin-bottom: var(--space-2); }
|
|
19
|
+
|
|
5
20
|
.app-side .count {
|
|
6
21
|
padding: 1px 8px; font-size: var(--fs-micro); font-weight: 700;
|
|
7
22
|
font-family: var(--ff-mono); letter-spacing: 0.04em;
|