@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
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { useLocation } from '@rspress/core/runtime'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { match } from 'massaman/match'
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
5
|
+
import type React from 'react'
|
|
6
|
+
|
|
7
|
+
import { RouteLink } from '../../lib/route-link.tsx'
|
|
8
|
+
import { Icon } from '../shared/icon.tsx'
|
|
9
|
+
|
|
10
|
+
import './ciderpress-nav-menu.css'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Width reserved at the end of the menu strip for the overflow toggle
|
|
14
|
+
* (the "More ▾" button). Subtracted from the available width when
|
|
15
|
+
* deciding how many items can fit inline.
|
|
16
|
+
*/
|
|
17
|
+
const OVERFLOW_TOGGLE_WIDTH = 96
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Inter-item gap matching `--cp-nav-menu-gap`. Used during width
|
|
21
|
+
* accounting so we don't have to query computed style on every frame.
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_GAP_PX = 16
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Single primary-nav entry — matches the shape of `site.nav[*]` in
|
|
27
|
+
* `ciderpress.config.ts`.
|
|
28
|
+
*/
|
|
29
|
+
export interface CiderpressNavMenuItem {
|
|
30
|
+
readonly text: string
|
|
31
|
+
readonly link: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Props for `<CiderpressNavMenu />`.
|
|
36
|
+
*/
|
|
37
|
+
export interface CiderpressNavMenuProps {
|
|
38
|
+
readonly items: readonly CiderpressNavMenuItem[]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Primary nav menu with overflow → dropdown handling. Renders all items
|
|
43
|
+
* inline when they fit; when the container is too narrow, the trailing
|
|
44
|
+
* items collapse into a "More ▾" popover so the strip never pushes off
|
|
45
|
+
* screen.
|
|
46
|
+
*
|
|
47
|
+
* Sizing is measured with a `ResizeObserver` on the wrapper plus a
|
|
48
|
+
* hidden measurement row that always renders every item at full width.
|
|
49
|
+
* The hidden row gives us a stable per-item width to walk against the
|
|
50
|
+
* live available width.
|
|
51
|
+
*
|
|
52
|
+
* @param props - Item list
|
|
53
|
+
* @returns Nav element
|
|
54
|
+
*/
|
|
55
|
+
export function CiderpressNavMenu(props: CiderpressNavMenuProps): React.ReactElement {
|
|
56
|
+
// Pull items from props when configured, otherwise fall back to scraping
|
|
57
|
+
// Rspress's hidden `.rp-nav-menu` (it's the source of truth at runtime
|
|
58
|
+
// when the `nav` field isn't exposed on the Rspress site typings).
|
|
59
|
+
const [scrapedItems, setScrapedItems] = useState<readonly CiderpressNavMenuItem[]>([])
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (props.items.length > 0) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
const initial = scrapeNavItems()
|
|
65
|
+
if (initial.length > 0) {
|
|
66
|
+
setScrapedItems(initial)
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
const observer = new MutationObserver(() => {
|
|
70
|
+
const fresh = scrapeNavItems()
|
|
71
|
+
if (fresh.length > 0) {
|
|
72
|
+
setScrapedItems(fresh)
|
|
73
|
+
observer.disconnect()
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
observer.observe(document.body, { childList: true, subtree: true })
|
|
77
|
+
return () => {
|
|
78
|
+
observer.disconnect()
|
|
79
|
+
}
|
|
80
|
+
}, [props.items])
|
|
81
|
+
const items = useMemo<readonly CiderpressNavMenuItem[]>(
|
|
82
|
+
() =>
|
|
83
|
+
match(props.items.length > 0)
|
|
84
|
+
.with(true, () => props.items)
|
|
85
|
+
.otherwise(() => scrapedItems),
|
|
86
|
+
[props.items, scrapedItems]
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
90
|
+
const measureRef = useRef<HTMLDivElement>(null)
|
|
91
|
+
const [visibleCount, setVisibleCount] = useState(items.length)
|
|
92
|
+
const [overflowOpen, setOverflowOpen] = useState(false)
|
|
93
|
+
const overflowRef = useRef<HTMLDivElement>(null)
|
|
94
|
+
const { pathname } = useLocation()
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
const container = containerRef.current
|
|
98
|
+
const measure = measureRef.current
|
|
99
|
+
if (container === null || measure === null) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// We observe the menu's PARENT (the wrap), not the menu itself.
|
|
104
|
+
// Measuring the menu would self-collapse: when items hide, the
|
|
105
|
+
// menu shrinks, clientWidth drops, the budget shrinks, more items
|
|
106
|
+
// hide. Observing the parent gives us a width that's a function of
|
|
107
|
+
// the layout (not of how many items we currently render).
|
|
108
|
+
const parent = container.parentElement
|
|
109
|
+
if (parent === null) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const observer = new ResizeObserver(() => {
|
|
114
|
+
setVisibleCount(computeMenuFit({ measure, parent, container }))
|
|
115
|
+
})
|
|
116
|
+
observer.observe(parent)
|
|
117
|
+
const observedChildren = [...parent.children].filter(
|
|
118
|
+
(child) => child !== container && inLayoutFlow(child)
|
|
119
|
+
)
|
|
120
|
+
observedChildren.map((child) => observer.observe(child))
|
|
121
|
+
setVisibleCount(computeMenuFit({ measure, parent, container }))
|
|
122
|
+
return () => {
|
|
123
|
+
observer.disconnect()
|
|
124
|
+
}
|
|
125
|
+
}, [items])
|
|
126
|
+
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
if (!overflowOpen) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
function onDocClick(event: MouseEvent): void {
|
|
132
|
+
const target = event.target as Node | null
|
|
133
|
+
if (
|
|
134
|
+
target !== null &&
|
|
135
|
+
overflowRef.current !== null &&
|
|
136
|
+
!overflowRef.current.contains(target)
|
|
137
|
+
) {
|
|
138
|
+
setOverflowOpen(false)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
document.addEventListener('mousedown', onDocClick)
|
|
142
|
+
return () => {
|
|
143
|
+
document.removeEventListener('mousedown', onDocClick)
|
|
144
|
+
}
|
|
145
|
+
}, [overflowOpen])
|
|
146
|
+
|
|
147
|
+
const visible = items.slice(0, visibleCount)
|
|
148
|
+
const overflow = items.slice(visibleCount)
|
|
149
|
+
const hasOverflow = overflow.length > 0
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<>
|
|
153
|
+
<div ref={measureRef} className="cp-nav-menu-measure" aria-hidden="true">
|
|
154
|
+
{items.map((item) => (
|
|
155
|
+
<span key={item.link} data-cp-menu-item className="cp-nav-menu__item">
|
|
156
|
+
{item.text}
|
|
157
|
+
</span>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<nav ref={containerRef} className="cp-nav-menu" aria-label="Primary">
|
|
162
|
+
{visible.map((item) => (
|
|
163
|
+
<RouteLink
|
|
164
|
+
key={item.link}
|
|
165
|
+
href={item.link}
|
|
166
|
+
className={clsx('cp-nav-menu__item', {
|
|
167
|
+
'cp-nav-menu__item--active': isActive(pathname, item.link),
|
|
168
|
+
})}
|
|
169
|
+
>
|
|
170
|
+
{item.text}
|
|
171
|
+
</RouteLink>
|
|
172
|
+
))}
|
|
173
|
+
{hasOverflow && (
|
|
174
|
+
<div ref={overflowRef} className="cp-nav-menu__overflow">
|
|
175
|
+
<button
|
|
176
|
+
type="button"
|
|
177
|
+
className="cp-nav-menu__overflow-toggle"
|
|
178
|
+
onClick={() => setOverflowOpen((open) => !open)}
|
|
179
|
+
aria-haspopup="menu"
|
|
180
|
+
aria-expanded={overflowOpen}
|
|
181
|
+
>
|
|
182
|
+
<span>More</span>
|
|
183
|
+
<Icon icon="pixelarticons:chevron-down" width={12} height={12} />
|
|
184
|
+
</button>
|
|
185
|
+
{overflowOpen && (
|
|
186
|
+
<ul className="cp-nav-menu__overflow-popover" role="menu">
|
|
187
|
+
{overflow.map((item) => (
|
|
188
|
+
<li key={item.link} role="none">
|
|
189
|
+
<RouteLink
|
|
190
|
+
href={item.link}
|
|
191
|
+
role="menuitem"
|
|
192
|
+
className={clsx('cp-nav-menu__overflow-item', {
|
|
193
|
+
'cp-nav-menu__overflow-item--active': isActive(pathname, item.link),
|
|
194
|
+
})}
|
|
195
|
+
onClick={() => setOverflowOpen(false)}
|
|
196
|
+
>
|
|
197
|
+
{item.text}
|
|
198
|
+
</RouteLink>
|
|
199
|
+
</li>
|
|
200
|
+
))}
|
|
201
|
+
</ul>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
)}
|
|
205
|
+
</nav>
|
|
206
|
+
</>
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export { CiderpressNavMenu as default }
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Walk the per-item widths left-to-right, accumulating until we'd
|
|
214
|
+
* exceed the available width. When the accumulator already exceeds the
|
|
215
|
+
* cheap-fit budget, reserve space for the overflow toggle so the toggle
|
|
216
|
+
* itself doesn't push the last visible item out.
|
|
217
|
+
*
|
|
218
|
+
* @private
|
|
219
|
+
*/
|
|
220
|
+
function computeVisibleCount(params: {
|
|
221
|
+
readonly widths: readonly number[]
|
|
222
|
+
readonly available: number
|
|
223
|
+
readonly gap: number
|
|
224
|
+
readonly overflowReserve: number
|
|
225
|
+
}): number {
|
|
226
|
+
const { widths, available, gap, overflowReserve } = params
|
|
227
|
+
// No items, or the container hasn't been laid out yet — assume every
|
|
228
|
+
// item fits. The ResizeObserver will recompute as soon as the
|
|
229
|
+
// container has a real width.
|
|
230
|
+
if (widths.length === 0 || available <= 0) {
|
|
231
|
+
return widths.length
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const fullTotal = widths.reduce((acc, w, i) => acc + w + gapAt(i, gap), 0)
|
|
235
|
+
if (fullTotal <= available) {
|
|
236
|
+
return widths.length
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Otherwise we know we need overflow; reserve space for the toggle.
|
|
240
|
+
const budget = available - overflowReserve
|
|
241
|
+
const walked = widths.reduce<{
|
|
242
|
+
readonly running: number
|
|
243
|
+
readonly count: number
|
|
244
|
+
readonly done: boolean
|
|
245
|
+
}>(
|
|
246
|
+
(state, width, index) => {
|
|
247
|
+
if (state.done) {
|
|
248
|
+
return state
|
|
249
|
+
}
|
|
250
|
+
const next = state.running + width + gapAt(index, gap)
|
|
251
|
+
if (next > budget) {
|
|
252
|
+
return { ...state, done: true }
|
|
253
|
+
}
|
|
254
|
+
return { running: next, count: state.count + 1, done: false }
|
|
255
|
+
},
|
|
256
|
+
{ running: 0, count: 0, done: false }
|
|
257
|
+
)
|
|
258
|
+
return walked.count
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Gap to add before the item at `index` when summing widths. Index 0
|
|
263
|
+
* has no leading gap; subsequent items get the menu's inter-item gap.
|
|
264
|
+
*
|
|
265
|
+
* @private
|
|
266
|
+
* @param index - Position of the item in the width array.
|
|
267
|
+
* @param gap - Inter-item gap in pixels.
|
|
268
|
+
* @returns Leading gap to add before this item.
|
|
269
|
+
*/
|
|
270
|
+
function gapAt(index: number, gap: number): number {
|
|
271
|
+
if (index === 0) {
|
|
272
|
+
return 0
|
|
273
|
+
}
|
|
274
|
+
return gap
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Read every anchor under Rspress's hidden `.rp-nav-menu` and project
|
|
279
|
+
* it into a `{ text, link }` item. Anchors with empty text or `href`
|
|
280
|
+
* are dropped so we never surface a placeholder entry.
|
|
281
|
+
*
|
|
282
|
+
* @private
|
|
283
|
+
* @returns Nav items currently in the DOM (empty array when not mounted).
|
|
284
|
+
*/
|
|
285
|
+
function scrapeNavItems(): readonly CiderpressNavMenuItem[] {
|
|
286
|
+
const anchors = document.querySelectorAll<HTMLAnchorElement>('.rp-nav-menu .rp-nav-menu__item a')
|
|
287
|
+
return [...anchors]
|
|
288
|
+
.map((anchor) => ({
|
|
289
|
+
text: readAnchorText(anchor),
|
|
290
|
+
link: anchor.getAttribute('href') ?? '',
|
|
291
|
+
}))
|
|
292
|
+
.filter((item) => item.text !== '' && item.link !== '')
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Pull the trimmed text content from an anchor. Returns an empty
|
|
297
|
+
* string when `textContent` is missing — callers treat empty as "skip
|
|
298
|
+
* this anchor".
|
|
299
|
+
*
|
|
300
|
+
* @private
|
|
301
|
+
* @param anchor - Anchor element to read.
|
|
302
|
+
* @returns Trimmed inner text, or empty string when absent.
|
|
303
|
+
*/
|
|
304
|
+
function readAnchorText(anchor: HTMLAnchorElement): string {
|
|
305
|
+
const text = anchor.textContent
|
|
306
|
+
if (text === null) {
|
|
307
|
+
return ''
|
|
308
|
+
}
|
|
309
|
+
return text.trim()
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Exclude elements removed from the layout — the hidden measure layer
|
|
314
|
+
* is `position: absolute`, anything `display: none` is gone, anything
|
|
315
|
+
* `visibility: hidden` still occupies space so it stays counted. We
|
|
316
|
+
* only want flex-contributing siblings.
|
|
317
|
+
*
|
|
318
|
+
* @private
|
|
319
|
+
* @param child - Sibling element to test.
|
|
320
|
+
* @returns True when the element contributes to the parent's flex layout.
|
|
321
|
+
*/
|
|
322
|
+
function inLayoutFlow(child: Element): boolean {
|
|
323
|
+
const cs = globalThis.getComputedStyle(child)
|
|
324
|
+
return cs.display !== 'none' && cs.position !== 'absolute' && cs.position !== 'fixed'
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Compute how many items fit inline given the live layout. Measures
|
|
329
|
+
* each item's full-width footprint from the hidden measure row, then
|
|
330
|
+
* subtracts every layout sibling's width (plus inter-flex gaps) from
|
|
331
|
+
* the parent's clientWidth to derive the budget for the menu strip.
|
|
332
|
+
*
|
|
333
|
+
* @private
|
|
334
|
+
* @param params - Refs to the measure row, container, and parent.
|
|
335
|
+
* @returns Number of items that fit inline.
|
|
336
|
+
*/
|
|
337
|
+
function computeMenuFit(params: {
|
|
338
|
+
readonly measure: HTMLDivElement
|
|
339
|
+
readonly parent: HTMLElement
|
|
340
|
+
readonly container: HTMLDivElement
|
|
341
|
+
}): number {
|
|
342
|
+
const { measure, parent, container } = params
|
|
343
|
+
const itemElements = measure.querySelectorAll<HTMLElement>('[data-cp-menu-item]')
|
|
344
|
+
const widths = [...itemElements].map((el) => el.getBoundingClientRect().width)
|
|
345
|
+
const parentWidth = parent.clientWidth
|
|
346
|
+
const parentGap = parseFloat(globalThis.getComputedStyle(parent).columnGap || '0') || 0
|
|
347
|
+
const layoutSiblings = [...parent.children].filter(
|
|
348
|
+
(child) => child !== container && inLayoutFlow(child)
|
|
349
|
+
)
|
|
350
|
+
const siblingsWidth = layoutSiblings.reduce(
|
|
351
|
+
(sum, child) => sum + child.getBoundingClientRect().width,
|
|
352
|
+
0
|
|
353
|
+
)
|
|
354
|
+
const gapCount = Math.max(0, layoutSiblings.length + 1 - 1)
|
|
355
|
+
const available = Math.max(0, parentWidth - siblingsWidth - gapCount * parentGap)
|
|
356
|
+
return computeVisibleCount({
|
|
357
|
+
widths,
|
|
358
|
+
available,
|
|
359
|
+
gap: DEFAULT_GAP_PX,
|
|
360
|
+
overflowReserve: OVERFLOW_TOGGLE_WIDTH,
|
|
361
|
+
})
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @private
|
|
366
|
+
*/
|
|
367
|
+
function isActive(pathname: string, link: string): boolean {
|
|
368
|
+
if (link === '/') {
|
|
369
|
+
return pathname === '/'
|
|
370
|
+
}
|
|
371
|
+
return pathname.startsWith(link)
|
|
372
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CiderpressNavSearch — pill-shaped trigger that opens Rspress's
|
|
3
|
+
* search modal via a synthetic Cmd+K event.
|
|
4
|
+
*
|
|
5
|
+
* Theme-author API:
|
|
6
|
+
* --cp-nav-search-bg background colour
|
|
7
|
+
* --cp-nav-search-border border colour (idle)
|
|
8
|
+
* --cp-nav-search-border-hover border colour on hover
|
|
9
|
+
* --cp-nav-search-color text colour
|
|
10
|
+
* --cp-nav-search-width total button width (default 200px)
|
|
11
|
+
* --cp-nav-search-radius pill radius (default 999px)
|
|
12
|
+
* --cp-nav-search-padding horizontal padding (default 12px)
|
|
13
|
+
*/
|
|
14
|
+
.cp-nav-search {
|
|
15
|
+
display: inline-flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: 8px;
|
|
18
|
+
width: var(--cp-nav-search-width, 160px);
|
|
19
|
+
height: 32px;
|
|
20
|
+
padding: 0 var(--cp-nav-search-padding, 12px);
|
|
21
|
+
background: var(--cp-nav-search-bg, var(--cp-c-bg-soft));
|
|
22
|
+
border: 1px solid var(--cp-nav-search-border, var(--cp-c-border));
|
|
23
|
+
border-radius: var(--cp-nav-search-radius, 8px);
|
|
24
|
+
color: var(--cp-nav-search-color, var(--cp-c-text-3));
|
|
25
|
+
font-family: var(--cp-font-family-base);
|
|
26
|
+
font-size: 13px;
|
|
27
|
+
font-weight: 500;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
transition:
|
|
30
|
+
border-color 0.15s ease,
|
|
31
|
+
color 0.15s ease;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.cp-nav-search:hover {
|
|
35
|
+
border-color: var(--cp-nav-search-border-hover, var(--cp-c-brand-1));
|
|
36
|
+
color: var(--cp-c-text-1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.cp-nav-search__icon {
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
color: var(--cp-c-text-3);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.cp-nav-search__label {
|
|
45
|
+
flex: 1 1 auto;
|
|
46
|
+
text-align: left;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.cp-nav-search__hotkey {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 1px;
|
|
53
|
+
flex-shrink: 0;
|
|
54
|
+
padding: 1px 5px;
|
|
55
|
+
background: var(--cp-c-bg-elv, rgba(255, 255, 255, 0.08));
|
|
56
|
+
border: 1px solid var(--cp-c-border);
|
|
57
|
+
border-radius: 4px;
|
|
58
|
+
font-family: inherit;
|
|
59
|
+
font-size: 11px;
|
|
60
|
+
line-height: 1.2;
|
|
61
|
+
color: var(--cp-c-text-3);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (max-width: 640px) {
|
|
65
|
+
.cp-nav-search__label,
|
|
66
|
+
.cp-nav-search__hotkey {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
.cp-nav-search {
|
|
70
|
+
width: auto;
|
|
71
|
+
padding: 0 10px;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Icon } from '../shared/icon.tsx'
|
|
4
|
+
|
|
5
|
+
import './ciderpress-nav-search.css'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Search trigger button. Click dispatches a synthetic `Cmd+K` keyboard
|
|
9
|
+
* event so Rspress's underlying search modal opens — same shortcut the
|
|
10
|
+
* user can press globally. We don't reach into Rspress's search
|
|
11
|
+
* internals; the keyboard handler is the public contract.
|
|
12
|
+
*
|
|
13
|
+
* @returns Search trigger button
|
|
14
|
+
*/
|
|
15
|
+
export function CiderpressNavSearch(): React.ReactElement {
|
|
16
|
+
return (
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
className="cp-nav-search"
|
|
20
|
+
onClick={dispatchSearchHotkey}
|
|
21
|
+
aria-label="Search docs"
|
|
22
|
+
>
|
|
23
|
+
<Icon icon="pixelarticons:search" width={16} height={16} className="cp-nav-search__icon" />
|
|
24
|
+
<span className="cp-nav-search__label">Search</span>
|
|
25
|
+
<kbd className="cp-nav-search__hotkey" aria-hidden="true">
|
|
26
|
+
<span>⌘</span>
|
|
27
|
+
<span>K</span>
|
|
28
|
+
</kbd>
|
|
29
|
+
</button>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Dispatch a synthetic `Cmd+K` (mac) or `Ctrl+K` (everything else)
|
|
35
|
+
* `keydown` so Rspress's global search modal opens. Modifier choice is
|
|
36
|
+
* driven off `navigator.platform`, which is the same heuristic
|
|
37
|
+
* Rspress's own shortcut handler uses.
|
|
38
|
+
*
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
function dispatchSearchHotkey(): void {
|
|
42
|
+
const isMac = typeof navigator !== 'undefined' && navigator.platform.toLowerCase().includes('mac')
|
|
43
|
+
const event = new KeyboardEvent('keydown', {
|
|
44
|
+
key: 'k',
|
|
45
|
+
code: 'KeyK',
|
|
46
|
+
keyCode: 75,
|
|
47
|
+
metaKey: isMac,
|
|
48
|
+
ctrlKey: !isMac,
|
|
49
|
+
bubbles: true,
|
|
50
|
+
cancelable: true,
|
|
51
|
+
})
|
|
52
|
+
document.dispatchEvent(event)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { CiderpressNavSearch as default }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CiderpressNavSocialLinks — icon cluster in the topbar right zone.
|
|
3
|
+
*
|
|
4
|
+
* Theme-author API:
|
|
5
|
+
* --cp-nav-social-gap spacing between icons (default 4px)
|
|
6
|
+
* --cp-nav-social-color icon colour (idle)
|
|
7
|
+
* --cp-nav-social-color-hover icon colour on hover
|
|
8
|
+
* --cp-nav-social-size clickable area (default 32px)
|
|
9
|
+
*/
|
|
10
|
+
.cp-nav-social {
|
|
11
|
+
display: inline-flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: var(--cp-nav-social-gap, 4px);
|
|
14
|
+
flex-shrink: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.cp-nav-social__item {
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
width: var(--cp-nav-social-size, 32px);
|
|
22
|
+
height: var(--cp-nav-social-size, 32px);
|
|
23
|
+
border-radius: 6px;
|
|
24
|
+
color: var(--cp-nav-social-color, var(--cp-c-text-2));
|
|
25
|
+
text-decoration: none;
|
|
26
|
+
transition:
|
|
27
|
+
color 0.15s ease,
|
|
28
|
+
background 0.15s ease;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.cp-nav-social__item:hover {
|
|
32
|
+
background: var(--cp-c-bg-soft);
|
|
33
|
+
color: var(--cp-nav-social-color-hover, var(--cp-c-brand-1));
|
|
34
|
+
text-decoration: none;
|
|
35
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type React from 'react'
|
|
2
|
+
|
|
3
|
+
import { safeUrl } from '../../lib/safe-url.ts'
|
|
4
|
+
import { Icon } from '../shared/icon.tsx'
|
|
5
|
+
|
|
6
|
+
import './ciderpress-nav-social-links.css'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Single social-link entry — matches the shape of `socialLinks` in
|
|
10
|
+
* `ciderpress.config.ts`.
|
|
11
|
+
*/
|
|
12
|
+
export interface CiderpressSocialLink {
|
|
13
|
+
readonly icon: string
|
|
14
|
+
readonly mode: string
|
|
15
|
+
readonly content: string
|
|
16
|
+
readonly label?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface CiderpressNavSocialLinksProps {
|
|
20
|
+
readonly links: readonly CiderpressSocialLink[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Maps Rspress's social-link `icon` slugs to pixelarticons icon ids.
|
|
25
|
+
* Fallback for unmapped slugs is the generic `link` glyph.
|
|
26
|
+
*/
|
|
27
|
+
const ICON_MAP: Readonly<Record<string, string>> = Object.freeze({
|
|
28
|
+
github: 'pixelarticons:github',
|
|
29
|
+
npm: 'pixelarticons:package',
|
|
30
|
+
twitter: 'pixelarticons:twitter',
|
|
31
|
+
x: 'pixelarticons:twitter',
|
|
32
|
+
discord: 'pixelarticons:chat',
|
|
33
|
+
youtube: 'pixelarticons:play',
|
|
34
|
+
bluesky: 'pixelarticons:bluesky',
|
|
35
|
+
mastodon: 'pixelarticons:user',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Renders the configured social links as a cluster of icon buttons in
|
|
40
|
+
* the topbar. Returns `null` when no links are configured.
|
|
41
|
+
*
|
|
42
|
+
* @param props - List of social links from `site.socialLinks`
|
|
43
|
+
* @returns Cluster of icon links, or `null`
|
|
44
|
+
*/
|
|
45
|
+
export function CiderpressNavSocialLinks(
|
|
46
|
+
props: CiderpressNavSocialLinksProps
|
|
47
|
+
): React.ReactElement | null {
|
|
48
|
+
if (props.links.length === 0) {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const safeLinks = props.links
|
|
53
|
+
.map((link) => ({ link, href: safeUrl(link.content) }))
|
|
54
|
+
.filter((entry): entry is { readonly link: CiderpressSocialLink; readonly href: string } => {
|
|
55
|
+
if (entry.href === null) {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
return entry.href.length > 0
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
if (safeLinks.length === 0) {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div className="cp-nav-social">
|
|
67
|
+
{safeLinks.map(({ link, href }) => (
|
|
68
|
+
<a
|
|
69
|
+
key={link.content}
|
|
70
|
+
href={href}
|
|
71
|
+
target="_blank"
|
|
72
|
+
rel="noopener noreferrer"
|
|
73
|
+
className="cp-nav-social__item"
|
|
74
|
+
aria-label={link.label ?? link.icon}
|
|
75
|
+
>
|
|
76
|
+
<Icon
|
|
77
|
+
icon={ICON_MAP[link.icon.toLowerCase()] ?? 'pixelarticons:link'}
|
|
78
|
+
width={20}
|
|
79
|
+
height={20}
|
|
80
|
+
/>
|
|
81
|
+
</a>
|
|
82
|
+
))}
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { CiderpressNavSocialLinks as default }
|