docstra 1.7.6 ā 1.7.9
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 +14 -4
- package/cli/commands/init.js +149 -0
- package/cli/index.js +12 -16
- package/cli/templates/docstra-config.js +53 -0
- package/cli/templates/index.js +11 -0
- package/cli/templates/mdx-components.js +8 -0
- package/cli/templates/next-config.js +7 -0
- package/cli/templates/pages.js +63 -0
- package/cli/utils/fs.js +31 -0
- package/dist/server/index.js +3 -5
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +3 -5
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
# Docstra
|
|
1
|
+
# **Docstra**
|
|
2
2
|
|
|
3
3
|
**The Modern Documentation Framework for Next.js**
|
|
4
4
|
|
|
5
|
-
Docstra is a
|
|
5
|
+
Docstra is a fast, flexible, and beautifully designed documentation framework built specifically for the **Next.js App Router**.
|
|
6
|
+
With first-class **MDX support**, a clean UI, and powerful components, you can build production-ready documentation sites in just minutes.
|
|
6
7
|
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
### **Documentation & Guide**
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
Visit the official website for full guides, examples and API references:
|
|
13
|
+
|
|
14
|
+
š **[https://docstra.sudhucodes.com](https://docstra.sudhucodes.com)**
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### **Thank You**
|
|
19
|
+
|
|
20
|
+
Thanks for choosing Docstra!
|
|
21
|
+
Happy documenting ā and build something great.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const { safeWrite, createFolder } = require("../utils/fs");
|
|
4
|
+
const {
|
|
5
|
+
DOCSTRA_CONFIG,
|
|
6
|
+
MDX_COMPONENTS,
|
|
7
|
+
NEXT_CONFIG,
|
|
8
|
+
INDEX_MDX,
|
|
9
|
+
PAGE_TSX,
|
|
10
|
+
SOURCE_TS
|
|
11
|
+
} = require("../templates");
|
|
12
|
+
|
|
13
|
+
function initDocstra() {
|
|
14
|
+
console.log("\nš§ Initializing Docstra...\n");
|
|
15
|
+
|
|
16
|
+
const root = process.cwd();
|
|
17
|
+
|
|
18
|
+
// 1. Create structure
|
|
19
|
+
createFolder(path.join(root, "app"));
|
|
20
|
+
|
|
21
|
+
// 2. Create docs content
|
|
22
|
+
const contentDir = path.join(root, "app", "docs", "content");
|
|
23
|
+
const slugDir = path.join(root, "app", "docs", "[[...slug]]");
|
|
24
|
+
|
|
25
|
+
createFolder(contentDir);
|
|
26
|
+
createFolder(slugDir);
|
|
27
|
+
|
|
28
|
+
safeWrite(path.join(contentDir, "index.mdx"), INDEX_MDX);
|
|
29
|
+
safeWrite(path.join(slugDir, "page.tsx"), PAGE_TSX);
|
|
30
|
+
|
|
31
|
+
// 3. Create lib/source.ts
|
|
32
|
+
const libDir = path.join(root, "lib");
|
|
33
|
+
createFolder(libDir);
|
|
34
|
+
safeWrite(path.join(libDir, "source.ts"), SOURCE_TS);
|
|
35
|
+
|
|
36
|
+
// 4. Config files
|
|
37
|
+
safeWrite(path.join(root, "mdx-components.tsx"), MDX_COMPONENTS);
|
|
38
|
+
safeWrite(path.join(root, "docstra.config.ts"), DOCSTRA_CONFIG);
|
|
39
|
+
|
|
40
|
+
// 5. Update next.config
|
|
41
|
+
updateNextConfig(root);
|
|
42
|
+
|
|
43
|
+
// 6. Check/Update Tailwind
|
|
44
|
+
updateTailwindGlobals(root);
|
|
45
|
+
|
|
46
|
+
// 7. Instructions
|
|
47
|
+
console.log(`
|
|
48
|
+
Please install latest version of Docstra by running:
|
|
49
|
+
|
|
50
|
+
Package Manager | Command
|
|
51
|
+
npm | npm install docstra@latest
|
|
52
|
+
yarn | yarn add docstra@latest
|
|
53
|
+
pnpm | pnpm add docstra@latest
|
|
54
|
+
`);
|
|
55
|
+
|
|
56
|
+
console.log("\nš Docstra initialized successfully!\n");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function updateNextConfig(root) {
|
|
60
|
+
const tsPath = path.join(root, "next.config.ts");
|
|
61
|
+
const jsPath = path.join(root, "next.config.js");
|
|
62
|
+
|
|
63
|
+
let nextConfigPath = fs.existsSync(tsPath) ? tsPath :
|
|
64
|
+
fs.existsSync(jsPath) ? jsPath :
|
|
65
|
+
null;
|
|
66
|
+
|
|
67
|
+
if (!nextConfigPath) {
|
|
68
|
+
// Create new if none exists
|
|
69
|
+
safeWrite(tsPath, NEXT_CONFIG);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let content = fs.readFileSync(nextConfigPath, "utf8");
|
|
74
|
+
|
|
75
|
+
if (content.includes("withDocstra")) {
|
|
76
|
+
console.log("ā next.config already uses withDocstra");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!content.includes("withDocstra")) {
|
|
81
|
+
content = `import { withDocstra } from "docstra/server";\n` + content;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const exportRegex = /export\s+default\s+(.+);?/;
|
|
85
|
+
const match = content.match(exportRegex);
|
|
86
|
+
|
|
87
|
+
if (!match) {
|
|
88
|
+
console.log("ā Could not detect export default. Skipped patch.");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let exportValue = match[1].trim();
|
|
93
|
+
if (exportValue.endsWith(";")) {
|
|
94
|
+
exportValue = exportValue.slice(0, -1).trim();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const wrapped = `export default withDocstra(${exportValue});`;
|
|
98
|
+
content = content.replace(exportRegex, wrapped);
|
|
99
|
+
|
|
100
|
+
fs.writeFileSync(nextConfigPath, content);
|
|
101
|
+
console.log("ā Updated next.config with withDocstra()");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
function updateTailwindGlobals(root) {
|
|
106
|
+
const globalsPath = path.join(root, "app", "globals.css");
|
|
107
|
+
|
|
108
|
+
if (!fs.existsSync(globalsPath)) {
|
|
109
|
+
console.log("ā app/globals.css not found.");
|
|
110
|
+
console.log("Please ensure Tailwind is installed correctly before running Docstra init.");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let css = fs.readFileSync(globalsPath, "utf8");
|
|
115
|
+
|
|
116
|
+
// Simple check for tailwind import/usage would go here if needed,
|
|
117
|
+
// but we'll focus on injecting our styles.
|
|
118
|
+
|
|
119
|
+
if (css.includes('@import "docstra/css";')) {
|
|
120
|
+
console.log("ā docstra/css already imported in globals.css");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Try to find where to insert
|
|
125
|
+
const tailwindRegex = /@import ['"]tailwindcss[^'"]*['"];?/g;
|
|
126
|
+
let lastMatch = null, match;
|
|
127
|
+
while ((match = tailwindRegex.exec(css)) !== null) {
|
|
128
|
+
lastMatch = match;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (lastMatch) {
|
|
132
|
+
const insertPos = lastMatch.index + lastMatch[0].length;
|
|
133
|
+
const updatedCSS = css.slice(0, insertPos) + `\n@import "docstra/css";\n` + css.slice(insertPos);
|
|
134
|
+
fs.writeFileSync(globalsPath, updatedCSS, "utf8");
|
|
135
|
+
console.log("ā Injected @import \"docstra/css\" into app/globals.css");
|
|
136
|
+
} else {
|
|
137
|
+
// If no explicit tailwind import found (e.g. using @tailwind directives or v4), just append or warn?
|
|
138
|
+
// For now, let's just append appropriately or warn.
|
|
139
|
+
// The original code warned if no tailwind imports were found.
|
|
140
|
+
// Let's keep it simple:
|
|
141
|
+
console.log(`
|
|
142
|
+
ā Tailwind imports not detected (or using different format).
|
|
143
|
+
Add manually:
|
|
144
|
+
@import "docstra/css";
|
|
145
|
+
`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { initDocstra };
|
package/cli/index.js
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const pkg = require("../package.json");
|
|
4
|
+
const { initDocstra } = require("./commands/init");
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Docstra CLI ${package.version}
|
|
9
|
-
${package.description}
|
|
6
|
+
// --- CLI ENTRY ---
|
|
7
|
+
const command = process.argv[2];
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
switch (command) {
|
|
10
|
+
case "init":
|
|
11
|
+
initDocstra();
|
|
12
|
+
break;
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
`);
|
|
17
|
-
} else {
|
|
14
|
+
default:
|
|
18
15
|
console.log(`
|
|
19
|
-
|
|
20
|
-
docstra init
|
|
16
|
+
Docstra CLI ${pkg.version}
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
Usage:
|
|
19
|
+
docstra init Initialize Docstra in your project
|
|
24
20
|
`);
|
|
25
21
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module.exports = `import { defineDocstraConfig } from "docstra/config";
|
|
2
|
+
|
|
3
|
+
export default defineDocstraConfig({
|
|
4
|
+
siteName: "Docstra",
|
|
5
|
+
githubRepo: "https://github.com/sudhucodes/docstra",
|
|
6
|
+
contentDir: "app/docs/content",
|
|
7
|
+
editOnGithub: {
|
|
8
|
+
owner: "sudhucodes",
|
|
9
|
+
repo: "docstra",
|
|
10
|
+
path: "docs/content",
|
|
11
|
+
},
|
|
12
|
+
feedback: {
|
|
13
|
+
enabled: true,
|
|
14
|
+
formSyncFormID: "69c728a1-ccd2-4dab-a9f7-bb52baeb4d31",
|
|
15
|
+
},
|
|
16
|
+
navbar: {
|
|
17
|
+
logo: {
|
|
18
|
+
link: "/",
|
|
19
|
+
src: "/brand/logo.svg",
|
|
20
|
+
alt: "Logo",
|
|
21
|
+
className: "h-8 w-auto",
|
|
22
|
+
},
|
|
23
|
+
links: [
|
|
24
|
+
{ name: "Guides", href: "/docs/guides" },
|
|
25
|
+
{ name: "Examples", href: "/docs/examples" },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
sidebar: {
|
|
29
|
+
links: [
|
|
30
|
+
{
|
|
31
|
+
section: 'Section 1',
|
|
32
|
+
items: [
|
|
33
|
+
{
|
|
34
|
+
name: 'Docs',
|
|
35
|
+
href: '/docs',
|
|
36
|
+
icon: '<Any-Lucide-Icon>'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Link 2',
|
|
40
|
+
href: '/docs/link-2',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
section: 'Section 2',
|
|
46
|
+
items: [
|
|
47
|
+
{ name: 'Link 3', href: '/docs/link-3' },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const docstraConfig = require("./docstra-config");
|
|
2
|
+
const mdxComponents = require("./mdx-components");
|
|
3
|
+
const nextConfig = require("./next-config");
|
|
4
|
+
const pages = require("./pages");
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
DOCSTRA_CONFIG: docstraConfig,
|
|
8
|
+
MDX_COMPONENTS: mdxComponents,
|
|
9
|
+
NEXT_CONFIG: nextConfig,
|
|
10
|
+
...pages,
|
|
11
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
exports.INDEX_MDX = `# Welcome to Docstra
|
|
2
|
+
|
|
3
|
+
Your documentation starts inside \`app/docs\`!
|
|
4
|
+
|
|
5
|
+
Start editing this file or add more MDX pages.
|
|
6
|
+
|
|
7
|
+
## Tips
|
|
8
|
+
- Pages in \`app/docs/content\` render automatically.
|
|
9
|
+
- \`[[...slug]]\` handles dynamic routing.
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports.PAGE_TSX = `import docstraConfig from "@/docstra.config";
|
|
13
|
+
import { mdxComponents } from "@/mdx-components";
|
|
14
|
+
import {
|
|
15
|
+
DocstraBody,
|
|
16
|
+
DocstraHeader,
|
|
17
|
+
DocstraPage,
|
|
18
|
+
DocstraProvider,
|
|
19
|
+
} from "docstra";
|
|
20
|
+
|
|
21
|
+
import { source } from "@/lib/source";
|
|
22
|
+
import { notFound } from "next/navigation";
|
|
23
|
+
|
|
24
|
+
export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
25
|
+
const { slug } = await params
|
|
26
|
+
const page = source.getPage(slug);
|
|
27
|
+
if (!page) return notFound();
|
|
28
|
+
|
|
29
|
+
const MDX = page.body;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<DocstraProvider docstraConfig={docstraConfig} docs={source.files} pageData={page.info}>
|
|
33
|
+
<DocstraHeader />
|
|
34
|
+
<DocstraPage>
|
|
35
|
+
<DocstraBody>
|
|
36
|
+
<MDX components={mdxComponents} />
|
|
37
|
+
</DocstraBody>
|
|
38
|
+
</DocstraPage>
|
|
39
|
+
</DocstraProvider>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function generateStaticParams() {
|
|
44
|
+
return source.generateStaticParams();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function generateMetadata({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
48
|
+
const { slug } = await params
|
|
49
|
+
const page = source.getPage(slug);
|
|
50
|
+
if (!page) return notFound();
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
title: page.info.data.metadata.title,
|
|
54
|
+
description: page.info.data.metadata.description,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
exports.SOURCE_TS = `import { docs } from "@/.docstra/index";
|
|
60
|
+
import { createSource } from "docstra/server";
|
|
61
|
+
|
|
62
|
+
export const source = createSource(docs);
|
|
63
|
+
`;
|
package/cli/utils/fs.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
function safeWrite(filePath, content) {
|
|
5
|
+
if (!fs.existsSync(filePath)) {
|
|
6
|
+
// Ensure directory exists
|
|
7
|
+
const dir = path.dirname(filePath);
|
|
8
|
+
if (!fs.existsSync(dir)) {
|
|
9
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
fs.writeFileSync(filePath, content);
|
|
13
|
+
console.log(`ā Created ${filePath.replace(process.cwd() + path.sep, "")}`);
|
|
14
|
+
} else {
|
|
15
|
+
console.log(`ā Already exists: ${filePath.replace(process.cwd() + path.sep, "")}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createFolder(folderPath) {
|
|
20
|
+
if (!fs.existsSync(folderPath)) {
|
|
21
|
+
fs.mkdirSync(folderPath, { recursive: true });
|
|
22
|
+
console.log(`ā Created /${path.relative(process.cwd(), folderPath).replace(/\\/g, "/")}`);
|
|
23
|
+
} else {
|
|
24
|
+
console.log(`ā /${path.relative(process.cwd(), folderPath).replace(/\\/g, "/")} already exists`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
safeWrite,
|
|
30
|
+
createFolder
|
|
31
|
+
};
|
package/dist/server/index.js
CHANGED
|
@@ -1836,7 +1836,6 @@ export const docs = [
|
|
|
1836
1836
|
];
|
|
1837
1837
|
`;
|
|
1838
1838
|
import_fs.default.writeFileSync(outFile, finalOutput, "utf8");
|
|
1839
|
-
logger.success(`MDX content compiled successfully`);
|
|
1840
1839
|
}
|
|
1841
1840
|
function getAllMdxFiles(dir) {
|
|
1842
1841
|
return import_fs.default.readdirSync(dir).flatMap((file) => {
|
|
@@ -1869,18 +1868,16 @@ async function runDocstraDev(contentDir) {
|
|
|
1869
1868
|
ignored: ["node_modules", ".next"]
|
|
1870
1869
|
});
|
|
1871
1870
|
watcher.add([contentDir, configFile]);
|
|
1872
|
-
|
|
1873
|
-
logger.info("Watching for changes...");
|
|
1874
|
-
});
|
|
1871
|
+
logger.info(`Dev server started...`);
|
|
1875
1872
|
watcher.on("all", async (_, file) => {
|
|
1876
1873
|
if (!file.endsWith(".md") && !file.endsWith(".mdx") && !file.endsWith("docstra.config.ts")) {
|
|
1877
1874
|
return;
|
|
1878
1875
|
}
|
|
1879
1876
|
if (rebuildTimeout) clearTimeout(rebuildTimeout);
|
|
1880
1877
|
rebuildTimeout = setTimeout(async () => {
|
|
1881
|
-
logger.info(`Rebuilding...`);
|
|
1882
1878
|
await runDocstraBuild(contentDir);
|
|
1883
1879
|
}, 200);
|
|
1880
|
+
logger.info(`MDX content rebuilt successfully`);
|
|
1884
1881
|
});
|
|
1885
1882
|
process.on("exit", () => {
|
|
1886
1883
|
if (!watcher.closed) {
|
|
@@ -1930,6 +1927,7 @@ function withDocstra(nextConfig = {}) {
|
|
|
1930
1927
|
}
|
|
1931
1928
|
if (isBuild) {
|
|
1932
1929
|
runDocstraBuild(contentDir);
|
|
1930
|
+
logger.info(`MDX content generated successfully`);
|
|
1933
1931
|
}
|
|
1934
1932
|
}
|
|
1935
1933
|
const turbopack = {
|