chore: add helix-api and workspace config to monorepo
This commit is contained in:
40 files changed
+7145
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
# Claude Code local tooling
|
||||||
|
.claude/
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"java.compile.nullAnalysis.mode": "disabled",
|
||||||
|
"java.configuration.updateBuildConfiguration": "automatic"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Secrets
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
info:
|
||||||
|
name: Login
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
url: "{{BaseURL}}/auth/login"
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: |-
|
||||||
|
{
|
||||||
|
"username": "helix",
|
||||||
|
"password": "123456"
|
||||||
|
}
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
info:
|
||||||
|
name: Authentication
|
||||||
|
type: folder
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
request:
|
||||||
|
auth: inherit
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
info:
|
||||||
|
name: Add Department
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
url: "{{BaseURL}}/departments"
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: |-
|
||||||
|
{
|
||||||
|
"name": "Domestic Marketing",
|
||||||
|
"parentId": 10,
|
||||||
|
"sort": null,
|
||||||
|
"status": null
|
||||||
|
}
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
info:
|
||||||
|
name: Departments
|
||||||
|
type: folder
|
||||||
|
seq: 2
|
||||||
|
|
||||||
|
request:
|
||||||
|
auth: inherit
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
name: Development
|
||||||
|
variables:
|
||||||
|
- name: BaseURL
|
||||||
|
value: http://localhost:5000
|
||||||
|
- name: language
|
||||||
|
value: zh-CN
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
opencollection: 1.0.0
|
||||||
|
|
||||||
|
info:
|
||||||
|
name: Helix
|
||||||
|
config:
|
||||||
|
proxy:
|
||||||
|
inherit: true
|
||||||
|
config:
|
||||||
|
protocol: http
|
||||||
|
hostname: ""
|
||||||
|
port: ""
|
||||||
|
auth:
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
bypassProxy: ""
|
||||||
|
|
||||||
|
request:
|
||||||
|
headers:
|
||||||
|
- name: Accept-Language
|
||||||
|
value: "{{language}}"
|
||||||
|
bundled: false
|
||||||
|
extensions:
|
||||||
|
bruno:
|
||||||
|
ignore:
|
||||||
|
- node_modules
|
||||||
|
- .git
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.DS_Store
|
||||||
|
/node_modules/
|
||||||
|
|
||||||
|
# React Router
|
||||||
|
/.react-router/
|
||||||
|
/build/
|
||||||
|
.source
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Helix API Docs
|
||||||
|
|
||||||
|
Vite + React Router + Fumadocs documentation app with OpenAPI support.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open these pages:
|
||||||
|
|
||||||
|
- `/api-reference`: OpenAPI interactive reference
|
||||||
|
- `/docs`: MDX docs pages
|
||||||
|
|
||||||
|
## Edit OpenAPI
|
||||||
|
|
||||||
|
Manually maintain:
|
||||||
|
|
||||||
|
- `openapi/openapi.yaml`
|
||||||
|
|
||||||
|
After changes, refresh the `/api-reference` page.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@import 'tailwindcss';
|
||||||
|
@import 'fumadocs-ui/css/neutral.css';
|
||||||
|
@import 'fumadocs-ui/css/preset.css';
|
||||||
|
@import 'fumadocs-openapi/css/preset.css';
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { openapi } from '@/lib/openapi';
|
||||||
|
import { createAPIPage } from 'fumadocs-openapi/ui';
|
||||||
|
|
||||||
|
export const APIPage = createAPIPage(openapi);
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||||
|
import type { MDXComponents } from 'mdx/types';
|
||||||
|
|
||||||
|
export function getMDXComponents(components?: MDXComponents) {
|
||||||
|
return {
|
||||||
|
...defaultMdxComponents,
|
||||||
|
...components,
|
||||||
|
} satisfies MDXComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMDXComponents = getMDXComponents;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
'use client';
|
||||||
|
import {
|
||||||
|
SearchDialog,
|
||||||
|
SearchDialogClose,
|
||||||
|
SearchDialogContent,
|
||||||
|
SearchDialogHeader,
|
||||||
|
SearchDialogIcon,
|
||||||
|
SearchDialogInput,
|
||||||
|
SearchDialogList,
|
||||||
|
SearchDialogOverlay,
|
||||||
|
type SharedProps,
|
||||||
|
} from 'fumadocs-ui/components/dialog/search';
|
||||||
|
import { useDocsSearch } from 'fumadocs-core/search/client';
|
||||||
|
import { create } from '@orama/orama';
|
||||||
|
import { useI18n } from 'fumadocs-ui/contexts/i18n';
|
||||||
|
|
||||||
|
function initOrama() {
|
||||||
|
return create({
|
||||||
|
schema: { _: 'string' },
|
||||||
|
language: 'english',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DefaultSearchDialog(props: SharedProps) {
|
||||||
|
const { locale } = useI18n();
|
||||||
|
const { search, setSearch, query } = useDocsSearch({
|
||||||
|
type: 'static',
|
||||||
|
initOrama,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SearchDialog search={search} onSearchChange={setSearch} isLoading={query.isLoading} {...props}>
|
||||||
|
<SearchDialogOverlay />
|
||||||
|
<SearchDialogContent>
|
||||||
|
<SearchDialogHeader>
|
||||||
|
<SearchDialogIcon />
|
||||||
|
<SearchDialogInput />
|
||||||
|
<SearchDialogClose />
|
||||||
|
</SearchDialogHeader>
|
||||||
|
<SearchDialogList items={query.data !== 'empty' ? query.data : null} />
|
||||||
|
</SearchDialogContent>
|
||||||
|
</SearchDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { twMerge as cn } from 'tailwind-merge';
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
|
||||||
|
|
||||||
|
// fill this with your actual GitHub info, for example:
|
||||||
|
export const gitConfig = {
|
||||||
|
user: 'fuma-nama',
|
||||||
|
repo: 'fumadocs',
|
||||||
|
branch: 'main',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function baseOptions(): BaseLayoutProps {
|
||||||
|
return {
|
||||||
|
nav: {
|
||||||
|
title: 'React Router',
|
||||||
|
},
|
||||||
|
githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import path from 'node:path';
|
||||||
|
import { createOpenAPI } from 'fumadocs-openapi/server';
|
||||||
|
|
||||||
|
export const openapi = createOpenAPI({
|
||||||
|
input: () => ({
|
||||||
|
helix: path.resolve('./openapi/openapi.yaml'),
|
||||||
|
}),
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { loader, type InferPageType } from 'fumadocs-core/source';
|
||||||
|
import { docs } from 'collections/server';
|
||||||
|
|
||||||
|
export const source = loader({
|
||||||
|
source: docs.toFumadocsSource(),
|
||||||
|
baseUrl: '/docs',
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function getLLMText(page: InferPageType<typeof source>) {
|
||||||
|
const processed = await page.data.getText('processed');
|
||||||
|
|
||||||
|
return `# ${page.data.title} (${page.url})
|
||||||
|
|
||||||
|
${processed}`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { getLLMText, source } from '@/lib/source';
|
||||||
|
|
||||||
|
export async function loader() {
|
||||||
|
const scan = source.getPages().map(getLLMText);
|
||||||
|
const scanned = await Promise.all(scan);
|
||||||
|
|
||||||
|
return new Response(scanned.join('\n\n'));
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { source } from '@/lib/source';
|
||||||
|
import { llms } from 'fumadocs-core/source';
|
||||||
|
|
||||||
|
export function loader() {
|
||||||
|
return new Response(llms(source).index());
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import type { Route } from './+types/mdx';
|
||||||
|
import { getLLMText, source } from '@/lib/source';
|
||||||
|
|
||||||
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const slugs = params['*'].split('/').filter((v) => v.length > 0);
|
||||||
|
// remove the appended "index.mdx" that's added to avoid React Router issues
|
||||||
|
slugs.pop();
|
||||||
|
const page = source.getPage(slugs);
|
||||||
|
if (!page) {
|
||||||
|
return new Response('not found', { status: 404 });
|
||||||
|
}
|
||||||
|
return new Response(await getLLMText(page), {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/markdown',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import {
|
||||||
|
isRouteErrorResponse,
|
||||||
|
Links,
|
||||||
|
Meta,
|
||||||
|
Outlet,
|
||||||
|
Scripts,
|
||||||
|
ScrollRestoration,
|
||||||
|
} from 'react-router';
|
||||||
|
import { RootProvider } from 'fumadocs-ui/provider/react-router';
|
||||||
|
import type { Route } from './+types/root';
|
||||||
|
import './app.css';
|
||||||
|
import SearchDialog from '@/components/search';
|
||||||
|
import NotFound from './routes/not-found';
|
||||||
|
|
||||||
|
export const links: Route.LinksFunction = () => [
|
||||||
|
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
|
||||||
|
{
|
||||||
|
rel: 'preconnect',
|
||||||
|
href: 'https://fonts.gstatic.com',
|
||||||
|
crossOrigin: 'anonymous',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'stylesheet',
|
||||||
|
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html lang="en" suppressHydrationWarning>
|
||||||
|
<head>
|
||||||
|
<meta charSet="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<Meta />
|
||||||
|
<Links />
|
||||||
|
</head>
|
||||||
|
<body className="flex flex-col min-h-screen">
|
||||||
|
<RootProvider search={{ SearchDialog }}>{children}</RootProvider>
|
||||||
|
<ScrollRestoration />
|
||||||
|
<Scripts />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return <Outlet />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
||||||
|
let message = 'Oops!';
|
||||||
|
let details = 'An unexpected error occurred.';
|
||||||
|
let stack: string | undefined;
|
||||||
|
|
||||||
|
if (isRouteErrorResponse(error)) {
|
||||||
|
if (error.status === 404) return <NotFound />;
|
||||||
|
message = 'Error';
|
||||||
|
details = error.statusText;
|
||||||
|
} else if (import.meta.env.DEV && error && error instanceof Error) {
|
||||||
|
details = error.message;
|
||||||
|
stack = error.stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="pt-16 p-4 w-full max-w-[1400px] mx-auto">
|
||||||
|
<h1>{message}</h1>
|
||||||
|
<p>{details}</p>
|
||||||
|
{stack && (
|
||||||
|
<pre className="w-full p-4 overflow-x-auto">
|
||||||
|
<code>{stack}</code>
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { index, route, type RouteConfig } from '@react-router/dev/routes';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
index('routes/home.tsx'),
|
||||||
|
route('docs/*', 'routes/docs.tsx'),
|
||||||
|
route('api-reference', 'routes/api-reference.tsx'),
|
||||||
|
route('api/search', 'routes/search.ts'),
|
||||||
|
|
||||||
|
// LLM integration:
|
||||||
|
route('llms.txt', 'llms/index.ts'),
|
||||||
|
route('llms-full.txt', 'llms/full.ts'),
|
||||||
|
route('llms.mdx/docs/*', 'llms/mdx.ts'),
|
||||||
|
|
||||||
|
route('*', 'routes/not-found.tsx'),
|
||||||
|
] satisfies RouteConfig;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type { Route } from './+types/api-reference';
|
||||||
|
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||||
|
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
|
||||||
|
import { source } from '@/lib/source';
|
||||||
|
import { baseOptions } from '@/lib/layout.shared';
|
||||||
|
import { APIPage } from '@/components/api-page';
|
||||||
|
|
||||||
|
export function meta({}: Route.MetaArgs) {
|
||||||
|
return [
|
||||||
|
{ title: 'API Reference' },
|
||||||
|
{ name: 'description', content: 'OpenAPI reference for Helix API.' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ApiReference() {
|
||||||
|
return (
|
||||||
|
<DocsLayout {...baseOptions()} tree={source.getPageTree()}>
|
||||||
|
<DocsPage full>
|
||||||
|
<DocsTitle>API Reference</DocsTitle>
|
||||||
|
<DocsDescription>
|
||||||
|
Edit openapi/openapi.yaml to maintain this API documentation.
|
||||||
|
</DocsDescription>
|
||||||
|
<DocsBody>
|
||||||
|
<APIPage document="helix" />
|
||||||
|
</DocsBody>
|
||||||
|
</DocsPage>
|
||||||
|
</DocsLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import type { Route } from './+types/docs';
|
||||||
|
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||||
|
import {
|
||||||
|
DocsBody,
|
||||||
|
DocsDescription,
|
||||||
|
DocsPage,
|
||||||
|
DocsTitle,
|
||||||
|
MarkdownCopyButton,
|
||||||
|
ViewOptionsPopover,
|
||||||
|
} from 'fumadocs-ui/layouts/docs/page';
|
||||||
|
import { source } from '@/lib/source';
|
||||||
|
import browserCollections from 'collections/browser';
|
||||||
|
import { baseOptions, gitConfig } from '@/lib/layout.shared';
|
||||||
|
import { useFumadocsLoader } from 'fumadocs-core/source/client';
|
||||||
|
import { useMDXComponents } from '@/components/mdx';
|
||||||
|
|
||||||
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const slugs = params['*'].split('/').filter((v) => v.length > 0);
|
||||||
|
const page = source.getPage(slugs);
|
||||||
|
if (!page) throw new Response('Not found', { status: 404 });
|
||||||
|
|
||||||
|
return {
|
||||||
|
slugs: page.slugs,
|
||||||
|
path: page.path,
|
||||||
|
pageTree: await source.serializePageTree(source.getPageTree()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientLoader = browserCollections.docs.createClientLoader({
|
||||||
|
component(
|
||||||
|
{ toc, frontmatter, default: Mdx },
|
||||||
|
// you can define props for the component
|
||||||
|
{
|
||||||
|
markdownUrl,
|
||||||
|
path,
|
||||||
|
}: {
|
||||||
|
markdownUrl: string;
|
||||||
|
path: string;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<DocsPage toc={toc}>
|
||||||
|
<title>{frontmatter.title}</title>
|
||||||
|
<meta name="description" content={frontmatter.description} />
|
||||||
|
<DocsTitle>{frontmatter.title}</DocsTitle>
|
||||||
|
<DocsDescription>{frontmatter.description}</DocsDescription>
|
||||||
|
<div className="flex flex-row gap-2 items-center border-b -mt-4 pb-6">
|
||||||
|
<MarkdownCopyButton markdownUrl={markdownUrl} />
|
||||||
|
<ViewOptionsPopover
|
||||||
|
markdownUrl={markdownUrl}
|
||||||
|
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${path}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<DocsBody>
|
||||||
|
<Mdx components={useMDXComponents()} />
|
||||||
|
</DocsBody>
|
||||||
|
</DocsPage>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function Page({ loaderData }: Route.ComponentProps) {
|
||||||
|
const { pageTree, slugs, path } = useFumadocsLoader(loaderData);
|
||||||
|
const markdownUrl = `/llms.mdx/docs/${[...slugs, 'index.mdx'].join('/')}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DocsLayout {...baseOptions()} tree={pageTree}>
|
||||||
|
{clientLoader.useContent(loaderData.path, {
|
||||||
|
markdownUrl,
|
||||||
|
path,
|
||||||
|
})}
|
||||||
|
</DocsLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import type { Route } from './+types/home';
|
||||||
|
import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
import { baseOptions } from '@/lib/layout.shared';
|
||||||
|
|
||||||
|
export function meta({}: Route.MetaArgs) {
|
||||||
|
return [
|
||||||
|
{ title: 'New React Router App' },
|
||||||
|
{ name: 'description', content: 'Welcome to React Router!' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<HomeLayout {...baseOptions()}>
|
||||||
|
<div className="p-4 flex flex-col items-center justify-center text-center flex-1">
|
||||||
|
<h1 className="text-xl font-bold mb-2">Helix API Documentation</h1>
|
||||||
|
<p className="text-fd-muted-foreground mb-4">
|
||||||
|
Powered by Vite, React Router and Fumadocs OpenAPI.
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<Link
|
||||||
|
className="text-sm bg-fd-primary text-fd-primary-foreground rounded-full font-medium px-4 py-2.5"
|
||||||
|
to="/api-reference"
|
||||||
|
>
|
||||||
|
Open API Reference
|
||||||
|
</Link>
|
||||||
|
<Link className="text-sm rounded-full font-medium px-4 py-2.5 border" to="/docs">
|
||||||
|
Open MDX Docs
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</HomeLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import type { Route } from './+types/not-found';
|
||||||
|
import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
import { baseOptions } from '@/lib/layout.shared';
|
||||||
|
|
||||||
|
export function meta({}: Route.MetaArgs) {
|
||||||
|
return [{ title: 'Not Found' }];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<HomeLayout {...baseOptions()}>
|
||||||
|
<div className="p-4 flex flex-col items-center justify-center text-center flex-1">
|
||||||
|
<h1 className="text-xl font-bold mb-2">Not Found</h1>
|
||||||
|
<p className="text-fd-muted-foreground mb-4">This page could not be found.</p>
|
||||||
|
<Link
|
||||||
|
className="text-sm bg-fd-primary text-fd-primary-foreground rounded-full font-medium px-4 py-2.5"
|
||||||
|
to="/docs"
|
||||||
|
>
|
||||||
|
Back to Docs
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</HomeLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { createFromSource } from 'fumadocs-core/search/server';
|
||||||
|
import { source } from '@/lib/source';
|
||||||
|
|
||||||
|
const server = createFromSource(source, {
|
||||||
|
language: 'english',
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function loader() {
|
||||||
|
return server.staticGET();
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
title: Hello World
|
||||||
|
description: |
|
||||||
|
Your first `document`
|
||||||
|
You'll love it!
|
||||||
|
---
|
||||||
|
|
||||||
|
Hey there! Fumadocs is the docs framework that also works on React Router!
|
||||||
|
|
||||||
|
## Heading
|
||||||
|
|
||||||
|
Hello World
|
||||||
|
|
||||||
|
<Cards>
|
||||||
|
<Card title="Learn more about React Router" href="https://reactrouter.com" />
|
||||||
|
<Card title="Learn more about Fumadocs" href="https://fumadocs.dev" />
|
||||||
|
</Cards>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
console.log('I love React!');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Heading
|
||||||
|
|
||||||
|
#### Heading
|
||||||
|
|
||||||
|
| Head | Description |
|
||||||
|
| ------------------------------- | ----------------------------------- |
|
||||||
|
| `hello` | Hello World |
|
||||||
|
| very **important** | Hey |
|
||||||
|
| _Surprisingly_ | Fumadocs |
|
||||||
|
| very long text that looks weird | hello world hello world hello world |
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
title: Test
|
||||||
|
description: A document to test Fumadocs
|
||||||
|
---
|
||||||
|
|
||||||
|
Hey there!
|
||||||
|
|
||||||
|
## Cards
|
||||||
|
|
||||||
|
<Cards>
|
||||||
|
<Card title="Learn more about Next.js" href="https://nextjs.org/docs" />
|
||||||
|
<Card title="Learn more about Fumadocs" href="https://fumadocs.dev" />
|
||||||
|
</Cards>
|
||||||
|
|
||||||
|
### CodeBlock
|
||||||
|
|
||||||
|
```js
|
||||||
|
console.log('Hello World');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### List
|
||||||
|
|
||||||
|
- Hello
|
||||||
|
- World
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Helix API
|
||||||
|
version: 0.1.0
|
||||||
|
description: |
|
||||||
|
Initial OpenAPI skeleton.
|
||||||
|
Maintain this file manually.
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:5000
|
||||||
|
description: Local development
|
||||||
|
paths:
|
||||||
|
/health:
|
||||||
|
get:
|
||||||
|
summary: Health check
|
||||||
|
operationId: healthCheck
|
||||||
|
tags:
|
||||||
|
- System
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Service is available
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: ok
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
components:
|
||||||
|
securitySchemes: {}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "docs",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "react-router build",
|
||||||
|
"dev": "react-router dev",
|
||||||
|
"start": "serve ./build/client --config ../../serve.json",
|
||||||
|
"types:check": "react-router typegen && fumadocs-mdx && tsc --noEmit",
|
||||||
|
"postinstall": "fumadocs-mdx"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@orama/orama": "^3.1.18",
|
||||||
|
"@react-router/node": "^7.13.1",
|
||||||
|
"fumadocs-core": "16.7.5",
|
||||||
|
"fumadocs-mdx": "14.2.11",
|
||||||
|
"fumadocs-openapi": "^10.4.1",
|
||||||
|
"fumadocs-ui": "16.7.5",
|
||||||
|
"isbot": "^5.1.36",
|
||||||
|
"lucide-react": "^0.577.0",
|
||||||
|
"react": "^19.2.4",
|
||||||
|
"react-dom": "^19.2.4",
|
||||||
|
"react-router": "^7.13.1",
|
||||||
|
"tailwind-merge": "^3.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@react-router/dev": "^7.13.1",
|
||||||
|
"@tailwindcss/vite": "^4.2.2",
|
||||||
|
"@types/mdx": "^2.0.13",
|
||||||
|
"@types/node": "^25.5.0",
|
||||||
|
"@types/react": "^19.2.14",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"react-router-devtools": "^6.2.0",
|
||||||
|
"serve": "^14.2.6",
|
||||||
|
"tailwindcss": "^4.2.2",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"vite": "^8.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+6401
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,27 @@
|
|||||||
|
import type { Config } from '@react-router/dev/config';
|
||||||
|
import { glob } from 'node:fs/promises';
|
||||||
|
import { createGetUrl, getSlugs } from 'fumadocs-core/source';
|
||||||
|
|
||||||
|
const getUrl = createGetUrl('/docs');
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ssr: false,
|
||||||
|
future: {
|
||||||
|
v8_middleware: true,
|
||||||
|
},
|
||||||
|
async prerender({ getStaticPaths }) {
|
||||||
|
const paths: string[] = [];
|
||||||
|
const excluded: string[] = ['/api-reference', '/api-reference/'];
|
||||||
|
|
||||||
|
for (const path of getStaticPaths()) {
|
||||||
|
if (!excluded.includes(path)) paths.push(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
for await (const entry of glob('**/*.mdx', { cwd: 'content/docs' })) {
|
||||||
|
const slugs = getSlugs(entry);
|
||||||
|
paths.push(getUrl(slugs), `/llms.mdx/docs/${[...slugs, 'index.mdx'].join('/')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
},
|
||||||
|
} satisfies Config;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"rewrites": [{ "source": "/**", "destination": "/__spa-fallback.html" }]
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
|
||||||
|
|
||||||
|
export const docs = defineDocs({
|
||||||
|
dir: 'content/docs',
|
||||||
|
docs: {
|
||||||
|
postprocess: {
|
||||||
|
includeProcessedMarkdown: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default defineConfig();
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"include": ["**/*", "**/.server/**/*", "**/.client/**/*", ".react-router/types/**/*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||||
|
"types": ["node", "vite/client"],
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"rootDirs": [".", "./.react-router/types"],
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./app/*"],
|
||||||
|
"collections/*": [".source/*"]
|
||||||
|
},
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { reactRouter } from '@react-router/dev/vite';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import mdx from 'fumadocs-mdx/vite';
|
||||||
|
import * as MdxConfig from './source.config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [mdx(MdxConfig), tailwindcss(), reactRouter()],
|
||||||
|
resolve: {
|
||||||
|
tsconfigPaths: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in new issue
Block a user