jamdesk 1.0.0
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 +323 -0
- package/bin/jamdesk.js +76 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.d.ts +8 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.js +165 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.js.map +1 -0
- package/dist/__tests__/integration/migrate.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/migrate.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/migrate.integration.test.js +64 -0
- package/dist/__tests__/integration/migrate.integration.test.js.map +1 -0
- package/dist/__tests__/integration/prepublish.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/prepublish.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/prepublish.integration.test.js +27 -0
- package/dist/__tests__/integration/prepublish.integration.test.js.map +1 -0
- package/dist/__tests__/integration/validate.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/validate.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/validate.integration.test.js +56 -0
- package/dist/__tests__/integration/validate.integration.test.js.map +1 -0
- package/dist/__tests__/unit/deploy-templates.test.d.ts +2 -0
- package/dist/__tests__/unit/deploy-templates.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deploy-templates.test.js +124 -0
- package/dist/__tests__/unit/deploy-templates.test.js.map +1 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.d.ts +2 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.js +69 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.js.map +1 -0
- package/dist/__tests__/unit/deps-sync.test.d.ts +14 -0
- package/dist/__tests__/unit/deps-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deps-sync.test.js +166 -0
- package/dist/__tests__/unit/deps-sync.test.js.map +1 -0
- package/dist/__tests__/unit/docs-config.test.d.ts +2 -0
- package/dist/__tests__/unit/docs-config.test.d.ts.map +1 -0
- package/dist/__tests__/unit/docs-config.test.js +288 -0
- package/dist/__tests__/unit/docs-config.test.js.map +1 -0
- package/dist/__tests__/unit/errors.test.d.ts +2 -0
- package/dist/__tests__/unit/errors.test.d.ts.map +1 -0
- package/dist/__tests__/unit/errors.test.js +27 -0
- package/dist/__tests__/unit/errors.test.js.map +1 -0
- package/dist/__tests__/unit/extract-hooks.test.d.ts +5 -0
- package/dist/__tests__/unit/extract-hooks.test.d.ts.map +1 -0
- package/dist/__tests__/unit/extract-hooks.test.js +205 -0
- package/dist/__tests__/unit/extract-hooks.test.js.map +1 -0
- package/dist/__tests__/unit/frontmatter-sync.test.d.ts +8 -0
- package/dist/__tests__/unit/frontmatter-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/frontmatter-sync.test.js +26 -0
- package/dist/__tests__/unit/frontmatter-sync.test.js.map +1 -0
- package/dist/__tests__/unit/mdx-validator.test.d.ts +2 -0
- package/dist/__tests__/unit/mdx-validator.test.d.ts.map +1 -0
- package/dist/__tests__/unit/mdx-validator.test.js +264 -0
- package/dist/__tests__/unit/mdx-validator.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-convert.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-convert.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-convert.test.js +297 -0
- package/dist/__tests__/unit/migrate-convert.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-detect.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-detect.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-detect.test.js +35 -0
- package/dist/__tests__/unit/migrate-detect.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-mdx.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-mdx.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-mdx.test.js +158 -0
- package/dist/__tests__/unit/migrate-mdx.test.js.map +1 -0
- package/dist/__tests__/unit/openapi.test.d.ts +2 -0
- package/dist/__tests__/unit/openapi.test.d.ts.map +1 -0
- package/dist/__tests__/unit/openapi.test.js +52 -0
- package/dist/__tests__/unit/openapi.test.js.map +1 -0
- package/dist/__tests__/unit/package-config.test.d.ts +2 -0
- package/dist/__tests__/unit/package-config.test.d.ts.map +1 -0
- package/dist/__tests__/unit/package-config.test.js +63 -0
- package/dist/__tests__/unit/package-config.test.js.map +1 -0
- package/dist/__tests__/unit/port.test.d.ts +2 -0
- package/dist/__tests__/unit/port.test.d.ts.map +1 -0
- package/dist/__tests__/unit/port.test.js +20 -0
- package/dist/__tests__/unit/port.test.js.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.d.ts +14 -0
- package/dist/__tests__/unit/vendored-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.js +90 -0
- package/dist/__tests__/unit/vendored-sync.test.js.map +1 -0
- package/dist/commands/broken-links.d.ts +11 -0
- package/dist/commands/broken-links.d.ts.map +1 -0
- package/dist/commands/broken-links.js +95 -0
- package/dist/commands/broken-links.js.map +1 -0
- package/dist/commands/clean.d.ts +7 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +59 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/deploy/cloudflare.d.ts +12 -0
- package/dist/commands/deploy/cloudflare.d.ts.map +1 -0
- package/dist/commands/deploy/cloudflare.js +409 -0
- package/dist/commands/deploy/cloudflare.js.map +1 -0
- package/dist/commands/deploy/templates.d.ts +23 -0
- package/dist/commands/deploy/templates.d.ts.map +1 -0
- package/dist/commands/deploy/templates.js +179 -0
- package/dist/commands/deploy/templates.js.map +1 -0
- package/dist/commands/deploy/types.d.ts +19 -0
- package/dist/commands/deploy/types.d.ts.map +1 -0
- package/dist/commands/deploy/types.js +5 -0
- package/dist/commands/deploy/types.js.map +1 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +817 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +159 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +96 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate/convert-mdx.d.ts +50 -0
- package/dist/commands/migrate/convert-mdx.d.ts.map +1 -0
- package/dist/commands/migrate/convert-mdx.js +108 -0
- package/dist/commands/migrate/convert-mdx.js.map +1 -0
- package/dist/commands/migrate/convert.d.ts +80 -0
- package/dist/commands/migrate/convert.d.ts.map +1 -0
- package/dist/commands/migrate/convert.js +158 -0
- package/dist/commands/migrate/convert.js.map +1 -0
- package/dist/commands/migrate/detect.d.ts +31 -0
- package/dist/commands/migrate/detect.d.ts.map +1 -0
- package/dist/commands/migrate/detect.js +62 -0
- package/dist/commands/migrate/detect.js.map +1 -0
- package/dist/commands/migrate/extract-hooks.d.ts +71 -0
- package/dist/commands/migrate/extract-hooks.d.ts.map +1 -0
- package/dist/commands/migrate/extract-hooks.js +473 -0
- package/dist/commands/migrate/extract-hooks.js.map +1 -0
- package/dist/commands/migrate/index.d.ts +17 -0
- package/dist/commands/migrate/index.d.ts.map +1 -0
- package/dist/commands/migrate/index.js +282 -0
- package/dist/commands/migrate/index.js.map +1 -0
- package/dist/commands/migrate/prompts.d.ts +22 -0
- package/dist/commands/migrate/prompts.d.ts.map +1 -0
- package/dist/commands/migrate/prompts.js +67 -0
- package/dist/commands/migrate/prompts.js.map +1 -0
- package/dist/commands/migrate/types.d.ts +22 -0
- package/dist/commands/migrate/types.d.ts.map +1 -0
- package/dist/commands/migrate/types.js +26 -0
- package/dist/commands/migrate/types.js.map +1 -0
- package/dist/commands/openapi-check.d.ts +11 -0
- package/dist/commands/openapi-check.d.ts.map +1 -0
- package/dist/commands/openapi-check.js +88 -0
- package/dist/commands/openapi-check.js.map +1 -0
- package/dist/commands/rename.d.ts +10 -0
- package/dist/commands/rename.d.ts.map +1 -0
- package/dist/commands/rename.js +125 -0
- package/dist/commands/rename.js.map +1 -0
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +57 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +163 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +334 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +18 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deprecated-components.d.ts +72 -0
- package/dist/lib/deprecated-components.d.ts.map +1 -0
- package/dist/lib/deprecated-components.js +138 -0
- package/dist/lib/deprecated-components.js.map +1 -0
- package/dist/lib/deps.d.ts +17 -0
- package/dist/lib/deps.d.ts.map +1 -0
- package/dist/lib/deps.js +186 -0
- package/dist/lib/deps.js.map +1 -0
- package/dist/lib/docs-config.d.ts +67 -0
- package/dist/lib/docs-config.d.ts.map +1 -0
- package/dist/lib/docs-config.js +294 -0
- package/dist/lib/docs-config.js.map +1 -0
- package/dist/lib/errors.d.ts +23 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/frontmatter-utils.d.ts +25 -0
- package/dist/lib/frontmatter-utils.d.ts.map +1 -0
- package/dist/lib/frontmatter-utils.js +64 -0
- package/dist/lib/frontmatter-utils.js.map +1 -0
- package/dist/lib/mdx-validator.d.ts +27 -0
- package/dist/lib/mdx-validator.d.ts.map +1 -0
- package/dist/lib/mdx-validator.js +148 -0
- package/dist/lib/mdx-validator.js.map +1 -0
- package/dist/lib/navigation-validator.d.ts +31 -0
- package/dist/lib/navigation-validator.d.ts.map +1 -0
- package/dist/lib/navigation-validator.js +75 -0
- package/dist/lib/navigation-validator.js.map +1 -0
- package/dist/lib/normalize-config.d.ts +57 -0
- package/dist/lib/normalize-config.d.ts.map +1 -0
- package/dist/lib/normalize-config.js +63 -0
- package/dist/lib/normalize-config.js.map +1 -0
- package/dist/lib/openapi/cache.d.ts +40 -0
- package/dist/lib/openapi/cache.d.ts.map +1 -0
- package/dist/lib/openapi/cache.js +76 -0
- package/dist/lib/openapi/cache.js.map +1 -0
- package/dist/lib/openapi/errors.d.ts +36 -0
- package/dist/lib/openapi/errors.d.ts.map +1 -0
- package/dist/lib/openapi/errors.js +162 -0
- package/dist/lib/openapi/errors.js.map +1 -0
- package/dist/lib/openapi/index.d.ts +10 -0
- package/dist/lib/openapi/index.d.ts.map +1 -0
- package/dist/lib/openapi/index.js +12 -0
- package/dist/lib/openapi/index.js.map +1 -0
- package/dist/lib/openapi/types.d.ts +198 -0
- package/dist/lib/openapi/types.d.ts.map +1 -0
- package/dist/lib/openapi/types.js +8 -0
- package/dist/lib/openapi/types.js.map +1 -0
- package/dist/lib/openapi/validator.d.ts +45 -0
- package/dist/lib/openapi/validator.d.ts.map +1 -0
- package/dist/lib/openapi/validator.js +128 -0
- package/dist/lib/openapi/validator.js.map +1 -0
- package/dist/lib/openapi.d.ts +7 -0
- package/dist/lib/openapi.d.ts.map +1 -0
- package/dist/lib/openapi.js +7 -0
- package/dist/lib/openapi.js.map +1 -0
- package/dist/lib/output.d.ts +14 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +19 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/path-security.d.ts +23 -0
- package/dist/lib/path-security.d.ts.map +1 -0
- package/dist/lib/path-security.js +35 -0
- package/dist/lib/path-security.js.map +1 -0
- package/dist/lib/port.d.ts +18 -0
- package/dist/lib/port.d.ts.map +1 -0
- package/dist/lib/port.js +65 -0
- package/dist/lib/port.js.map +1 -0
- package/dist/lib/spinner.d.ts +4 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +16 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +49 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/utils/update-checker.d.ts +34 -0
- package/dist/utils/update-checker.d.ts.map +1 -0
- package/dist/utils/update-checker.js +142 -0
- package/dist/utils/update-checker.js.map +1 -0
- package/package.json +125 -0
- package/templates/docs.json +11 -0
- package/templates/introduction.mdx +19 -0
- package/templates/quickstart.mdx +20 -0
- package/vendored/app/[[...slug]]/error.tsx +103 -0
- package/vendored/app/[[...slug]]/page.tsx +690 -0
- package/vendored/app/api/assets/[...path]/route.ts +78 -0
- package/vendored/app/api/ev/route.ts +61 -0
- package/vendored/app/api/isr-health/route.ts +66 -0
- package/vendored/app/api/mcp/[project]/route.ts +435 -0
- package/vendored/app/api/og/route.tsx +167 -0
- package/vendored/app/api/r2/[project]/[...path]/route.ts +214 -0
- package/vendored/app/api/revalidate/route.ts +76 -0
- package/vendored/app/globals.css +37 -0
- package/vendored/app/layout.tsx +571 -0
- package/vendored/app/not-found.tsx +47 -0
- package/vendored/components/CodeBlockCopyButton.tsx +146 -0
- package/vendored/components/HeaderLinkCopy.tsx +135 -0
- package/vendored/components/errors/NotFoundContent.tsx +147 -0
- package/vendored/components/layout/LayoutWrapper.tsx +128 -0
- package/vendored/components/mdx/Accordion.tsx +91 -0
- package/vendored/components/mdx/ApiCodePanel.tsx +51 -0
- package/vendored/components/mdx/ApiEndpoint.tsx +104 -0
- package/vendored/components/mdx/ApiPage.tsx +379 -0
- package/vendored/components/mdx/Badge.tsx +169 -0
- package/vendored/components/mdx/Callouts.tsx +140 -0
- package/vendored/components/mdx/Card.tsx +214 -0
- package/vendored/components/mdx/CodeGroup.tsx +136 -0
- package/vendored/components/mdx/Color.tsx +244 -0
- package/vendored/components/mdx/Columns.tsx +37 -0
- package/vendored/components/mdx/Expandable.tsx +37 -0
- package/vendored/components/mdx/Frame.tsx +51 -0
- package/vendored/components/mdx/Icon.tsx +132 -0
- package/vendored/components/mdx/Latex.tsx +75 -0
- package/vendored/components/mdx/MDXComponents.tsx +414 -0
- package/vendored/components/mdx/Mermaid.tsx +35 -0
- package/vendored/components/mdx/MermaidInner.tsx +342 -0
- package/vendored/components/mdx/OpenApiEndpoint.tsx +971 -0
- package/vendored/components/mdx/Panel.tsx +26 -0
- package/vendored/components/mdx/PanelWrapper.tsx +100 -0
- package/vendored/components/mdx/ParamField.tsx +75 -0
- package/vendored/components/mdx/RequestExample.tsx +91 -0
- package/vendored/components/mdx/ResponseExample.tsx +145 -0
- package/vendored/components/mdx/ResponseField.tsx +109 -0
- package/vendored/components/mdx/Steps.tsx +173 -0
- package/vendored/components/mdx/Table.tsx +352 -0
- package/vendored/components/mdx/Tabs.tsx +147 -0
- package/vendored/components/mdx/Tile.tsx +127 -0
- package/vendored/components/mdx/Tooltip.tsx +111 -0
- package/vendored/components/mdx/Tree.tsx +484 -0
- package/vendored/components/mdx/Update.tsx +90 -0
- package/vendored/components/mdx/View.tsx +354 -0
- package/vendored/components/mdx/YouTube.tsx +35 -0
- package/vendored/components/mdx/ZoomableImage.tsx +83 -0
- package/vendored/components/navigation/Breadcrumb.tsx +241 -0
- package/vendored/components/navigation/DefaultLogo.tsx +81 -0
- package/vendored/components/navigation/Header.tsx +512 -0
- package/vendored/components/navigation/LanguageSelector.tsx +249 -0
- package/vendored/components/navigation/PageNavigation.tsx +174 -0
- package/vendored/components/navigation/Sidebar.tsx +713 -0
- package/vendored/components/navigation/SocialFooter.tsx +186 -0
- package/vendored/components/navigation/TableOfContents.tsx +435 -0
- package/vendored/components/navigation/TabsNav.tsx +182 -0
- package/vendored/components/search/LazySearchModal.tsx +19 -0
- package/vendored/components/search/SearchModal.tsx +573 -0
- package/vendored/components/snippets/ProjectSnippets.tsx +4 -0
- package/vendored/components/theme/ThemeProvider.tsx +31 -0
- package/vendored/components/theme/ThemeToggle.tsx +134 -0
- package/vendored/components/ui/CodePanel.tsx +517 -0
- package/vendored/components/ui/CodePanelModal.tsx +342 -0
- package/vendored/contexts/TabSyncContext.tsx +30 -0
- package/vendored/hooks/useFocusTrap.ts +42 -0
- package/vendored/hooks/useHashNavigation.ts +39 -0
- package/vendored/hooks/useShikiHighlight.ts +101 -0
- package/vendored/lib/analytics-client.ts +77 -0
- package/vendored/lib/build/cache.ts +138 -0
- package/vendored/lib/build/error-parser.ts +690 -0
- package/vendored/lib/build/estimation.ts +113 -0
- package/vendored/lib/build/index.ts +17 -0
- package/vendored/lib/build/page-file-map.ts +48 -0
- package/vendored/lib/build/r2-upload.ts +179 -0
- package/vendored/lib/cache-keys.ts +117 -0
- package/vendored/lib/code-utils.ts +42 -0
- package/vendored/lib/content-loader.ts +176 -0
- package/vendored/lib/deprecated-components.ts +185 -0
- package/vendored/lib/docs-isr.ts +180 -0
- package/vendored/lib/docs-types.ts +874 -0
- package/vendored/lib/docs.ts +203 -0
- package/vendored/lib/domain-helpers.ts +107 -0
- package/vendored/lib/email-notifier.ts +102 -0
- package/vendored/lib/email-templates/build-failure.tsx +193 -0
- package/vendored/lib/email-templates/components/base-layout.tsx +150 -0
- package/vendored/lib/email-templates/components/error-box.tsx +88 -0
- package/vendored/lib/email-templates/components/info-row.tsx +63 -0
- package/vendored/lib/email-templates/index.ts +13 -0
- package/vendored/lib/empty-polyfill.js +3 -0
- package/vendored/lib/extract-highlights.ts +124 -0
- package/vendored/lib/fonts.ts +227 -0
- package/vendored/lib/frontmatter-utils.ts +77 -0
- package/vendored/lib/fs-utils.ts +20 -0
- package/vendored/lib/git-utils.ts +87 -0
- package/vendored/lib/health-checks.ts +224 -0
- package/vendored/lib/icon-utils.ts +492 -0
- package/vendored/lib/infer-page-type.ts +14 -0
- package/vendored/lib/isr-build-executor.ts +185 -0
- package/vendored/lib/language-icons.ts +152 -0
- package/vendored/lib/language-utils.ts +338 -0
- package/vendored/lib/latex-config.ts +64 -0
- package/vendored/lib/link-prefix-context.tsx +32 -0
- package/vendored/lib/logger.ts +63 -0
- package/vendored/lib/mcp-search.ts +255 -0
- package/vendored/lib/mdx-inline-components.ts +155 -0
- package/vendored/lib/mdx.ts +100 -0
- package/vendored/lib/middleware-helpers.ts +519 -0
- package/vendored/lib/navigation-resolver.ts +621 -0
- package/vendored/lib/navigation-utils.ts +103 -0
- package/vendored/lib/normalize-config.ts +94 -0
- package/vendored/lib/openapi/cache.ts +92 -0
- package/vendored/lib/openapi/code-examples.ts +389 -0
- package/vendored/lib/openapi/errors.ts +253 -0
- package/vendored/lib/openapi/generator.ts +230 -0
- package/vendored/lib/openapi/index.ts +84 -0
- package/vendored/lib/openapi/parser.ts +474 -0
- package/vendored/lib/openapi/types.ts +232 -0
- package/vendored/lib/openapi/validator.ts +156 -0
- package/vendored/lib/openapi-isr.ts +121 -0
- package/vendored/lib/page-isr-helpers.ts +137 -0
- package/vendored/lib/path-safety.ts +130 -0
- package/vendored/lib/paths.ts +35 -0
- package/vendored/lib/preprocess-mdx.ts +951 -0
- package/vendored/lib/process-mdx-with-exports.ts +75 -0
- package/vendored/lib/project-resolver.ts +165 -0
- package/vendored/lib/r2-content.ts +60 -0
- package/vendored/lib/r2-manifest.ts +84 -0
- package/vendored/lib/recent-searches.ts +41 -0
- package/vendored/lib/recma-compound-components.ts +84 -0
- package/vendored/lib/redirect-compiler.ts +160 -0
- package/vendored/lib/redirect-matcher.ts +296 -0
- package/vendored/lib/redis.ts +23 -0
- package/vendored/lib/rehype-class-to-classname.ts +31 -0
- package/vendored/lib/rehype-code-meta.ts +275 -0
- package/vendored/lib/rehype-nozoom-to-data.ts +45 -0
- package/vendored/lib/remark-extract-exports.ts +104 -0
- package/vendored/lib/resilience.ts +260 -0
- package/vendored/lib/revalidation-helpers.ts +200 -0
- package/vendored/lib/revalidation-trigger.ts +150 -0
- package/vendored/lib/screenshot-capture.ts +229 -0
- package/vendored/lib/search-client.ts +91 -0
- package/vendored/lib/search-suggestions.ts +38 -0
- package/vendored/lib/search.ts +158 -0
- package/vendored/lib/seo.ts +264 -0
- package/vendored/lib/shiki-client.ts +131 -0
- package/vendored/lib/shiki-config.ts +289 -0
- package/vendored/lib/shiki-css-theme.ts +46 -0
- package/vendored/lib/shiki-highlighter.ts +62 -0
- package/vendored/lib/shiki-transformers.ts +337 -0
- package/vendored/lib/slack-notifier.ts +248 -0
- package/vendored/lib/snippet-compiler-isr.ts +114 -0
- package/vendored/lib/snippet-loader-isr.ts +276 -0
- package/vendored/lib/static-artifacts.ts +375 -0
- package/vendored/lib/static-file-route.ts +72 -0
- package/vendored/lib/tracking-script.ts +19 -0
- package/vendored/lib/typography-config.ts +42 -0
- package/vendored/lib/validate-config.ts +268 -0
- package/vendored/next.config.js +45 -0
- package/vendored/postcss.config.js +6 -0
- package/vendored/schema/README.md +28 -0
- package/vendored/schema/docs-schema.json +4631 -0
- package/vendored/scripts/build-project.cjs +174 -0
- package/vendored/scripts/build-search-index.cjs +347 -0
- package/vendored/scripts/compile-snippets.cjs +488 -0
- package/vendored/scripts/copy-files.cjs +295 -0
- package/vendored/scripts/dev-project.cjs +534 -0
- package/vendored/scripts/enhance-navigation.cjs +354 -0
- package/vendored/scripts/validate-links.cjs +423 -0
- package/vendored/shared/constants.ts +6 -0
- package/vendored/shared/index.ts +19 -0
- package/vendored/shared/logger.ts +62 -0
- package/vendored/shared/memory-monitor.ts +190 -0
- package/vendored/shared/navigation-validator.ts +101 -0
- package/vendored/shared/path-security.ts +39 -0
- package/vendored/shared/status-reporter.ts +199 -0
- package/vendored/shared/timer.ts +51 -0
- package/vendored/shared/types.ts +102 -0
- package/vendored/tailwind.config.ts +39 -0
- package/vendored/themes/base.css +1311 -0
- package/vendored/themes/index.ts +119 -0
- package/vendored/themes/jam/variables.css +835 -0
- package/vendored/themes/nebula/variables.css +282 -0
- package/vendored/themes/pulsar/variables.css +1009 -0
- package/vendored/themes/types.ts +89 -0
- package/vendored/tsconfig.json +48 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { usePathname } from 'next/navigation';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Helper to create an icon element safely
|
|
8
|
+
*/
|
|
9
|
+
function createIcon(iconClass: string, additionalClass?: string): HTMLElement {
|
|
10
|
+
const icon = document.createElement('i');
|
|
11
|
+
icon.className = `${iconClass} text-sm${additionalClass ? ' ' + additionalClass : ''}`;
|
|
12
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
13
|
+
return icon;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Client component that adds copy buttons to code blocks after hydration.
|
|
18
|
+
* This avoids server/client component conflicts by manipulating the DOM directly.
|
|
19
|
+
* Also enables copy functionality for HTTP code blocks.
|
|
20
|
+
* Re-runs on page changes to handle new code blocks from client-side navigation.
|
|
21
|
+
*/
|
|
22
|
+
export function CodeBlockCopyButton() {
|
|
23
|
+
const pathname = usePathname();
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
// Enable copy functionality for HTTP code blocks
|
|
27
|
+
const httpBlocks = document.querySelectorAll('.http-code-block:not([data-copy-initialized])');
|
|
28
|
+
httpBlocks.forEach((block) => {
|
|
29
|
+
block.setAttribute('data-copy-initialized', 'true');
|
|
30
|
+
const copyBtn = block.querySelector('.http-copy-btn');
|
|
31
|
+
const copyText = block.getAttribute('data-copy-text');
|
|
32
|
+
|
|
33
|
+
if (copyBtn && copyText) {
|
|
34
|
+
copyBtn.addEventListener('click', async () => {
|
|
35
|
+
try {
|
|
36
|
+
await navigator.clipboard.writeText(copyText);
|
|
37
|
+
// Replace icon with check
|
|
38
|
+
const icon = copyBtn.querySelector('i');
|
|
39
|
+
if (icon) {
|
|
40
|
+
icon.className = 'fa-solid fa-check text-sm text-emerald-500';
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
icon.className = 'fa-regular fa-copy text-sm';
|
|
43
|
+
}, 2000);
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error('Failed to copy:', err);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Enable copy functionality for Color component items
|
|
53
|
+
const colorItems = document.querySelectorAll('.color-item-compact:not([data-copy-initialized]), .color-item-table:not([data-copy-initialized])');
|
|
54
|
+
colorItems.forEach((item) => {
|
|
55
|
+
item.setAttribute('data-copy-initialized', 'true');
|
|
56
|
+
const copyText = item.getAttribute('data-copy-text');
|
|
57
|
+
|
|
58
|
+
if (copyText) {
|
|
59
|
+
item.addEventListener('click', async () => {
|
|
60
|
+
try {
|
|
61
|
+
await navigator.clipboard.writeText(copyText);
|
|
62
|
+
// Show feedback via icon if present (table variant)
|
|
63
|
+
const icon = item.querySelector('i.fa-copy');
|
|
64
|
+
if (icon) {
|
|
65
|
+
icon.className = 'fa-solid fa-check text-xs text-emerald-500';
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
icon.className = 'fa-regular fa-copy text-xs text-[var(--color-text-muted)]';
|
|
68
|
+
}, 2000);
|
|
69
|
+
}
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.error('Failed to copy:', err);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Find all pre.shiki elements that don't already have a copy button
|
|
78
|
+
const allCodeBlocks = document.querySelectorAll('pre.shiki:not([data-copy-button])');
|
|
79
|
+
|
|
80
|
+
allCodeBlocks.forEach((pre) => {
|
|
81
|
+
// Skip code blocks inside CodePanel (they already have a copy button in the header)
|
|
82
|
+
if (pre.closest('[data-code-panel]')) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Mark as processed
|
|
86
|
+
pre.setAttribute('data-copy-button', 'true');
|
|
87
|
+
|
|
88
|
+
// Create wrapper div
|
|
89
|
+
const wrapper = document.createElement('div');
|
|
90
|
+
wrapper.className = 'code-block-wrapper relative group';
|
|
91
|
+
wrapper.style.cssText = 'position: relative;';
|
|
92
|
+
|
|
93
|
+
// Insert wrapper before pre and move pre inside
|
|
94
|
+
pre.parentNode?.insertBefore(wrapper, pre);
|
|
95
|
+
wrapper.appendChild(pre);
|
|
96
|
+
|
|
97
|
+
// Create copy button - minimal styling to match HTTP code block
|
|
98
|
+
const button = document.createElement('button');
|
|
99
|
+
button.className = 'code-copy-btn';
|
|
100
|
+
button.title = 'Copy code';
|
|
101
|
+
button.appendChild(createIcon('fa-regular fa-copy'));
|
|
102
|
+
button.style.cssText = `
|
|
103
|
+
position: absolute;
|
|
104
|
+
top: 8px;
|
|
105
|
+
right: 8px;
|
|
106
|
+
padding: 6px;
|
|
107
|
+
background: transparent;
|
|
108
|
+
border: none;
|
|
109
|
+
border-radius: var(--radius-sm, 6px);
|
|
110
|
+
color: var(--color-text-muted, #6b7280);
|
|
111
|
+
cursor: pointer;
|
|
112
|
+
transition: color 0.2s, background-color 0.2s;
|
|
113
|
+
z-index: 10;
|
|
114
|
+
`;
|
|
115
|
+
|
|
116
|
+
// Copy functionality
|
|
117
|
+
button.addEventListener('click', async () => {
|
|
118
|
+
const code = pre.textContent || '';
|
|
119
|
+
try {
|
|
120
|
+
await navigator.clipboard.writeText(code);
|
|
121
|
+
// Replace icon with check
|
|
122
|
+
button.replaceChildren(createIcon('fa-solid fa-check', 'text-emerald-500'));
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
button.replaceChildren(createIcon('fa-regular fa-copy'));
|
|
125
|
+
}, 2000);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
console.error('Failed to copy:', err);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Hover effect - subtle background like HTTP code block
|
|
132
|
+
button.addEventListener('mouseenter', () => {
|
|
133
|
+
button.style.backgroundColor = 'var(--color-bg-secondary, rgba(0,0,0,0.1))';
|
|
134
|
+
button.style.color = 'var(--color-text-primary, #111827)';
|
|
135
|
+
});
|
|
136
|
+
button.addEventListener('mouseleave', () => {
|
|
137
|
+
button.style.backgroundColor = 'transparent';
|
|
138
|
+
button.style.color = 'var(--color-text-muted, #6b7280)';
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
wrapper.appendChild(button);
|
|
142
|
+
});
|
|
143
|
+
}, [pathname]); // Re-run when pathname changes (client-side navigation)
|
|
144
|
+
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useCallback } from 'react';
|
|
4
|
+
import { usePathname } from 'next/navigation';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Helper to create an icon element
|
|
8
|
+
*/
|
|
9
|
+
function createIcon(iconClass: string): HTMLElement {
|
|
10
|
+
const icon = document.createElement('i');
|
|
11
|
+
icon.className = iconClass;
|
|
12
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
13
|
+
return icon;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Copy text to clipboard and return success status
|
|
18
|
+
*/
|
|
19
|
+
async function copyToClipboard(text: string): Promise<boolean> {
|
|
20
|
+
try {
|
|
21
|
+
await navigator.clipboard.writeText(text);
|
|
22
|
+
return true;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.error('Failed to copy:', err);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Client component that adds link icons and copy functionality to H2/H3 headings.
|
|
31
|
+
* - Hover: Shows link icon to the left of header text (instant, no animation)
|
|
32
|
+
* - Click header text: Copies link AND navigates to anchor
|
|
33
|
+
* - Click icon: Copies link only (no navigation)
|
|
34
|
+
* - Visual feedback: Icon turns accent color for 1.5s after copy
|
|
35
|
+
* - Mobile: Icon hidden, headers function normally
|
|
36
|
+
*/
|
|
37
|
+
export function HeaderLinkCopy() {
|
|
38
|
+
const pathname = usePathname();
|
|
39
|
+
|
|
40
|
+
const processHeadings = useCallback(() => {
|
|
41
|
+
// Find all h2 and h3 elements with IDs in main content that haven't been processed
|
|
42
|
+
const headings = document.querySelectorAll(
|
|
43
|
+
'main h2[id]:not([data-header-link]), main h3[id]:not([data-header-link])'
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
headings.forEach((heading) => {
|
|
47
|
+
const headingEl = heading as HTMLHeadingElement;
|
|
48
|
+
const headingId = headingEl.id;
|
|
49
|
+
const headingText = headingEl.textContent?.trim() || '';
|
|
50
|
+
|
|
51
|
+
// Skip empty headings
|
|
52
|
+
if (!headingId || !headingText) return;
|
|
53
|
+
|
|
54
|
+
// Mark as processed
|
|
55
|
+
headingEl.setAttribute('data-header-link', 'true');
|
|
56
|
+
headingEl.classList.add('header-link-wrapper');
|
|
57
|
+
|
|
58
|
+
// Move all existing child nodes to a document fragment
|
|
59
|
+
const fragment = document.createDocumentFragment();
|
|
60
|
+
while (headingEl.firstChild) {
|
|
61
|
+
fragment.appendChild(headingEl.firstChild);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Create link icon element
|
|
65
|
+
const linkIcon = document.createElement('a');
|
|
66
|
+
linkIcon.href = `#${headingId}`;
|
|
67
|
+
linkIcon.className = 'header-link-icon';
|
|
68
|
+
linkIcon.setAttribute('aria-label', `Copy link to ${headingText}`);
|
|
69
|
+
linkIcon.appendChild(createIcon('fa-solid fa-link'));
|
|
70
|
+
|
|
71
|
+
// Create text wrapper and move original content into it
|
|
72
|
+
const textWrapper = document.createElement('span');
|
|
73
|
+
textWrapper.className = 'header-link-text';
|
|
74
|
+
textWrapper.appendChild(fragment);
|
|
75
|
+
|
|
76
|
+
// Add new structure to heading
|
|
77
|
+
headingEl.appendChild(linkIcon);
|
|
78
|
+
headingEl.appendChild(textWrapper);
|
|
79
|
+
|
|
80
|
+
// Build the full URL for copying
|
|
81
|
+
const buildUrl = () => {
|
|
82
|
+
return `${window.location.origin}${window.location.pathname}#${headingId}`;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Visual feedback function
|
|
86
|
+
const showCopiedFeedback = () => {
|
|
87
|
+
linkIcon.classList.add('copied');
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
linkIcon.classList.remove('copied');
|
|
90
|
+
}, 1500);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Icon click: Copy only, no navigation
|
|
94
|
+
linkIcon.addEventListener('click', async (e) => {
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
e.stopPropagation();
|
|
97
|
+
|
|
98
|
+
const url = buildUrl();
|
|
99
|
+
const success = await copyToClipboard(url);
|
|
100
|
+
if (success) {
|
|
101
|
+
showCopiedFeedback();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Text click: Copy AND navigate
|
|
106
|
+
textWrapper.addEventListener('click', async (e) => {
|
|
107
|
+
// Don't interfere with links inside the heading
|
|
108
|
+
if ((e.target as HTMLElement).tagName === 'A') return;
|
|
109
|
+
|
|
110
|
+
const url = buildUrl();
|
|
111
|
+
const success = await copyToClipboard(url);
|
|
112
|
+
if (success) {
|
|
113
|
+
showCopiedFeedback();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Navigate to the anchor
|
|
117
|
+
window.history.pushState(null, '', `#${headingId}`);
|
|
118
|
+
headingEl.scrollIntoView({ behavior: 'instant', block: 'start' });
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}, []);
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
// Process immediately
|
|
125
|
+
processHeadings();
|
|
126
|
+
|
|
127
|
+
// Also process after a delay for dynamically rendered content
|
|
128
|
+
// (e.g., OpenAPI endpoints that render after hydration)
|
|
129
|
+
const timer = setTimeout(processHeadings, 500);
|
|
130
|
+
|
|
131
|
+
return () => clearTimeout(timer);
|
|
132
|
+
}, [pathname, processHeadings]);
|
|
133
|
+
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import type { DocsConfig } from '@/lib/docs-types';
|
|
6
|
+
import { SearchModal } from '@/components/search/SearchModal';
|
|
7
|
+
import { useLinkPrefix } from '@/lib/link-prefix-context';
|
|
8
|
+
|
|
9
|
+
interface NotFoundContentProps {
|
|
10
|
+
config: DocsConfig;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function NotFoundContent({ config }: NotFoundContentProps) {
|
|
14
|
+
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
|
15
|
+
const linkPrefix = useLinkPrefix();
|
|
16
|
+
|
|
17
|
+
// Get custom 404 config or use defaults
|
|
18
|
+
const errorConfig = config.errors?.['404'];
|
|
19
|
+
const title = errorConfig?.title || 'Page not found';
|
|
20
|
+
const description =
|
|
21
|
+
errorConfig?.description ||
|
|
22
|
+
"The page you're looking for doesn't exist or has been moved.";
|
|
23
|
+
|
|
24
|
+
// Get the first page from navigation for the home link
|
|
25
|
+
const getHomePath = () => {
|
|
26
|
+
const navigation = config.navigation;
|
|
27
|
+
if (!navigation) return `${linkPrefix}/docs`;
|
|
28
|
+
|
|
29
|
+
// Helper to extract path from a page entry
|
|
30
|
+
// Pages can be: string, NavigationPageObject (has 'page'), or GroupConfig (has 'group')
|
|
31
|
+
const getPagePath = (page: unknown): string | null => {
|
|
32
|
+
if (typeof page === 'string') return page;
|
|
33
|
+
if (page && typeof page === 'object' && 'page' in page) {
|
|
34
|
+
return (page as { page: string }).page;
|
|
35
|
+
}
|
|
36
|
+
return null; // GroupConfig or other nested structure
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Check tabs first
|
|
40
|
+
if (navigation.tabs && navigation.tabs.length > 0) {
|
|
41
|
+
const firstTab = navigation.tabs[0];
|
|
42
|
+
if (firstTab.groups && firstTab.groups.length > 0) {
|
|
43
|
+
const firstGroup = firstTab.groups[0];
|
|
44
|
+
if (firstGroup.pages && firstGroup.pages.length > 0) {
|
|
45
|
+
for (const page of firstGroup.pages) {
|
|
46
|
+
const path = getPagePath(page);
|
|
47
|
+
if (path) return `${linkPrefix}/${path}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Check groups (top-level groups)
|
|
54
|
+
if (navigation.groups && navigation.groups.length > 0) {
|
|
55
|
+
const firstGroup = navigation.groups[0];
|
|
56
|
+
if (firstGroup.pages && firstGroup.pages.length > 0) {
|
|
57
|
+
for (const page of firstGroup.pages) {
|
|
58
|
+
const path = getPagePath(page);
|
|
59
|
+
if (path) return `${linkPrefix}/${path}`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check pages array (Mintlify format with groups inside pages)
|
|
65
|
+
if (navigation.pages && Array.isArray(navigation.pages)) {
|
|
66
|
+
for (const item of navigation.pages) {
|
|
67
|
+
// Could be a string page
|
|
68
|
+
const directPath = getPagePath(item);
|
|
69
|
+
if (directPath) return `${linkPrefix}/${directPath}`;
|
|
70
|
+
|
|
71
|
+
// Could be a group object { group: "...", pages: [...] }
|
|
72
|
+
if (item && typeof item === 'object' && 'group' in item && 'pages' in item) {
|
|
73
|
+
const group = item as { group: string; pages: unknown[] };
|
|
74
|
+
if (group.pages && group.pages.length > 0) {
|
|
75
|
+
for (const page of group.pages) {
|
|
76
|
+
const pagePath = getPagePath(page);
|
|
77
|
+
if (pagePath) return `${linkPrefix}/${pagePath}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return `${linkPrefix}/index`;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className="flex-1 flex flex-col items-center justify-center min-h-[60vh] px-4 py-16">
|
|
89
|
+
{/* 404 Badge */}
|
|
90
|
+
<div className="text-[120px] sm:text-[160px] font-bold leading-none text-[var(--color-accent)] opacity-20 select-none">
|
|
91
|
+
404
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Title */}
|
|
95
|
+
<h1 className="text-2xl sm:text-3xl font-bold text-[var(--color-text-primary)] mb-3 text-center -mt-4">
|
|
96
|
+
{title}
|
|
97
|
+
</h1>
|
|
98
|
+
|
|
99
|
+
{/* Description */}
|
|
100
|
+
<p className="text-[var(--color-text-secondary)] text-center max-w-md mb-8">
|
|
101
|
+
{description}
|
|
102
|
+
</p>
|
|
103
|
+
|
|
104
|
+
{/* Actions */}
|
|
105
|
+
<div className="flex flex-col sm:flex-row gap-3">
|
|
106
|
+
<button
|
|
107
|
+
onClick={() => setIsSearchOpen(true)}
|
|
108
|
+
className="inline-flex items-center justify-center gap-2 px-5 py-2.5 rounded-lg border border-[var(--color-border)] text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors"
|
|
109
|
+
>
|
|
110
|
+
<i className="fa-solid fa-magnifying-glass text-sm" aria-hidden="true" />
|
|
111
|
+
Search docs
|
|
112
|
+
</button>
|
|
113
|
+
<Link
|
|
114
|
+
href={getHomePath()}
|
|
115
|
+
className="inline-flex items-center justify-center gap-2 px-5 py-2.5 rounded-lg bg-[var(--color-accent)] text-white hover:opacity-90 transition-opacity"
|
|
116
|
+
>
|
|
117
|
+
<i className="fa-solid fa-house text-sm" aria-hidden="true" />
|
|
118
|
+
Go to homepage
|
|
119
|
+
</Link>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{/* Helpful suggestions */}
|
|
123
|
+
<div className="mt-12 text-center">
|
|
124
|
+
<p className="text-sm text-[var(--color-text-muted)] mb-4">
|
|
125
|
+
Here are some things you can try:
|
|
126
|
+
</p>
|
|
127
|
+
<ul className="text-sm text-[var(--color-text-secondary)] space-y-2">
|
|
128
|
+
<li className="flex items-center justify-center gap-2">
|
|
129
|
+
<i className="fa-solid fa-check text-[var(--color-accent)] text-xs" aria-hidden="true" />
|
|
130
|
+
Check the URL for typos
|
|
131
|
+
</li>
|
|
132
|
+
<li className="flex items-center justify-center gap-2">
|
|
133
|
+
<i className="fa-solid fa-check text-[var(--color-accent)] text-xs" aria-hidden="true" />
|
|
134
|
+
Use the search to find what you need
|
|
135
|
+
</li>
|
|
136
|
+
<li className="flex items-center justify-center gap-2">
|
|
137
|
+
<i className="fa-solid fa-check text-[var(--color-accent)] text-xs" aria-hidden="true" />
|
|
138
|
+
Browse the sidebar navigation
|
|
139
|
+
</li>
|
|
140
|
+
</ul>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{/* Search Modal */}
|
|
144
|
+
<SearchModal isOpen={isSearchOpen} onClose={() => setIsSearchOpen(false)} />
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useMemo, useEffect } from 'react';
|
|
4
|
+
import { Header } from '@/components/navigation/Header';
|
|
5
|
+
import { Sidebar } from '@/components/navigation/Sidebar';
|
|
6
|
+
import { TabsNav } from '@/components/navigation/TabsNav';
|
|
7
|
+
import { useHashNavigation } from '@/hooks/useHashNavigation';
|
|
8
|
+
import type { DocsConfig } from '@/lib/docs-types';
|
|
9
|
+
import { getTheme, type ThemeName } from '@/themes';
|
|
10
|
+
|
|
11
|
+
interface LayoutWrapperProps {
|
|
12
|
+
config: DocsConfig;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function LayoutWrapper({ config, children }: LayoutWrapperProps) {
|
|
17
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
|
18
|
+
|
|
19
|
+
// Handle hash navigation for three-column independent scroll layout
|
|
20
|
+
useHashNavigation();
|
|
21
|
+
|
|
22
|
+
// Toggle 'scrolled' class on body when user scrolls past 500px
|
|
23
|
+
// Used by Jam theme to hide gradient and make header solid
|
|
24
|
+
// The gradient extends 500px from top, so we hide it after scrolling past that point
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const contentScroll = document.getElementById('content-scroll-container');
|
|
27
|
+
const scrollTarget = contentScroll || window;
|
|
28
|
+
|
|
29
|
+
const handleScroll = () => {
|
|
30
|
+
const scrollY = contentScroll ? contentScroll.scrollTop : window.scrollY;
|
|
31
|
+
if (scrollY > 500) {
|
|
32
|
+
document.body.classList.add('scrolled');
|
|
33
|
+
} else {
|
|
34
|
+
document.body.classList.remove('scrolled');
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
scrollTarget.addEventListener('scroll', handleScroll);
|
|
39
|
+
handleScroll(); // Check initial position
|
|
40
|
+
|
|
41
|
+
return () => scrollTarget.removeEventListener('scroll', handleScroll);
|
|
42
|
+
}, []);
|
|
43
|
+
|
|
44
|
+
// Get theme config to determine layout
|
|
45
|
+
const themeConfig = useMemo(() => {
|
|
46
|
+
return getTheme(config.theme as ThemeName | undefined);
|
|
47
|
+
}, [config.theme]);
|
|
48
|
+
|
|
49
|
+
const layout = themeConfig.layout;
|
|
50
|
+
|
|
51
|
+
const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen);
|
|
52
|
+
const closeSidebar = () => setIsSidebarOpen(false);
|
|
53
|
+
|
|
54
|
+
// Sidebar-logo layout: Sidebar is full height, header only above content
|
|
55
|
+
// Tabs are rendered inline in the header for this layout
|
|
56
|
+
// Uses fixed viewport height on desktop with independent scroll for each column
|
|
57
|
+
if (layout === 'sidebar-logo') {
|
|
58
|
+
return (
|
|
59
|
+
<div className="flex min-h-screen lg:h-screen lg:overflow-hidden">
|
|
60
|
+
{/* Full-height sidebar - already has its own scroll */}
|
|
61
|
+
<Sidebar
|
|
62
|
+
config={config}
|
|
63
|
+
layout={layout}
|
|
64
|
+
isOpen={isSidebarOpen}
|
|
65
|
+
onClose={closeSidebar}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
{/* Content area with header (tabs are inline in header) */}
|
|
69
|
+
<div className="flex-1 lg:ml-[295px] flex flex-col lg:h-screen bg-[var(--color-bg-content,var(--color-bg-primary))]">
|
|
70
|
+
<Header
|
|
71
|
+
config={config}
|
|
72
|
+
layout={layout}
|
|
73
|
+
isSidebarOpen={isSidebarOpen}
|
|
74
|
+
onToggleSidebar={toggleSidebar}
|
|
75
|
+
/>
|
|
76
|
+
{/* Main content area - contains content scroll container and TOC */}
|
|
77
|
+
<main
|
|
78
|
+
id="main-content"
|
|
79
|
+
className="flex-1 flex flex-col lg:min-h-0 transition-colors overflow-x-hidden"
|
|
80
|
+
>
|
|
81
|
+
{children}
|
|
82
|
+
</main>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Header-logo layout (Jam, Nebula): Uses sticky positioning for max-width support
|
|
89
|
+
// Outer wrapper constrains entire layout to --layout-max-width
|
|
90
|
+
// Uses fixed viewport height on desktop with independent scroll for each column
|
|
91
|
+
return (
|
|
92
|
+
<div
|
|
93
|
+
className="min-h-screen lg:h-screen flex flex-col lg:overflow-hidden mx-auto px-4 lg:px-6"
|
|
94
|
+
style={{ maxWidth: 'var(--layout-max-width, none)' }}
|
|
95
|
+
>
|
|
96
|
+
{/* Header - stays at top, does not scroll */}
|
|
97
|
+
<Header
|
|
98
|
+
config={config}
|
|
99
|
+
layout={layout}
|
|
100
|
+
isSidebarOpen={isSidebarOpen}
|
|
101
|
+
onToggleSidebar={toggleSidebar}
|
|
102
|
+
/>
|
|
103
|
+
|
|
104
|
+
{/* Tabs bar - below header, same height */}
|
|
105
|
+
<TabsNav config={config} />
|
|
106
|
+
|
|
107
|
+
{/* Main layout area with sidebar and content - fills remaining height */}
|
|
108
|
+
<div className="flex flex-1 lg:min-h-0">
|
|
109
|
+
{/* Sidebar - has its own scroll via sidebar-scroll class */}
|
|
110
|
+
<Sidebar
|
|
111
|
+
config={config}
|
|
112
|
+
layout={layout}
|
|
113
|
+
isOpen={isSidebarOpen}
|
|
114
|
+
onClose={closeSidebar}
|
|
115
|
+
/>
|
|
116
|
+
|
|
117
|
+
{/* Main content area - contains content scroll container and TOC */}
|
|
118
|
+
<main
|
|
119
|
+
id="main-content"
|
|
120
|
+
className="flex-1 flex flex-col lg:min-h-0 bg-[var(--color-bg-primary)] transition-colors overflow-x-hidden"
|
|
121
|
+
>
|
|
122
|
+
{children}
|
|
123
|
+
</main>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ReactNode, useState, memo } from 'react';
|
|
4
|
+
import { getIconClass } from '@/lib/icon-utils';
|
|
5
|
+
|
|
6
|
+
interface AccordionProps {
|
|
7
|
+
/** Title in the Accordion preview (required) */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Detail below the title in the Accordion preview */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Whether the Accordion is open by default */
|
|
12
|
+
defaultOpen?: boolean;
|
|
13
|
+
/** The icon to display */
|
|
14
|
+
icon?: string;
|
|
15
|
+
/** The Font Awesome icon style */
|
|
16
|
+
iconType?: 'regular' | 'solid' | 'light' | 'thin' | 'sharp-solid' | 'duotone' | 'brands';
|
|
17
|
+
/** Accordion content */
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface AccordionGroupProps {
|
|
22
|
+
/** Grouped accordions */
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Accordion = memo(function Accordion({
|
|
27
|
+
title,
|
|
28
|
+
description,
|
|
29
|
+
defaultOpen = false,
|
|
30
|
+
icon,
|
|
31
|
+
iconType,
|
|
32
|
+
children
|
|
33
|
+
}: AccordionProps) {
|
|
34
|
+
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className="border border-[var(--color-border)] rounded-lg mb-2 last:mb-0 not-prose overflow-hidden">
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
41
|
+
className="w-full flex items-center gap-3 p-4 text-left hover:bg-[var(--color-bg-secondary)] transition-colors"
|
|
42
|
+
aria-expanded={isOpen}
|
|
43
|
+
>
|
|
44
|
+
{/* Icon */}
|
|
45
|
+
{icon && (
|
|
46
|
+
<i className={`${getIconClass(icon)} h-5 w-5 text-[var(--color-accent)] flex-shrink-0`} aria-hidden="true" />
|
|
47
|
+
)}
|
|
48
|
+
|
|
49
|
+
{/* Title and description */}
|
|
50
|
+
<div className="flex-1 min-w-0">
|
|
51
|
+
<div className="font-medium text-[var(--color-text-primary)]">
|
|
52
|
+
{title}
|
|
53
|
+
</div>
|
|
54
|
+
{description && (
|
|
55
|
+
<div className="text-sm text-[var(--color-text-secondary)] mt-0.5">
|
|
56
|
+
{description}
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{/* Chevron */}
|
|
62
|
+
<i
|
|
63
|
+
className={`fa-solid fa-chevron-down h-5 w-5 text-[var(--color-text-muted)] flex-shrink-0 transition-transform duration-200 ${
|
|
64
|
+
isOpen ? 'rotate-180' : ''
|
|
65
|
+
}`}
|
|
66
|
+
aria-hidden="true"
|
|
67
|
+
/>
|
|
68
|
+
</button>
|
|
69
|
+
|
|
70
|
+
{/* Content */}
|
|
71
|
+
<div
|
|
72
|
+
className={`overflow-hidden transition-all duration-200 ${
|
|
73
|
+
isOpen ? 'max-h-[2000px] opacity-100' : 'max-h-0 opacity-0'
|
|
74
|
+
}`}
|
|
75
|
+
>
|
|
76
|
+
<div className="px-4 pb-4 pt-0 text-sm text-[var(--color-text-secondary)] leading-relaxed [&>p]:mb-3 [&>p:last-child]:mb-0 [&>pre]:my-3 [&_code]:bg-[var(--color-code-bg)] [&_code]:px-1 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-[12px] [&_code]:font-mono [&>a]:text-[var(--color-accent)] [&>a]:no-underline [&>a:hover]:underline">
|
|
77
|
+
{children}
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export const AccordionGroup = memo(function AccordionGroup({ children }: AccordionGroupProps) {
|
|
85
|
+
return (
|
|
86
|
+
<div className="my-4 not-prose">
|
|
87
|
+
{children}
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|