@wrikka/create-docs 0.1.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/README.md +137 -0
- package/bin/cli.js +408 -0
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +475 -0
- package/dist/index.d.ts +475 -0
- package/dist/index.js +20 -0
- package/docs/_dir.yml +2 -0
- package/docs/config.md +75 -0
- package/docs/data-sources.md +88 -0
- package/docs/deploy.md +38 -0
- package/docs/features.md +51 -0
- package/docs/getting-started.md +42 -0
- package/docs/index.md +34 -0
- package/docs/markdown.md +154 -0
- package/docs/theming.md +53 -0
- package/package.json +142 -0
- package/scripts/generate-docs-index.ts +111 -0
- package/scripts/github-pull.ts +124 -0
- package/src/adapters/config/index.ts +1 -0
- package/src/adapters/config/node-config-loader.ts +36 -0
- package/src/adapters/fs/fs-docs-loader.ts +31 -0
- package/src/adapters/fs/index.ts +12 -0
- package/src/adapters/fs/memory-fs.ts +60 -0
- package/src/adapters/fs/node-fs.ts +116 -0
- package/src/adapters/git/index.ts +164 -0
- package/src/adapters/github/github-pull.ts +340 -0
- package/src/adapters/index.ts +6 -0
- package/src/adapters/velite.ts +112 -0
- package/src/adapters/vite/docs-watcher.ts +36 -0
- package/src/adapters/vite/index.ts +2 -0
- package/src/adapters/vite/polling-watcher.ts +89 -0
- package/src/code-block-enhancements/index.ts +3 -0
- package/src/config/index.ts +15 -0
- package/src/content/index.ts +11 -0
- package/src/content-validation/index.ts +5 -0
- package/src/index.ts +174 -0
- package/src/live-editor/index.ts +7 -0
- package/src/modules/analytics/application/plausible-adapter.ts +103 -0
- package/src/modules/analytics/application/umami-adapter.ts +109 -0
- package/src/modules/analytics/domain/events/index.ts +37 -0
- package/src/modules/analytics/domain/models/index.ts +35 -0
- package/src/modules/analytics/domain/operations/analytics-operations.ts +67 -0
- package/src/modules/analytics/domain/validators/index.ts +50 -0
- package/src/modules/analytics/index.ts +9 -0
- package/src/modules/analytics/ports/analytics-port.ts +17 -0
- package/src/modules/analytics/types/analytics.ts +16 -0
- package/src/modules/api-docs/application/type-docs-adapter.ts +34 -0
- package/src/modules/api-docs/domain/events/index.ts +42 -0
- package/src/modules/api-docs/domain/models/index.ts +40 -0
- package/src/modules/api-docs/domain/operations/api-docs-operations.ts +59 -0
- package/src/modules/api-docs/domain/validators/index.ts +56 -0
- package/src/modules/api-docs/index.ts +8 -0
- package/src/modules/api-docs/ports/api-docs-port.ts +21 -0
- package/src/modules/api-docs/types/api-docs.ts +15 -0
- package/src/modules/api-reference/openapi.ts +166 -0
- package/src/modules/api-reference/orpc.ts +94 -0
- package/src/modules/code-block-enhancements/application/usecases/index.ts +39 -0
- package/src/modules/code-block-enhancements/domain/code-operations.ts +72 -0
- package/src/modules/code-block-enhancements/domain/events/index.ts +58 -0
- package/src/modules/code-block-enhancements/domain/index.ts +11 -0
- package/src/modules/code-block-enhancements/domain/models/index.ts +36 -0
- package/src/modules/code-block-enhancements/domain/validators/index.ts +50 -0
- package/src/modules/code-block-enhancements/index.ts +10 -0
- package/src/modules/code-block-enhancements/ports/index.ts +18 -0
- package/src/modules/code-block-enhancements/types/index.ts +37 -0
- package/src/modules/code-execution/application/sandbox-adapter.ts +44 -0
- package/src/modules/code-execution/domain/events/index.ts +58 -0
- package/src/modules/code-execution/domain/models/index.ts +33 -0
- package/src/modules/code-execution/domain/operations/execution-operations.ts +60 -0
- package/src/modules/code-execution/domain/validators/index.ts +50 -0
- package/src/modules/code-execution/index.ts +8 -0
- package/src/modules/code-execution/ports/execution-port.ts +15 -0
- package/src/modules/code-execution/types/execution.ts +15 -0
- package/src/modules/comments/application/giscus-adapter.ts +55 -0
- package/src/modules/comments/domain/events/index.ts +55 -0
- package/src/modules/comments/domain/models/index.ts +30 -0
- package/src/modules/comments/domain/operations/comment-operations.ts +46 -0
- package/src/modules/comments/domain/validators/index.ts +50 -0
- package/src/modules/comments/index.ts +8 -0
- package/src/modules/comments/ports/comment-port.ts +18 -0
- package/src/modules/comments/types/comments.ts +19 -0
- package/src/modules/config/application/usecases/index.ts +1 -0
- package/src/modules/config/application/usecases/loadConfig.ts +38 -0
- package/src/modules/config/application/workflows/index.ts +1 -0
- package/src/modules/config/application/workflows/validateConfig.ts +14 -0
- package/src/modules/config/domain/events/index.ts +50 -0
- package/src/modules/config/domain/models/index.ts +9 -0
- package/src/modules/config/domain/operations/defaults.ts +74 -0
- package/src/modules/config/domain/operations/index.ts +2 -0
- package/src/modules/config/domain/operations/resolve.ts +40 -0
- package/src/modules/config/domain/validators/index.ts +152 -0
- package/src/modules/config/index.ts +23 -0
- package/src/modules/config/ports/index.ts +15 -0
- package/src/modules/config/types/index.ts +113 -0
- package/src/modules/config/types/public.ts +19 -0
- package/src/modules/content/application/cache/index.ts +6 -0
- package/src/modules/content/application/cache/parse-cache.ts +6 -0
- package/src/modules/content/application/cache/parseCache.ts +56 -0
- package/src/modules/content/application/usecases/index.ts +2 -0
- package/src/modules/content/application/usecases/load-doc-page.ts +1 -0
- package/src/modules/content/application/usecases/loadDocPage.ts +111 -0
- package/src/modules/content/application/usecases/scanDocsDir.ts +105 -0
- package/src/modules/content/application/workflows/index.ts +1 -0
- package/src/modules/content/application/workflows/processDocs.ts +51 -0
- package/src/modules/content/domain/events/index.ts +61 -0
- package/src/modules/content/domain/models/index.ts +13 -0
- package/src/modules/content/domain/operations/build-page.ts +146 -0
- package/src/modules/content/domain/operations/buildPage.ts +93 -0
- package/src/modules/content/domain/operations/index.ts +17 -0
- package/src/modules/content/domain/operations/parse.ts +241 -0
- package/src/modules/content/domain/validators/frontmatter.ts +82 -0
- package/src/modules/content/domain/validators/index.ts +6 -0
- package/src/modules/content/index.ts +27 -0
- package/src/modules/content/ports/index.ts +45 -0
- package/src/modules/content/ports/velite.ts +134 -0
- package/src/modules/content/types/index.ts +76 -0
- package/src/modules/content/types/public.ts +1 -0
- package/src/modules/content-linting/application/builtin-linting-adapter.ts +82 -0
- package/src/modules/content-linting/domain/events/index.ts +58 -0
- package/src/modules/content-linting/domain/models/index.ts +46 -0
- package/src/modules/content-linting/domain/operations/linting-operations.ts +82 -0
- package/src/modules/content-linting/domain/validators/index.ts +50 -0
- package/src/modules/content-linting/index.ts +8 -0
- package/src/modules/content-linting/ports/linting-port.ts +21 -0
- package/src/modules/content-linting/types/linting.ts +18 -0
- package/src/modules/content-validation/application/usecases/index.ts +18 -0
- package/src/modules/content-validation/domain/events/index.ts +7 -0
- package/src/modules/content-validation/domain/index.ts +16 -0
- package/src/modules/content-validation/domain/models/index.ts +33 -0
- package/src/modules/content-validation/domain/operations/index.ts +157 -0
- package/src/modules/content-validation/domain/types/index.ts +17 -0
- package/src/modules/content-validation/domain/validators/index.ts +8 -0
- package/src/modules/content-validation/index.ts +9 -0
- package/src/modules/content-validation/ports/index.ts +15 -0
- package/src/modules/content-validation/types/index.ts +5 -0
- package/src/modules/export/application/puppeteer-export-adapter.ts +63 -0
- package/src/modules/export/domain/events/index.ts +55 -0
- package/src/modules/export/domain/models/index.ts +38 -0
- package/src/modules/export/domain/operations/export-operations.ts +56 -0
- package/src/modules/export/domain/validators/index.ts +52 -0
- package/src/modules/export/index.ts +8 -0
- package/src/modules/export/ports/export-port.ts +15 -0
- package/src/modules/export/types/export.ts +15 -0
- package/src/modules/external-search/application/algolia-adapter.ts +182 -0
- package/src/modules/external-search/application/meilisearch-adapter.ts +161 -0
- package/src/modules/external-search/domain/events/index.ts +42 -0
- package/src/modules/external-search/domain/models/index.ts +42 -0
- package/src/modules/external-search/domain/operations/search-operations.ts +53 -0
- package/src/modules/external-search/domain/validators/index.ts +55 -0
- package/src/modules/external-search/index.ts +9 -0
- package/src/modules/external-search/ports/external-search-port.ts +23 -0
- package/src/modules/external-search/types/search.ts +19 -0
- package/src/modules/git-history/application/simple-git-adapter.ts +46 -0
- package/src/modules/git-history/domain/events/index.ts +34 -0
- package/src/modules/git-history/domain/models/index.ts +25 -0
- package/src/modules/git-history/domain/operations/git-history-operations.ts +56 -0
- package/src/modules/git-history/domain/validators/index.ts +52 -0
- package/src/modules/git-history/index.ts +8 -0
- package/src/modules/git-history/ports/git-history-port.ts +21 -0
- package/src/modules/git-history/types/git-history.ts +15 -0
- package/src/modules/i18n/application/fs-locale-loader.ts +39 -0
- package/src/modules/i18n/domain/events/index.ts +34 -0
- package/src/modules/i18n/domain/models/index.ts +34 -0
- package/src/modules/i18n/domain/operations/locale-operations.ts +74 -0
- package/src/modules/i18n/domain/validators/index.ts +52 -0
- package/src/modules/i18n/index.ts +8 -0
- package/src/modules/i18n/ports/locale-loader-port.ts +18 -0
- package/src/modules/i18n/types/locale.ts +17 -0
- package/src/modules/image-optimization/application/sharp-adapter.ts +58 -0
- package/src/modules/image-optimization/domain/events/index.ts +39 -0
- package/src/modules/image-optimization/domain/models/index.ts +27 -0
- package/src/modules/image-optimization/domain/operations/image-operations.ts +65 -0
- package/src/modules/image-optimization/domain/validators/index.ts +52 -0
- package/src/modules/image-optimization/index.ts +8 -0
- package/src/modules/image-optimization/ports/image-optimizer-port.ts +15 -0
- package/src/modules/image-optimization/types/image.ts +17 -0
- package/src/modules/live-editor/application/usecases/index.ts +60 -0
- package/src/modules/live-editor/domain/events/index.ts +37 -0
- package/src/modules/live-editor/domain/gitOperations.ts +110 -0
- package/src/modules/live-editor/domain/index.ts +15 -0
- package/src/modules/live-editor/domain/models/index.ts +21 -0
- package/src/modules/live-editor/domain/validators/index.ts +55 -0
- package/src/modules/live-editor/index.ts +14 -0
- package/src/modules/live-editor/ports/index.ts +49 -0
- package/src/modules/live-editor/types/index.ts +80 -0
- package/src/modules/live-preview/application/vite-preview-adapter.ts +20 -0
- package/src/modules/live-preview/domain/operations/preview-operations.ts +56 -0
- package/src/modules/live-preview/index.ts +8 -0
- package/src/modules/live-preview/ports/preview-port.ts +20 -0
- package/src/modules/live-preview/types/preview.ts +16 -0
- package/src/modules/mdx/application/mdx-js-adapter.ts +38 -0
- package/src/modules/mdx/domain/operations/parse-mdx.ts +43 -0
- package/src/modules/mdx/index.ts +8 -0
- package/src/modules/mdx/ports/mdx-parser-port.ts +15 -0
- package/src/modules/mdx/types/mdx.ts +14 -0
- package/src/modules/navigation/application/usecases/buildNav.ts +15 -0
- package/src/modules/navigation/application/usecases/buildSidebar.ts +45 -0
- package/src/modules/navigation/application/usecases/index.ts +2 -0
- package/src/modules/navigation/domain/events/index.ts +30 -0
- package/src/modules/navigation/domain/models/index.ts +7 -0
- package/src/modules/navigation/domain/operations/group.ts +79 -0
- package/src/modules/navigation/domain/operations/index.ts +10 -0
- package/src/modules/navigation/domain/operations/sort.ts +27 -0
- package/src/modules/navigation/domain/shared/utils/array.ts +39 -0
- package/src/modules/navigation/domain/validators/index.ts +88 -0
- package/src/modules/navigation/index.ts +15 -0
- package/src/modules/navigation/ports/index.ts +9 -0
- package/src/modules/navigation/types/index.ts +38 -0
- package/src/modules/navigation/types/public.ts +9 -0
- package/src/modules/openapi/application/swagger-parser-adapter.ts +178 -0
- package/src/modules/openapi/domain/operations/parse-openapi.ts +46 -0
- package/src/modules/openapi/index.ts +8 -0
- package/src/modules/openapi/ports/openapi-parser-port.ts +15 -0
- package/src/modules/openapi/types/openapi.ts +37 -0
- package/src/modules/plugin/application/usecases/build-virtual-modules.ts +53 -0
- package/src/modules/plugin/application/usecases/index.ts +1 -0
- package/src/modules/plugin/application/workflows/build-docs.ts +79 -0
- package/src/modules/plugin/application/workflows/index.ts +1 -0
- package/src/modules/plugin/domain/events/index.ts +62 -0
- package/src/modules/plugin/domain/models/index.ts +1 -0
- package/src/modules/plugin/domain/operations/build-virtual.ts +76 -0
- package/src/modules/plugin/domain/operations/index.ts +11 -0
- package/src/modules/plugin/domain/validators/index.ts +30 -0
- package/src/modules/plugin/index.ts +14 -0
- package/src/modules/plugin/ports/index.ts +21 -0
- package/src/modules/plugin/types/index.ts +27 -0
- package/src/modules/plugin/types/public.ts +1 -0
- package/src/modules/search/application/usecases/index.ts +1 -0
- package/src/modules/search/application/usecases/indexPages.ts +15 -0
- package/src/modules/search/domain/events/index.ts +32 -0
- package/src/modules/search/domain/models/index.ts +1 -0
- package/src/modules/search/domain/operations/build-index.ts +6 -0
- package/src/modules/search/domain/operations/buildIndex.ts +70 -0
- package/src/modules/search/domain/operations/index.ts +7 -0
- package/src/modules/search/domain/operations/query.ts +186 -0
- package/src/modules/search/domain/validators/index.ts +32 -0
- package/src/modules/search/index.ts +9 -0
- package/src/modules/search/types/index.ts +22 -0
- package/src/modules/search/types/public.ts +1 -0
- package/src/modules/search-analytics/application/local-storage-adapter.ts +68 -0
- package/src/modules/search-analytics/domain/operations/search-analytics-operations.ts +74 -0
- package/src/modules/search-analytics/index.ts +8 -0
- package/src/modules/search-analytics/ports/search-analytics-port.ts +20 -0
- package/src/modules/search-analytics/types/search-analytics.ts +16 -0
- package/src/modules/search-highlighting/application/dom-highlighting-adapter.ts +36 -0
- package/src/modules/search-highlighting/domain/operations/highlighting-operations.ts +72 -0
- package/src/modules/search-highlighting/index.ts +8 -0
- package/src/modules/search-highlighting/ports/highlighting-port.ts +14 -0
- package/src/modules/search-highlighting/types/highlighting.ts +15 -0
- package/src/modules/seo-optimization/application/usecases/index.ts +18 -0
- package/src/modules/seo-optimization/domain/index.ts +12 -0
- package/src/modules/seo-optimization/domain/seoOperations.ts +92 -0
- package/src/modules/seo-optimization/index.ts +8 -0
- package/src/modules/seo-optimization/ports/index.ts +18 -0
- package/src/modules/seo-optimization/types/index.ts +41 -0
- package/src/modules/theme/application/css-theme-adapter.ts +50 -0
- package/src/modules/theme/domain/operations/theme-operations.ts +68 -0
- package/src/modules/theme/index.ts +8 -0
- package/src/modules/theme/ports/theme-port.ts +8 -0
- package/src/modules/theme/types/theme.ts +12 -0
- package/src/modules/toc/application/markdown-toc-adapter.ts +106 -0
- package/src/modules/toc/domain/operations/toc-operations.ts +92 -0
- package/src/modules/toc/index.ts +8 -0
- package/src/modules/toc/ports/toc-port.ts +21 -0
- package/src/modules/toc/types/toc.ts +17 -0
- package/src/modules/toc-generator/application/usecases/index.ts +30 -0
- package/src/modules/toc-generator/domain/index.ts +12 -0
- package/src/modules/toc-generator/domain/tocOperations.ts +104 -0
- package/src/modules/toc-generator/index.ts +9 -0
- package/src/modules/toc-generator/ports/index.ts +20 -0
- package/src/modules/toc-generator/types/index.ts +50 -0
- package/src/modules/version-control/domain/events/index.ts +39 -0
- package/src/modules/version-control/domain/models/index.ts +25 -0
- package/src/modules/version-control/domain/validators/index.ts +50 -0
- package/src/modules/versioning/application/fs-version-loader.ts +44 -0
- package/src/modules/versioning/domain/operations/versioning-operations.ts +80 -0
- package/src/modules/versioning/index.ts +8 -0
- package/src/modules/versioning/ports/version-loader-port.ts +18 -0
- package/src/modules/versioning/types/versioning.ts +17 -0
- package/src/modules/workflow/domain/events/index.ts +55 -0
- package/src/modules/workflow/domain/models/index.ts +40 -0
- package/src/modules/workflow/domain/validators/index.ts +50 -0
- package/src/modules/yaml-parser/application/js-yaml-adapter.ts +34 -0
- package/src/modules/yaml-parser/domain/operations/parse-yaml.ts +58 -0
- package/src/modules/yaml-parser/index.ts +7 -0
- package/src/modules/yaml-parser/ports/yaml-parser-port.ts +18 -0
- package/src/navigation/index.ts +9 -0
- package/src/plugin/index.ts +4 -0
- package/src/presentation/index.ts +1 -0
- package/src/presentation/live-editor/index.ts +22 -0
- package/src/presentation/live-editor/live-editor-component.ts +219 -0
- package/src/presentation/live-editor/virtual-module.ts +16 -0
- package/src/presentation/solid/CodeBlock.tsx +120 -0
- package/src/presentation/solid/Toc.tsx +58 -0
- package/src/presentation/solid/index.ts +11 -0
- package/src/presentation/vite-plugin/docs-plugin.ts +212 -0
- package/src/presentation/vite-plugin/index.ts +9 -0
- package/src/presentation/vite-plugin/transform-markdown.ts +26 -0
- package/src/runtime/analytics.ts +59 -0
- package/src/runtime/api-diff.ts +115 -0
- package/src/runtime/app.tsx +32 -0
- package/src/runtime/components/AccentPicker.tsx +114 -0
- package/src/runtime/components/ApiPlayground.tsx +332 -0
- package/src/runtime/components/AskAiDialog.tsx +127 -0
- package/src/runtime/components/BackToTop.tsx +38 -0
- package/src/runtime/components/Banner.tsx +75 -0
- package/src/runtime/components/Breadcrumbs.tsx +42 -0
- package/src/runtime/components/CollectionDropdown.tsx +85 -0
- package/src/runtime/components/CustomizeDrawer.tsx +195 -0
- package/src/runtime/components/DocMarkdown.tsx +579 -0
- package/src/runtime/components/DocPrevNext.tsx +54 -0
- package/src/runtime/components/DocToc.tsx +147 -0
- package/src/runtime/components/DocsDropdown.tsx +184 -0
- package/src/runtime/components/Footer.tsx +52 -0
- package/src/runtime/components/GitHubAuth.tsx +82 -0
- package/src/runtime/components/GitHubStats.tsx +73 -0
- package/src/runtime/components/Head.tsx +225 -0
- package/src/runtime/components/LocaleDropdown.tsx +75 -0
- package/src/runtime/components/MobileBottomNav.tsx +111 -0
- package/src/runtime/components/NotFound.tsx +139 -0
- package/src/runtime/components/PageActions.tsx +144 -0
- package/src/runtime/components/RelatedDocs.tsx +50 -0
- package/src/runtime/components/ScrollProgress.tsx +32 -0
- package/src/runtime/components/SearchPalette.tsx +333 -0
- package/src/runtime/components/ShowcaseCard.tsx +87 -0
- package/src/runtime/components/SidebarNav.tsx +237 -0
- package/src/runtime/components/Skeleton.tsx +39 -0
- package/src/runtime/components/ThemeToggle.tsx +26 -0
- package/src/runtime/components/TopNav.tsx +270 -0
- package/src/runtime/components/VersionDropdown.tsx +189 -0
- package/src/runtime/components/markdown/components.ts +280 -0
- package/src/runtime/config.ts +225 -0
- package/src/runtime/content.ts +451 -0
- package/src/runtime/context.tsx +30 -0
- package/src/runtime/data.ts +93 -0
- package/src/runtime/github.ts +226 -0
- package/src/runtime/icons.ts +32 -0
- package/src/runtime/index.ts +153 -0
- package/src/runtime/layouts/DocsLayout.tsx +144 -0
- package/src/runtime/markdown-content.css +996 -0
- package/src/runtime/pages/AbTestPage.tsx +88 -0
- package/src/runtime/pages/AnalyticsPage.tsx +90 -0
- package/src/runtime/pages/ApiDiffPage.tsx +86 -0
- package/src/runtime/pages/ApiEndpointPage.tsx +248 -0
- package/src/runtime/pages/BuilderPage.tsx +150 -0
- package/src/runtime/pages/ChangelogPage.tsx +210 -0
- package/src/runtime/pages/CollectionPage.tsx +140 -0
- package/src/runtime/pages/CommunityPage.tsx +384 -0
- package/src/runtime/pages/CreatePage.tsx +448 -0
- package/src/runtime/pages/DocPage.tsx +193 -0
- package/src/runtime/pages/EditPage.tsx +201 -0
- package/src/runtime/pages/HomePage.tsx +187 -0
- package/src/runtime/pages/IssuesPage.tsx +140 -0
- package/src/runtime/pages/OAuthCallbackPage.tsx +80 -0
- package/src/runtime/pages/PluginsPage.tsx +249 -0
- package/src/runtime/pages/ShowcasePage.tsx +202 -0
- package/src/runtime/pwa.ts +39 -0
- package/src/runtime/router.tsx +192 -0
- package/src/runtime/seo.ts +192 -0
- package/src/runtime/theme.css +175 -0
- package/src/runtime/theme.ts +224 -0
- package/src/runtime/types.ts +217 -0
- package/src/search/index.ts +6 -0
- package/src/seo-optimization/index.ts +4 -0
- package/src/shared/constants/index.ts +26 -0
- package/src/shared/errors/index.ts +195 -0
- package/src/shared/index.ts +27 -0
- package/src/shared/types/brand.ts +14 -0
- package/src/shared/types/client.d.ts +45 -0
- package/src/shared/types/either.ts +38 -0
- package/src/shared/types/index.ts +42 -0
- package/src/shared/types/option.ts +52 -0
- package/src/shared/types/result.ts +81 -0
- package/src/shared/utils/array.ts +97 -0
- package/src/shared/utils/index.ts +46 -0
- package/src/shared/utils/object.ts +47 -0
- package/src/shared/utils/string.ts +74 -0
- package/src/toc-generator/index.ts +1 -0
- package/src/types/js-yaml.d.ts +42 -0
- package/src/worker.ts +462 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { useParams } from "@tanstack/solid-router";
|
|
2
|
+
import { dump as dumpYaml } from "js-yaml";
|
|
3
|
+
import { createResource, createSignal, Show } from "solid-js";
|
|
4
|
+
import { DocMarkdown } from "../components/DocMarkdown";
|
|
5
|
+
import { getGitHubToken } from "../components/GitHubAuth";
|
|
6
|
+
import { useDocs } from "../context";
|
|
7
|
+
import { useCollections } from "../data";
|
|
8
|
+
|
|
9
|
+
function repoInfo(url?: string) {
|
|
10
|
+
if (!url) return null;
|
|
11
|
+
const match = url.match(/github\.com[:/]([^/]+)\/([^/]+)/);
|
|
12
|
+
if (!match) return null;
|
|
13
|
+
return { owner: match[1], repo: match[2].replace(/\.git$/, "") };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function stringifyFrontmatter(fm: Record<string, unknown>): string {
|
|
17
|
+
const body = dumpYaml(fm, { lineWidth: -1, noRefs: true }).trimEnd();
|
|
18
|
+
return `---\n${body}\n---`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function EditPage() {
|
|
22
|
+
const params = useParams({ strict: false });
|
|
23
|
+
const collection = () => params().collection ?? "";
|
|
24
|
+
const docId = () => params().docId ?? "";
|
|
25
|
+
const config = useDocs();
|
|
26
|
+
const dataSource = config.dataSource;
|
|
27
|
+
const collections = useCollections();
|
|
28
|
+
const colMeta = () => collections()?.find((c) => c.id === collection());
|
|
29
|
+
|
|
30
|
+
const [doc] = createResource(
|
|
31
|
+
() => ({ collection: collection(), id: docId() }),
|
|
32
|
+
async ({ collection, id }) => {
|
|
33
|
+
if (!collection || !id)
|
|
34
|
+
return {
|
|
35
|
+
id: "",
|
|
36
|
+
label: "",
|
|
37
|
+
content: "",
|
|
38
|
+
frontmatter: {},
|
|
39
|
+
};
|
|
40
|
+
return dataSource.get(collection, id);
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const [source, setSource] = createSignal("");
|
|
45
|
+
const [message, setMessage] = createSignal("");
|
|
46
|
+
const [showPreview, setShowPreview] = createSignal(true);
|
|
47
|
+
|
|
48
|
+
const fullSource = () => {
|
|
49
|
+
const d = doc();
|
|
50
|
+
if (!d) return "";
|
|
51
|
+
const fm = d.frontmatter;
|
|
52
|
+
if (!fm || Object.keys(fm).length === 0) return d.content ?? "";
|
|
53
|
+
return `${stringifyFrontmatter(fm)}\n${d.content ?? ""}`;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
createResource(
|
|
57
|
+
() => doc(),
|
|
58
|
+
(d) => {
|
|
59
|
+
if (d) setSource(fullSource());
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const handleDownload = () => {
|
|
64
|
+
const blob = new Blob([source()], { type: "text/markdown" });
|
|
65
|
+
const url = URL.createObjectURL(blob);
|
|
66
|
+
const a = document.createElement("a");
|
|
67
|
+
a.href = url;
|
|
68
|
+
a.download = `${docId()}.md`;
|
|
69
|
+
a.click();
|
|
70
|
+
URL.revokeObjectURL(url);
|
|
71
|
+
setMessage("Downloaded .md");
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleCopy = async () => {
|
|
75
|
+
try {
|
|
76
|
+
await navigator.clipboard.writeText(source());
|
|
77
|
+
setMessage("Copied .md to clipboard");
|
|
78
|
+
} catch {
|
|
79
|
+
setMessage("Copy failed");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleSave = async () => {
|
|
84
|
+
const repo = config.site.repoUrl ? repoInfo(config.site.repoUrl) : null;
|
|
85
|
+
if (!repo) {
|
|
86
|
+
setMessage("GitHub repo not configured");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const filePath = doc()?.path;
|
|
90
|
+
if (!filePath) {
|
|
91
|
+
setMessage("Document path unknown");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const userToken = getGitHubToken();
|
|
96
|
+
const res = await fetch("/api/content/save", {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
...(userToken ? { Authorization: `Bearer ${userToken}` } : {}),
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
...repo,
|
|
104
|
+
path: `apps/web/create-docs/${collection()}/${filePath}`,
|
|
105
|
+
content: source(),
|
|
106
|
+
message: `docs: update ${collection()}/${docId()} [via create-docs editor]`,
|
|
107
|
+
branch: config.github?.branch ?? "main",
|
|
108
|
+
owner: repo.owner,
|
|
109
|
+
repo: repo.repo,
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
const data = (await res.json()) as { ok?: boolean; error?: string };
|
|
113
|
+
if (!res.ok) throw new Error(data.error ?? "Save failed");
|
|
114
|
+
setMessage("Saved to GitHub");
|
|
115
|
+
} catch (e) {
|
|
116
|
+
setMessage(e instanceof Error ? e.message : "Save failed");
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const canSave = () => !!config.site.repoUrl;
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div class="max-w-6xl mx-auto px-6 py-8">
|
|
124
|
+
<div class="flex items-center gap-3 mb-6 flex-wrap">
|
|
125
|
+
<h1 class="text-xl font-semibold text-foreground">
|
|
126
|
+
Edit: {collection()}/{docId()}
|
|
127
|
+
</h1>
|
|
128
|
+
<span class="text-sm text-muted">{colMeta()?.label}</span>
|
|
129
|
+
<div class="flex-1" />
|
|
130
|
+
<button
|
|
131
|
+
type="button"
|
|
132
|
+
onClick={() => setShowPreview((s) => !s)}
|
|
133
|
+
class="inline-flex items-center gap-1.5 px-3 h-8 rounded-md border border-border text-xs text-muted hover:text-foreground hover:bg-surface transition-colors bg-transparent"
|
|
134
|
+
>
|
|
135
|
+
<span class="i-mdi:eye" aria-hidden="true" />
|
|
136
|
+
{showPreview() ? "Hide preview" : "Show preview"}
|
|
137
|
+
</button>
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
onClick={handleCopy}
|
|
141
|
+
class="inline-flex items-center gap-1.5 px-3 h-8 rounded-md border border-border text-xs text-muted hover:text-foreground hover:bg-surface transition-colors bg-transparent"
|
|
142
|
+
>
|
|
143
|
+
<span class="i-mdi:content-copy" aria-hidden="true" />
|
|
144
|
+
Copy .md
|
|
145
|
+
</button>
|
|
146
|
+
<button
|
|
147
|
+
type="button"
|
|
148
|
+
onClick={handleDownload}
|
|
149
|
+
class="inline-flex items-center gap-1.5 px-3 h-8 rounded-md border border-border text-xs text-muted hover:text-foreground hover:bg-surface transition-colors bg-transparent"
|
|
150
|
+
>
|
|
151
|
+
<span class="i-mdi:download" aria-hidden="true" />
|
|
152
|
+
Download .md
|
|
153
|
+
</button>
|
|
154
|
+
<Show when={canSave()}>
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
onClick={handleSave}
|
|
158
|
+
class="inline-flex items-center gap-1.5 px-3 h-8 rounded-md border border-border text-xs text-success hover:text-foreground hover:bg-surface transition-colors bg-transparent"
|
|
159
|
+
>
|
|
160
|
+
<span class="i-mdi:github" aria-hidden="true" />
|
|
161
|
+
Save to GitHub
|
|
162
|
+
</button>
|
|
163
|
+
</Show>
|
|
164
|
+
</div>
|
|
165
|
+
<Show when={message()}>
|
|
166
|
+
<div class="mb-4 text-sm text-success">{message()}</div>
|
|
167
|
+
</Show>
|
|
168
|
+
<div
|
|
169
|
+
class={`grid gap-6 ${showPreview() ? "grid-cols-1 lg:grid-cols-2" : "grid-cols-1"}`}
|
|
170
|
+
>
|
|
171
|
+
<div class="flex flex-col gap-2">
|
|
172
|
+
<label class="text-xs text-muted uppercase tracking-wider">
|
|
173
|
+
Markdown source
|
|
174
|
+
<textarea
|
|
175
|
+
value={source()}
|
|
176
|
+
onInput={(e) => setSource(e.currentTarget.value)}
|
|
177
|
+
class="w-full h-[70vh] p-4 mt-2 rounded-md border border-border bg-surface font-mono text-sm text-foreground resize-none focus:outline-none focus:border-focus"
|
|
178
|
+
spellcheck={false}
|
|
179
|
+
/>
|
|
180
|
+
</label>
|
|
181
|
+
</div>
|
|
182
|
+
<Show when={showPreview()}>
|
|
183
|
+
<div class="flex flex-col gap-2 min-w-0">
|
|
184
|
+
<div
|
|
185
|
+
id="edit-preview-label"
|
|
186
|
+
class="text-xs text-muted uppercase tracking-wider"
|
|
187
|
+
>
|
|
188
|
+
Live preview
|
|
189
|
+
</div>
|
|
190
|
+
<section
|
|
191
|
+
aria-labelledby="edit-preview-label"
|
|
192
|
+
class="flex-1 rounded-md border border-border bg-surface p-4 overflow-auto h-[70vh]"
|
|
193
|
+
>
|
|
194
|
+
<DocMarkdown source={source()} />
|
|
195
|
+
</section>
|
|
196
|
+
</div>
|
|
197
|
+
</Show>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Link } from "@tanstack/solid-router";
|
|
2
|
+
import { createSignal, For, onCleanup, onMount, Show } from "solid-js";
|
|
3
|
+
import { GitHubStats } from "../components/GitHubStats";
|
|
4
|
+
import type { HomeFeature } from "../config";
|
|
5
|
+
import { useDocs } from "../context";
|
|
6
|
+
|
|
7
|
+
function FeatureCard(props: { f: HomeFeature; class?: string }) {
|
|
8
|
+
const f = () => props.f;
|
|
9
|
+
const inner = (
|
|
10
|
+
<>
|
|
11
|
+
<Show when={f().icon}>
|
|
12
|
+
<span class={`${f().icon} text-2xl text-primary`} aria-hidden="true" />
|
|
13
|
+
</Show>
|
|
14
|
+
<h2 class="text-base font-semibold text-foreground m-0">{f().title}</h2>
|
|
15
|
+
<Show when={f().details}>
|
|
16
|
+
<p class="text-sm text-muted m-0 leading-relaxed">{f().details}</p>
|
|
17
|
+
</Show>
|
|
18
|
+
</>
|
|
19
|
+
);
|
|
20
|
+
const cls = `flex flex-col gap-2 p-5 rounded-xl border border-border bg-surface no-underline hover:border-focus hover:-translate-y-0.5 hover:shadow-lg transition-all ${props.class ?? ""}`;
|
|
21
|
+
return f().link ? (
|
|
22
|
+
<Link to={f().link ?? "/"} class={cls}>
|
|
23
|
+
{inner}
|
|
24
|
+
</Link>
|
|
25
|
+
) : (
|
|
26
|
+
<div class={cls}>{inner}</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function FeatureSlider(props: { items: HomeFeature[] }) {
|
|
31
|
+
const [index, setIndex] = createSignal(0);
|
|
32
|
+
const [paused, setPaused] = createSignal(false);
|
|
33
|
+
let track: HTMLDivElement | undefined;
|
|
34
|
+
|
|
35
|
+
const go = (i: number) => {
|
|
36
|
+
const n = props.items.length;
|
|
37
|
+
if (!n) return;
|
|
38
|
+
const next = ((i % n) + n) % n;
|
|
39
|
+
setIndex(next);
|
|
40
|
+
const child = track?.children[next] as HTMLElement | undefined;
|
|
41
|
+
child?.scrollIntoView({
|
|
42
|
+
behavior: "smooth",
|
|
43
|
+
inline: "nearest",
|
|
44
|
+
block: "nearest",
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
onMount(() => {
|
|
49
|
+
const t = setInterval(() => {
|
|
50
|
+
if (!paused()) go(index() + 1);
|
|
51
|
+
}, 5000);
|
|
52
|
+
onCleanup(() => clearInterval(t));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<section
|
|
57
|
+
class="max-w-5xl mx-auto px-6 pb-16"
|
|
58
|
+
aria-label="Feature highlights"
|
|
59
|
+
onMouseEnter={() => setPaused(true)}
|
|
60
|
+
onMouseLeave={() => setPaused(false)}
|
|
61
|
+
>
|
|
62
|
+
<div class="flex items-center justify-between mb-4">
|
|
63
|
+
<h2 class="text-lg font-semibold text-foreground m-0">Highlights</h2>
|
|
64
|
+
<div class="flex items-center gap-1">
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
onClick={() => go(index() - 1)}
|
|
68
|
+
aria-label="Previous slide"
|
|
69
|
+
class="w-8 h-8 inline-flex items-center justify-center rounded-md border border-border text-muted hover:text-foreground hover:bg-surface transition-colors cursor-pointer bg-transparent"
|
|
70
|
+
>
|
|
71
|
+
<span class="i-mdi:chevron-left" aria-hidden="true" />
|
|
72
|
+
</button>
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
onClick={() => go(index() + 1)}
|
|
76
|
+
aria-label="Next slide"
|
|
77
|
+
class="w-8 h-8 inline-flex items-center justify-center rounded-md border border-border text-muted hover:text-foreground hover:bg-surface transition-colors cursor-pointer bg-transparent"
|
|
78
|
+
>
|
|
79
|
+
<span class="i-mdi:chevron-right" aria-hidden="true" />
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<div
|
|
84
|
+
ref={track}
|
|
85
|
+
class="flex gap-4 overflow-x-auto snap-x snap-mandatory pb-2 [scrollbar-width:thin]"
|
|
86
|
+
>
|
|
87
|
+
<For each={props.items}>
|
|
88
|
+
{(f) => (
|
|
89
|
+
<div class="snap-start shrink-0 w-72">
|
|
90
|
+
<FeatureCard f={f} class="h-full" />
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
</For>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="flex justify-center gap-1.5 mt-3">
|
|
96
|
+
<For each={props.items}>
|
|
97
|
+
{(_, i) => (
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
onClick={() => go(i())}
|
|
101
|
+
aria-label={`Go to slide ${i() + 1}`}
|
|
102
|
+
class={`h-1.5 rounded-full transition-all cursor-pointer border-none p-0 ${
|
|
103
|
+
index() === i()
|
|
104
|
+
? "w-5 bg-primary"
|
|
105
|
+
: "w-1.5 bg-border hover:bg-muted"
|
|
106
|
+
}`}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
</For>
|
|
110
|
+
</div>
|
|
111
|
+
</section>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** VitePress-style home layout: hero + actions + feature cards + slider. */
|
|
116
|
+
export function HomePage() {
|
|
117
|
+
const config = useDocs();
|
|
118
|
+
const home = () => config.home;
|
|
119
|
+
const slides = () => home()?.slides ?? home()?.features ?? [];
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div class="flex-1">
|
|
123
|
+
<Show when={home()?.hero}>
|
|
124
|
+
{(hero) => (
|
|
125
|
+
<section class="relative max-w-4xl mx-auto px-6 pt-20 pb-12 text-center overflow-hidden">
|
|
126
|
+
<div
|
|
127
|
+
class="absolute inset-0 -z-10 pointer-events-none"
|
|
128
|
+
aria-hidden="true"
|
|
129
|
+
style={{
|
|
130
|
+
background:
|
|
131
|
+
"radial-gradient(ellipse 60% 50% at 50% 0%, hsl(var(--color-primary) / 0.12), transparent 70%)",
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
<Show when={hero().badge}>
|
|
135
|
+
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full border border-border bg-surface text-xs text-muted mb-4">
|
|
136
|
+
<span class="i-mdi:sparkles text-primary" aria-hidden="true" />
|
|
137
|
+
{hero().badge}
|
|
138
|
+
</span>
|
|
139
|
+
</Show>
|
|
140
|
+
<Show when={hero().name}>
|
|
141
|
+
<p class="text-sm font-semibold tracking-widest uppercase text-primary m-0 mb-3">
|
|
142
|
+
{hero().name}
|
|
143
|
+
</p>
|
|
144
|
+
</Show>
|
|
145
|
+
<h1 class="text-4xl md:text-5xl font-bold text-foreground m-0 mb-4 leading-tight">
|
|
146
|
+
{hero().text ?? config.site.title}
|
|
147
|
+
</h1>
|
|
148
|
+
<Show when={hero().tagline}>
|
|
149
|
+
<p class="text-lg text-muted m-0 mb-8 max-w-2xl mx-auto">
|
|
150
|
+
{hero().tagline}
|
|
151
|
+
</p>
|
|
152
|
+
</Show>
|
|
153
|
+
<Show when={hero().actions?.length}>
|
|
154
|
+
<div class="flex items-center justify-center gap-3 flex-wrap">
|
|
155
|
+
<For each={hero().actions}>
|
|
156
|
+
{(a) => (
|
|
157
|
+
<Link
|
|
158
|
+
to={a.link}
|
|
159
|
+
class={`inline-flex items-center px-5 h-11 rounded-lg text-sm font-medium no-underline transition-colors ${
|
|
160
|
+
a.theme === "alt"
|
|
161
|
+
? "border border-border text-foreground hover:bg-surface"
|
|
162
|
+
: "bg-primary text-primary-foreground hover:bg-primary-hover"
|
|
163
|
+
}`}
|
|
164
|
+
>
|
|
165
|
+
{a.text}
|
|
166
|
+
</Link>
|
|
167
|
+
)}
|
|
168
|
+
</For>
|
|
169
|
+
</div>
|
|
170
|
+
</Show>
|
|
171
|
+
<div class="mt-8 flex justify-center">
|
|
172
|
+
<GitHubStats />
|
|
173
|
+
</div>
|
|
174
|
+
</section>
|
|
175
|
+
)}
|
|
176
|
+
</Show>
|
|
177
|
+
<Show when={slides().length > 0}>
|
|
178
|
+
<FeatureSlider items={slides()} />
|
|
179
|
+
</Show>
|
|
180
|
+
<Show when={home()?.features?.length}>
|
|
181
|
+
<section class="max-w-5xl mx-auto px-6 pb-20 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
182
|
+
<For each={home()?.features}>{(f) => <FeatureCard f={f} />}</For>
|
|
183
|
+
</section>
|
|
184
|
+
</Show>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createSignal, For, onMount, Show } from "solid-js";
|
|
2
|
+
import { SkeletonPage } from "../components/Skeleton";
|
|
3
|
+
import { useDocs } from "../context";
|
|
4
|
+
import { fetchIssues, GitHubFetchError, type IssueInfo } from "../github";
|
|
5
|
+
|
|
6
|
+
function formatDate(iso: string) {
|
|
7
|
+
try {
|
|
8
|
+
return new Date(iso).toLocaleDateString(undefined, {
|
|
9
|
+
year: "numeric",
|
|
10
|
+
month: "short",
|
|
11
|
+
day: "numeric",
|
|
12
|
+
});
|
|
13
|
+
} catch {
|
|
14
|
+
return iso;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function IssuesPage() {
|
|
19
|
+
const config = useDocs();
|
|
20
|
+
const [issues, setIssues] = createSignal<IssueInfo[]>([]);
|
|
21
|
+
const [loading, setLoading] = createSignal(true);
|
|
22
|
+
const [error, setError] = createSignal<string | null>(null);
|
|
23
|
+
|
|
24
|
+
onMount(async () => {
|
|
25
|
+
const cfg = config.github;
|
|
26
|
+
if (!cfg?.issues) {
|
|
27
|
+
setLoading(false);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
setIssues(await fetchIssues(cfg));
|
|
32
|
+
} catch (err) {
|
|
33
|
+
if (err instanceof GitHubFetchError) {
|
|
34
|
+
setError(
|
|
35
|
+
err.status === 404
|
|
36
|
+
? "Issues not found. Make sure the repository is public."
|
|
37
|
+
: `${err.message}: ${err.payload ?? ""}`.slice(0, 200),
|
|
38
|
+
);
|
|
39
|
+
} else if (err instanceof Error) {
|
|
40
|
+
setError(err.message);
|
|
41
|
+
} else {
|
|
42
|
+
setError("Could not load issues from GitHub.");
|
|
43
|
+
}
|
|
44
|
+
} finally {
|
|
45
|
+
setLoading(false);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div class="max-w-4xl mx-auto px-6 py-8">
|
|
51
|
+
<h1 class="text-3xl font-bold mb-2">Issues</h1>
|
|
52
|
+
<p class="text-muted mb-8">Open issues from GitHub</p>
|
|
53
|
+
|
|
54
|
+
<Show when={loading()}>
|
|
55
|
+
<SkeletonPage />
|
|
56
|
+
</Show>
|
|
57
|
+
|
|
58
|
+
<Show when={!loading() && error()}>
|
|
59
|
+
<div class="border border-destructive/30 bg-destructive/10 rounded-lg p-5 mb-6">
|
|
60
|
+
<div class="flex items-center gap-2 mb-1 text-destructive font-medium">
|
|
61
|
+
<span class="i-mdi:alert-circle" aria-hidden="true" />
|
|
62
|
+
Failed to load issues
|
|
63
|
+
</div>
|
|
64
|
+
<p class="text-sm text-destructive/90 mb-3">{error()}</p>
|
|
65
|
+
<Show when={config.site.repoUrl}>
|
|
66
|
+
<a
|
|
67
|
+
href={`${config.site.repoUrl}/issues`}
|
|
68
|
+
target="_blank"
|
|
69
|
+
rel="noreferrer"
|
|
70
|
+
class="inline-flex items-center gap-1.5 text-sm text-primary hover:underline"
|
|
71
|
+
>
|
|
72
|
+
<span class="i-mdi:open-in-new" aria-hidden="true" />
|
|
73
|
+
View on GitHub
|
|
74
|
+
</a>
|
|
75
|
+
</Show>
|
|
76
|
+
</div>
|
|
77
|
+
</Show>
|
|
78
|
+
|
|
79
|
+
<Show when={!loading() && !error() && issues().length === 0}>
|
|
80
|
+
<div class="flex flex-col items-center gap-3 py-16 rounded-lg border border-dashed border-border text-muted">
|
|
81
|
+
<span class="i-mdi:check-circle text-4xl" aria-hidden="true" />
|
|
82
|
+
<p class="m-0">No open issues.</p>
|
|
83
|
+
</div>
|
|
84
|
+
</Show>
|
|
85
|
+
|
|
86
|
+
<div class="space-y-3">
|
|
87
|
+
<For each={issues()}>
|
|
88
|
+
{(issue) => (
|
|
89
|
+
<article class="border border-border rounded-lg p-4 bg-surface/30 hover:border-focus transition-colors">
|
|
90
|
+
<div class="flex items-start gap-3">
|
|
91
|
+
<span
|
|
92
|
+
class="i-mdi:alert-circle-outline text-lg text-primary mt-0.5"
|
|
93
|
+
aria-hidden="true"
|
|
94
|
+
/>
|
|
95
|
+
<div class="flex-1 min-w-0">
|
|
96
|
+
<div class="flex items-center gap-2 mb-1">
|
|
97
|
+
<span class="text-xs text-muted font-mono">
|
|
98
|
+
#{issue.number}
|
|
99
|
+
</span>
|
|
100
|
+
<a
|
|
101
|
+
href={issue.html_url}
|
|
102
|
+
target="_blank"
|
|
103
|
+
rel="noreferrer"
|
|
104
|
+
class="font-medium hover:text-primary transition-colors truncate"
|
|
105
|
+
>
|
|
106
|
+
{issue.title}
|
|
107
|
+
</a>
|
|
108
|
+
</div>
|
|
109
|
+
<div class="flex flex-wrap items-center gap-2 text-xs text-muted mb-2">
|
|
110
|
+
<span>opened {formatDate(issue.created_at)}</span>
|
|
111
|
+
<span>·</span>
|
|
112
|
+
<span>{issue.comments} comments</span>
|
|
113
|
+
</div>
|
|
114
|
+
<Show when={issue.labels.length}>
|
|
115
|
+
<div class="flex flex-wrap gap-1.5">
|
|
116
|
+
<For each={issue.labels}>
|
|
117
|
+
{(label) => (
|
|
118
|
+
<span
|
|
119
|
+
class="text-[10px] px-2 py-0.5 rounded-full border border-border"
|
|
120
|
+
style={{
|
|
121
|
+
"background-color": `#${label.color}20`,
|
|
122
|
+
color: `#${label.color}`,
|
|
123
|
+
"border-color": `#${label.color}40`,
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
{label.name}
|
|
127
|
+
</span>
|
|
128
|
+
)}
|
|
129
|
+
</For>
|
|
130
|
+
</div>
|
|
131
|
+
</Show>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</article>
|
|
135
|
+
)}
|
|
136
|
+
</For>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useNavigate } from "@tanstack/solid-router";
|
|
2
|
+
import { createSignal, onMount, Show } from "solid-js";
|
|
3
|
+
import { setGitHubToken } from "../components/GitHubAuth";
|
|
4
|
+
|
|
5
|
+
export function OAuthCallbackPage() {
|
|
6
|
+
const navigate = useNavigate();
|
|
7
|
+
const [error, setError] = createSignal("");
|
|
8
|
+
|
|
9
|
+
onMount(async () => {
|
|
10
|
+
const params = new URLSearchParams(window.location.search);
|
|
11
|
+
const code = params.get("code");
|
|
12
|
+
const state = params.get("state");
|
|
13
|
+
const expected = sessionStorage.getItem("create-docs:oauth-state");
|
|
14
|
+
const oauthError = params.get("error");
|
|
15
|
+
const errorDescription = params.get("error_description");
|
|
16
|
+
|
|
17
|
+
if (oauthError) {
|
|
18
|
+
setError(errorDescription ?? oauthError);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
sessionStorage.removeItem("create-docs:oauth-state");
|
|
23
|
+
|
|
24
|
+
if (!code || !state || state !== expected) {
|
|
25
|
+
setError("Invalid OAuth callback. Please try authorizing again.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch("/api/github/token", {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: { "Content-Type": "application/json" },
|
|
33
|
+
body: JSON.stringify({ code }),
|
|
34
|
+
});
|
|
35
|
+
const data = (await res.json()) as {
|
|
36
|
+
access_token?: string;
|
|
37
|
+
error?: string;
|
|
38
|
+
message?: string;
|
|
39
|
+
};
|
|
40
|
+
if (!res.ok || data.error || !data.access_token) {
|
|
41
|
+
throw new Error(data.message ?? data.error ?? "Token exchange failed.");
|
|
42
|
+
}
|
|
43
|
+
setGitHubToken(data.access_token);
|
|
44
|
+
navigate({ to: "/create" });
|
|
45
|
+
} catch (e) {
|
|
46
|
+
setError(e instanceof Error ? e.message : "Token exchange failed.");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div class="min-h-[70vh] flex flex-col items-center justify-center px-6 py-20 text-center">
|
|
52
|
+
<Show
|
|
53
|
+
when={!error()}
|
|
54
|
+
fallback={
|
|
55
|
+
<>
|
|
56
|
+
<span
|
|
57
|
+
class="i-mdi:alert-circle text-3xl text-destructive mb-4"
|
|
58
|
+
aria-hidden="true"
|
|
59
|
+
/>
|
|
60
|
+
<h1 class="text-xl font-bold mb-2">Authorization failed</h1>
|
|
61
|
+
<p class="text-sm text-muted mb-6">{error()}</p>
|
|
62
|
+
<a
|
|
63
|
+
href="/create"
|
|
64
|
+
class="inline-flex items-center gap-2 px-4 h-10 rounded-md bg-primary text-primary-foreground no-underline font-medium"
|
|
65
|
+
>
|
|
66
|
+
Back to create
|
|
67
|
+
</a>
|
|
68
|
+
</>
|
|
69
|
+
}
|
|
70
|
+
>
|
|
71
|
+
<span
|
|
72
|
+
class="i-mdi:loading animate-spin text-3xl text-primary mb-4"
|
|
73
|
+
aria-hidden="true"
|
|
74
|
+
/>
|
|
75
|
+
<h1 class="text-xl font-bold mb-2">Completing GitHub authorization…</h1>
|
|
76
|
+
<p class="text-sm text-muted">You will be redirected in a moment.</p>
|
|
77
|
+
</Show>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|