@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,200 @@
|
|
|
1
|
+
import { match, P } from 'massaman/match'
|
|
2
|
+
import type React from 'react'
|
|
3
|
+
|
|
4
|
+
import { CodeSample } from './code-sample'
|
|
5
|
+
import { MethodBadge } from './method-badge'
|
|
6
|
+
import { ParametersTable } from './parameters-table'
|
|
7
|
+
import { RequestBody } from './request-body'
|
|
8
|
+
import { ResponseList } from './response-list'
|
|
9
|
+
import { SecurityBadges } from './security-badges'
|
|
10
|
+
import { resolveBaseUrl, resolveOperation, resolveSecurities } from './spec-utils'
|
|
11
|
+
|
|
12
|
+
export interface OpenAPIOperationProps {
|
|
13
|
+
/**
|
|
14
|
+
* Parsed OpenAPI spec object.
|
|
15
|
+
*/
|
|
16
|
+
readonly spec: Record<string, unknown>
|
|
17
|
+
/**
|
|
18
|
+
* HTTP method (get, post, put, patch, delete).
|
|
19
|
+
*/
|
|
20
|
+
readonly method: string
|
|
21
|
+
/**
|
|
22
|
+
* URL path (e.g. /users/{id}).
|
|
23
|
+
*/
|
|
24
|
+
readonly path: string
|
|
25
|
+
/**
|
|
26
|
+
* Operation ID for identification.
|
|
27
|
+
*/
|
|
28
|
+
readonly operationId: string
|
|
29
|
+
/**
|
|
30
|
+
* Pre-rendered markdown for the SSG-MD pass.
|
|
31
|
+
* When provided and `import.meta.env.SSG_MD` is true, this string
|
|
32
|
+
* is rendered instead of the interactive UI.
|
|
33
|
+
*/
|
|
34
|
+
readonly markdown?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Main OpenAPI operation page component.
|
|
39
|
+
*
|
|
40
|
+
* Two-column layout: left column shows spec details (header,
|
|
41
|
+
* parameters, request body, responses, security), right column
|
|
42
|
+
* shows auto-generated code examples.
|
|
43
|
+
*
|
|
44
|
+
* @param props - Operation props with spec, method, path, and operationId
|
|
45
|
+
* @returns React element with operation details and code examples
|
|
46
|
+
*/
|
|
47
|
+
export function OpenAPIOperation({
|
|
48
|
+
spec,
|
|
49
|
+
method,
|
|
50
|
+
path,
|
|
51
|
+
operationId,
|
|
52
|
+
markdown,
|
|
53
|
+
}: OpenAPIOperationProps): React.ReactElement {
|
|
54
|
+
if (import.meta.env.SSG_MD && markdown) {
|
|
55
|
+
return <>{markdown}</>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const operation = resolveOperation({ spec, path, method })
|
|
59
|
+
|
|
60
|
+
return match(operation)
|
|
61
|
+
.with(P.nonNullable, (op) => {
|
|
62
|
+
const parameters = (op['parameters'] ?? []) as readonly Record<string, unknown>[]
|
|
63
|
+
const requestBody = op['requestBody'] as Record<string, unknown> | undefined
|
|
64
|
+
const responses = (op['responses'] ?? {}) as Record<string, unknown>
|
|
65
|
+
const summary = op['summary'] as string | undefined
|
|
66
|
+
const description = op['description'] as string | undefined
|
|
67
|
+
const deprecated = op['deprecated'] === true
|
|
68
|
+
const securities = resolveSecurities({ operation: op, spec })
|
|
69
|
+
const baseUrl = resolveBaseUrl(spec)
|
|
70
|
+
|
|
71
|
+
const displaySummary: string | undefined = match(summary)
|
|
72
|
+
.with(P.nonNullable, (s) => s)
|
|
73
|
+
.otherwise(() =>
|
|
74
|
+
match(description)
|
|
75
|
+
.with(P.nonNullable, (d) => d as string | undefined)
|
|
76
|
+
.otherwise(() => undefined as string | undefined)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const parametersEl = match(parameters)
|
|
80
|
+
.with(
|
|
81
|
+
P.when((p): p is readonly Record<string, unknown>[] => p.length > 0),
|
|
82
|
+
(p) => <ParametersTable parameters={p} />
|
|
83
|
+
)
|
|
84
|
+
.otherwise(() => null)
|
|
85
|
+
|
|
86
|
+
const requestBodyEl = match(requestBody)
|
|
87
|
+
.with(P.nonNullable, (rb) => <RequestBody requestBody={rb} />)
|
|
88
|
+
.otherwise(() => null)
|
|
89
|
+
|
|
90
|
+
const responsesEl = match(Object.keys(responses))
|
|
91
|
+
.with(
|
|
92
|
+
P.when((k): k is string[] => k.length > 0),
|
|
93
|
+
() => <ResponseList responses={responses} />
|
|
94
|
+
)
|
|
95
|
+
.otherwise(() => null)
|
|
96
|
+
|
|
97
|
+
const securityEl = match(securities)
|
|
98
|
+
.with(
|
|
99
|
+
P.when((s): s is readonly Record<string, unknown>[] => s.length > 0),
|
|
100
|
+
(s) => <SecurityBadges securities={s} />
|
|
101
|
+
)
|
|
102
|
+
.otherwise(() => null)
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className="cp-oas-operation">
|
|
106
|
+
<div className="cp-oas-operation-spec">
|
|
107
|
+
<OperationHeader
|
|
108
|
+
method={method}
|
|
109
|
+
path={path}
|
|
110
|
+
operationId={operationId}
|
|
111
|
+
summary={displaySummary}
|
|
112
|
+
deprecated={deprecated}
|
|
113
|
+
/>
|
|
114
|
+
{parametersEl}
|
|
115
|
+
{requestBodyEl}
|
|
116
|
+
{responsesEl}
|
|
117
|
+
{securityEl}
|
|
118
|
+
</div>
|
|
119
|
+
<div className="cp-oas-operation-examples">
|
|
120
|
+
<CodeSample
|
|
121
|
+
method={method}
|
|
122
|
+
path={path}
|
|
123
|
+
baseUrl={baseUrl}
|
|
124
|
+
parameters={parameters}
|
|
125
|
+
requestBody={requestBody}
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
)
|
|
130
|
+
})
|
|
131
|
+
.otherwise(() => <NotFound method={method} path={path} />)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Render the operation header with method badge, path, and optional deprecation tag.
|
|
136
|
+
*
|
|
137
|
+
* @private
|
|
138
|
+
* @param props - Header props including method, path, operationId, summary, and deprecated flag
|
|
139
|
+
* @returns Header element
|
|
140
|
+
*/
|
|
141
|
+
function OperationHeader({
|
|
142
|
+
method,
|
|
143
|
+
path,
|
|
144
|
+
operationId,
|
|
145
|
+
summary,
|
|
146
|
+
deprecated,
|
|
147
|
+
}: {
|
|
148
|
+
readonly method: string
|
|
149
|
+
readonly path: string
|
|
150
|
+
readonly operationId: string
|
|
151
|
+
readonly summary: string | undefined
|
|
152
|
+
readonly deprecated: boolean
|
|
153
|
+
}): React.ReactElement {
|
|
154
|
+
const summaryEl = match(summary)
|
|
155
|
+
.with(P.nonNullable, (s) => <div className="cp-oas-operation-summary">{s}</div>)
|
|
156
|
+
.otherwise(() => null)
|
|
157
|
+
|
|
158
|
+
const deprecatedEl = match(deprecated)
|
|
159
|
+
.with(true, () => <span className="cp-oas-operation-deprecated">Deprecated</span>)
|
|
160
|
+
.otherwise(() => null)
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<div>
|
|
164
|
+
<div className="cp-oas-operation-header">
|
|
165
|
+
<MethodBadge method={method} />
|
|
166
|
+
<span className="cp-oas-operation-header__path">{path}</span>
|
|
167
|
+
{deprecatedEl}
|
|
168
|
+
</div>
|
|
169
|
+
<div className="cp-oas-operation-header__id">{operationId}</div>
|
|
170
|
+
{summaryEl}
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Render a fallback when the operation is not found in the spec.
|
|
177
|
+
*
|
|
178
|
+
* @private
|
|
179
|
+
* @param props - Props with method and path
|
|
180
|
+
* @returns Not-found element
|
|
181
|
+
*/
|
|
182
|
+
function NotFound({
|
|
183
|
+
method,
|
|
184
|
+
path,
|
|
185
|
+
}: {
|
|
186
|
+
readonly method: string
|
|
187
|
+
readonly path: string
|
|
188
|
+
}): React.ReactElement {
|
|
189
|
+
return (
|
|
190
|
+
<div className="cp-oas-operation">
|
|
191
|
+
<div className="cp-oas-operation-spec">
|
|
192
|
+
<div className="cp-oas-operation-header">
|
|
193
|
+
<MethodBadge method={method} />
|
|
194
|
+
<span className="cp-oas-operation-header__path">{path}</span>
|
|
195
|
+
</div>
|
|
196
|
+
<div className="cp-oas-operation-summary">Operation not found in the provided spec.</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { countBy } from 'massaman/array'
|
|
2
|
+
import { identity } from 'massaman/function'
|
|
3
|
+
import { match, P } from 'massaman/match'
|
|
4
|
+
import type React from 'react'
|
|
5
|
+
import { useMemo } from 'react'
|
|
6
|
+
|
|
7
|
+
import { LockIcon } from './icons'
|
|
8
|
+
import { HTTP_METHODS } from './spec-utils'
|
|
9
|
+
|
|
10
|
+
export interface OpenAPIOverviewProps {
|
|
11
|
+
/**
|
|
12
|
+
* Parsed OpenAPI spec object.
|
|
13
|
+
*/
|
|
14
|
+
readonly spec: Record<string, unknown>
|
|
15
|
+
/**
|
|
16
|
+
* Pre-rendered markdown for the SSG-MD pass.
|
|
17
|
+
* When provided and `import.meta.env.SSG_MD` is true, this string
|
|
18
|
+
* is rendered instead of the interactive UI.
|
|
19
|
+
*/
|
|
20
|
+
readonly markdown?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface TagInfo {
|
|
24
|
+
readonly name: string
|
|
25
|
+
readonly description: string
|
|
26
|
+
readonly operationCount: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* API overview page component.
|
|
31
|
+
*
|
|
32
|
+
* Renders the API title, version, description, server URLs,
|
|
33
|
+
* authentication schemes, and tag groups with operation counts.
|
|
34
|
+
*
|
|
35
|
+
* @param props - Overview props with parsed spec
|
|
36
|
+
* @returns React element with full API overview
|
|
37
|
+
*/
|
|
38
|
+
export function OpenAPIOverview({ spec, markdown }: OpenAPIOverviewProps): React.ReactElement {
|
|
39
|
+
if (import.meta.env.SSG_MD && markdown) {
|
|
40
|
+
return <>{markdown}</>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const info = (spec['info'] ?? {}) as Record<string, unknown>
|
|
44
|
+
const description = info['description'] as string | undefined
|
|
45
|
+
const servers = (spec['servers'] ?? []) as readonly Record<string, unknown>[]
|
|
46
|
+
const components = (spec['components'] ?? {}) as Record<string, unknown>
|
|
47
|
+
const securitySchemes = (components['securitySchemes'] ?? {}) as Record<
|
|
48
|
+
string,
|
|
49
|
+
Record<string, unknown>
|
|
50
|
+
>
|
|
51
|
+
const tags = useMemo(() => collectTags(spec), [spec])
|
|
52
|
+
|
|
53
|
+
const descEl = match(description)
|
|
54
|
+
.with(P.nonNullable, (d) => <div className="cp-oas-overview__description">{d}</div>)
|
|
55
|
+
.otherwise(() => null)
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="cp-oas-overview">
|
|
59
|
+
{descEl}
|
|
60
|
+
<ServerList servers={servers} />
|
|
61
|
+
<AuthSchemes schemes={securitySchemes} />
|
|
62
|
+
<TagGroups tags={tags} />
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Collect all tags from the spec and count their operations.
|
|
69
|
+
*
|
|
70
|
+
* @private
|
|
71
|
+
* @param spec - Parsed OpenAPI spec object
|
|
72
|
+
* @returns Array of tag info with operation counts
|
|
73
|
+
*/
|
|
74
|
+
function collectTags(spec: Record<string, unknown>): readonly TagInfo[] {
|
|
75
|
+
const paths = (spec['paths'] ?? {}) as Record<string, Record<string, unknown>>
|
|
76
|
+
|
|
77
|
+
const allTags = Object.values(paths).flatMap((pathItem) =>
|
|
78
|
+
HTTP_METHODS.filter((method) => pathItem[method] !== undefined).flatMap((method) => {
|
|
79
|
+
const operation = pathItem[method] as Record<string, unknown>
|
|
80
|
+
const tags = (operation['tags'] ?? ['default']) as readonly string[]
|
|
81
|
+
return tags
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const tagMap = countBy(allTags, identity)
|
|
86
|
+
|
|
87
|
+
const specTags = (spec['tags'] ?? []) as readonly Record<string, unknown>[]
|
|
88
|
+
const specTagMap = Object.fromEntries(
|
|
89
|
+
specTags.map((t) => [String(t['name'] ?? ''), String(t['description'] ?? '')])
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return Object.entries(tagMap).map(([name, count]) => ({
|
|
93
|
+
name,
|
|
94
|
+
description: specTagMap[name] ?? '',
|
|
95
|
+
operationCount: count,
|
|
96
|
+
}))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Render the server list section.
|
|
101
|
+
*
|
|
102
|
+
* @private
|
|
103
|
+
* @param props - Props with servers array
|
|
104
|
+
* @returns Server list element or null
|
|
105
|
+
*/
|
|
106
|
+
function ServerList({
|
|
107
|
+
servers,
|
|
108
|
+
}: {
|
|
109
|
+
readonly servers: readonly Record<string, unknown>[]
|
|
110
|
+
}): React.ReactElement | null {
|
|
111
|
+
return match(servers)
|
|
112
|
+
.with(
|
|
113
|
+
P.when((s): s is readonly Record<string, unknown>[] => s.length > 0),
|
|
114
|
+
(s) => (
|
|
115
|
+
<div className="cp-oas-servers">
|
|
116
|
+
<div className="cp-oas-overview__section-title">Servers</div>
|
|
117
|
+
{s.map((server) => {
|
|
118
|
+
const url = String(server['url'] ?? '')
|
|
119
|
+
const description = server['description'] as string | undefined
|
|
120
|
+
const descEl = match(description)
|
|
121
|
+
.with(P.nonNullable, (d) => (
|
|
122
|
+
<span className="cp-oas-server__description">{` — ${d}`}</span>
|
|
123
|
+
))
|
|
124
|
+
.otherwise(() => null)
|
|
125
|
+
return (
|
|
126
|
+
<div key={url} className="cp-oas-server">
|
|
127
|
+
<span className="cp-oas-server__url">{url}</span>
|
|
128
|
+
{descEl}
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
})}
|
|
132
|
+
</div>
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
.otherwise(() => null)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Render the authentication schemes section.
|
|
140
|
+
*
|
|
141
|
+
* @private
|
|
142
|
+
* @param props - Props with security schemes
|
|
143
|
+
* @returns Auth schemes element or null
|
|
144
|
+
*/
|
|
145
|
+
function AuthSchemes({
|
|
146
|
+
schemes,
|
|
147
|
+
}: {
|
|
148
|
+
readonly schemes: Record<string, Record<string, unknown>>
|
|
149
|
+
}): React.ReactElement | null {
|
|
150
|
+
const entries = Object.entries(schemes)
|
|
151
|
+
return match(entries)
|
|
152
|
+
.with(
|
|
153
|
+
P.when((e): e is [string, Record<string, unknown>][] => e.length > 0),
|
|
154
|
+
(e) => (
|
|
155
|
+
<div className="cp-oas-auth-schemes">
|
|
156
|
+
<div className="cp-oas-overview__section-title">Authentication</div>
|
|
157
|
+
{e.map(([name, scheme]) => (
|
|
158
|
+
<div key={name} className="cp-oas-auth-scheme">
|
|
159
|
+
<LockIcon />
|
|
160
|
+
<span className="cp-oas-auth-scheme__name">{name}</span>
|
|
161
|
+
<span className="cp-oas-auth-scheme__type">{String(scheme['type'] ?? '')}</span>
|
|
162
|
+
</div>
|
|
163
|
+
))}
|
|
164
|
+
</div>
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
.otherwise(() => null)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Render the tag groups section with operation counts.
|
|
172
|
+
*
|
|
173
|
+
* @private
|
|
174
|
+
* @param props - Props with tags array
|
|
175
|
+
* @returns Tag groups element or null
|
|
176
|
+
*/
|
|
177
|
+
function TagGroups({ tags }: { readonly tags: readonly TagInfo[] }): React.ReactElement | null {
|
|
178
|
+
return match(tags)
|
|
179
|
+
.with(
|
|
180
|
+
P.when((t): t is readonly TagInfo[] => t.length > 0),
|
|
181
|
+
(t) => (
|
|
182
|
+
<div className="cp-oas-tags">
|
|
183
|
+
<div className="cp-oas-overview__section-title">Operations</div>
|
|
184
|
+
{t.map((tag) => {
|
|
185
|
+
const descEl = match(tag.description)
|
|
186
|
+
.with(
|
|
187
|
+
P.when((d): d is string => d.length > 0),
|
|
188
|
+
(d) => <div className="cp-oas-tag-group__description">{d}</div>
|
|
189
|
+
)
|
|
190
|
+
.otherwise(() => null)
|
|
191
|
+
return (
|
|
192
|
+
<div key={tag.name} className="cp-oas-tag-group">
|
|
193
|
+
<div className="cp-oas-tag-group__header">
|
|
194
|
+
<span className="cp-oas-tag-group__name">{tag.name}</span>
|
|
195
|
+
<span className="cp-oas-tag-group__count">
|
|
196
|
+
{`${String(tag.operationCount)} operations`}
|
|
197
|
+
</span>
|
|
198
|
+
</div>
|
|
199
|
+
{descEl}
|
|
200
|
+
</div>
|
|
201
|
+
)
|
|
202
|
+
})}
|
|
203
|
+
</div>
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
.otherwise(() => null)
|
|
207
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { match, P } from 'massaman/match'
|
|
2
|
+
import type React from 'react'
|
|
3
|
+
|
|
4
|
+
export interface ParametersTableProps {
|
|
5
|
+
/**
|
|
6
|
+
* OpenAPI parameter objects.
|
|
7
|
+
*/
|
|
8
|
+
readonly parameters: readonly Record<string, unknown>[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface ParameterGroup {
|
|
12
|
+
readonly label: string
|
|
13
|
+
readonly items: readonly Record<string, unknown>[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Renders operation parameters grouped by location (path, query, header).
|
|
18
|
+
*
|
|
19
|
+
* Each group displays a table with name, type, required, description, and default columns.
|
|
20
|
+
*
|
|
21
|
+
* @param props - Parameters table props
|
|
22
|
+
* @returns React element or null if no parameters
|
|
23
|
+
*/
|
|
24
|
+
export function ParametersTable({ parameters }: ParametersTableProps): React.ReactElement | null {
|
|
25
|
+
const groups = groupByIn(parameters)
|
|
26
|
+
|
|
27
|
+
return match(groups)
|
|
28
|
+
.with(
|
|
29
|
+
P.when((g): g is readonly ParameterGroup[] => g.length > 0),
|
|
30
|
+
(g) => (
|
|
31
|
+
<div className="cp-oas-parameters">
|
|
32
|
+
<div className="cp-oas-parameters__title">Parameters</div>
|
|
33
|
+
{g.map(renderGroup)}
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
.otherwise(() => null)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Group parameters by their `in` field (path, query, header, etc.).
|
|
42
|
+
*
|
|
43
|
+
* @private
|
|
44
|
+
* @param params - OpenAPI parameter objects
|
|
45
|
+
* @returns Array of parameter groups
|
|
46
|
+
*/
|
|
47
|
+
function groupByIn(params: readonly Record<string, unknown>[]): readonly ParameterGroup[] {
|
|
48
|
+
const grouped = Map.groupBy(params, (param) => String(param['in'] ?? 'other'))
|
|
49
|
+
return [...grouped.entries()].map(([label, items]) => ({ label, items }))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Render a required badge if the parameter is required.
|
|
54
|
+
*
|
|
55
|
+
* @private
|
|
56
|
+
* @param param - OpenAPI parameter object
|
|
57
|
+
* @returns Required badge element or null
|
|
58
|
+
*/
|
|
59
|
+
function renderRequired(param: Record<string, unknown>): React.ReactElement | null {
|
|
60
|
+
return match(param['required'])
|
|
61
|
+
.with(true, () => <span className="cp-oas-parameters__required">required</span>)
|
|
62
|
+
.otherwise(() => null)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Render a default value badge if one exists in the parameter schema.
|
|
67
|
+
*
|
|
68
|
+
* @private
|
|
69
|
+
* @param param - OpenAPI parameter object
|
|
70
|
+
* @returns Default value element or null
|
|
71
|
+
*/
|
|
72
|
+
function renderDefault(param: Record<string, unknown>): React.ReactElement | null {
|
|
73
|
+
const schemaDefault = match(param['schema'])
|
|
74
|
+
.with(P.nonNullable, (schema) => (schema as Record<string, unknown>)['default'])
|
|
75
|
+
.otherwise(() => null)
|
|
76
|
+
const defaultValue = schemaDefault ?? param['default']
|
|
77
|
+
|
|
78
|
+
return match(defaultValue)
|
|
79
|
+
.with(P.nonNullable, (def) => <span className="cp-oas-parameters__default">{String(def)}</span>)
|
|
80
|
+
.otherwise(() => null)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Extract the type string from a parameter's schema.
|
|
85
|
+
*
|
|
86
|
+
* @private
|
|
87
|
+
* @param param - OpenAPI parameter object
|
|
88
|
+
* @returns Type string or dash placeholder
|
|
89
|
+
*/
|
|
90
|
+
function extractType(param: Record<string, unknown>): string {
|
|
91
|
+
const schemaType = match(param['schema'])
|
|
92
|
+
.with(
|
|
93
|
+
P.nonNullable,
|
|
94
|
+
(schema) => (schema as Record<string, unknown>)['type'] as string | undefined
|
|
95
|
+
)
|
|
96
|
+
.otherwise(() => null)
|
|
97
|
+
|
|
98
|
+
return String(schemaType ?? param['type'] ?? '—')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Render a single parameter row in the table.
|
|
103
|
+
*
|
|
104
|
+
* @private
|
|
105
|
+
* @param param - OpenAPI parameter object
|
|
106
|
+
* @returns Table row element
|
|
107
|
+
*/
|
|
108
|
+
function renderRow(param: Record<string, unknown>): React.ReactElement {
|
|
109
|
+
return (
|
|
110
|
+
<tr key={String(param['name'])}>
|
|
111
|
+
<td>
|
|
112
|
+
<span className="cp-oas-parameters__name">{String(param['name'] ?? '')}</span>
|
|
113
|
+
</td>
|
|
114
|
+
<td>
|
|
115
|
+
<span className="cp-oas-parameters__type">{extractType(param)}</span>
|
|
116
|
+
</td>
|
|
117
|
+
<td>{renderRequired(param)}</td>
|
|
118
|
+
<td>{String(param['description'] ?? '')}</td>
|
|
119
|
+
<td>{renderDefault(param)}</td>
|
|
120
|
+
</tr>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Render a parameter group with its label and table.
|
|
126
|
+
*
|
|
127
|
+
* @private
|
|
128
|
+
* @param group - Parameter group with label and items
|
|
129
|
+
* @returns Group container element
|
|
130
|
+
*/
|
|
131
|
+
function renderGroup(group: ParameterGroup): React.ReactElement {
|
|
132
|
+
return (
|
|
133
|
+
<div key={group.label}>
|
|
134
|
+
<div className="cp-oas-parameters__group-label">{group.label}</div>
|
|
135
|
+
<table className="cp-oas-parameters__table">
|
|
136
|
+
<thead>
|
|
137
|
+
<tr>
|
|
138
|
+
<th>Name</th>
|
|
139
|
+
<th>Type</th>
|
|
140
|
+
<th>Required</th>
|
|
141
|
+
<th>Description</th>
|
|
142
|
+
<th>Default</th>
|
|
143
|
+
</tr>
|
|
144
|
+
</thead>
|
|
145
|
+
<tbody>{group.items.map(renderRow)}</tbody>
|
|
146
|
+
</table>
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { CodeBlockRuntime } from '@rspress/core/theme'
|
|
2
|
+
import { match, P } from 'massaman/match'
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
|
|
5
|
+
import { SchemaViewer } from './schema-viewer'
|
|
6
|
+
|
|
7
|
+
export interface RequestBodyProps {
|
|
8
|
+
/**
|
|
9
|
+
* OpenAPI requestBody object.
|
|
10
|
+
*/
|
|
11
|
+
readonly requestBody: Record<string, unknown>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ParsedContent {
|
|
15
|
+
readonly contentType: string
|
|
16
|
+
readonly schema: Record<string, unknown>
|
|
17
|
+
readonly example: unknown | null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Renders the request body section of an OpenAPI operation.
|
|
22
|
+
*
|
|
23
|
+
* Shows the content type, description, schema tree, and example payload.
|
|
24
|
+
*
|
|
25
|
+
* @param props - Request body props
|
|
26
|
+
* @returns React element with request body details
|
|
27
|
+
*/
|
|
28
|
+
export function RequestBody({ requestBody }: RequestBodyProps): React.ReactElement {
|
|
29
|
+
const description = requestBody['description'] as string | undefined
|
|
30
|
+
const parsed = extractFirstContent(requestBody)
|
|
31
|
+
|
|
32
|
+
const descEl = match(description)
|
|
33
|
+
.with(P.nonNullable, (d) => <div className="cp-oas-request-body__description">{d}</div>)
|
|
34
|
+
.otherwise(() => null)
|
|
35
|
+
|
|
36
|
+
const bodyEl = match(parsed)
|
|
37
|
+
.with(P.nonNullable, (p) => (
|
|
38
|
+
<div>
|
|
39
|
+
<div className="cp-oas-request-body__content-type">{p.contentType}</div>
|
|
40
|
+
<SchemaViewer schema={p.schema} />
|
|
41
|
+
</div>
|
|
42
|
+
))
|
|
43
|
+
.otherwise(() => null)
|
|
44
|
+
|
|
45
|
+
const exampleEl = match(parsed)
|
|
46
|
+
.with(P.nonNullable, (p) =>
|
|
47
|
+
match(p.example)
|
|
48
|
+
.with(P.nonNullable, (ex) => (
|
|
49
|
+
<CodeBlockRuntime lang="json" code={JSON.stringify(ex, null, 2)} />
|
|
50
|
+
))
|
|
51
|
+
.otherwise(() => null)
|
|
52
|
+
)
|
|
53
|
+
.otherwise(() => null)
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="cp-oas-request-body">
|
|
57
|
+
<div className="cp-oas-request-body__title">Request Body</div>
|
|
58
|
+
{descEl}
|
|
59
|
+
{bodyEl}
|
|
60
|
+
{exampleEl}
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Extract the first content type entry from a request body.
|
|
67
|
+
*
|
|
68
|
+
* @private
|
|
69
|
+
* @param requestBody - OpenAPI request body object
|
|
70
|
+
* @returns Parsed content with type, schema, and example, or null
|
|
71
|
+
*/
|
|
72
|
+
function extractFirstContent(requestBody: Record<string, unknown>): ParsedContent | null {
|
|
73
|
+
const content = requestBody['content'] as Record<string, Record<string, unknown>> | undefined
|
|
74
|
+
return match(content)
|
|
75
|
+
.with(P.nonNullable, (c) => {
|
|
76
|
+
const entries = Object.entries(c)
|
|
77
|
+
return match(entries)
|
|
78
|
+
.with(
|
|
79
|
+
P.when((e): e is [string, Record<string, unknown>][] => e.length > 0),
|
|
80
|
+
(e) => {
|
|
81
|
+
const [[contentType, mediaType]] = e
|
|
82
|
+
const schema = (mediaType['schema'] ?? {}) as Record<string, unknown>
|
|
83
|
+
const { example } = mediaType as { readonly example?: unknown }
|
|
84
|
+
return { contentType, schema, example: example ?? null }
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
.otherwise(() => null)
|
|
88
|
+
})
|
|
89
|
+
.otherwise(() => null)
|
|
90
|
+
}
|