@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,426 @@
|
|
|
1
|
+
import { useFrontmatter, useLocation } from '@rspress/core/runtime'
|
|
2
|
+
import {
|
|
3
|
+
LlmsContainer,
|
|
4
|
+
LlmsCopyButton,
|
|
5
|
+
LlmsViewOptions,
|
|
6
|
+
ReadPercent,
|
|
7
|
+
renderInlineMarkdown,
|
|
8
|
+
Toc,
|
|
9
|
+
useActiveAnchor,
|
|
10
|
+
useDynamicToc,
|
|
11
|
+
} from '@rspress/core/theme'
|
|
12
|
+
import { match, P } from 'massaman/match'
|
|
13
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
14
|
+
import type React from 'react'
|
|
15
|
+
|
|
16
|
+
import { RouteLink } from '../../lib/route-link.tsx'
|
|
17
|
+
import { Icon } from '../shared/icon.tsx'
|
|
18
|
+
import { useCiderpressLayout } from './ciderpress-layout-context'
|
|
19
|
+
|
|
20
|
+
import './ciderpress-docs-bar.css'
|
|
21
|
+
|
|
22
|
+
const SIDEBAR_STORAGE_KEY = 'ciderpress-sidebar-collapsed'
|
|
23
|
+
const SIDEBAR_HTML_ATTR = 'cpSidebarCollapsed'
|
|
24
|
+
const OUTLINE_STORAGE_KEY = 'ciderpress-outline-collapsed'
|
|
25
|
+
const OUTLINE_HTML_ATTR = 'cpOutlineCollapsed'
|
|
26
|
+
/**
|
|
27
|
+
* Below this viewport width, the sidebar behaves as a fixed overlay
|
|
28
|
+
* drawer (drawer-base rules ship in `sidebar/sidebar-toggle.css` —
|
|
29
|
+
* Rspress only provides the rules natively at <=768px, so the same
|
|
30
|
+
* stylesheet extends them up to 1279px to keep this threshold). Above,
|
|
31
|
+
* the sidebar is a sticky rail — `data-cp-sidebar-collapsed` is the
|
|
32
|
+
* right toggle. Matches `OUTLINE_DRAWER_MAX_WIDTH` so Menu and "On
|
|
33
|
+
* this page" flip to mobile behaviour in lockstep — and matches the
|
|
34
|
+
* CSS half (`sidebar-toggle.css`) so clicks fire the right state on
|
|
35
|
+
* either side of the threshold.
|
|
36
|
+
*/
|
|
37
|
+
const SIDEBAR_DRAWER_MAX_WIDTH = 1279
|
|
38
|
+
/**
|
|
39
|
+
* Below this viewport width, Rspress styles `.rp-doc-layout__outline`
|
|
40
|
+
* as a fixed overlay drawer (DocLayout/index.css `@media (width <= 1279px)`).
|
|
41
|
+
* Above, the outline is a sticky rail — `data-cp-outline-collapsed`
|
|
42
|
+
* hides it. Same caveat: must match Rspress's media query exactly.
|
|
43
|
+
*/
|
|
44
|
+
const OUTLINE_DRAWER_MAX_WIDTH = 1279
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sticky bar below the site header that replaces Rspress's built-in
|
|
48
|
+
* `.rp-doc-layout__menu` (which Ciderpress hides via CSS in `rail.css`).
|
|
49
|
+
*
|
|
50
|
+
* Left cluster: sidebar toggle + breadcrumbs (Section › Page).
|
|
51
|
+
* - Desktop (>= 960px): the toggle collapses/expands the docs sidebar
|
|
52
|
+
* via `html[data-cp-sidebar-collapsed]`, persisted to localStorage.
|
|
53
|
+
* - Narrow viewports: the toggle programmatically clicks Rspress's
|
|
54
|
+
* hidden `.rp-sidebar-menu__left` so the native sidebar drawer
|
|
55
|
+
* opens (overlay slide-in).
|
|
56
|
+
*
|
|
57
|
+
* Right cluster: "On this page" label + `<ReadPercent />` progress
|
|
58
|
+
* ring + chevron toggle for the outline rail.
|
|
59
|
+
*
|
|
60
|
+
* Mounted from `<Layout />` via `<OriginalLayout>`'s `beforeDoc` slot
|
|
61
|
+
* so it sits between the header and the doc-layout container — outside
|
|
62
|
+
* the sidebar, so it stays reachable even when the sidebar collapses.
|
|
63
|
+
*
|
|
64
|
+
* @returns Sticky docs sub-header.
|
|
65
|
+
*/
|
|
66
|
+
export function CiderpressDocsBar(): React.ReactElement | null {
|
|
67
|
+
const { pathname } = useLocation()
|
|
68
|
+
const { frontmatter } = useFrontmatter()
|
|
69
|
+
const headers = useDynamicToc()
|
|
70
|
+
const { scrolledHeader } = useActiveAnchor(headers)
|
|
71
|
+
const { isOutlineOpen, setIsSidebarOpen, setIsOutlineOpen } = useCiderpressLayout()
|
|
72
|
+
const [sidebarCollapsed, setSidebarCollapsed] = useState(readSidebarCollapsed)
|
|
73
|
+
const [outlineCollapsed, setOutlineCollapsed] = useState(readOutlineCollapsed)
|
|
74
|
+
const outlineWrapRef = useRef<HTMLDivElement | null>(null)
|
|
75
|
+
|
|
76
|
+
// Close the outline dropdown when the user clicks anywhere outside
|
|
77
|
+
// it. Cheaper than a transparent backdrop element, and means clicks
|
|
78
|
+
// *inside* the dropdown (notably on TOC `<a>` links) still bubble
|
|
79
|
+
// up to React-Router's link handler and actually navigate. Only
|
|
80
|
+
// arms while the dropdown is open.
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!isOutlineOpen) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
// Use `click` not `mousedown` — on touch devices `mousedown`
|
|
86
|
+
// fires at the START of a touch-scroll gesture, which would
|
|
87
|
+
// close the dropdown the moment the user tries to scroll the
|
|
88
|
+
// page. `click` only fires on a completed tap (no drag), so
|
|
89
|
+
// touch-scrolling outside the dropdown leaves it alone.
|
|
90
|
+
function handleDocumentClick(event: MouseEvent): void {
|
|
91
|
+
const wrap = outlineWrapRef.current
|
|
92
|
+
if (wrap === null) {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
if (event.target instanceof Node && wrap.contains(event.target)) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
setIsOutlineOpen(false)
|
|
99
|
+
}
|
|
100
|
+
globalThis.document.addEventListener('click', handleDocumentClick)
|
|
101
|
+
return () => {
|
|
102
|
+
globalThis.document.removeEventListener('click', handleDocumentClick)
|
|
103
|
+
}
|
|
104
|
+
}, [isOutlineOpen, setIsOutlineOpen])
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
applyAttr(SIDEBAR_HTML_ATTR, sidebarCollapsed)
|
|
108
|
+
}, [sidebarCollapsed])
|
|
109
|
+
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
applyAttr(OUTLINE_HTML_ATTR, outlineCollapsed)
|
|
112
|
+
}, [outlineCollapsed])
|
|
113
|
+
|
|
114
|
+
const fmRecord = frontmatter as Record<string, unknown>
|
|
115
|
+
const isHome = fmRecord.pageType === 'home'
|
|
116
|
+
const isBlank = fmRecord.pageType === 'blank'
|
|
117
|
+
|
|
118
|
+
const pageTitle = readStringField(fmRecord.title)
|
|
119
|
+
|
|
120
|
+
const breadcrumbs = buildBreadcrumbs(pathname, pageTitle)
|
|
121
|
+
const outlineEnabled = match(fmRecord.outline)
|
|
122
|
+
.with(false, () => false)
|
|
123
|
+
.otherwise(() => true)
|
|
124
|
+
|
|
125
|
+
const handleMenuClick = useCallback(() => {
|
|
126
|
+
if (globalThis.innerWidth <= SIDEBAR_DRAWER_MAX_WIDTH) {
|
|
127
|
+
setIsSidebarOpen((prev) => !prev)
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
setSidebarCollapsed((prev) => {
|
|
131
|
+
const next = !prev
|
|
132
|
+
writeStorage(SIDEBAR_STORAGE_KEY, next)
|
|
133
|
+
return next
|
|
134
|
+
})
|
|
135
|
+
}, [setIsSidebarOpen])
|
|
136
|
+
|
|
137
|
+
const handleOutlineClick = useCallback(() => {
|
|
138
|
+
if (globalThis.innerWidth <= OUTLINE_DRAWER_MAX_WIDTH) {
|
|
139
|
+
setIsOutlineOpen((prev) => !prev)
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
setOutlineCollapsed((prev) => {
|
|
143
|
+
const next = !prev
|
|
144
|
+
writeStorage(OUTLINE_STORAGE_KEY, next)
|
|
145
|
+
return next
|
|
146
|
+
})
|
|
147
|
+
}, [setIsOutlineOpen])
|
|
148
|
+
|
|
149
|
+
if (isHome || isBlank) {
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<div className="cp-docs-bar">
|
|
155
|
+
<div className="cp-docs-bar__menu">
|
|
156
|
+
<button
|
|
157
|
+
type="button"
|
|
158
|
+
className="cp-docs-bar__menu-btn"
|
|
159
|
+
onClick={handleMenuClick}
|
|
160
|
+
aria-label="Toggle sidebar"
|
|
161
|
+
>
|
|
162
|
+
<Icon icon="pixelarticons:layout-sidebar-left" width={14} height={14} />
|
|
163
|
+
<span>Menu</span>
|
|
164
|
+
</button>
|
|
165
|
+
</div>
|
|
166
|
+
<div className="cp-docs-bar__center">
|
|
167
|
+
{breadcrumbs.length > 0 && (
|
|
168
|
+
<nav className="cp-docs-bar__crumbs" aria-label="Breadcrumb">
|
|
169
|
+
<RouteLink href="/" className="cp-docs-bar__crumb-home" aria-label="Home">
|
|
170
|
+
<Icon icon="pixelarticons:home" width={14} height={14} />
|
|
171
|
+
</RouteLink>
|
|
172
|
+
{breadcrumbs.map((crumb) => (
|
|
173
|
+
<span key={crumb.href} className="cp-docs-bar__crumb-wrap">
|
|
174
|
+
<span className="cp-docs-bar__sep">›</span>
|
|
175
|
+
{match(crumb.current)
|
|
176
|
+
.with(true, () => (
|
|
177
|
+
<span className="cp-docs-bar__crumb" aria-current="page">
|
|
178
|
+
{crumb.label}
|
|
179
|
+
</span>
|
|
180
|
+
))
|
|
181
|
+
.otherwise(() => (
|
|
182
|
+
<RouteLink href={crumb.href} className="cp-docs-bar__crumb">
|
|
183
|
+
{crumb.label}
|
|
184
|
+
</RouteLink>
|
|
185
|
+
))}
|
|
186
|
+
</span>
|
|
187
|
+
))}
|
|
188
|
+
</nav>
|
|
189
|
+
)}
|
|
190
|
+
<div className="cp-docs-bar__llms">
|
|
191
|
+
<LlmsContainer>
|
|
192
|
+
<LlmsCopyButton />
|
|
193
|
+
<LlmsViewOptions />
|
|
194
|
+
</LlmsContainer>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
{outlineEnabled && (
|
|
198
|
+
<div className="cp-docs-bar__outline-wrap" ref={outlineWrapRef}>
|
|
199
|
+
<button
|
|
200
|
+
type="button"
|
|
201
|
+
className="cp-docs-bar__outline"
|
|
202
|
+
onClick={handleOutlineClick}
|
|
203
|
+
aria-label="Toggle outline"
|
|
204
|
+
aria-expanded={isOutlineOpen}
|
|
205
|
+
>
|
|
206
|
+
<span className="cp-docs-bar__label">On this page</span>
|
|
207
|
+
{match(scrolledHeader)
|
|
208
|
+
.with(P.nullish, () => null)
|
|
209
|
+
.with({ text: P.string }, (header) => (
|
|
210
|
+
<span className="cp-docs-bar__section" {...renderInlineMarkdown(header.text)} />
|
|
211
|
+
))
|
|
212
|
+
.otherwise(() => null)}
|
|
213
|
+
<ReadPercent size={14} strokeWidth={2} />
|
|
214
|
+
<Icon
|
|
215
|
+
icon="pixelarticons:chevron-down"
|
|
216
|
+
width={14}
|
|
217
|
+
height={14}
|
|
218
|
+
className="cp-docs-bar__chev"
|
|
219
|
+
/>
|
|
220
|
+
</button>
|
|
221
|
+
{isOutlineOpen && (
|
|
222
|
+
<nav
|
|
223
|
+
/* `rp-doc-layout__outline` is here ONLY so Rspress's
|
|
224
|
+
`<TocItem>` auto-scroll-into-view boundary check stops
|
|
225
|
+
at this element (its boundary returns false for
|
|
226
|
+
elements with that class). Without it the library walks
|
|
227
|
+
up past our dropdown and scrolls the WHOLE PAGE every
|
|
228
|
+
time the active section changes — which felt like the
|
|
229
|
+
page was jumping every time you opened the menu or
|
|
230
|
+
scrolled past a heading. The `cp-docs-bar__outline-dropdown`
|
|
231
|
+
styles below override every Rspress outline rule we
|
|
232
|
+
don't want (position, visibility, layout). */
|
|
233
|
+
className="cp-docs-bar__outline-dropdown rp-doc-layout__outline"
|
|
234
|
+
aria-label="On this page"
|
|
235
|
+
onClick={makeLinkClickCloser(setIsOutlineOpen)}
|
|
236
|
+
>
|
|
237
|
+
<Toc />
|
|
238
|
+
</nav>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
)}
|
|
242
|
+
</div>
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Single rendered breadcrumb — its display label, the route it links to,
|
|
248
|
+
* and whether it represents the current page (the last crumb, which
|
|
249
|
+
* renders as a non-link span with `aria-current="page"`).
|
|
250
|
+
*/
|
|
251
|
+
interface Crumb {
|
|
252
|
+
readonly label: string
|
|
253
|
+
readonly href: string
|
|
254
|
+
readonly current: boolean
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Build a 1- or 2-level breadcrumb trail from the current path and the
|
|
259
|
+
* page's frontmatter title. The section label comes from titlecasing
|
|
260
|
+
* the first path segment (e.g. `framework` → `Framework`) and links to
|
|
261
|
+
* that section's index page (`/framework/`). The page crumb links to
|
|
262
|
+
* the current pathname and is marked `current` so the renderer skips
|
|
263
|
+
* the anchor (you don't link to where you already are).
|
|
264
|
+
*
|
|
265
|
+
* @private
|
|
266
|
+
* @param pathname - The current location pathname.
|
|
267
|
+
* @param pageTitle - The page's frontmatter `title`, if defined.
|
|
268
|
+
* @returns Ordered breadcrumb entries (section first).
|
|
269
|
+
*/
|
|
270
|
+
function buildBreadcrumbs(pathname: string, pageTitle: string | undefined): readonly Crumb[] {
|
|
271
|
+
const segments = pathname.split('/').filter((s) => s !== '')
|
|
272
|
+
if (segments.length === 0) {
|
|
273
|
+
return []
|
|
274
|
+
}
|
|
275
|
+
const section = titleCase(segments[0])
|
|
276
|
+
const sectionHref = `/${segments[0]}/`
|
|
277
|
+
const pageLabel = match(pageTitle)
|
|
278
|
+
.with(P.string, (t) => t)
|
|
279
|
+
.otherwise(() =>
|
|
280
|
+
match(segments.length > 1)
|
|
281
|
+
.with(true, () => titleCase(segments.at(-1) ?? ''))
|
|
282
|
+
.otherwise(() => '')
|
|
283
|
+
)
|
|
284
|
+
return match(pageLabel === '' || pageLabel === section)
|
|
285
|
+
.with(true, () => [{ label: section, href: sectionHref, current: true }])
|
|
286
|
+
.otherwise(() => [
|
|
287
|
+
{ label: section, href: sectionHref, current: false },
|
|
288
|
+
{ label: pageLabel, href: pathname, current: true },
|
|
289
|
+
])
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Build an onClick handler for the outline TOC dropdown that closes
|
|
294
|
+
* it whenever the user clicks an `<a>` (or anything nested under
|
|
295
|
+
* one). Hash-only navigation doesn't trigger React Router's pathname
|
|
296
|
+
* effect, so the drawer-close useEffect in `<CiderpressDocLayout />`
|
|
297
|
+
* never fires for TOC clicks — this handler is what actually closes
|
|
298
|
+
* the dropdown.
|
|
299
|
+
*
|
|
300
|
+
* @private
|
|
301
|
+
* @param setIsOutlineOpen - Outline open-state setter from the layout context.
|
|
302
|
+
* @returns Click handler suitable for the dropdown root element.
|
|
303
|
+
*/
|
|
304
|
+
function makeLinkClickCloser(
|
|
305
|
+
setIsOutlineOpen: React.Dispatch<React.SetStateAction<boolean>>
|
|
306
|
+
): React.MouseEventHandler<HTMLElement> {
|
|
307
|
+
return (event) => {
|
|
308
|
+
const { target } = event
|
|
309
|
+
if (!(target instanceof HTMLElement)) {
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
if (target.closest('a') !== null) {
|
|
313
|
+
setIsOutlineOpen(false)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Convert a kebab-case path segment into Title Case.
|
|
320
|
+
*
|
|
321
|
+
* @private
|
|
322
|
+
* @param segment - A single path segment (e.g. `getting-started`).
|
|
323
|
+
* @returns Title-cased label (e.g. `Getting Started`).
|
|
324
|
+
*/
|
|
325
|
+
function titleCase(segment: string): string {
|
|
326
|
+
return segment
|
|
327
|
+
.split('-')
|
|
328
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
329
|
+
.join(' ')
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Narrow an `unknown` frontmatter field to `string`, returning a bare
|
|
334
|
+
* (no explicit `undefined`) absent value when the field is missing or
|
|
335
|
+
* non-string. Used to coerce gray-matter's loose typing into the
|
|
336
|
+
* `string | undefined` shape downstream helpers expect.
|
|
337
|
+
*
|
|
338
|
+
* @private
|
|
339
|
+
* @param value - Frontmatter field value.
|
|
340
|
+
* @returns The string when typed as such, otherwise an absent value.
|
|
341
|
+
*/
|
|
342
|
+
function readStringField(value: unknown): string | undefined {
|
|
343
|
+
if (typeof value === 'string') {
|
|
344
|
+
return value
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Read the persisted sidebar-collapsed state from localStorage.
|
|
350
|
+
*
|
|
351
|
+
* @private
|
|
352
|
+
* @returns true when the sidebar should start collapsed.
|
|
353
|
+
*/
|
|
354
|
+
function readSidebarCollapsed(): boolean {
|
|
355
|
+
return readStorage(SIDEBAR_STORAGE_KEY)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Read the persisted outline-collapsed state from localStorage.
|
|
360
|
+
*
|
|
361
|
+
* @private
|
|
362
|
+
* @returns true when the outline should start collapsed.
|
|
363
|
+
*/
|
|
364
|
+
function readOutlineCollapsed(): boolean {
|
|
365
|
+
return readStorage(OUTLINE_STORAGE_KEY)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Read a boolean flag from localStorage.
|
|
370
|
+
*
|
|
371
|
+
* @private
|
|
372
|
+
* @param key - localStorage key.
|
|
373
|
+
* @returns true when the stored value is `'1'`.
|
|
374
|
+
*/
|
|
375
|
+
function readStorage(key: string): boolean {
|
|
376
|
+
if (globalThis.window === undefined) {
|
|
377
|
+
return false
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
return globalThis.localStorage.getItem(key) === '1'
|
|
381
|
+
} catch {
|
|
382
|
+
return false
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Persist a boolean flag to localStorage. Removes the entry when
|
|
388
|
+
* `value` is false so the key is absent rather than `'0'`.
|
|
389
|
+
*
|
|
390
|
+
* @private
|
|
391
|
+
* @param key - localStorage key.
|
|
392
|
+
* @param value - true to write `'1'`, false to delete the key.
|
|
393
|
+
*/
|
|
394
|
+
function writeStorage(key: string, value: boolean): void {
|
|
395
|
+
if (globalThis.window === undefined) {
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
match(value)
|
|
400
|
+
.with(true, () => globalThis.localStorage.setItem(key, '1'))
|
|
401
|
+
.otherwise(() => globalThis.localStorage.removeItem(key))
|
|
402
|
+
} catch {
|
|
403
|
+
// ignore — storage may be unavailable
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Apply a boolean flag to the html dataset for CSS targeting.
|
|
409
|
+
*
|
|
410
|
+
* @private
|
|
411
|
+
* @param attr - Dataset key (camelCase, mapped to `data-*` by React).
|
|
412
|
+
* @param value - true to write `'true'`, false to delete the attribute.
|
|
413
|
+
*/
|
|
414
|
+
function applyAttr(attr: string, value: boolean): void {
|
|
415
|
+
if (globalThis.document === undefined) {
|
|
416
|
+
return
|
|
417
|
+
}
|
|
418
|
+
const html = globalThis.document.documentElement
|
|
419
|
+
match(value)
|
|
420
|
+
.with(true, () => {
|
|
421
|
+
html.dataset[attr] = 'true'
|
|
422
|
+
})
|
|
423
|
+
.otherwise(() => {
|
|
424
|
+
delete html.dataset[attr]
|
|
425
|
+
})
|
|
426
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CiderpressHeader — sticky site header that fully replaces Rspress's
|
|
3
|
+
* built-in `.rp-nav` chrome. All visual properties are themable via
|
|
4
|
+
* `--cp-*` custom properties.
|
|
5
|
+
*
|
|
6
|
+
* Theme-author API:
|
|
7
|
+
* --cp-header-bg background colour
|
|
8
|
+
* --cp-header-border bottom border colour
|
|
9
|
+
* --cp-header-height total row height (default 56px)
|
|
10
|
+
* --cp-header-pad-x inline padding (default 16px)
|
|
11
|
+
* --cp-header-max-width inner content max width (default 1280px)
|
|
12
|
+
* --cp-header-gap flex gap between header items (default 8px)
|
|
13
|
+
* --cp-header-z stacking index (default 60 — matches the
|
|
14
|
+
* Rspress nav slot it replaces and sits
|
|
15
|
+
* above `--rp-z-index-sidebar: 50` so the
|
|
16
|
+
* sidebar doesn't punch through when the
|
|
17
|
+
* page is scrolled)
|
|
18
|
+
*/
|
|
19
|
+
.cp-header {
|
|
20
|
+
position: sticky;
|
|
21
|
+
top: 0;
|
|
22
|
+
z-index: var(--cp-header-z, 60);
|
|
23
|
+
width: 100%;
|
|
24
|
+
background: var(--cp-header-bg, var(--cp-c-bg));
|
|
25
|
+
backdrop-filter: blur(8px);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.cp-header-inner {
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
gap: var(--cp-header-gap, 8px);
|
|
32
|
+
height: var(--cp-header-height, 56px);
|
|
33
|
+
padding: 0 var(--cp-header-pad-x, 16px);
|
|
34
|
+
margin: 0 auto;
|
|
35
|
+
/* Border lives on the inner so it stays aligned with the constrained
|
|
36
|
+
container, not the full viewport. Docs pages keep the bottom edge
|
|
37
|
+
(full-width inner). Landing also picks up left + right edges to
|
|
38
|
+
match `.cp-page-rail`'s box treatment. */
|
|
39
|
+
border-bottom: 1px solid var(--cp-header-border, var(--cp-c-border));
|
|
40
|
+
/* Allow `.cp-nav-menu__overflow-popover` to escape vertically; the
|
|
41
|
+
CiderpressNavMenu owns horizontal overflow via its own measure +
|
|
42
|
+
collapse logic. */
|
|
43
|
+
overflow: visible;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Landing / home pages: align edge-for-edge with `.cp-page-rail` so
|
|
47
|
+
the header sits inside the same outer frame as the hero. We mirror
|
|
48
|
+
page-rail's positioning rules (margin gutter under 1248px, centered
|
|
49
|
+
margin auto above) and use the same `--cp-landing-max-width` token
|
|
50
|
+
so both move together when a theme overrides the width. */
|
|
51
|
+
.cp-header--landing .cp-header-inner {
|
|
52
|
+
max-width: var(--cp-landing-max-width, 1200px);
|
|
53
|
+
margin: 0 var(--cp-frame-gutter);
|
|
54
|
+
padding: 0 16px;
|
|
55
|
+
border-left: 1px solid var(--cp-header-border, var(--cp-c-border));
|
|
56
|
+
border-right: 1px solid var(--cp-header-border, var(--cp-c-border));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (min-width: 1248px) {
|
|
60
|
+
.cp-header--landing .cp-header-inner {
|
|
61
|
+
margin: 0 auto;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Doc pages: span the full viewport, matching Rspress's sidebar + main
|
|
66
|
+
layout which already stretches edge-to-edge. */
|
|
67
|
+
.cp-header--docs .cp-header-inner {
|
|
68
|
+
max-width: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.cp-header-logo {
|
|
72
|
+
display: inline-flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
color: inherit;
|
|
76
|
+
text-decoration: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.cp-header-logo > svg {
|
|
80
|
+
height: var(--cp-header-logo-height, 28px);
|
|
81
|
+
width: auto;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* `.cp-sidebar-toggle` ships with `position: absolute; left: 16px` so it
|
|
85
|
+
pins to the far-left of its container — fine inside Rspress's own
|
|
86
|
+
`.rp-nav`, but inside our header it overlaps the logo. Restore inline
|
|
87
|
+
flex positioning so it flows alongside the other items. */
|
|
88
|
+
.cp-header-inner .cp-sidebar-toggle {
|
|
89
|
+
position: static;
|
|
90
|
+
transform: none;
|
|
91
|
+
margin: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Menu wrapper claims every pixel between the left cluster (logo) and
|
|
95
|
+
the trailing chrome (theme / socials / CTA). `justify-content:
|
|
96
|
+
flex-end` pushes both children (search + menu) to the right edge of
|
|
97
|
+
the wrapper, putting them side-by-side as a single right-anchored
|
|
98
|
+
cluster. CiderpressNavMenu observes this wrapper (not its own width)
|
|
99
|
+
to decide how many items fit — see ciderpress-nav-menu.tsx. */
|
|
100
|
+
.cp-header-menu-wrap {
|
|
101
|
+
flex: 1 1 0;
|
|
102
|
+
min-width: 0;
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
gap: 8px;
|
|
106
|
+
justify-content: flex-end;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.cp-header-menu-wrap > .cp-nav-search {
|
|
110
|
+
flex-shrink: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.cp-header-menu-wrap > .cp-nav-menu {
|
|
114
|
+
/* Reset the `width: 100%` baked into ciderpress-nav-menu.css; in the
|
|
115
|
+
header context we want the menu to size to its content so the wrap's
|
|
116
|
+
`justify-content: flex-end` cleanly pushes both search and the menu
|
|
117
|
+
items to the right edge as a single right-anchored cluster. */
|
|
118
|
+
flex: 0 1 auto;
|
|
119
|
+
width: auto;
|
|
120
|
+
min-width: 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ── Mobile collapse ───────────────────────────────────────────────
|
|
124
|
+
At <=1024px the desktop chrome (inline menu, variant toggle,
|
|
125
|
+
socials, CTA, dividers) collapses into the slide-out drawer
|
|
126
|
+
surfaced by `<CiderpressNavHamburger />`. Each of the hidden
|
|
127
|
+
elements is still in the React tree — the drawer renders its own
|
|
128
|
+
copies so nothing is actually lost from the mobile UX. The
|
|
129
|
+
threshold matches `.cp-nav-hamburger`'s show breakpoint and the
|
|
130
|
+
docs bar's mobile layout (`@media (max-width: 1024px)` everywhere)
|
|
131
|
+
so the three pieces flip to mobile in lockstep. */
|
|
132
|
+
@media (max-width: 1024px) {
|
|
133
|
+
/* Hide the chrome that the drawer surfaces. Keep the menu wrap (it
|
|
134
|
+
still holds the search button), but hide the inline menu items
|
|
135
|
+
and right-anchor the search to the viewport edge. */
|
|
136
|
+
.cp-header-inner > .cp-nav-divider,
|
|
137
|
+
.cp-header-inner > .cp-nav-social,
|
|
138
|
+
.cp-header-inner > .cp-topbar-cta,
|
|
139
|
+
.cp-header-inner > .rp-switch-appearance,
|
|
140
|
+
.cp-header-inner > .cp-variant-toggle,
|
|
141
|
+
.cp-header-inner > .cp-sidebar-toggle {
|
|
142
|
+
display: none;
|
|
143
|
+
}
|
|
144
|
+
.cp-header-menu-wrap > .cp-nav-menu,
|
|
145
|
+
.cp-header-menu-wrap > .cp-nav-divider {
|
|
146
|
+
display: none;
|
|
147
|
+
}
|
|
148
|
+
.cp-header-menu-wrap > .cp-nav-search {
|
|
149
|
+
margin-left: auto;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Hide Rspress's built-in nav entirely. Its DOM stays mounted (so the
|
|
154
|
+
keyboard-driven search modal still wires up) but it claims zero
|
|
155
|
+
visual space and zero interaction surface. */
|
|
156
|
+
html .rp-nav {
|
|
157
|
+
position: absolute !important;
|
|
158
|
+
width: 1px !important;
|
|
159
|
+
height: 1px !important;
|
|
160
|
+
padding: 0 !important;
|
|
161
|
+
border: 0 !important;
|
|
162
|
+
opacity: 0 !important;
|
|
163
|
+
pointer-events: none !important;
|
|
164
|
+
overflow: hidden !important;
|
|
165
|
+
clip: rect(0, 0, 0, 0) !important;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* `--rp-nav-height` is defined at `html:root` in
|
|
169
|
+
`styles/overrides/rail.css` to clear the announcement + header +
|
|
170
|
+
docs bar stack. Rspress 2.x dropped the `.rp-doc-container` /
|
|
171
|
+
`.rspress-doc-container` wrapper, so a scoped override here would
|
|
172
|
+
never match anything. */
|