@ciderpress/ui 1.0.0-rc.1
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/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/0~142.js +2 -0
- package/dist/0~164.js +2 -0
- package/dist/0~2.js +2 -0
- package/dist/0~225.js +2 -0
- package/dist/0~288.js +2 -0
- package/dist/0~299.js +2 -0
- package/dist/0~3.js +2 -0
- package/dist/0~301.js +2 -0
- package/dist/0~311.js +2 -0
- package/dist/0~326.js +2 -0
- package/dist/0~40.js +2 -0
- package/dist/0~43.js +2 -0
- package/dist/0~433.js +2 -0
- package/dist/0~453.js +2 -0
- package/dist/0~457.js +2 -0
- package/dist/0~497.js +2 -0
- package/dist/0~511.js +2 -0
- package/dist/0~603.js +2 -0
- package/dist/0~616.js +2 -0
- package/dist/0~659.js +2 -0
- package/dist/0~670.js +2 -0
- package/dist/0~687.js +2 -0
- package/dist/0~706.js +2 -0
- package/dist/0~729.js +2 -0
- package/dist/0~768.js +2 -0
- package/dist/0~819.js +2 -0
- package/dist/0~830.js +2 -0
- package/dist/0~854.js +2 -0
- package/dist/0~863.js +2 -0
- package/dist/0~879.js +2 -0
- package/dist/0~96.js +2 -0
- package/dist/0~97.js +2 -0
- package/dist/components/FileTree/FileTree.css +90 -0
- package/dist/components/FileTree/FileTree.d.ts +7 -0
- package/dist/components/FileTree/FileTree.js +531 -0
- package/dist/components/FileTree/FileTreeItem.d.ts +8 -0
- package/dist/components/FileTree/RemoteSvgIcon.d.ts +11 -0
- package/dist/components/FileTree/index.d.ts +4 -0
- package/dist/components/folder-icons.d.ts +32 -0
- package/dist/components/languages.d.ts +7 -0
- package/dist/components/tree-parser/tree-parser.d.ts +12 -0
- package/dist/components/tree-parser/types.d.ts +11 -0
- package/dist/head/css/loader-apple.css +1 -0
- package/dist/head/css/loader-backdrop.css +1 -0
- package/dist/head/css/loader-dots.css +1 -0
- package/dist/head/css/themes/amber.css +1 -0
- package/dist/head/css/themes/arcade.css +1 -0
- package/dist/head/css/themes/grannysmith.css +1 -0
- package/dist/head/css/themes/honeycrisp.css +1 -0
- package/dist/head/css/themes/midnight.css +1 -0
- package/dist/head/css/themes/mulled.css +1 -0
- package/dist/head/js/loader-dots.js +1 -0
- package/dist/head/js/vscode-nav.js +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.mjs +40 -0
- package/dist/node.d.ts +81 -0
- package/dist/node.mjs +17762 -0
- package/dist/plugins/mermaid/MermaidRenderer.tsx +480 -0
- package/dist/plugins/mermaid/mermaid.css +199 -0
- package/dist/theme/components/announcement/announcement-bar.css +103 -0
- package/dist/theme/components/announcement/announcement-bar.tsx +173 -0
- package/dist/theme/components/ask-ai/ask-ai-button.css +52 -0
- package/dist/theme/components/ask-ai/ask-ai-button.tsx +56 -0
- package/dist/theme/components/content-footer/content-footer-portal.tsx +70 -0
- package/dist/theme/components/content-footer/feedback.css +47 -0
- package/dist/theme/components/content-footer/feedback.tsx +96 -0
- package/dist/theme/components/content-footer/meta-actions.css +25 -0
- package/dist/theme/components/content-footer/meta-actions.tsx +57 -0
- package/dist/theme/components/content-footer/page-pager.css +61 -0
- package/dist/theme/components/content-footer/page-pager.tsx +110 -0
- package/dist/theme/components/edit-source-button.tsx +97 -0
- package/dist/theme/components/footer/site-footer.css +179 -0
- package/dist/theme/components/footer/site-footer.tsx +115 -0
- package/dist/theme/components/home/cta.css +67 -0
- package/dist/theme/components/home/cta.tsx +77 -0
- package/dist/theme/components/home/feature-card.css +52 -0
- package/dist/theme/components/home/feature-card.tsx +131 -0
- package/dist/theme/components/home/feature.tsx +79 -0
- package/dist/theme/components/home/hero-demo.css +66 -0
- package/dist/theme/components/home/hero-demo.tsx +46 -0
- package/dist/theme/components/home/hero.css +96 -0
- package/dist/theme/components/home/hero.tsx +111 -0
- package/dist/theme/components/home/layout.tsx +183 -0
- package/dist/theme/components/home/page-rail.css +21 -0
- package/dist/theme/components/home/page-rail.tsx +19 -0
- package/dist/theme/components/home/split.css +148 -0
- package/dist/theme/components/home/split.tsx +120 -0
- package/dist/theme/components/home/trust-strip.css +33 -0
- package/dist/theme/components/home/trust-strip.tsx +43 -0
- package/dist/theme/components/home/workspaces.tsx +71 -0
- package/dist/theme/components/nav/branch-tag.css +54 -0
- package/dist/theme/components/nav/branch-tag.tsx +101 -0
- package/dist/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
- package/dist/theme/components/nav/ciderpress-docs-bar.css +505 -0
- package/dist/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
- package/dist/theme/components/nav/ciderpress-header.css +172 -0
- package/dist/theme/components/nav/ciderpress-header.tsx +113 -0
- package/dist/theme/components/nav/ciderpress-layout-context.tsx +49 -0
- package/dist/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
- package/dist/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
- package/dist/theme/components/nav/ciderpress-nav-menu.css +130 -0
- package/dist/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
- package/dist/theme/components/nav/ciderpress-nav-search.css +73 -0
- package/dist/theme/components/nav/ciderpress-nav-search.tsx +55 -0
- package/dist/theme/components/nav/ciderpress-nav-social-links.css +35 -0
- package/dist/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
- package/dist/theme/components/nav/floating-branch-indicator.css +106 -0
- package/dist/theme/components/nav/floating-branch-indicator.tsx +109 -0
- package/dist/theme/components/nav/layout.tsx +268 -0
- package/dist/theme/components/nav/mobile-nav-cta.tsx +79 -0
- package/dist/theme/components/nav/nav-divider.css +15 -0
- package/dist/theme/components/nav/nav-divider.tsx +19 -0
- package/dist/theme/components/nav/nav-logo.css +42 -0
- package/dist/theme/components/nav/nav-logo.tsx +262 -0
- package/dist/theme/components/nav/theme-switcher.css +92 -0
- package/dist/theme/components/nav/theme-switcher.tsx +298 -0
- package/dist/theme/components/nav/topbar-cta.css +45 -0
- package/dist/theme/components/nav/topbar-cta.tsx +39 -0
- package/dist/theme/components/nav/variant-toggle.css +70 -0
- package/dist/theme/components/nav/variant-toggle.tsx +83 -0
- package/dist/theme/components/nav/version-chip.css +31 -0
- package/dist/theme/components/nav/version-chip.tsx +45 -0
- package/dist/theme/components/nav/vscode-tag.css +32 -0
- package/dist/theme/components/nav/vscode-tag.tsx +20 -0
- package/dist/theme/components/openapi/code-sample.tsx +341 -0
- package/dist/theme/components/openapi/copy-markdown-button.tsx +41 -0
- package/dist/theme/components/openapi/icons.tsx +45 -0
- package/dist/theme/components/openapi/index.ts +6 -0
- package/dist/theme/components/openapi/method-badge.tsx +24 -0
- package/dist/theme/components/openapi/openapi.css +665 -0
- package/dist/theme/components/openapi/operation.tsx +200 -0
- package/dist/theme/components/openapi/overview.tsx +207 -0
- package/dist/theme/components/openapi/parameters-table.tsx +149 -0
- package/dist/theme/components/openapi/request-body.tsx +90 -0
- package/dist/theme/components/openapi/response-list.tsx +112 -0
- package/dist/theme/components/openapi/schema-viewer.tsx +277 -0
- package/dist/theme/components/openapi/security-badges.tsx +63 -0
- package/dist/theme/components/openapi/spec-utils.ts +122 -0
- package/dist/theme/components/shared/accordion.css +118 -0
- package/dist/theme/components/shared/accordion.stories.tsx +96 -0
- package/dist/theme/components/shared/accordion.tsx +191 -0
- package/dist/theme/components/shared/brand-logo.stories.tsx +49 -0
- package/dist/theme/components/shared/brand-mark.stories.tsx +53 -0
- package/dist/theme/components/shared/browser-window.css +1 -0
- package/dist/theme/components/shared/browser-window.stories.tsx +100 -0
- package/dist/theme/components/shared/browser-window.tsx +2 -0
- package/dist/theme/components/shared/card.stories.tsx +50 -0
- package/dist/theme/components/shared/card.tsx +35 -0
- package/dist/theme/components/shared/ciderpress-logo.tsx +93 -0
- package/dist/theme/components/shared/ciderpress-mark.tsx +77 -0
- package/dist/theme/components/shared/color.css +56 -0
- package/dist/theme/components/shared/color.stories.tsx +47 -0
- package/dist/theme/components/shared/color.tsx +69 -0
- package/dist/theme/components/shared/columns.css +37 -0
- package/dist/theme/components/shared/columns.stories.tsx +91 -0
- package/dist/theme/components/shared/columns.tsx +50 -0
- package/dist/theme/components/shared/desktop-window.css +339 -0
- package/dist/theme/components/shared/desktop-window.tsx +535 -0
- package/dist/theme/components/shared/field.css +158 -0
- package/dist/theme/components/shared/field.stories.tsx +100 -0
- package/dist/theme/components/shared/field.tsx +186 -0
- package/dist/theme/components/shared/frame.css +39 -0
- package/dist/theme/components/shared/frame.stories.tsx +49 -0
- package/dist/theme/components/shared/frame.tsx +76 -0
- package/dist/theme/components/shared/icon.stories.tsx +90 -0
- package/dist/theme/components/shared/icon.tsx +41 -0
- package/dist/theme/components/shared/prompt.css +178 -0
- package/dist/theme/components/shared/prompt.stories.tsx +57 -0
- package/dist/theme/components/shared/prompt.tsx +369 -0
- package/dist/theme/components/shared/resolve-card-icon.ts +28 -0
- package/dist/theme/components/shared/section-card.stories.tsx +51 -0
- package/dist/theme/components/shared/section-card.tsx +44 -0
- package/dist/theme/components/shared/section-grid.stories.tsx +46 -0
- package/dist/theme/components/shared/section-grid.tsx +15 -0
- package/dist/theme/components/shared/status-badge.css +37 -0
- package/dist/theme/components/shared/status-badge.stories.tsx +61 -0
- package/dist/theme/components/shared/status-badge.tsx +74 -0
- package/dist/theme/components/shared/steps.css +88 -0
- package/dist/theme/components/shared/steps.stories.tsx +68 -0
- package/dist/theme/components/shared/steps.tsx +100 -0
- package/dist/theme/components/shared/tech-icon-table.stories.tsx +29 -0
- package/dist/theme/components/shared/tech-icon-table.tsx +71 -0
- package/dist/theme/components/shared/tech-tag.stories.tsx +40 -0
- package/dist/theme/components/shared/tech-tag.tsx +31 -0
- package/dist/theme/components/shared/theme-color-palette.css +80 -0
- package/dist/theme/components/shared/theme-color-palette.stories.tsx +52 -0
- package/dist/theme/components/shared/theme-color-palette.tsx +275 -0
- package/dist/theme/components/shared/tooltip.css +69 -0
- package/dist/theme/components/shared/tooltip.stories.tsx +72 -0
- package/dist/theme/components/shared/tooltip.tsx +77 -0
- package/dist/theme/components/sidebar/framework-picker.css +77 -0
- package/dist/theme/components/sidebar/framework-picker.tsx +78 -0
- package/dist/theme/components/sidebar/sidebar-filter.test.ts +140 -0
- package/dist/theme/components/sidebar/sidebar-filter.ts +79 -0
- package/dist/theme/components/sidebar/sidebar-links.css +102 -0
- package/dist/theme/components/sidebar/sidebar-links.tsx +122 -0
- package/dist/theme/components/sidebar/sidebar-promo.css +42 -0
- package/dist/theme/components/sidebar/sidebar-promo.tsx +52 -0
- package/dist/theme/components/sidebar/sidebar-scope.tsx +151 -0
- package/dist/theme/components/sidebar/sidebar-toggle.css +181 -0
- package/dist/theme/components/sidebar/sidebar-toggle.tsx +127 -0
- package/dist/theme/components/theme-provider.tsx +637 -0
- package/dist/theme/components/workspaces/card.css +151 -0
- package/dist/theme/components/workspaces/card.tsx +166 -0
- package/dist/theme/components/workspaces/grid.tsx +62 -0
- package/dist/theme/css.d.ts +1 -0
- package/dist/theme/env.d.ts +12 -0
- package/dist/theme/fonts/GeistMono-Variable.woff2 +0 -0
- package/dist/theme/fonts/GeistPixel-Square.woff2 +0 -0
- package/dist/theme/fonts/GeistSans-Variable.woff2 +0 -0
- package/dist/theme/hooks/use-ciderpress.ts +61 -0
- package/dist/theme/hooks/use-nav-items.ts +76 -0
- package/dist/theme/icons/index.ts +2 -0
- package/dist/theme/icons/tech-map.ts +228 -0
- package/dist/theme/index.tsx +180 -0
- package/dist/theme/lib/read-social-links.ts +27 -0
- package/dist/theme/lib/route-link.tsx +126 -0
- package/dist/theme/lib/safe-url.test.ts +0 -0
- package/dist/theme/lib/safe-url.ts +68 -0
- package/dist/theme/lib/theme-favicon.ts +125 -0
- package/dist/theme/lib/user-config-stub.ts +12 -0
- package/dist/theme/styles/layers.css +32 -0
- package/dist/theme/styles/overrides/badge.css +26 -0
- package/dist/theme/styles/overrides/content-footer.css +80 -0
- package/dist/theme/styles/overrides/details.css +61 -0
- package/dist/theme/styles/overrides/fonts.css +32 -0
- package/dist/theme/styles/overrides/home-card.css +133 -0
- package/dist/theme/styles/overrides/home.css +243 -0
- package/dist/theme/styles/overrides/rail.css +337 -0
- package/dist/theme/styles/overrides/rspress.css +62 -0
- package/dist/theme/styles/overrides/scrollbar.css +25 -0
- package/dist/theme/styles/overrides/section-card.css +114 -0
- package/dist/theme/styles/overrides/sidebar.css +144 -0
- package/dist/theme/styles/overrides/tokens.css +288 -0
- package/dist/theme/styles/overrides/vscode.css +88 -0
- package/dist/theme/styles/themes/amber.css +545 -0
- package/dist/theme/styles/themes/arcade-fx.css +366 -0
- package/dist/theme/styles/themes/arcade.css +273 -0
- package/dist/theme/styles/themes/grannysmith.css +545 -0
- package/dist/theme/styles/themes/honeycrisp.css +545 -0
- package/dist/theme/styles/themes/midnight.css +273 -0
- package/dist/theme/styles/themes/mulled.css +817 -0
- package/package.json +103 -0
- package/src/theme/components/announcement/announcement-bar.css +103 -0
- package/src/theme/components/announcement/announcement-bar.tsx +173 -0
- package/src/theme/components/ask-ai/ask-ai-button.css +52 -0
- package/src/theme/components/ask-ai/ask-ai-button.tsx +56 -0
- package/src/theme/components/content-footer/content-footer-portal.tsx +70 -0
- package/src/theme/components/content-footer/feedback.css +47 -0
- package/src/theme/components/content-footer/feedback.tsx +96 -0
- package/src/theme/components/content-footer/meta-actions.css +25 -0
- package/src/theme/components/content-footer/meta-actions.tsx +57 -0
- package/src/theme/components/content-footer/page-pager.css +61 -0
- package/src/theme/components/content-footer/page-pager.tsx +110 -0
- package/src/theme/components/edit-source-button.tsx +97 -0
- package/src/theme/components/footer/site-footer.css +179 -0
- package/src/theme/components/footer/site-footer.tsx +115 -0
- package/src/theme/components/home/cta.css +67 -0
- package/src/theme/components/home/cta.tsx +77 -0
- package/src/theme/components/home/feature-card.css +52 -0
- package/src/theme/components/home/feature-card.tsx +131 -0
- package/src/theme/components/home/feature.tsx +79 -0
- package/src/theme/components/home/hero-demo.css +66 -0
- package/src/theme/components/home/hero-demo.tsx +46 -0
- package/src/theme/components/home/hero.css +96 -0
- package/src/theme/components/home/hero.tsx +111 -0
- package/src/theme/components/home/layout.tsx +183 -0
- package/src/theme/components/home/page-rail.css +21 -0
- package/src/theme/components/home/page-rail.tsx +19 -0
- package/src/theme/components/home/split.css +148 -0
- package/src/theme/components/home/split.tsx +120 -0
- package/src/theme/components/home/trust-strip.css +33 -0
- package/src/theme/components/home/trust-strip.tsx +43 -0
- package/src/theme/components/home/workspaces.tsx +71 -0
- package/src/theme/components/nav/branch-tag.css +54 -0
- package/src/theme/components/nav/branch-tag.tsx +101 -0
- package/src/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
- package/src/theme/components/nav/ciderpress-docs-bar.css +505 -0
- package/src/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
- package/src/theme/components/nav/ciderpress-header.css +172 -0
- package/src/theme/components/nav/ciderpress-header.tsx +113 -0
- package/src/theme/components/nav/ciderpress-layout-context.tsx +49 -0
- package/src/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
- package/src/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
- package/src/theme/components/nav/ciderpress-nav-menu.css +130 -0
- package/src/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
- package/src/theme/components/nav/ciderpress-nav-search.css +73 -0
- package/src/theme/components/nav/ciderpress-nav-search.tsx +55 -0
- package/src/theme/components/nav/ciderpress-nav-social-links.css +35 -0
- package/src/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
- package/src/theme/components/nav/floating-branch-indicator.css +106 -0
- package/src/theme/components/nav/floating-branch-indicator.tsx +109 -0
- package/src/theme/components/nav/layout.tsx +268 -0
- package/src/theme/components/nav/mobile-nav-cta.tsx +79 -0
- package/src/theme/components/nav/nav-divider.css +15 -0
- package/src/theme/components/nav/nav-divider.tsx +19 -0
- package/src/theme/components/nav/nav-logo.css +42 -0
- package/src/theme/components/nav/nav-logo.tsx +262 -0
- package/src/theme/components/nav/theme-switcher.css +92 -0
- package/src/theme/components/nav/theme-switcher.tsx +298 -0
- package/src/theme/components/nav/topbar-cta.css +45 -0
- package/src/theme/components/nav/topbar-cta.tsx +39 -0
- package/src/theme/components/nav/variant-toggle.css +70 -0
- package/src/theme/components/nav/variant-toggle.tsx +83 -0
- package/src/theme/components/nav/version-chip.css +31 -0
- package/src/theme/components/nav/version-chip.tsx +45 -0
- package/src/theme/components/nav/vscode-tag.css +32 -0
- package/src/theme/components/nav/vscode-tag.tsx +20 -0
- package/src/theme/components/openapi/code-sample.tsx +341 -0
- package/src/theme/components/openapi/copy-markdown-button.tsx +41 -0
- package/src/theme/components/openapi/icons.tsx +45 -0
- package/src/theme/components/openapi/index.ts +6 -0
- package/src/theme/components/openapi/method-badge.tsx +24 -0
- package/src/theme/components/openapi/openapi.css +665 -0
- package/src/theme/components/openapi/operation.tsx +200 -0
- package/src/theme/components/openapi/overview.tsx +207 -0
- package/src/theme/components/openapi/parameters-table.tsx +149 -0
- package/src/theme/components/openapi/request-body.tsx +90 -0
- package/src/theme/components/openapi/response-list.tsx +112 -0
- package/src/theme/components/openapi/schema-viewer.tsx +277 -0
- package/src/theme/components/openapi/security-badges.tsx +63 -0
- package/src/theme/components/openapi/spec-utils.ts +122 -0
- package/src/theme/components/shared/accordion.css +118 -0
- package/src/theme/components/shared/accordion.stories.tsx +96 -0
- package/src/theme/components/shared/accordion.tsx +191 -0
- package/src/theme/components/shared/brand-logo.stories.tsx +49 -0
- package/src/theme/components/shared/brand-mark.stories.tsx +53 -0
- package/src/theme/components/shared/browser-window.css +1 -0
- package/src/theme/components/shared/browser-window.stories.tsx +100 -0
- package/src/theme/components/shared/browser-window.tsx +2 -0
- package/src/theme/components/shared/card.stories.tsx +50 -0
- package/src/theme/components/shared/card.tsx +35 -0
- package/src/theme/components/shared/ciderpress-logo.tsx +93 -0
- package/src/theme/components/shared/ciderpress-mark.tsx +77 -0
- package/src/theme/components/shared/color.css +56 -0
- package/src/theme/components/shared/color.stories.tsx +47 -0
- package/src/theme/components/shared/color.tsx +69 -0
- package/src/theme/components/shared/columns.css +37 -0
- package/src/theme/components/shared/columns.stories.tsx +91 -0
- package/src/theme/components/shared/columns.tsx +50 -0
- package/src/theme/components/shared/desktop-window.css +339 -0
- package/src/theme/components/shared/desktop-window.tsx +535 -0
- package/src/theme/components/shared/field.css +158 -0
- package/src/theme/components/shared/field.stories.tsx +100 -0
- package/src/theme/components/shared/field.tsx +186 -0
- package/src/theme/components/shared/frame.css +39 -0
- package/src/theme/components/shared/frame.stories.tsx +49 -0
- package/src/theme/components/shared/frame.tsx +76 -0
- package/src/theme/components/shared/icon.stories.tsx +90 -0
- package/src/theme/components/shared/icon.tsx +41 -0
- package/src/theme/components/shared/prompt.css +178 -0
- package/src/theme/components/shared/prompt.stories.tsx +57 -0
- package/src/theme/components/shared/prompt.tsx +369 -0
- package/src/theme/components/shared/resolve-card-icon.ts +28 -0
- package/src/theme/components/shared/section-card.stories.tsx +51 -0
- package/src/theme/components/shared/section-card.tsx +44 -0
- package/src/theme/components/shared/section-grid.stories.tsx +46 -0
- package/src/theme/components/shared/section-grid.tsx +15 -0
- package/src/theme/components/shared/status-badge.css +37 -0
- package/src/theme/components/shared/status-badge.stories.tsx +61 -0
- package/src/theme/components/shared/status-badge.tsx +74 -0
- package/src/theme/components/shared/steps.css +88 -0
- package/src/theme/components/shared/steps.stories.tsx +68 -0
- package/src/theme/components/shared/steps.tsx +100 -0
- package/src/theme/components/shared/tech-icon-table.stories.tsx +29 -0
- package/src/theme/components/shared/tech-icon-table.tsx +71 -0
- package/src/theme/components/shared/tech-tag.stories.tsx +40 -0
- package/src/theme/components/shared/tech-tag.tsx +31 -0
- package/src/theme/components/shared/theme-color-palette.css +80 -0
- package/src/theme/components/shared/theme-color-palette.stories.tsx +52 -0
- package/src/theme/components/shared/theme-color-palette.tsx +275 -0
- package/src/theme/components/shared/tooltip.css +69 -0
- package/src/theme/components/shared/tooltip.stories.tsx +72 -0
- package/src/theme/components/shared/tooltip.tsx +77 -0
- package/src/theme/components/sidebar/framework-picker.css +77 -0
- package/src/theme/components/sidebar/framework-picker.tsx +78 -0
- package/src/theme/components/sidebar/sidebar-filter.test.ts +140 -0
- package/src/theme/components/sidebar/sidebar-filter.ts +79 -0
- package/src/theme/components/sidebar/sidebar-links.css +102 -0
- package/src/theme/components/sidebar/sidebar-links.tsx +122 -0
- package/src/theme/components/sidebar/sidebar-promo.css +42 -0
- package/src/theme/components/sidebar/sidebar-promo.tsx +52 -0
- package/src/theme/components/sidebar/sidebar-scope.tsx +151 -0
- package/src/theme/components/sidebar/sidebar-toggle.css +181 -0
- package/src/theme/components/sidebar/sidebar-toggle.tsx +127 -0
- package/src/theme/components/theme-provider.tsx +637 -0
- package/src/theme/components/workspaces/card.css +151 -0
- package/src/theme/components/workspaces/card.tsx +166 -0
- package/src/theme/components/workspaces/grid.tsx +62 -0
- package/src/theme/css.d.ts +1 -0
- package/src/theme/env.d.ts +12 -0
- package/src/theme/fonts/GeistMono-Variable.woff2 +0 -0
- package/src/theme/fonts/GeistPixel-Square.woff2 +0 -0
- package/src/theme/fonts/GeistSans-Variable.woff2 +0 -0
- package/src/theme/hooks/use-ciderpress.ts +61 -0
- package/src/theme/hooks/use-nav-items.ts +76 -0
- package/src/theme/icons/index.ts +2 -0
- package/src/theme/icons/tech-map.ts +228 -0
- package/src/theme/index.tsx +180 -0
- package/src/theme/lib/read-social-links.ts +27 -0
- package/src/theme/lib/route-link.tsx +126 -0
- package/src/theme/lib/safe-url.test.ts +0 -0
- package/src/theme/lib/safe-url.ts +68 -0
- package/src/theme/lib/theme-favicon.ts +125 -0
- package/src/theme/lib/user-config-stub.ts +12 -0
- package/src/theme/styles/layers.css +32 -0
- package/src/theme/styles/overrides/badge.css +26 -0
- package/src/theme/styles/overrides/content-footer.css +80 -0
- package/src/theme/styles/overrides/details.css +61 -0
- package/src/theme/styles/overrides/fonts.css +32 -0
- package/src/theme/styles/overrides/home-card.css +133 -0
- package/src/theme/styles/overrides/home.css +243 -0
- package/src/theme/styles/overrides/rail.css +337 -0
- package/src/theme/styles/overrides/rspress.css +62 -0
- package/src/theme/styles/overrides/scrollbar.css +25 -0
- package/src/theme/styles/overrides/section-card.css +114 -0
- package/src/theme/styles/overrides/sidebar.css +144 -0
- package/src/theme/styles/overrides/tokens.css +288 -0
- package/src/theme/styles/overrides/vscode.css +88 -0
- package/src/theme/styles/themes/amber.css +545 -0
- package/src/theme/styles/themes/arcade-fx.css +366 -0
- package/src/theme/styles/themes/arcade.css +273 -0
- package/src/theme/styles/themes/grannysmith.css +545 -0
- package/src/theme/styles/themes/honeycrisp.css +545 -0
- package/src/theme/styles/themes/midnight.css +273 -0
- package/src/theme/styles/themes/mulled.css +817 -0
package/package.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ciderpress/ui",
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
|
+
"description": "Rspress plugin, theme components, and styles for ciderpress",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ciderpress",
|
|
7
|
+
"react",
|
|
8
|
+
"rspress",
|
|
9
|
+
"theme",
|
|
10
|
+
"ui"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/thebytefarm/ciderpress/tree/main/packages/ui#readme",
|
|
13
|
+
"bugs": "https://github.com/thebytefarm/ciderpress/issues",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/thebytefarm/ciderpress.git",
|
|
18
|
+
"directory": "packages/ui"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"src/theme"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./node": {
|
|
31
|
+
"types": "./dist/node.d.ts",
|
|
32
|
+
"import": "./dist/node.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./theme": {
|
|
35
|
+
"types": "./src/theme/index.tsx",
|
|
36
|
+
"import": "./src/theme/index.tsx"
|
|
37
|
+
},
|
|
38
|
+
"./icons": {
|
|
39
|
+
"types": "./src/theme/icons/index.ts",
|
|
40
|
+
"import": "./src/theme/icons/index.ts"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public",
|
|
45
|
+
"provenance": false
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@iconify-json/catppuccin": "^1.2.17",
|
|
49
|
+
"@iconify-json/devicon": "^1.2.62",
|
|
50
|
+
"@iconify-json/logos": "^1.2.11",
|
|
51
|
+
"@iconify-json/material-icon-theme": "^1.2.67",
|
|
52
|
+
"@iconify-json/mdi": "^1.2.3",
|
|
53
|
+
"@iconify-json/pixelarticons": "^1.2.6",
|
|
54
|
+
"@iconify-json/simple-icons": "^1.2.86",
|
|
55
|
+
"@iconify-json/skill-icons": "^1.2.4",
|
|
56
|
+
"@iconify-json/vscode-icons": "^1.2.55",
|
|
57
|
+
"@iconify/react": "^6.0.2",
|
|
58
|
+
"clsx": "^2.1.1",
|
|
59
|
+
"katex": "^0.17.0",
|
|
60
|
+
"massaman": "^0.2.0",
|
|
61
|
+
"mermaid": "^10.9.6",
|
|
62
|
+
"openapi-sampler": "^1.7.4",
|
|
63
|
+
"react-aria-components": "^1.18.0",
|
|
64
|
+
"ts-morph": "^28.0.0",
|
|
65
|
+
"unist-util-visit": "^5.1.0",
|
|
66
|
+
"@ciderpress/theme": "1.0.0-rc.1",
|
|
67
|
+
"@ciderpress/config": "1.0.0-rc.1"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@ladle/react": "^5.1.1",
|
|
71
|
+
"@rslib/core": "^0.22.0",
|
|
72
|
+
"@rspress/core": "^2.0.14",
|
|
73
|
+
"@types/react": "^19.2.17",
|
|
74
|
+
"@types/react-dom": "^19.2.3",
|
|
75
|
+
"esbuild": "^0.28.0",
|
|
76
|
+
"geist": "^1.7.2",
|
|
77
|
+
"react": "^19.2.7",
|
|
78
|
+
"react-dom": "^19.2.7",
|
|
79
|
+
"rspress-plugin-devkit": "^1.0.0",
|
|
80
|
+
"rspress-plugin-file-tree": "^1.0.5",
|
|
81
|
+
"rspress-plugin-katex": "^1.0.1",
|
|
82
|
+
"rspress-plugin-supersub": "^1.0.0",
|
|
83
|
+
"typescript": "^6.0.3",
|
|
84
|
+
"vitest": "^4.1.8"
|
|
85
|
+
},
|
|
86
|
+
"peerDependencies": {
|
|
87
|
+
"@rspress/core": "^2.0.14",
|
|
88
|
+
"react": "^19.2.5",
|
|
89
|
+
"react-dom": "^19.2.5"
|
|
90
|
+
},
|
|
91
|
+
"engines": {
|
|
92
|
+
"node": ">=24.0.0"
|
|
93
|
+
},
|
|
94
|
+
"scripts": {
|
|
95
|
+
"build": "rslib build",
|
|
96
|
+
"postbuild": "node scripts/generate-theme-css.mjs && oxfmt --write src/theme/styles/themes src/head/css/themes && node scripts/minify-head.mjs",
|
|
97
|
+
"dev": "rslib build --watch --no-clean",
|
|
98
|
+
"generate:theme-css": "node scripts/generate-theme-css.mjs",
|
|
99
|
+
"ladle": "ladle serve",
|
|
100
|
+
"test": "vitest run",
|
|
101
|
+
"typecheck": "tsgo --noEmit"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
.cp-announce {
|
|
2
|
+
position: relative;
|
|
3
|
+
height: var(--cp-announce-h);
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
gap: 12px;
|
|
8
|
+
padding: 0 48px;
|
|
9
|
+
background: linear-gradient(
|
|
10
|
+
90deg,
|
|
11
|
+
var(--cp-c-brand-soft) 0%,
|
|
12
|
+
transparent 50%,
|
|
13
|
+
var(--cp-c-brand-soft) 100%
|
|
14
|
+
);
|
|
15
|
+
border-bottom: 1px solid var(--cp-c-border);
|
|
16
|
+
font-size: 12.5px;
|
|
17
|
+
color: var(--cp-c-text-2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.cp-announce__pulse {
|
|
21
|
+
width: 6px;
|
|
22
|
+
height: 6px;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
background: var(--cp-c-brand-1);
|
|
25
|
+
animation: cp-announce-pulse 2.4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes cp-announce-pulse {
|
|
29
|
+
0%,
|
|
30
|
+
100% {
|
|
31
|
+
box-shadow: 0 0 0 0 var(--cp-c-brand-soft);
|
|
32
|
+
}
|
|
33
|
+
50% {
|
|
34
|
+
box-shadow: 0 0 0 6px transparent;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.cp-announce__msg {
|
|
39
|
+
display: inline-flex;
|
|
40
|
+
flex-wrap: wrap;
|
|
41
|
+
gap: 4px;
|
|
42
|
+
align-items: center;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.cp-announce__lead {
|
|
46
|
+
color: var(--cp-c-text-1);
|
|
47
|
+
font-style: normal;
|
|
48
|
+
font-weight: 500;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.cp-announce__cta {
|
|
52
|
+
color: var(--cp-c-brand-1);
|
|
53
|
+
font-weight: 500;
|
|
54
|
+
margin-left: 4px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.cp-announce__cta:hover {
|
|
58
|
+
color: var(--cp-c-brand-2);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.cp-announce__close {
|
|
62
|
+
position: absolute;
|
|
63
|
+
right: 12px;
|
|
64
|
+
top: 50%;
|
|
65
|
+
transform: translateY(-50%);
|
|
66
|
+
width: 22px;
|
|
67
|
+
height: 22px;
|
|
68
|
+
display: grid;
|
|
69
|
+
place-items: center;
|
|
70
|
+
background: transparent;
|
|
71
|
+
border: 0;
|
|
72
|
+
border-radius: 4px;
|
|
73
|
+
color: var(--cp-c-text-3);
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.cp-announce__close:hover {
|
|
78
|
+
background: var(--cp-c-bg-soft);
|
|
79
|
+
color: var(--cp-c-text-1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Mobile: shrink padding so the message doesn't wrap weirdly inside a
|
|
83
|
+
fixed 36px row. Let the bar grow vertically when the message + CTA
|
|
84
|
+
would otherwise collide with the close button. */
|
|
85
|
+
@media (max-width: 720px) {
|
|
86
|
+
html .cp-announce {
|
|
87
|
+
height: auto;
|
|
88
|
+
min-height: var(--cp-announce-h);
|
|
89
|
+
padding: 6px 36px 6px 12px;
|
|
90
|
+
font-size: 12px;
|
|
91
|
+
line-height: 1.35;
|
|
92
|
+
text-align: left;
|
|
93
|
+
justify-content: flex-start;
|
|
94
|
+
}
|
|
95
|
+
html .cp-announce__msg {
|
|
96
|
+
flex: 1;
|
|
97
|
+
flex-wrap: wrap;
|
|
98
|
+
row-gap: 2px;
|
|
99
|
+
}
|
|
100
|
+
html .cp-announce__close {
|
|
101
|
+
right: 6px;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { match } from 'massaman/match'
|
|
2
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
import { RouteLink } from '../../lib/route-link.tsx'
|
|
5
|
+
import { safeUrl } from '../../lib/safe-url.ts'
|
|
6
|
+
|
|
7
|
+
import './announcement-bar.css'
|
|
8
|
+
|
|
9
|
+
const STORAGE_PREFIX = 'ciderpress-announcement-dismissed:'
|
|
10
|
+
/**
|
|
11
|
+
* Initial height assumption before the bar mounts and measures itself.
|
|
12
|
+
* Matches the value Rspress's own `<Banner />` uses (`useState(36)`) so
|
|
13
|
+
* downstream sticky offsets are roughly correct on the first paint.
|
|
14
|
+
*/
|
|
15
|
+
const INITIAL_HEIGHT = 36
|
|
16
|
+
|
|
17
|
+
export interface AnnouncementBarProps {
|
|
18
|
+
/**
|
|
19
|
+
* Stable ID — when present, dismissal is remembered in localStorage.
|
|
20
|
+
*/
|
|
21
|
+
readonly id?: string
|
|
22
|
+
/**
|
|
23
|
+
* Lead text. Use for the highlighted phrase ("ciderpress 1.0", "NEW:", etc).
|
|
24
|
+
*/
|
|
25
|
+
readonly lead?: React.ReactNode
|
|
26
|
+
/**
|
|
27
|
+
* Body of the announcement.
|
|
28
|
+
*/
|
|
29
|
+
readonly children: React.ReactNode
|
|
30
|
+
/**
|
|
31
|
+
* Optional CTA link rendered after the message.
|
|
32
|
+
*/
|
|
33
|
+
readonly cta?: { readonly href: string; readonly label: string }
|
|
34
|
+
/**
|
|
35
|
+
* Hide the dismiss button.
|
|
36
|
+
*/
|
|
37
|
+
readonly persistent?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* AnnouncementBar — full-width banner rendered above the topbar via the
|
|
42
|
+
* Layout `top` slot. Ships with a pulsing accent dot and an optional
|
|
43
|
+
* dismiss button that persists in localStorage when an `id` is provided.
|
|
44
|
+
*
|
|
45
|
+
* @param props - AnnouncementBar configuration.
|
|
46
|
+
* @returns React element, or null when the bar has been dismissed.
|
|
47
|
+
*/
|
|
48
|
+
export function AnnouncementBar(props: AnnouncementBarProps): React.ReactElement | null {
|
|
49
|
+
const { id, lead, children, cta, persistent } = props
|
|
50
|
+
const [dismissed, setDismissed] = useState(() => readDismissed(id))
|
|
51
|
+
// Track the rendered height so downstream sticky offsets
|
|
52
|
+
// (`--rp-nav-height` calc + the docs bar's sticky `top`) clear the
|
|
53
|
+
// announcement bar without anybody hardcoding a number. Mirrors the
|
|
54
|
+
// pattern Rspress's own `<Banner />` uses: a state value + a
|
|
55
|
+
// callback ref + a sibling `<style>` tag exposing the value as a
|
|
56
|
+
// CSS variable.
|
|
57
|
+
const [height, setHeight] = useState(INITIAL_HEIGHT)
|
|
58
|
+
const measureRef = useRef<HTMLDivElement | null>(null)
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
setDismissed(readDismissed(id))
|
|
62
|
+
}, [id])
|
|
63
|
+
|
|
64
|
+
const handleDismiss = useCallback(() => {
|
|
65
|
+
writeDismissed(id)
|
|
66
|
+
setDismissed(true)
|
|
67
|
+
}, [id])
|
|
68
|
+
|
|
69
|
+
const setMeasureRef = useCallback((element: HTMLDivElement | null) => {
|
|
70
|
+
measureRef.current = element
|
|
71
|
+
if (element !== null && element.offsetHeight > 0) {
|
|
72
|
+
setHeight(element.offsetHeight)
|
|
73
|
+
}
|
|
74
|
+
}, [])
|
|
75
|
+
|
|
76
|
+
return match(dismissed)
|
|
77
|
+
.with(true, () => null)
|
|
78
|
+
.otherwise(() => (
|
|
79
|
+
<>
|
|
80
|
+
<div ref={setMeasureRef} className="cp-announce" role="region" aria-label="Announcement">
|
|
81
|
+
<span className="cp-announce__pulse" aria-hidden="true" />
|
|
82
|
+
<span className="cp-announce__msg">
|
|
83
|
+
{match(lead)
|
|
84
|
+
.with(undefined, () => null)
|
|
85
|
+
.otherwise((l) => (
|
|
86
|
+
<em className="cp-announce__lead">{l}</em>
|
|
87
|
+
))}{' '}
|
|
88
|
+
{children}
|
|
89
|
+
{match(cta)
|
|
90
|
+
.with(undefined, () => null)
|
|
91
|
+
.otherwise((c) => {
|
|
92
|
+
const href = safeUrl(c.href)
|
|
93
|
+
if (href === null) {
|
|
94
|
+
return null
|
|
95
|
+
}
|
|
96
|
+
return (
|
|
97
|
+
<RouteLink className="cp-announce__cta" href={href}>
|
|
98
|
+
{c.label} →
|
|
99
|
+
</RouteLink>
|
|
100
|
+
)
|
|
101
|
+
})}
|
|
102
|
+
</span>
|
|
103
|
+
{match(persistent === true)
|
|
104
|
+
.with(true, () => null)
|
|
105
|
+
.otherwise(() => (
|
|
106
|
+
<button
|
|
107
|
+
className="cp-announce__close"
|
|
108
|
+
type="button"
|
|
109
|
+
onClick={handleDismiss}
|
|
110
|
+
aria-label="Dismiss announcement"
|
|
111
|
+
>
|
|
112
|
+
<svg
|
|
113
|
+
width="12"
|
|
114
|
+
height="12"
|
|
115
|
+
viewBox="0 0 24 24"
|
|
116
|
+
fill="none"
|
|
117
|
+
stroke="currentColor"
|
|
118
|
+
strokeWidth="2"
|
|
119
|
+
>
|
|
120
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
121
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
122
|
+
</svg>
|
|
123
|
+
</button>
|
|
124
|
+
))}
|
|
125
|
+
</div>
|
|
126
|
+
{/* Expose the measured height as a CSS variable so the docs
|
|
127
|
+
bar's sticky `top:` and the `--rp-nav-height` calc clear
|
|
128
|
+
the announcement without anybody hardcoding 36px. Pattern
|
|
129
|
+
cribbed directly from Rspress's `<Banner />`. */}
|
|
130
|
+
<style>{`:root { --cp-announcement-height: ${height}px; }`}</style>
|
|
131
|
+
</>
|
|
132
|
+
))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Read the dismissed flag from localStorage.
|
|
137
|
+
*
|
|
138
|
+
* @private
|
|
139
|
+
* @param id - Announcement ID, or undefined.
|
|
140
|
+
* @returns true when the announcement has been dismissed.
|
|
141
|
+
*/
|
|
142
|
+
function readDismissed(id: string | undefined): boolean {
|
|
143
|
+
return match(id)
|
|
144
|
+
.with(undefined, () => false)
|
|
145
|
+
.otherwise((key) => {
|
|
146
|
+
if (globalThis.window === undefined) {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
return globalThis.localStorage.getItem(STORAGE_PREFIX + key) === '1'
|
|
151
|
+
} catch {
|
|
152
|
+
return false
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Persist the dismissed flag to localStorage.
|
|
159
|
+
*
|
|
160
|
+
* @private
|
|
161
|
+
* @param id - Announcement ID, or undefined.
|
|
162
|
+
*/
|
|
163
|
+
function writeDismissed(id: string | undefined): void {
|
|
164
|
+
match(id)
|
|
165
|
+
.with(undefined, () => {})
|
|
166
|
+
.otherwise((key) => {
|
|
167
|
+
try {
|
|
168
|
+
globalThis.localStorage.setItem(STORAGE_PREFIX + key, '1')
|
|
169
|
+
} catch {
|
|
170
|
+
// ignore — storage may be unavailable
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.cp-ask-ai {
|
|
2
|
+
position: fixed;
|
|
3
|
+
bottom: var(--cp-s-20);
|
|
4
|
+
right: var(--cp-s-20);
|
|
5
|
+
z-index: var(--cp-z-floating);
|
|
6
|
+
display: inline-flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
gap: var(--cp-s-8);
|
|
9
|
+
padding: var(--cp-s-10) var(--cp-s-14);
|
|
10
|
+
background: var(--cp-c-bg-soft);
|
|
11
|
+
border: 1px solid var(--cp-c-border);
|
|
12
|
+
border-radius: var(--cp-radius-pill);
|
|
13
|
+
color: var(--cp-c-text-1);
|
|
14
|
+
font-family: var(--cp-font-family-base);
|
|
15
|
+
font-size: var(--cp-fs-ask-ai);
|
|
16
|
+
font-weight: 500;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
box-shadow: var(--cp-shadow-ask-ai);
|
|
19
|
+
backdrop-filter: blur(var(--cp-blur-base));
|
|
20
|
+
transition: border-color var(--cp-duration-fast) var(--cp-ease-base);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.cp-ask-ai:hover {
|
|
24
|
+
border-color: var(--cp-c-brand-soft);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.cp-ask-ai__icon {
|
|
28
|
+
width: var(--cp-size-ask-ai-icon);
|
|
29
|
+
height: var(--cp-size-ask-ai-icon);
|
|
30
|
+
border-radius: 50%;
|
|
31
|
+
background: var(--cp-gradient-brand);
|
|
32
|
+
display: grid;
|
|
33
|
+
place-items: center;
|
|
34
|
+
color: var(--cp-c-brand-fg);
|
|
35
|
+
font-family: var(--cp-font-family-mono);
|
|
36
|
+
font-size: var(--cp-fs-ask-ai-mark);
|
|
37
|
+
font-weight: 700;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.cp-ask-ai__label {
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.cp-ask-ai__shortcut {
|
|
45
|
+
font-family: var(--cp-font-family-mono);
|
|
46
|
+
font-size: var(--cp-fs-ask-ai-shortcut);
|
|
47
|
+
color: var(--cp-c-text-3);
|
|
48
|
+
padding: var(--cp-s-1) var(--cp-s-5);
|
|
49
|
+
border: 1px solid var(--cp-c-border);
|
|
50
|
+
border-radius: var(--cp-radius-xs-sm);
|
|
51
|
+
margin-left: var(--cp-s-4);
|
|
52
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { match } from 'massaman/match'
|
|
2
|
+
import React, { useCallback } from 'react'
|
|
3
|
+
|
|
4
|
+
import './ask-ai-button.css'
|
|
5
|
+
|
|
6
|
+
export interface AskAIButtonProps {
|
|
7
|
+
/**
|
|
8
|
+
* Click handler. When omitted, the button does nothing.
|
|
9
|
+
*/
|
|
10
|
+
readonly onClick?: () => void
|
|
11
|
+
/**
|
|
12
|
+
* Visible label. Defaults to "Ask AI".
|
|
13
|
+
*/
|
|
14
|
+
readonly label?: string
|
|
15
|
+
/**
|
|
16
|
+
* Optional shortcut hint (e.g. "⌘J").
|
|
17
|
+
*/
|
|
18
|
+
readonly shortcut?: string
|
|
19
|
+
/**
|
|
20
|
+
* Pre-positioned glyph for the badge (default: ★).
|
|
21
|
+
*/
|
|
22
|
+
readonly badge?: React.ReactNode
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* AskAIButton — floating CTA pill anchored bottom-right of the viewport.
|
|
27
|
+
* Visual sibling of the page chrome; pairs with AI-search integrations.
|
|
28
|
+
*
|
|
29
|
+
* @param props - AskAIButton configuration.
|
|
30
|
+
* @returns React element.
|
|
31
|
+
*/
|
|
32
|
+
export function AskAIButton(props: AskAIButtonProps): React.ReactElement {
|
|
33
|
+
const { onClick, label = 'Ask AI', shortcut, badge = '★' } = props
|
|
34
|
+
|
|
35
|
+
const handleClick = useCallback(() => {
|
|
36
|
+
match(onClick)
|
|
37
|
+
.with(undefined, () => {})
|
|
38
|
+
.otherwise((fn) => {
|
|
39
|
+
fn()
|
|
40
|
+
})
|
|
41
|
+
}, [onClick])
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<button className="cp-ask-ai" type="button" onClick={handleClick} aria-label={label}>
|
|
45
|
+
<span className="cp-ask-ai__icon" aria-hidden="true">
|
|
46
|
+
{badge}
|
|
47
|
+
</span>
|
|
48
|
+
<span className="cp-ask-ai__label">{label}</span>
|
|
49
|
+
{match(shortcut)
|
|
50
|
+
.with(undefined, () => null)
|
|
51
|
+
.otherwise((s) => (
|
|
52
|
+
<span className="cp-ask-ai__shortcut">{s}</span>
|
|
53
|
+
))}
|
|
54
|
+
</button>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import { createPortal } from 'react-dom'
|
|
3
|
+
|
|
4
|
+
export interface ContentFooterPortalProps {
|
|
5
|
+
/**
|
|
6
|
+
* Children to portal into the in-rail doc footer slot.
|
|
7
|
+
*/
|
|
8
|
+
readonly children: React.ReactNode
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const HOST_ATTR = 'data-cp-content-footer-host'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ContentFooterPortal — portals its children into Rspress's `.rp-doc-footer`
|
|
15
|
+
* so the content lives INSIDE the doc rail (at the reading width) rather
|
|
16
|
+
* than at body level (where the `afterDoc` slot otherwise lands).
|
|
17
|
+
*
|
|
18
|
+
* Inserts a sentinel div as the FIRST child of `.rp-doc-footer` so the
|
|
19
|
+
* portalled content appears above Rspress's built-in `.rp-prev-next-page`
|
|
20
|
+
* pager. Watches DOM mutations so the portal re-attaches on client-side
|
|
21
|
+
* route changes (Rspress re-renders the doc-footer per page).
|
|
22
|
+
*
|
|
23
|
+
* @param props - Portal configuration.
|
|
24
|
+
* @returns React element.
|
|
25
|
+
*/
|
|
26
|
+
export function ContentFooterPortal(props: ContentFooterPortalProps): React.ReactElement | null {
|
|
27
|
+
const [host, setHost] = useState<HTMLElement | null>(null)
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
function ensureHost(): HTMLElement | null {
|
|
31
|
+
const docFooter = globalThis.document.querySelector('.rp-doc-footer')
|
|
32
|
+
if (docFooter === null) {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
const existing = docFooter.querySelector(`[${HOST_ATTR}]`) as HTMLElement | null
|
|
36
|
+
if (existing !== null) {
|
|
37
|
+
return existing
|
|
38
|
+
}
|
|
39
|
+
const node = globalThis.document.createElement('div')
|
|
40
|
+
node.setAttribute(HOST_ATTR, '')
|
|
41
|
+
const first = docFooter.firstChild
|
|
42
|
+
if (first === null) {
|
|
43
|
+
docFooter.append(node)
|
|
44
|
+
} else {
|
|
45
|
+
first.before(node)
|
|
46
|
+
}
|
|
47
|
+
return node
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setHost(ensureHost())
|
|
51
|
+
|
|
52
|
+
const observer = new globalThis.MutationObserver(() => {
|
|
53
|
+
const next = ensureHost()
|
|
54
|
+
setHost((prev) => {
|
|
55
|
+
if (prev !== null && prev.isConnected) {
|
|
56
|
+
return prev
|
|
57
|
+
}
|
|
58
|
+
return next
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
observer.observe(globalThis.document.body, { childList: true, subtree: true })
|
|
62
|
+
|
|
63
|
+
return () => observer.disconnect()
|
|
64
|
+
}, [])
|
|
65
|
+
|
|
66
|
+
if (host === null) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
return createPortal(<div className="cp-content-footer">{props.children}</div>, host)
|
|
70
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
.cp-feedback {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
padding: 14px 16px;
|
|
6
|
+
border: 1px solid var(--cp-c-border);
|
|
7
|
+
border-radius: var(--cp-radius-card);
|
|
8
|
+
margin-bottom: 24px;
|
|
9
|
+
background: var(--cp-c-bg-soft);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.cp-feedback__q {
|
|
13
|
+
font-size: 13px;
|
|
14
|
+
color: var(--cp-c-text-1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.cp-feedback__actions {
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: 6px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.cp-feedback__btn {
|
|
23
|
+
display: inline-flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 6px;
|
|
26
|
+
padding: 6px 12px;
|
|
27
|
+
font-size: 12px;
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
font-family: inherit;
|
|
30
|
+
border-radius: var(--cp-radius-pill);
|
|
31
|
+
border: 1px solid var(--cp-c-border);
|
|
32
|
+
background: transparent;
|
|
33
|
+
color: var(--cp-c-text-1);
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
transition: all 0.15s ease;
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.cp-feedback__btn:hover {
|
|
40
|
+
background: var(--cp-c-bg-elv);
|
|
41
|
+
border-color: var(--cp-c-border);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.cp-feedback__thanks {
|
|
45
|
+
font-size: 13px;
|
|
46
|
+
color: var(--cp-c-text-2);
|
|
47
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { match } from 'massaman/match'
|
|
2
|
+
import React, { useCallback, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
import './feedback.css'
|
|
5
|
+
|
|
6
|
+
export interface FeedbackProps {
|
|
7
|
+
/**
|
|
8
|
+
* Question shown to the reader. Defaults to "Was this page helpful?".
|
|
9
|
+
*/
|
|
10
|
+
readonly question?: string
|
|
11
|
+
/**
|
|
12
|
+
* Optional callback invoked with the user's answer.
|
|
13
|
+
*/
|
|
14
|
+
readonly onSubmit?: (answer: 'yes' | 'no') => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type FeedbackState = 'idle' | 'yes' | 'no'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Feedback — yes/no widget rendered at the bottom of doc pages.
|
|
21
|
+
* Submitting hides the buttons and shows a thank-you message.
|
|
22
|
+
*
|
|
23
|
+
* @param props - Feedback configuration.
|
|
24
|
+
* @returns React element.
|
|
25
|
+
*/
|
|
26
|
+
export function Feedback(props: FeedbackProps): React.ReactElement {
|
|
27
|
+
const { question = 'Was this page helpful?', onSubmit } = props
|
|
28
|
+
const [state, setState] = useState<FeedbackState>('idle')
|
|
29
|
+
|
|
30
|
+
const handleClick = useCallback(
|
|
31
|
+
(answer: 'yes' | 'no') => () => {
|
|
32
|
+
setState(answer)
|
|
33
|
+
match(onSubmit)
|
|
34
|
+
.with(undefined, () => {})
|
|
35
|
+
.otherwise((fn) => {
|
|
36
|
+
fn(answer)
|
|
37
|
+
})
|
|
38
|
+
},
|
|
39
|
+
[onSubmit]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="cp-feedback">
|
|
44
|
+
{match(state)
|
|
45
|
+
.with('idle', () => (
|
|
46
|
+
<>
|
|
47
|
+
<span className="cp-feedback__q">{question}</span>
|
|
48
|
+
<div className="cp-feedback__actions">
|
|
49
|
+
<button className="cp-feedback__btn" type="button" onClick={handleClick('yes')}>
|
|
50
|
+
<ThumbIcon />
|
|
51
|
+
Yes
|
|
52
|
+
</button>
|
|
53
|
+
<button className="cp-feedback__btn" type="button" onClick={handleClick('no')}>
|
|
54
|
+
<ThumbIcon flipped />
|
|
55
|
+
No
|
|
56
|
+
</button>
|
|
57
|
+
</div>
|
|
58
|
+
</>
|
|
59
|
+
))
|
|
60
|
+
.otherwise(() => (
|
|
61
|
+
<span className="cp-feedback__thanks">Thanks for the feedback.</span>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface ThumbIconProps {
|
|
68
|
+
readonly flipped?: boolean
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Thumb icon used in feedback buttons.
|
|
73
|
+
*
|
|
74
|
+
* @private
|
|
75
|
+
* @param props - Whether to flip the icon (for thumbs-down).
|
|
76
|
+
* @returns SVG element.
|
|
77
|
+
*/
|
|
78
|
+
function ThumbIcon(props: ThumbIconProps): React.ReactElement {
|
|
79
|
+
const transform = match(props.flipped === true)
|
|
80
|
+
.with(true, () => 'rotate(180deg)')
|
|
81
|
+
.otherwise(() => 'none')
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<svg
|
|
85
|
+
width="11"
|
|
86
|
+
height="11"
|
|
87
|
+
viewBox="0 0 24 24"
|
|
88
|
+
fill="none"
|
|
89
|
+
stroke="currentColor"
|
|
90
|
+
strokeWidth="2"
|
|
91
|
+
style={{ transform }}
|
|
92
|
+
>
|
|
93
|
+
<path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" />
|
|
94
|
+
</svg>
|
|
95
|
+
)
|
|
96
|
+
}
|