create-fumadocs-app 15.1.3 → 15.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/{chunk-K4QGKCVK.js → chunk-LCUIXVWC.js} +159 -68
  2. package/dist/create-app.js +1 -1
  3. package/dist/index.js +48 -24
  4. package/package.json +2 -2
  5. package/template/react-router/README.md +12 -0
  6. package/template/react-router/app/app.css +6 -0
  7. package/template/react-router/app/docs/page.tsx +63 -0
  8. package/template/react-router/app/docs/search.ts +18 -0
  9. package/template/react-router/app/root.tsx +78 -0
  10. package/template/react-router/app/routes/home.tsx +34 -0
  11. package/template/react-router/app/routes.ts +7 -0
  12. package/template/react-router/app/source.ts +60 -0
  13. package/template/react-router/content/docs/index.mdx +32 -0
  14. package/template/react-router/content/docs/test.mdx +8 -0
  15. package/template/react-router/example.gitignore +6 -0
  16. package/template/react-router/public/favicon.ico +0 -0
  17. package/template/react-router/react-router.config.ts +9 -0
  18. package/template/react-router/tsconfig.json +27 -0
  19. package/template/react-router/vite.config.ts +13 -0
  20. package/template/tanstack-start/README.md +12 -0
  21. package/template/tanstack-start/app/api.ts +6 -0
  22. package/template/tanstack-start/app/app.css +6 -0
  23. package/template/tanstack-start/app/client.tsx +7 -0
  24. package/template/tanstack-start/app/router.tsx +15 -0
  25. package/template/tanstack-start/app/routes/__root.tsx +49 -0
  26. package/template/tanstack-start/app/routes/api/search.ts +20 -0
  27. package/template/tanstack-start/app/routes/docs/$.tsx +71 -0
  28. package/template/tanstack-start/app/routes/index.tsx +25 -0
  29. package/template/tanstack-start/app/ssr.tsx +13 -0
  30. package/template/tanstack-start/app.config.ts +43 -0
  31. package/template/tanstack-start/content/docs/index.mdx +35 -0
  32. package/template/tanstack-start/example.gitignore +4 -0
  33. package/template/tanstack-start/lib/source.ts +70 -0
  34. package/template/tanstack-start/tsconfig.json +15 -0
  35. /package/template/{+shared → +next}/README.md +0 -0
  36. /package/template/{+shared → +next}/app/(home)/layout.tsx +0 -0
  37. /package/template/{+shared → +next}/app/(home)/page.tsx +0 -0
  38. /package/template/{+shared → +next}/app/api/search/route.ts +0 -0
  39. /package/template/{+shared → +next}/app/docs/layout.tsx +0 -0
  40. /package/template/{+shared → +next}/app/layout.config.tsx +0 -0
  41. /package/template/{+shared → +next}/app/layout.tsx +0 -0
  42. /package/template/{+shared → +next}/content/docs/index.mdx +0 -0
  43. /package/template/{+shared → +next}/content/docs/test.mdx +0 -0
  44. /package/template/{+shared → +next}/example.gitignore +0 -0
  45. /package/template/{content-collections → +next+content-collections}/app/docs/[[...slug]]/page.tsx +0 -0
  46. /package/template/{content-collections → +next+content-collections}/content-collections.ts +0 -0
  47. /package/template/{content-collections → +next+content-collections}/lib/source.ts +0 -0
  48. /package/template/{content-collections → +next+content-collections}/next.config.mjs +0 -0
  49. /package/template/{content-collections → +next+content-collections}/tsconfig.json +0 -0
  50. /package/template/{+eslint → +next+eslint}/.eslintrc.json +0 -0
  51. /package/template/{fuma-docs-mdx → +next+fuma-docs-mdx}/app/docs/[[...slug]]/page.tsx +0 -0
  52. /package/template/{fuma-docs-mdx → +next+fuma-docs-mdx}/lib/source.ts +0 -0
  53. /package/template/{fuma-docs-mdx → +next+fuma-docs-mdx}/next.config.mjs +0 -0
  54. /package/template/{fuma-docs-mdx → +next+fuma-docs-mdx}/source.config.ts +0 -0
  55. /package/template/{fuma-docs-mdx → +next+fuma-docs-mdx}/tsconfig.json +0 -0
  56. /package/template/{+tailwindcss → +next+tailwindcss}/app/(home)/page.tsx +0 -0
  57. /package/template/{+tailwindcss → +next+tailwindcss}/app/global.css +0 -0
  58. /package/template/{+tailwindcss → +next+tailwindcss}/app/layout.tsx +0 -0
  59. /package/template/{+tailwindcss → +next+tailwindcss}/postcss.config.mjs +0 -0
@@ -0,0 +1,60 @@
1
+ import {
2
+ loader,
3
+ type MetaData,
4
+ type PageData,
5
+ type Source,
6
+ type VirtualFile,
7
+ } from 'fumadocs-core/source';
8
+ import matter from 'gray-matter';
9
+ import * as path from 'node:path';
10
+
11
+ const files = Object.entries(
12
+ import.meta.glob<true, 'raw'>('/content/docs/**/*', {
13
+ eager: true,
14
+ query: '?raw',
15
+ import: 'default',
16
+ }),
17
+ );
18
+
19
+ const virtualFiles: VirtualFile[] = files.flatMap(([file, content]) => {
20
+ const ext = path.extname(file);
21
+ const virtualPath = path.relative(
22
+ 'content/docs',
23
+ path.join(process.cwd(), file),
24
+ );
25
+
26
+ if (ext === '.mdx' || ext === '.md') {
27
+ const parsed = matter(content);
28
+
29
+ return {
30
+ type: 'page',
31
+ path: virtualPath,
32
+ data: {
33
+ ...parsed.data,
34
+ content: parsed.content,
35
+ },
36
+ };
37
+ }
38
+
39
+ if (ext === '.json') {
40
+ return {
41
+ type: 'meta',
42
+ path: virtualPath,
43
+ data: JSON.parse(content),
44
+ };
45
+ }
46
+
47
+ return [];
48
+ });
49
+
50
+ export const source = loader({
51
+ source: {
52
+ files: virtualFiles,
53
+ } as Source<{
54
+ pageData: PageData & {
55
+ content: string;
56
+ };
57
+ metaData: MetaData;
58
+ }>,
59
+ baseUrl: '/docs',
60
+ });
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Hello World
3
+ description: |
4
+ Your first `document`
5
+ You'll love it!
6
+ ---
7
+
8
+ Hey there! Fumadocs is the docs framework that also works on React Router!
9
+
10
+ ## Heading
11
+
12
+ Hello World
13
+
14
+ <Cards>
15
+ <Card title="Learn more about React Router" href="https://reactrouter.com" />
16
+ <Card title="Learn more about Fumadocs" href="https://fumadocs.vercel.app" />
17
+ </Cards>
18
+
19
+ ```ts
20
+ console.log('I love React!');
21
+ ```
22
+
23
+ ### Heading
24
+
25
+ #### Heading
26
+
27
+ | Head | Description |
28
+ | ------------------------------- | ----------------------------------- |
29
+ | `hello` | Hello World |
30
+ | very **important** | Hey |
31
+ | _Surprisingly_ | Fumadocs |
32
+ | very long text that looks weird | hello world hello world hello world |
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Fumadocs
3
+ description: You can just be minimal.
4
+ ---
5
+
6
+ ## Overview
7
+
8
+ Fumadocs is a docs framework.
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ /node_modules/
3
+
4
+ # React Router
5
+ /.react-router/
6
+ /build/
@@ -0,0 +1,9 @@
1
+ import type { Config } from '@react-router/dev/config';
2
+ import { source } from './app/source';
3
+
4
+ export default {
5
+ ssr: true,
6
+ async prerender({ getStaticPaths }) {
7
+ return [...getStaticPaths(), ...source.getPages().map((page) => page.url)];
8
+ },
9
+ } satisfies Config;
@@ -0,0 +1,27 @@
1
+ {
2
+ "include": [
3
+ "**/*",
4
+ "**/.server/**/*",
5
+ "**/.client/**/*",
6
+ ".react-router/types/**/*"
7
+ ],
8
+ "compilerOptions": {
9
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
10
+ "types": ["node", "vite/client"],
11
+ "target": "esnext",
12
+ "module": "esnext",
13
+ "moduleResolution": "bundler",
14
+ "jsx": "react-jsx",
15
+ "rootDirs": [".", "./.react-router/types"],
16
+ "baseUrl": ".",
17
+ "paths": {
18
+ "@/*": ["./app/*"]
19
+ },
20
+ "esModuleInterop": true,
21
+ "verbatimModuleSyntax": true,
22
+ "noEmit": true,
23
+ "resolveJsonModule": true,
24
+ "skipLibCheck": true,
25
+ "strict": true
26
+ }
27
+ }
@@ -0,0 +1,13 @@
1
+ import { reactRouter } from '@react-router/dev/vite';
2
+ import tailwindcss from '@tailwindcss/vite';
3
+ import { defineConfig } from 'vite';
4
+ import tsconfigPaths from 'vite-tsconfig-paths';
5
+
6
+ export default defineConfig({
7
+ build: {
8
+ rollupOptions: {
9
+ external: ['shiki'],
10
+ },
11
+ },
12
+ plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
13
+ });
@@ -0,0 +1,12 @@
1
+ This is a Tanstack Start application generated with
2
+ [Create Fumadocs](https://github.com/fuma-nama/fumadocs).
3
+
4
+ Run development server:
5
+
6
+ ```bash
7
+ npm run dev
8
+ # or
9
+ pnpm dev
10
+ # or
11
+ yarn dev
12
+ ```
@@ -0,0 +1,6 @@
1
+ import {
2
+ createStartAPIHandler,
3
+ defaultAPIFileRouteHandler,
4
+ } from '@tanstack/react-start/api';
5
+
6
+ export default createStartAPIHandler(defaultAPIFileRouteHandler);
@@ -0,0 +1,6 @@
1
+ @import 'tailwindcss';
2
+ @import 'fumadocs-ui/css/neutral.css';
3
+ @import 'fumadocs-ui/css/preset.css';
4
+
5
+ /* path of `fumadocs-ui` relative to the CSS file */
6
+ @source '../node_modules/fumadocs-ui/dist/**/*.js';
@@ -0,0 +1,7 @@
1
+ import { hydrateRoot } from 'react-dom/client';
2
+ import { StartClient } from '@tanstack/react-start';
3
+ import { createRouter } from './router';
4
+
5
+ const router = createRouter();
6
+
7
+ hydrateRoot(document, <StartClient router={router} />);
@@ -0,0 +1,15 @@
1
+ import { createRouter as createTanStackRouter } from '@tanstack/react-router';
2
+ import { routeTree } from './routeTree.gen';
3
+
4
+ export function createRouter() {
5
+ return createTanStackRouter({
6
+ routeTree,
7
+ scrollRestoration: true,
8
+ });
9
+ }
10
+
11
+ declare module '@tanstack/react-router' {
12
+ interface Register {
13
+ router: ReturnType<typeof createRouter>;
14
+ }
15
+ }
@@ -0,0 +1,49 @@
1
+ import { type ReactNode } from 'react';
2
+ import { Outlet, createRootRoute, HeadContent } from '@tanstack/react-router';
3
+ import { RootProvider } from 'fumadocs-ui/provider/base';
4
+ import appCss from '../app.css?url';
5
+ import { TanstackProvider } from 'fumadocs-core/framework/tanstack';
6
+ import { Scripts } from '@tanstack/react-router';
7
+
8
+ export const Route = createRootRoute({
9
+ head: () => ({
10
+ meta: [
11
+ {
12
+ charSet: 'utf-8',
13
+ },
14
+ {
15
+ name: 'viewport',
16
+ content: 'width=device-width, initial-scale=1',
17
+ },
18
+ {
19
+ title: 'Fumadocs on TanStack Start',
20
+ },
21
+ ],
22
+ links: [{ rel: 'stylesheet', href: appCss }],
23
+ }),
24
+ component: RootComponent,
25
+ });
26
+
27
+ function RootComponent() {
28
+ return (
29
+ <RootDocument>
30
+ <Outlet />
31
+ </RootDocument>
32
+ );
33
+ }
34
+
35
+ function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
36
+ return (
37
+ <html suppressHydrationWarning>
38
+ <head>
39
+ <HeadContent />
40
+ </head>
41
+ <body>
42
+ <TanstackProvider>
43
+ <RootProvider>{children}</RootProvider>
44
+ </TanstackProvider>
45
+ <Scripts />
46
+ </body>
47
+ </html>
48
+ );
49
+ }
@@ -0,0 +1,20 @@
1
+ import { createAPIFileRoute } from '@tanstack/react-start/api';
2
+ import { createSearchAPI } from 'fumadocs-core/search/server';
3
+ import { source } from '@/lib/source';
4
+ import { structure } from 'fumadocs-core/mdx-plugins';
5
+
6
+ const server = createSearchAPI('advanced', {
7
+ indexes: source.getPages().map((page) => ({
8
+ id: page.url,
9
+ url: page.url,
10
+ title: page.data.title ?? '',
11
+ description: page.data.description,
12
+ structuredData: structure(page.data.content),
13
+ })),
14
+ });
15
+
16
+ export const APIRoute = createAPIFileRoute('/api/search')({
17
+ GET: ({ request }) => {
18
+ return server.GET(request);
19
+ },
20
+ });
@@ -0,0 +1,71 @@
1
+ import { createFileRoute, notFound } from '@tanstack/react-router';
2
+ import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3
+ import { source } from '@/lib/source';
4
+ import {
5
+ DocsBody,
6
+ DocsDescription,
7
+ DocsPage,
8
+ DocsTitle,
9
+ } from 'fumadocs-ui/page';
10
+ import { executeMdxSync } from '@fumadocs/mdx-remote/client';
11
+ import defaultMdxComponents from 'fumadocs-ui/mdx';
12
+ import { createServerFn } from '@tanstack/react-start';
13
+ import type { PageTree } from 'fumadocs-core/server';
14
+ import { createCompiler } from '@fumadocs/mdx-remote';
15
+ import * as path from 'node:path';
16
+
17
+ export const Route = createFileRoute('/docs/$')({
18
+ component: Page,
19
+ async loader({ params }) {
20
+ const slugs = (params._splat ?? '').split('/');
21
+
22
+ return loader({ data: slugs });
23
+ },
24
+ });
25
+
26
+ const compiler = createCompiler({
27
+ development: false,
28
+ });
29
+
30
+ const loader = createServerFn({
31
+ method: 'GET',
32
+ })
33
+ .validator((slugs: string[]) => slugs)
34
+ .handler(async ({ data: slugs }) => {
35
+ const page = source.getPage(slugs);
36
+ if (!page) throw notFound();
37
+
38
+ const { content, ...rest } = page.data;
39
+ const compiled = await compiler.compileFile({
40
+ path: path.resolve('content/docs', page.file.path),
41
+ value: content,
42
+ });
43
+
44
+ return {
45
+ tree: source.pageTree as object,
46
+ ...rest,
47
+ compiled: compiled.toString(),
48
+ };
49
+ });
50
+
51
+ function Page() {
52
+ const { tree, compiled, ...data } = Route.useLoaderData();
53
+ const { toc, default: MdxContent } = executeMdxSync(compiled);
54
+
55
+ return (
56
+ <DocsLayout
57
+ nav={{
58
+ title: 'Tanstack Start',
59
+ }}
60
+ tree={tree as PageTree.Root}
61
+ >
62
+ <DocsPage toc={toc}>
63
+ <DocsTitle>{data.title}</DocsTitle>
64
+ <DocsDescription>{data.title}</DocsDescription>
65
+ <DocsBody>
66
+ <MdxContent components={defaultMdxComponents} />
67
+ </DocsBody>
68
+ </DocsPage>
69
+ </DocsLayout>
70
+ );
71
+ }
@@ -0,0 +1,25 @@
1
+ import { createFileRoute, Link } from '@tanstack/react-router';
2
+ import { HomeLayout } from 'fumadocs-ui/layouts/home';
3
+
4
+ export const Route = createFileRoute('/')({
5
+ component: Home,
6
+ });
7
+
8
+ function Home() {
9
+ return (
10
+ <HomeLayout
11
+ nav={{
12
+ title: 'Tanstack Start',
13
+ }}
14
+ className="text-center py-32"
15
+ >
16
+ <h1 className="font-medium text-xl mb-4">Fumadocs on Tanstack Start.</h1>
17
+ <Link
18
+ to="/docs/$"
19
+ className="px-3 py-2 rounded-lg bg-fd-primary text-fd-primary-foreground font-medium text-sm mx-auto"
20
+ >
21
+ Open Docs
22
+ </Link>
23
+ </HomeLayout>
24
+ );
25
+ }
@@ -0,0 +1,13 @@
1
+ // app/ssr.tsx
2
+ import {
3
+ createStartHandler,
4
+ defaultStreamHandler,
5
+ } from '@tanstack/react-start/server';
6
+ import { getRouterManifest } from '@tanstack/react-start/router-manifest';
7
+
8
+ import { createRouter } from './router';
9
+
10
+ export default createStartHandler({
11
+ createRouter,
12
+ getRouterManifest,
13
+ })(defaultStreamHandler);
@@ -0,0 +1,43 @@
1
+ import { defineConfig } from '@tanstack/react-start/config';
2
+ import tsConfigPaths from 'vite-tsconfig-paths';
3
+ import tailwindcss from '@tailwindcss/vite';
4
+
5
+ export default defineConfig({
6
+ server: {
7
+ hooks: {
8
+ 'prerender:routes': async (routes) => {
9
+ const { source } = await import('./lib/source');
10
+ const pages = source.getPages();
11
+
12
+ for (const page of pages) {
13
+ routes.add(page.url);
14
+ }
15
+ },
16
+ },
17
+ prerender: {
18
+ routes: ['/'],
19
+ crawlLinks: true,
20
+ },
21
+ },
22
+ vite: {
23
+ build: {
24
+ rollupOptions: {
25
+ // Shiki results in a huge bundle because Rollup tries to bundle every language/theme
26
+ external: ['shiki'],
27
+ // most React.js libraries now include 'use client'
28
+ onwarn(warning, warn) {
29
+ if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
30
+ return;
31
+ }
32
+ warn(warning);
33
+ },
34
+ },
35
+ },
36
+ plugins: [
37
+ tsConfigPaths({
38
+ projects: ['./tsconfig.json'],
39
+ }),
40
+ tailwindcss(),
41
+ ],
42
+ },
43
+ });
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Hello World
3
+ description: |
4
+ Your first `document`
5
+ You'll love it!
6
+ ---
7
+
8
+ Hey there! Fumadocs is a docs framework built for Next.js, but do you know it also works on Tanstack Start?
9
+
10
+ ## Heading
11
+
12
+ Hello World!
13
+
14
+ <Cards>
15
+ <Card
16
+ title="Learn more about Tanstack Start"
17
+ href="https://tanstack.com/start"
18
+ />
19
+ <Card title="Learn more about Fumadocs" href="https://fumadocs.vercel.app" />
20
+ </Cards>
21
+
22
+ ### CodeBlock
23
+
24
+ ```ts
25
+ console.log('Hello World');
26
+ ```
27
+
28
+ #### Table
29
+
30
+ | Head | Description |
31
+ | ------------------------------- | ----------------------------------- |
32
+ | `hello` | Hello World |
33
+ | very **important** | Hey |
34
+ | _Surprisingly_ | Fumadocs |
35
+ | very long text that looks weird | hello world hello world hello world |
@@ -0,0 +1,4 @@
1
+ routeTree.gen.ts
2
+ node_modules
3
+ .output
4
+ .vinxi
@@ -0,0 +1,70 @@
1
+ import {
2
+ loader,
3
+ type MetaData,
4
+ type PageData,
5
+ type Source,
6
+ type VirtualFile,
7
+ } from 'fumadocs-core/source';
8
+ import matter from 'gray-matter';
9
+ import * as path from 'node:path';
10
+ import FastGlob from 'fast-glob';
11
+ import * as fs from 'node:fs';
12
+
13
+ let files: [string, string][];
14
+
15
+ if (typeof import.meta.glob === 'function') {
16
+ files = Object.entries(
17
+ import.meta.glob<true, 'raw'>('/content/docs/**/*', {
18
+ eager: true,
19
+ query: '?raw',
20
+ import: 'default',
21
+ }),
22
+ );
23
+ } else {
24
+ files = FastGlob.sync('content/docs/**/*').map((file) => {
25
+ return [file, fs.readFileSync(file).toString()];
26
+ });
27
+ }
28
+
29
+ const virtualFiles: VirtualFile[] = files.flatMap(([file, content]) => {
30
+ const ext = path.extname(file);
31
+ const virtualPath = path.relative(
32
+ 'content/docs',
33
+ path.join(process.cwd(), file),
34
+ );
35
+
36
+ if (ext === '.mdx' || ext === '.md') {
37
+ const parsed = matter(content);
38
+
39
+ return {
40
+ type: 'page',
41
+ path: virtualPath,
42
+ data: {
43
+ ...parsed.data,
44
+ content: parsed.content,
45
+ },
46
+ };
47
+ }
48
+
49
+ if (ext === '.json') {
50
+ return {
51
+ type: 'meta',
52
+ path: virtualPath,
53
+ data: JSON.parse(content),
54
+ };
55
+ }
56
+
57
+ return [];
58
+ });
59
+
60
+ export const source = loader({
61
+ source: {
62
+ files: virtualFiles,
63
+ } as Source<{
64
+ pageData: PageData & {
65
+ content: string;
66
+ };
67
+ metaData: MetaData;
68
+ }>,
69
+ baseUrl: '/docs',
70
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react-jsx",
4
+ "moduleResolution": "Bundler",
5
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
6
+ "types": ["node", "vite/client"],
7
+ "module": "ESNext",
8
+ "target": "ESNext",
9
+ "skipLibCheck": true,
10
+ "strictNullChecks": true,
11
+ "paths": {
12
+ "@/*": ["./*"]
13
+ }
14
+ }
15
+ }
File without changes
File without changes
File without changes
File without changes
File without changes