@hanzo/docs-create-app 16.0.50

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 (204) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/dist/auto-install-CenyMuK7.js +33 -0
  4. package/dist/auto-install-CenyMuK7.js.map +1 -0
  5. package/dist/bin.d.ts +1 -0
  6. package/dist/bin.js +165 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/constants-BkYWkLHa.d.ts +22 -0
  9. package/dist/constants-BkYWkLHa.d.ts.map +1 -0
  10. package/dist/constants-CbNzssp2.js +957 -0
  11. package/dist/constants-CbNzssp2.js.map +1 -0
  12. package/dist/index.d.ts +49 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +60 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/plugins/biome.base.d.ts +40 -0
  17. package/dist/plugins/biome.base.d.ts.map +1 -0
  18. package/dist/plugins/biome.base.js +38 -0
  19. package/dist/plugins/biome.base.js.map +1 -0
  20. package/dist/plugins/biome.d.ts +7 -0
  21. package/dist/plugins/biome.d.ts.map +1 -0
  22. package/dist/plugins/biome.js +33 -0
  23. package/dist/plugins/biome.js.map +1 -0
  24. package/dist/plugins/biome.next.d.ts +41 -0
  25. package/dist/plugins/biome.next.d.ts.map +1 -0
  26. package/dist/plugins/biome.next.js +44 -0
  27. package/dist/plugins/biome.next.js.map +1 -0
  28. package/dist/plugins/eslint.d.ts +7 -0
  29. package/dist/plugins/eslint.d.ts.map +1 -0
  30. package/dist/plugins/eslint.js +47 -0
  31. package/dist/plugins/eslint.js.map +1 -0
  32. package/dist/plugins/next-use-src.d.ts +10 -0
  33. package/dist/plugins/next-use-src.d.ts.map +1 -0
  34. package/dist/plugins/next-use-src.js +37 -0
  35. package/dist/plugins/next-use-src.js.map +1 -0
  36. package/dist/plugins/orama-cloud.d.ts +7 -0
  37. package/dist/plugins/orama-cloud.d.ts.map +1 -0
  38. package/dist/plugins/orama-cloud.js +296 -0
  39. package/dist/plugins/orama-cloud.js.map +1 -0
  40. package/package.json +63 -0
  41. package/template/+next+fuma-docs-mdx/app/(home)/layout.tsx +6 -0
  42. package/template/+next+fuma-docs-mdx/app/(home)/page.tsx +16 -0
  43. package/template/+next+fuma-docs-mdx/app/api/search/route.ts +7 -0
  44. package/template/+next+fuma-docs-mdx/app/docs/[[...slug]]/page.tsx +57 -0
  45. package/template/+next+fuma-docs-mdx/app/docs/layout.tsx +11 -0
  46. package/template/+next+fuma-docs-mdx/app/global.css +3 -0
  47. package/template/+next+fuma-docs-mdx/app/layout.tsx +17 -0
  48. package/template/+next+fuma-docs-mdx/app/llms-full.txt/route.ts +10 -0
  49. package/template/+next+fuma-docs-mdx/app/llms.mdx/docs/[[...slug]]/route.ts +20 -0
  50. package/template/+next+fuma-docs-mdx/app/llms.txt/route.ts +13 -0
  51. package/template/+next+fuma-docs-mdx/app/og/docs/[...slug]/route.tsx +27 -0
  52. package/template/+next+fuma-docs-mdx/components/ai/page-actions.tsx +240 -0
  53. package/template/+next+fuma-docs-mdx/content/docs/index.mdx +13 -0
  54. package/template/+next+fuma-docs-mdx/content/docs/test.mdx +17 -0
  55. package/template/+next+fuma-docs-mdx/example.gitignore +26 -0
  56. package/template/+next+fuma-docs-mdx/lib/cn.ts +1 -0
  57. package/template/+next+fuma-docs-mdx/lib/layout.shared.tsx +17 -0
  58. package/template/+next+fuma-docs-mdx/lib/source.ts +27 -0
  59. package/template/+next+fuma-docs-mdx/mdx-components.tsx +9 -0
  60. package/template/+next+fuma-docs-mdx/next.config.mjs +18 -0
  61. package/template/+next+fuma-docs-mdx/package.json +31 -0
  62. package/template/+next+fuma-docs-mdx/postcss.config.mjs +7 -0
  63. package/template/+next+fuma-docs-mdx/source.config.ts +23 -0
  64. package/template/+next+fuma-docs-mdx/tsconfig.json +36 -0
  65. package/template/+next+fuma-docs-mdx+static/README.md +45 -0
  66. package/template/+next+fuma-docs-mdx+static/app/(home)/layout.tsx +6 -0
  67. package/template/+next+fuma-docs-mdx+static/app/(home)/page.tsx +16 -0
  68. package/template/+next+fuma-docs-mdx+static/app/api/search/route.ts +9 -0
  69. package/template/+next+fuma-docs-mdx+static/app/docs/[[...slug]]/page.tsx +47 -0
  70. package/template/+next+fuma-docs-mdx+static/app/docs/layout.tsx +11 -0
  71. package/template/+next+fuma-docs-mdx+static/app/global.css +3 -0
  72. package/template/+next+fuma-docs-mdx+static/app/layout.tsx +17 -0
  73. package/template/+next+fuma-docs-mdx+static/app/llms-full.txt/route.ts +10 -0
  74. package/template/+next+fuma-docs-mdx+static/app/og/docs/[...slug]/route.tsx +27 -0
  75. package/template/+next+fuma-docs-mdx+static/components/provider.tsx +8 -0
  76. package/template/+next+fuma-docs-mdx+static/components/search.tsx +46 -0
  77. package/template/+next+fuma-docs-mdx+static/content/docs/index.mdx +13 -0
  78. package/template/+next+fuma-docs-mdx+static/content/docs/test.mdx +17 -0
  79. package/template/+next+fuma-docs-mdx+static/example.gitignore +26 -0
  80. package/template/+next+fuma-docs-mdx+static/lib/layout.shared.tsx +9 -0
  81. package/template/+next+fuma-docs-mdx+static/lib/source.ts +26 -0
  82. package/template/+next+fuma-docs-mdx+static/mdx-components.tsx +9 -0
  83. package/template/+next+fuma-docs-mdx+static/next.config.mjs +11 -0
  84. package/template/+next+fuma-docs-mdx+static/package.json +32 -0
  85. package/template/+next+fuma-docs-mdx+static/postcss.config.mjs +7 -0
  86. package/template/+next+fuma-docs-mdx+static/source.config.ts +23 -0
  87. package/template/+next+fuma-docs-mdx+static/tsconfig.json +36 -0
  88. package/template/+next+hanzo-docs-mdx/README.md +43 -0
  89. package/template/+next+hanzo-docs-mdx/app/(home)/layout.tsx +6 -0
  90. package/template/+next+hanzo-docs-mdx/app/(home)/page.tsx +16 -0
  91. package/template/+next+hanzo-docs-mdx/app/api/search/route.ts +7 -0
  92. package/template/+next+hanzo-docs-mdx/app/docs/[[...slug]]/page.tsx +61 -0
  93. package/template/+next+hanzo-docs-mdx/app/docs/layout.tsx +11 -0
  94. package/template/+next+hanzo-docs-mdx/app/global.css +3 -0
  95. package/template/+next+hanzo-docs-mdx/app/layout.tsx +17 -0
  96. package/template/+next+hanzo-docs-mdx/app/llms-full.txt/route.ts +10 -0
  97. package/template/+next+hanzo-docs-mdx/app/og/docs/[...slug]/route.tsx +27 -0
  98. package/template/+next+hanzo-docs-mdx/content/docs/index.mdx +13 -0
  99. package/template/+next+hanzo-docs-mdx/content/docs/test.mdx +17 -0
  100. package/template/+next+hanzo-docs-mdx/example.gitignore +26 -0
  101. package/template/+next+hanzo-docs-mdx/lib/cn.ts +1 -0
  102. package/template/+next+hanzo-docs-mdx/lib/layout.shared.tsx +9 -0
  103. package/template/+next+hanzo-docs-mdx/lib/source.ts +27 -0
  104. package/template/+next+hanzo-docs-mdx/mdx-components.tsx +9 -0
  105. package/template/+next+hanzo-docs-mdx/next.config.mjs +18 -0
  106. package/template/+next+hanzo-docs-mdx/package.json +31 -0
  107. package/template/+next+hanzo-docs-mdx/postcss.config.mjs +5 -0
  108. package/template/+next+hanzo-docs-mdx/source.config.ts +23 -0
  109. package/template/+next+hanzo-docs-mdx/tsconfig.json +36 -0
  110. package/template/+orama-cloud/@app/components/search.tsx +54 -0
  111. package/template/+orama-cloud/@app/lib/export-static-indexes.ts +14 -0
  112. package/template/+orama-cloud/@root/.env.example +6 -0
  113. package/template/react-router/README.md +12 -0
  114. package/template/react-router/app/app.css +3 -0
  115. package/template/react-router/app/docs/page.tsx +51 -0
  116. package/template/react-router/app/docs/search.ts +12 -0
  117. package/template/react-router/app/lib/layout.shared.tsx +9 -0
  118. package/template/react-router/app/lib/source.ts +7 -0
  119. package/template/react-router/app/root.tsx +73 -0
  120. package/template/react-router/app/routes/home.tsx +30 -0
  121. package/template/react-router/app/routes.ts +7 -0
  122. package/template/react-router/content/docs/index.mdx +32 -0
  123. package/template/react-router/content/docs/meta.json +3 -0
  124. package/template/react-router/content/docs/test.mdx +24 -0
  125. package/template/react-router/example.gitignore +7 -0
  126. package/template/react-router/package.json +35 -0
  127. package/template/react-router/public/favicon.ico +0 -0
  128. package/template/react-router/react-router.config.ts +23 -0
  129. package/template/react-router/source.config.ts +7 -0
  130. package/template/react-router/tsconfig.json +23 -0
  131. package/template/react-router/vite.config.ts +17 -0
  132. package/template/react-router-spa/README.md +12 -0
  133. package/template/react-router-spa/app/app.css +3 -0
  134. package/template/react-router-spa/app/components/search.tsx +45 -0
  135. package/template/react-router-spa/app/docs/page.tsx +53 -0
  136. package/template/react-router-spa/app/docs/search.ts +10 -0
  137. package/template/react-router-spa/app/lib/layout.shared.tsx +9 -0
  138. package/template/react-router-spa/app/lib/source.ts +7 -0
  139. package/template/react-router-spa/app/root.tsx +74 -0
  140. package/template/react-router-spa/app/routes/home.tsx +30 -0
  141. package/template/react-router-spa/app/routes.ts +7 -0
  142. package/template/react-router-spa/content/docs/index.mdx +32 -0
  143. package/template/react-router-spa/content/docs/test.mdx +24 -0
  144. package/template/react-router-spa/example.gitignore +7 -0
  145. package/template/react-router-spa/package.json +36 -0
  146. package/template/react-router-spa/public/favicon.ico +0 -0
  147. package/template/react-router-spa/react-router.config.ts +23 -0
  148. package/template/react-router-spa/serve.json +3 -0
  149. package/template/react-router-spa/source.config.ts +7 -0
  150. package/template/react-router-spa/tsconfig.json +23 -0
  151. package/template/react-router-spa/vite.config.ts +17 -0
  152. package/template/tanstack-start/README.md +12 -0
  153. package/template/tanstack-start/content/docs/index.mdx +31 -0
  154. package/template/tanstack-start/content/docs/test.mdx +12 -0
  155. package/template/tanstack-start/example.gitignore +18 -0
  156. package/template/tanstack-start/package.json +38 -0
  157. package/template/tanstack-start/source.config.ts +7 -0
  158. package/template/tanstack-start/src/components/not-found.tsx +28 -0
  159. package/template/tanstack-start/src/lib/layout.shared.tsx +9 -0
  160. package/template/tanstack-start/src/lib/source.ts +9 -0
  161. package/template/tanstack-start/src/router.tsx +12 -0
  162. package/template/tanstack-start/src/routes/__root.tsx +45 -0
  163. package/template/tanstack-start/src/routes/api/search.ts +16 -0
  164. package/template/tanstack-start/src/routes/docs/$.tsx +72 -0
  165. package/template/tanstack-start/src/routes/index.tsx +26 -0
  166. package/template/tanstack-start/src/styles/app.css +3 -0
  167. package/template/tanstack-start/tsconfig.json +24 -0
  168. package/template/tanstack-start/vite.config.ts +33 -0
  169. package/template/tanstack-start-spa/README.md +12 -0
  170. package/template/tanstack-start-spa/content/docs/index.mdx +31 -0
  171. package/template/tanstack-start-spa/content/docs/test.mdx +12 -0
  172. package/template/tanstack-start-spa/example.gitignore +18 -0
  173. package/template/tanstack-start-spa/package.json +41 -0
  174. package/template/tanstack-start-spa/source.config.ts +7 -0
  175. package/template/tanstack-start-spa/src/components/not-found.tsx +28 -0
  176. package/template/tanstack-start-spa/src/components/search.tsx +46 -0
  177. package/template/tanstack-start-spa/src/lib/layout.shared.tsx +9 -0
  178. package/template/tanstack-start-spa/src/lib/source.ts +9 -0
  179. package/template/tanstack-start-spa/src/router.tsx +12 -0
  180. package/template/tanstack-start-spa/src/routes/__root.tsx +46 -0
  181. package/template/tanstack-start-spa/src/routes/api/search.ts +16 -0
  182. package/template/tanstack-start-spa/src/routes/docs/$.tsx +74 -0
  183. package/template/tanstack-start-spa/src/routes/index.tsx +26 -0
  184. package/template/tanstack-start-spa/src/styles/app.css +3 -0
  185. package/template/tanstack-start-spa/tsconfig.json +24 -0
  186. package/template/tanstack-start-spa/vite.config.ts +42 -0
  187. package/template/waku/README.md +11 -0
  188. package/template/waku/content/docs/index.mdx +31 -0
  189. package/template/waku/content/docs/test.mdx +12 -0
  190. package/template/waku/example.gitignore +6 -0
  191. package/template/waku/package.json +33 -0
  192. package/template/waku/source.config.ts +7 -0
  193. package/template/waku/src/components/provider.tsx +7 -0
  194. package/template/waku/src/lib/layout.shared.tsx +9 -0
  195. package/template/waku/src/lib/source.ts +9 -0
  196. package/template/waku/src/pages/(home)/_layout.tsx +7 -0
  197. package/template/waku/src/pages/(home)/index.tsx +21 -0
  198. package/template/waku/src/pages/_api/api/search.ts +4 -0
  199. package/template/waku/src/pages/_root.tsx +20 -0
  200. package/template/waku/src/pages/docs/[...slugs].tsx +45 -0
  201. package/template/waku/src/pages/docs/_layout.tsx +12 -0
  202. package/template/waku/src/styles/globals.css +9 -0
  203. package/template/waku/tsconfig.json +25 -0
  204. package/template/waku/waku.config.ts +17 -0
@@ -0,0 +1,296 @@
1
+ import { a as copy, c as writeFile, o as pick, r as sourceDir, t as depVersions } from "../constants-CbNzssp2.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { IndentationText, Project, QuoteKind, StructureKind, SyntaxKind, ts } from "ts-morph";
5
+
6
+ //#region src/transform/shared.ts
7
+ const project = new Project({ manipulationSettings: {
8
+ indentationText: IndentationText.TwoSpaces,
9
+ quoteKind: QuoteKind.Single
10
+ } });
11
+ async function createSourceFile(path) {
12
+ return project.createSourceFile(path, (await fs.readFile(path)).toString(), { overwrite: true });
13
+ }
14
+ function getCodeValue(v) {
15
+ return new Function(`return ${v}`)();
16
+ }
17
+
18
+ //#endregion
19
+ //#region src/transform/react-router.ts
20
+ var SyntaxKind$1 = ts.SyntaxKind;
21
+ /**
22
+ * filter items in a specific array initializer in the prerender function
23
+ */
24
+ function filterReactRouterPrerenderArray(sourceFile, array, filter) {
25
+ const methodBody = getPrerenderMethod(sourceFile)?.getBody();
26
+ if (!methodBody) return;
27
+ const initializer = methodBody.getDescendantsOfKind(SyntaxKind$1.VariableDeclaration).find((item) => item.getName() === array)?.getInitializerIfKind(SyntaxKind$1.ArrayLiteralExpression);
28
+ if (!initializer) return;
29
+ for (const element of initializer.getElements()) if (!filter(getCodeValue(element.getText()))) initializer.removeElement(element);
30
+ }
31
+ /**
32
+ * Add a new route to route config
33
+ */
34
+ function addReactRouterRoute(sourceFile, routes) {
35
+ modifyReactRouterRoutes(sourceFile, (arr) => {
36
+ for (const { path, entry } of routes) arr.addElement(`route('${path}', '${entry}')`);
37
+ });
38
+ }
39
+ /**
40
+ * Remove routes from route config (root level only)
41
+ */
42
+ function filterReactRouterRoute(sourceFile, filter) {
43
+ modifyReactRouterRoutes(sourceFile, (arr) => {
44
+ for (const element of arr.getElements()) {
45
+ if (!element.isKind(SyntaxKind$1.CallExpression) || element.getFirstChildByKind(SyntaxKind$1.Identifier)?.getText() !== "route") continue;
46
+ const args = element.getArguments();
47
+ if (filter({
48
+ path: getCodeValue(args[0].getText()),
49
+ entry: getCodeValue(args[1].getText())
50
+ })) continue;
51
+ arr.removeElement(element);
52
+ }
53
+ });
54
+ }
55
+ function modifyReactRouterRoutes(sourceFile, mod) {
56
+ const initializer = sourceFile.getDefaultExportSymbol()?.getValueDeclaration()?.getFirstDescendantByKind(SyntaxKind$1.ArrayLiteralExpression);
57
+ if (initializer) mod(initializer);
58
+ }
59
+ /**
60
+ * Find the prerender method from the config
61
+ */
62
+ function getPrerenderMethod(sourceFile) {
63
+ return sourceFile.getDefaultExportSymbol()?.getValueDeclaration()?.getFirstDescendantByKind(SyntaxKind$1.ObjectLiteralExpression)?.getProperty("prerender")?.asKind(SyntaxKind$1.MethodDeclaration) ?? null;
64
+ }
65
+
66
+ //#endregion
67
+ //#region src/transform/tanstack-start.ts
68
+ /**
69
+ * Add path to the `pages` array in tanstack start vite config.
70
+ *
71
+ * If the `pages` property doesn't exist, create one.
72
+ */
73
+ function addTanstackPrerender(sourceFile, paths) {
74
+ const optionsArg = getTanstackStartCall(sourceFile)?.getArguments()[0]?.asKind(SyntaxKind.ObjectLiteralExpression);
75
+ if (!optionsArg) return;
76
+ const pagesProperty = optionsArg.getProperty("pages")?.asKind(SyntaxKind.PropertyAssignment);
77
+ function toItem(path) {
78
+ return `{ path: '${path}' }`;
79
+ }
80
+ if (pagesProperty) {
81
+ const initializer = pagesProperty.getInitializerIfKindOrThrow(SyntaxKind.ArrayLiteralExpression);
82
+ const existingPaths = /* @__PURE__ */ new Set();
83
+ for (const element of initializer.getElements()) {
84
+ const value = element.asKind(SyntaxKind.ObjectLiteralExpression)?.getProperty("path")?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer()?.getText();
85
+ if (value) existingPaths.add(getCodeValue(value));
86
+ }
87
+ for (const path of paths) {
88
+ if (existingPaths.has(path)) continue;
89
+ initializer.addElement(toItem(path));
90
+ }
91
+ } else optionsArg.addProperty(`pages: [\n${paths.map((path) => ` ${toItem(path)}`).join(",\n")}\n]`);
92
+ }
93
+ /**
94
+ * Find the tanstackStart call expression
95
+ */
96
+ function getTanstackStartCall(sourceFile) {
97
+ const pluginsProperty = sourceFile.getDefaultExportSymbol()?.getValueDeclaration()?.getFirstDescendantByKind(SyntaxKind.ObjectLiteralExpression)?.getProperty("plugins")?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
98
+ if (!pluginsProperty) return;
99
+ for (const element of pluginsProperty.getElements()) {
100
+ const expression = element.asKind(SyntaxKind.CallExpression);
101
+ if (expression?.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === "tanstackStart") return expression;
102
+ }
103
+ }
104
+
105
+ //#endregion
106
+ //#region src/transform/index.ts
107
+ async function rootProvider({ appDir, template }, fn) {
108
+ const file = await createSourceFile(path.join(appDir, template.rootProviderPath));
109
+ fn({ addSearchDialog(specifier) {
110
+ const elements = file.getDescendantsOfKind(SyntaxKind.JsxElement);
111
+ for (const element of elements) {
112
+ const provider = element.getFirstChildByKind(SyntaxKind.JsxOpeningElement);
113
+ if (provider?.getTagNameNode().getText() !== "RootProvider") continue;
114
+ if (provider.getAttributes().some((attr) => attr.isKind(SyntaxKind.JsxAttribute) && attr.getNameNode().getText() === "search")) continue;
115
+ provider.addAttribute({
116
+ kind: StructureKind.JsxAttribute,
117
+ name: "search",
118
+ initializer: "{{ SearchDialog }}"
119
+ });
120
+ file.addImportDeclaration({
121
+ moduleSpecifier: specifier,
122
+ defaultImport: "SearchDialog"
123
+ });
124
+ break;
125
+ }
126
+ } });
127
+ await file.save();
128
+ }
129
+ async function reactRouterRoutes({ dest, appDir }, fn) {
130
+ const configFile = await createSourceFile(path.join(dest, "react-router.config.ts"));
131
+ const routesFile = await createSourceFile(path.join(appDir, "routes.ts"));
132
+ const tasks = [];
133
+ function normalizePath(v) {
134
+ return v.split("/").filter(Boolean).join("/");
135
+ }
136
+ fn({
137
+ addRoute: (p, entry, code) => {
138
+ addReactRouterRoute(routesFile, [{
139
+ path: p,
140
+ entry
141
+ }]);
142
+ if (code) tasks.push(fs.writeFile(path.join(appDir, entry), code));
143
+ },
144
+ removeRoute: (p) => {
145
+ const normalizedPath = normalizePath(p);
146
+ filterReactRouterRoute(routesFile, (item) => {
147
+ if (normalizePath(item.path) !== normalizedPath) return true;
148
+ tasks.push(fs.unlink(path.join(appDir, item.entry)).catch(() => null));
149
+ return false;
150
+ });
151
+ filterReactRouterPrerenderArray(configFile, "excluded", (item) => normalizePath(item) !== normalizedPath);
152
+ filterReactRouterPrerenderArray(configFile, "paths", (item) => normalizePath(item) !== normalizedPath);
153
+ }
154
+ });
155
+ await Promise.all([
156
+ ...tasks,
157
+ routesFile.save(),
158
+ configFile.save()
159
+ ]);
160
+ }
161
+ async function tanstackStartRoutes({ appDir, dest }, fn) {
162
+ const configFile = await createSourceFile(path.join(dest, "vite.config.ts"));
163
+ const tasks = [];
164
+ fn({
165
+ addRoute(options) {
166
+ if (options.code) tasks.push(fs.writeFile(path.join(appDir, "routes", options.path), options.code));
167
+ if (options.prerender) addTanstackPrerender(configFile, [options.route]);
168
+ },
169
+ removeRoute(options) {
170
+ tasks.push(fs.unlink(path.join(appDir, "routes", options.path)).catch(() => null));
171
+ }
172
+ });
173
+ await Promise.all([...tasks, configFile.save()]);
174
+ }
175
+
176
+ //#endregion
177
+ //#region src/plugins/orama-cloud.ts
178
+ function oramaCloud() {
179
+ return {
180
+ packageJson(packageJson) {
181
+ return {
182
+ ...packageJson,
183
+ scripts: {
184
+ ...packageJson.scripts,
185
+ build: `${packageJson.scripts.build} && bun scripts/sync-content.ts`
186
+ },
187
+ dependencies: {
188
+ ...packageJson.dependencies,
189
+ ...pick(depVersions, ["@orama/core"])
190
+ }
191
+ };
192
+ },
193
+ readme(content) {
194
+ return `${content}\n\n## Orama Cloud
195
+
196
+ This project uses Orama Cloud for 3rd party search solution.
197
+
198
+ See https://hanzoai.github.io/docs/docs/headless/search/orama-cloud for integrating Orama Cloud to Hanzo Docs.`;
199
+ },
200
+ async afterWrite() {
201
+ const { dest, appDir, template } = this;
202
+ await copy(path.join(sourceDir, "template/+orama-cloud/@root"), dest);
203
+ await copy(path.join(sourceDir, "template/+orama-cloud/@app"), appDir);
204
+ await rootProvider(this, (mod) => mod.addSearchDialog("@/components/search"));
205
+ if (template.value === "tanstack-start") await tanstackStartRoutes(this, (mod) => {
206
+ mod.addRoute({
207
+ path: "static[.]json.ts",
208
+ route: "/static.json",
209
+ code: route.tanstack,
210
+ prerender: true
211
+ });
212
+ mod.removeRoute({
213
+ path: "api/search.ts",
214
+ route: "/api/search"
215
+ });
216
+ });
217
+ else if (template.value.startsWith("react-router")) await reactRouterRoutes(this, (mod) => {
218
+ mod.addRoute("static.json", "routes/static.ts", route["react-router"]);
219
+ mod.removeRoute("api/search");
220
+ });
221
+ else if (template.value.startsWith("+next")) await Promise.all([fs.unlink(path.join(appDir, "app/api/search/route.ts")).catch(() => null), writeFile(path.join(appDir, "app/static.json/route.ts"), route.next)]);
222
+ else await Promise.all([fs.unlink(path.join(appDir, "pages/_api/api/search.ts")).catch(() => null), writeFile(path.join(appDir, "pages/_api/static.json.ts"), route.waku)]);
223
+ const filePath = {
224
+ "+next+fuma-docs-mdx": ".next/server/app/static.json.body",
225
+ "+next+fuma-docs-mdx+static": ".next/server/app/static.json.body",
226
+ "tanstack-start": ".output/public/static.json",
227
+ "tanstack-start-spa": "dist/client/static.json",
228
+ "react-router": "build/client/static.json",
229
+ "react-router-spa": "build/client/static.json",
230
+ waku: "dist/public/static.json"
231
+ }[template.value];
232
+ await writeFile(path.join(dest, "scripts/sync-content.ts"), `import { type OramaDocument, sync } from '@hanzo/docs-core/search/orama-cloud';
233
+ import * as fs from 'node:fs/promises';
234
+ import { OramaCloud } from '@orama/core';
235
+
236
+ // the path of pre-rendered \`static.json\`
237
+ const filePath = '${filePath}';
238
+
239
+ async function main() {
240
+ const orama = new OramaCloud({
241
+ projectId: process.env.NEXT_PUBLIC_ORAMA_PROJECT_ID,
242
+ apiKey: process.env.ORAMA_PRIVATE_API_KEY,
243
+ });
244
+
245
+ const content = await fs.readFile(filePath);
246
+ const records = JSON.parse(content.toString()) as OramaDocument[];
247
+
248
+ await sync(orama, {
249
+ index: process.env.NEXT_PUBLIC_ORAMA_DATASOURCE_ID,
250
+ documents: records,
251
+ });
252
+
253
+ console.log(\`search updated: \${records.length} records\`);
254
+ }
255
+
256
+ void main();`);
257
+ }
258
+ };
259
+ }
260
+ const route = {
261
+ next: `import { exportSearchIndexes } from '@/lib/export-search-indexes';
262
+
263
+ export const revalidate = false;
264
+
265
+ export async function GET() {
266
+ return Response.json(await exportSearchIndexes());
267
+ }`,
268
+ "react-router": `import { exportSearchIndexes } from '@/lib/export-search-indexes';
269
+
270
+ export async function loader() {
271
+ return Response.json(await exportSearchIndexes());
272
+ }`,
273
+ tanstack: `import { createFileRoute } from '@tanstack/react-router';
274
+ import { exportSearchIndexes } from '@/lib/export-search-indexes';
275
+
276
+ export const Route = createFileRoute('/static.json')({
277
+ server: {
278
+ handlers: {
279
+ GET: async () => Response.json(await exportSearchIndexes()),
280
+ },
281
+ },
282
+ });`,
283
+ waku: `import { exportSearchIndexes } from '@/lib/export-search-indexes';
284
+
285
+ export async function GET() {
286
+ return Response.json(await exportSearchIndexes());
287
+ }
288
+
289
+ export const getConfig = () => ({
290
+ render: 'static',
291
+ });`
292
+ };
293
+
294
+ //#endregion
295
+ export { oramaCloud };
296
+ //# sourceMappingURL=orama-cloud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orama-cloud.js","names":["SyntaxKind"],"sources":["../../src/transform/shared.ts","../../src/transform/react-router.ts","../../src/transform/tanstack-start.ts","../../src/transform/index.ts","../../src/plugins/orama-cloud.ts"],"sourcesContent":["import { IndentationText, Project, QuoteKind } from 'ts-morph';\nimport fs from 'node:fs/promises';\n\nconst project = new Project({\n manipulationSettings: {\n indentationText: IndentationText.TwoSpaces,\n quoteKind: QuoteKind.Single,\n },\n});\n\nexport async function createSourceFile(path: string) {\n return project.createSourceFile(path, (await fs.readFile(path)).toString(), {\n overwrite: true,\n });\n}\n\nexport function getCodeValue(v: string) {\n return new Function(`return ${v}`)();\n}\n","import { ArrayLiteralExpression, MethodDeclaration, SourceFile, ts } from 'ts-morph';\nimport { getCodeValue } from '@/transform/shared';\nimport SyntaxKind = ts.SyntaxKind;\n\n/**\n * filter items in a specific array initializer in the prerender function\n */\nexport function filterReactRouterPrerenderArray(\n sourceFile: SourceFile,\n array: 'paths' | 'excluded',\n filter: (item: string) => boolean,\n) {\n const methodBody = getPrerenderMethod(sourceFile)?.getBody();\n if (!methodBody) return;\n\n const initializer = methodBody\n .getDescendantsOfKind(SyntaxKind.VariableDeclaration)\n .find((item) => item.getName() === array)\n ?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);\n\n if (!initializer) return;\n for (const element of initializer.getElements()) {\n if (!filter(getCodeValue(element.getText()))) {\n initializer.removeElement(element);\n }\n }\n}\n\n/**\n * Add a new route to route config\n */\nexport function addReactRouterRoute(\n sourceFile: SourceFile,\n routes: { path: string; entry: string }[],\n) {\n modifyReactRouterRoutes(sourceFile, (arr) => {\n for (const { path, entry } of routes) {\n arr.addElement(`route('${path}', '${entry}')`);\n }\n });\n}\n\n/**\n * Remove routes from route config (root level only)\n */\nexport function filterReactRouterRoute(\n sourceFile: SourceFile,\n filter: (item: { path: string; entry: string }) => boolean,\n) {\n modifyReactRouterRoutes(sourceFile, (arr) => {\n for (const element of arr.getElements()) {\n if (\n !element.isKind(SyntaxKind.CallExpression) ||\n element.getFirstChildByKind(SyntaxKind.Identifier)?.getText() !== 'route'\n )\n continue;\n const args = element.getArguments();\n\n if (\n filter({\n path: getCodeValue(args[0].getText()),\n entry: getCodeValue(args[1].getText()),\n })\n )\n continue;\n\n arr.removeElement(element);\n }\n });\n}\n\nexport function modifyReactRouterRoutes(\n sourceFile: SourceFile,\n mod: (array: ArrayLiteralExpression) => void,\n) {\n const initializer = sourceFile\n .getDefaultExportSymbol()\n ?.getValueDeclaration()\n ?.getFirstDescendantByKind(SyntaxKind.ArrayLiteralExpression);\n if (initializer) mod(initializer);\n}\n\n/**\n * Find the prerender method from the config\n */\nfunction getPrerenderMethod(sourceFile: SourceFile): MethodDeclaration | null {\n return (\n sourceFile\n .getDefaultExportSymbol()\n ?.getValueDeclaration()\n ?.getFirstDescendantByKind(SyntaxKind.ObjectLiteralExpression)\n ?.getProperty('prerender')\n ?.asKind(SyntaxKind.MethodDeclaration) ?? null\n );\n}\n","import { CallExpression, SourceFile, SyntaxKind } from 'ts-morph';\nimport { getCodeValue } from '@/transform/shared';\n\n/**\n * Add path to the `pages` array in tanstack start vite config.\n *\n * If the `pages` property doesn't exist, create one.\n */\nexport function addTanstackPrerender(sourceFile: SourceFile, paths: string[]) {\n const optionsArg = getTanstackStartCall(sourceFile)\n ?.getArguments()[0]\n ?.asKind(SyntaxKind.ObjectLiteralExpression);\n if (!optionsArg) {\n return;\n }\n\n const pagesProperty = optionsArg.getProperty('pages')?.asKind(SyntaxKind.PropertyAssignment);\n\n function toItem(path: string) {\n return `{ path: '${path}' }`;\n }\n\n if (pagesProperty) {\n const initializer = pagesProperty.getInitializerIfKindOrThrow(\n SyntaxKind.ArrayLiteralExpression,\n );\n\n const existingPaths = new Set<string>();\n for (const element of initializer.getElements()) {\n const value = element\n .asKind(SyntaxKind.ObjectLiteralExpression)\n ?.getProperty('path')\n ?.asKind(SyntaxKind.PropertyAssignment)\n ?.getInitializer()\n ?.getText();\n\n if (value) {\n existingPaths.add(getCodeValue(value));\n }\n }\n\n for (const path of paths) {\n if (existingPaths.has(path)) continue;\n initializer.addElement(toItem(path));\n }\n } else {\n optionsArg.addProperty(`pages: [\\n${paths.map((path) => ` ${toItem(path)}`).join(',\\n')}\\n]`);\n }\n}\n\n/**\n * Find the tanstackStart call expression\n */\nfunction getTanstackStartCall(sourceFile: SourceFile): CallExpression | undefined {\n const pluginsProperty = sourceFile\n .getDefaultExportSymbol()\n ?.getValueDeclaration()\n ?.getFirstDescendantByKind(SyntaxKind.ObjectLiteralExpression)\n ?.getProperty('plugins')\n ?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);\n\n if (!pluginsProperty) return;\n\n for (const element of pluginsProperty.getElements()) {\n const expression = element.asKind(SyntaxKind.CallExpression);\n if (expression?.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'tanstackStart') {\n return expression;\n }\n }\n}\n","import { TemplatePluginContext } from '@/index';\nimport { createSourceFile } from '@/transform/shared';\nimport path from 'node:path';\nimport {\n addReactRouterRoute,\n filterReactRouterPrerenderArray,\n filterReactRouterRoute,\n} from '@/transform/react-router';\nimport fs from 'node:fs/promises';\nimport { addTanstackPrerender } from '@/transform/tanstack-start';\nimport { StructureKind, SyntaxKind } from 'ts-morph';\n\ninterface RootLayoutMod {\n addSearchDialog: (specifier: string) => void;\n}\n\nexport async function rootProvider(\n { appDir, template }: TemplatePluginContext,\n fn: (mod: RootLayoutMod) => void,\n) {\n const file = await createSourceFile(path.join(appDir, template.rootProviderPath));\n fn({\n addSearchDialog(specifier) {\n const elements = file.getDescendantsOfKind(SyntaxKind.JsxElement);\n\n for (const element of elements) {\n const provider = element.getFirstChildByKind(SyntaxKind.JsxOpeningElement);\n if (provider?.getTagNameNode().getText() !== 'RootProvider') continue;\n\n // Skip if search prop already exists\n if (\n provider\n .getAttributes()\n .some(\n (attr) =>\n attr.isKind(SyntaxKind.JsxAttribute) && attr.getNameNode().getText() === 'search',\n )\n )\n continue;\n\n provider.addAttribute({\n kind: StructureKind.JsxAttribute,\n name: 'search',\n initializer: '{{ SearchDialog }}',\n });\n file.addImportDeclaration({\n moduleSpecifier: specifier,\n defaultImport: 'SearchDialog',\n });\n break;\n }\n },\n });\n await file.save();\n}\n\ninterface ReactRouterRoutesMod {\n /**\n * @param path API route's path\n * @param entry route's file path\n * @param code create the file if specified\n */\n addRoute: (path: string, entry: string, code?: string) => void;\n\n /**\n * @param path API route's path\n */\n removeRoute: (path: string) => void;\n}\n\nexport async function reactRouterRoutes(\n { dest, appDir }: TemplatePluginContext,\n fn: (mod: ReactRouterRoutesMod) => void,\n) {\n const configFile = await createSourceFile(path.join(dest, 'react-router.config.ts'));\n const routesFile = await createSourceFile(path.join(appDir, 'routes.ts'));\n const tasks: Promise<unknown>[] = [];\n\n function normalizePath(v: string) {\n return v.split('/').filter(Boolean).join('/');\n }\n\n fn({\n addRoute: (p, entry, code) => {\n addReactRouterRoute(routesFile, [{ path: p, entry }]);\n\n if (code) {\n tasks.push(fs.writeFile(path.join(appDir, entry), code));\n }\n },\n removeRoute: (p) => {\n const normalizedPath = normalizePath(p);\n\n filterReactRouterRoute(routesFile, (item) => {\n if (normalizePath(item.path) !== normalizedPath) return true;\n\n tasks.push(fs.unlink(path.join(appDir, item.entry)).catch(() => null));\n return false;\n });\n\n filterReactRouterPrerenderArray(\n configFile,\n 'excluded',\n (item) => normalizePath(item) !== normalizedPath,\n );\n\n filterReactRouterPrerenderArray(\n configFile,\n 'paths',\n (item) => normalizePath(item) !== normalizedPath,\n );\n },\n });\n\n await Promise.all([...tasks, routesFile.save(), configFile.save()]);\n}\n\nexport interface TanstackStartRoutesMod {\n addRoute: (options: {\n /**\n * file path relative to `routes`\n */\n path: string;\n\n /**\n * Generated route path of `path`\n */\n route: string;\n\n /**\n * if specified, create the file\n */\n code?: string;\n\n /**\n * if true, add to prerender list\n */\n prerender?: boolean;\n }) => void;\n\n removeRoute: (options: {\n /**\n * file path relative to routes directory\n */\n path: string;\n\n route: string;\n }) => void;\n}\n\nexport async function tanstackStartRoutes(\n { appDir, dest }: TemplatePluginContext,\n fn: (mod: TanstackStartRoutesMod) => void,\n) {\n const configFile = await createSourceFile(path.join(dest, 'vite.config.ts'));\n const tasks: Promise<unknown>[] = [];\n\n fn({\n addRoute(options) {\n if (options.code) {\n tasks.push(fs.writeFile(path.join(appDir, 'routes', options.path), options.code));\n }\n\n if (options.prerender) {\n addTanstackPrerender(configFile, [options.route]);\n }\n },\n removeRoute(options) {\n tasks.push(fs.unlink(path.join(appDir, 'routes', options.path)).catch(() => null));\n },\n });\n\n await Promise.all([...tasks, configFile.save()]);\n}\n","import { TemplatePlugin } from '@/index';\nimport { copy, pick, writeFile } from '@/utils';\nimport path from 'node:path';\nimport { depVersions, sourceDir } from '@/constants';\nimport fs from 'node:fs/promises';\nimport { reactRouterRoutes, rootProvider, tanstackStartRoutes } from '@/transform';\n\nexport function oramaCloud(): TemplatePlugin {\n return {\n packageJson(packageJson) {\n return {\n ...packageJson,\n scripts: {\n ...packageJson.scripts,\n build: `${packageJson.scripts!.build} && bun scripts/sync-content.ts`,\n },\n dependencies: {\n ...packageJson.dependencies,\n ...pick(depVersions, ['@orama/core']),\n },\n };\n },\n readme(content) {\n return `${content}\\n\\n## Orama Cloud\n \nThis project uses Orama Cloud for 3rd party search solution.\n\nSee https://hanzoai.github.io/docs/docs/headless/search/orama-cloud for integrating Orama Cloud to Hanzo Docs.`;\n },\n async afterWrite() {\n const { dest, appDir, template } = this;\n await copy(path.join(sourceDir, 'template/+orama-cloud/@root'), dest);\n await copy(path.join(sourceDir, 'template/+orama-cloud/@app'), appDir);\n\n await rootProvider(this, (mod) => mod.addSearchDialog('@/components/search'));\n\n if (template.value === 'tanstack-start') {\n await tanstackStartRoutes(this, (mod) => {\n mod.addRoute({\n path: 'static[.]json.ts',\n route: '/static.json',\n code: route.tanstack,\n prerender: true,\n });\n mod.removeRoute({\n path: 'api/search.ts',\n route: '/api/search',\n });\n });\n } else if (template.value.startsWith('react-router')) {\n await reactRouterRoutes(this, (mod) => {\n mod.addRoute('static.json', 'routes/static.ts', route['react-router']);\n mod.removeRoute('api/search');\n });\n } else if (template.value.startsWith('+next')) {\n await Promise.all([\n fs.unlink(path.join(appDir, 'app/api/search/route.ts')).catch(() => null),\n writeFile(path.join(appDir, 'app/static.json/route.ts'), route.next),\n ]);\n } else {\n await Promise.all([\n fs.unlink(path.join(appDir, 'pages/_api/api/search.ts')).catch(() => null),\n writeFile(path.join(appDir, 'pages/_api/static.json.ts'), route.waku),\n ]);\n }\n\n const filePath = {\n '+next+fuma-docs-mdx': '.next/server/app/static.json.body',\n '+next+fuma-docs-mdx+static': '.next/server/app/static.json.body',\n 'tanstack-start': '.output/public/static.json',\n 'tanstack-start-spa': 'dist/client/static.json',\n 'react-router': 'build/client/static.json',\n 'react-router-spa': 'build/client/static.json',\n waku: 'dist/public/static.json',\n }[template.value];\n\n await writeFile(\n path.join(dest, 'scripts/sync-content.ts'),\n `import { type OramaDocument, sync } from '@hanzo/docs-core/search/orama-cloud';\nimport * as fs from 'node:fs/promises';\nimport { OramaCloud } from '@orama/core';\n\n// the path of pre-rendered \\`static.json\\`\nconst filePath = '${filePath}';\n\nasync function main() {\n const orama = new OramaCloud({\n projectId: process.env.NEXT_PUBLIC_ORAMA_PROJECT_ID,\n apiKey: process.env.ORAMA_PRIVATE_API_KEY,\n });\n\n const content = await fs.readFile(filePath);\n const records = JSON.parse(content.toString()) as OramaDocument[];\n\n await sync(orama, {\n index: process.env.NEXT_PUBLIC_ORAMA_DATASOURCE_ID,\n documents: records,\n });\n\n console.log(\\`search updated: \\${records.length} records\\`);\n}\n\nvoid main();`,\n );\n },\n };\n}\n\nconst route = {\n next: `import { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport const revalidate = false;\n\nexport async function GET() {\n return Response.json(await exportSearchIndexes());\n}`,\n 'react-router': `import { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport async function loader() {\n return Response.json(await exportSearchIndexes());\n}`,\n tanstack: `import { createFileRoute } from '@tanstack/react-router';\nimport { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport const Route = createFileRoute('/static.json')({\n server: {\n handlers: {\n GET: async () => Response.json(await exportSearchIndexes()),\n },\n },\n});`,\n waku: `import { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport async function GET() {\n return Response.json(await exportSearchIndexes());\n}\n\nexport const getConfig = () => ({\n render: 'static',\n});`,\n};\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@hanzo/docs-create-app",
3
+ "version": "16.0.50",
4
+ "description": "Create a new documentation site with Hanzo Docs",
5
+ "keywords": [
6
+ "Docs",
7
+ "Hanzo Docs",
8
+ "react"
9
+ ],
10
+ "homepage": "https://hanzoai.github.io/docs",
11
+ "license": "MIT",
12
+ "author": "Hanzo AI",
13
+ "repository": "github:hanzoai/docs",
14
+ "bin": "./dist/bin.js",
15
+ "files": [
16
+ "dist/*",
17
+ "template/*"
18
+ ],
19
+ "type": "module",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./plugins/*": {
28
+ "types": "./dist/plugins/*.d.ts",
29
+ "import": "./dist/plugins/*.js"
30
+ }
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "dependencies": {
36
+ "@clack/prompts": "^1.0.0",
37
+ "@commander-js/extra-typings": "^14.0.0",
38
+ "commander": "^14.0.3",
39
+ "picocolors": "^1.1.1",
40
+ "tinyexec": "^1.0.2",
41
+ "ts-morph": "^27.0.2"
42
+ },
43
+ "devDependencies": {
44
+ "@types/cross-spawn": "^6.0.6",
45
+ "@types/node": "25.2.1",
46
+ "tinyglobby": "^0.2.15",
47
+ "tsdown": "^0.20.3",
48
+ "typescript": "^5.9.3",
49
+ "eslint-config-custom": "0.0.0",
50
+ "tsconfig": "0.0.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=18.17.0"
54
+ },
55
+ "scripts": {
56
+ "build": "pnpm run sync && tsdown",
57
+ "clean": "rimraf dist",
58
+ "dev": "tsdown --watch",
59
+ "lint": "eslint .",
60
+ "types:check": "tsc --noEmit",
61
+ "sync": "bun ./scripts/sync.ts"
62
+ }
63
+ }
@@ -0,0 +1,6 @@
1
+ import { HomeLayout } from '@hanzo/docs-base-ui/layouts/home';
2
+ import { baseOptions } from '@/lib/layout.shared';
3
+
4
+ export default function Layout({ children }: LayoutProps<'/'>) {
5
+ return <HomeLayout {...baseOptions()}>{children}</HomeLayout>;
6
+ }
@@ -0,0 +1,16 @@
1
+ import Link from 'next/link';
2
+
3
+ export default function HomePage() {
4
+ return (
5
+ <div className="flex flex-col justify-center text-center flex-1">
6
+ <h1 className="text-2xl font-bold mb-4">Hello World</h1>
7
+ <p>
8
+ You can open{' '}
9
+ <Link href="/docs" className="font-medium underline">
10
+ /docs
11
+ </Link>{' '}
12
+ and see the documentation.
13
+ </p>
14
+ </div>
15
+ );
16
+ }
@@ -0,0 +1,7 @@
1
+ import { source } from '@/lib/source';
2
+ import { createFromSource } from '@hanzo/docs/core/search/server';
3
+
4
+ export const { GET } = createFromSource(source, {
5
+ // https://docs.orama.com/docs/orama-js/supported-languages
6
+ language: 'english',
7
+ });
@@ -0,0 +1,57 @@
1
+ import { getPageImage, source } from '@/lib/source';
2
+ import { DocsBody, DocsDescription, DocsPage, DocsTitle } from '@hanzo/docs-ui/layouts/docs/page';
3
+ import { notFound } from 'next/navigation';
4
+ import { getMDXComponents } from '@/mdx-components';
5
+ import type { Metadata } from 'next';
6
+ import { createRelativeLink } from '@hanzo/docs-ui/mdx';
7
+ import { LLMCopyButton, ViewOptions } from '@/components/ai/page-actions';
8
+ import { gitConfig } from '@/lib/layout.shared';
9
+
10
+ export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
11
+ const params = await props.params;
12
+ const page = source.getPage(params.slug);
13
+ if (!page) notFound();
14
+
15
+ const MDX = page.data.body;
16
+
17
+ return (
18
+ <DocsPage toc={page.data.toc} full={page.data.full}>
19
+ <DocsTitle>{page.data.title}</DocsTitle>
20
+ <DocsDescription className="mb-0">{page.data.description}</DocsDescription>
21
+ <div className="flex flex-row gap-2 items-center border-b pb-6">
22
+ <LLMCopyButton markdownUrl={`${page.url}.mdx`} />
23
+ <ViewOptions
24
+ markdownUrl={`${page.url}.mdx`}
25
+ // update it to match your repo
26
+ githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`}
27
+ />
28
+ </div>
29
+ <DocsBody>
30
+ <MDX
31
+ components={getMDXComponents({
32
+ // this allows you to link to other pages with relative file paths
33
+ a: createRelativeLink(source, page),
34
+ })}
35
+ />
36
+ </DocsBody>
37
+ </DocsPage>
38
+ );
39
+ }
40
+
41
+ export async function generateStaticParams() {
42
+ return source.generateParams();
43
+ }
44
+
45
+ export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise<Metadata> {
46
+ const params = await props.params;
47
+ const page = source.getPage(params.slug);
48
+ if (!page) notFound();
49
+
50
+ return {
51
+ title: page.data.title,
52
+ description: page.data.description,
53
+ openGraph: {
54
+ images: getPageImage(page).url,
55
+ },
56
+ };
57
+ }
@@ -0,0 +1,11 @@
1
+ import { source } from '@/lib/source';
2
+ import { DocsLayout } from '@hanzo/docs-ui/layouts/docs';
3
+ import { baseOptions } from '@/lib/layout.shared';
4
+
5
+ export default function Layout({ children }: LayoutProps<'/docs'>) {
6
+ return (
7
+ <DocsLayout tree={source.getPageTree()} {...baseOptions()}>
8
+ {children}
9
+ </DocsLayout>
10
+ );
11
+ }
@@ -0,0 +1,3 @@
1
+ @import 'tailwindcss';
2
+ @import '@hanzo/docs-base-ui/css/neutral.css';
3
+ @import '@hanzo/docs-base-ui/css/preset.css';
@@ -0,0 +1,17 @@
1
+ import { RootProvider } from '@hanzo/docs/ui/provider/next';
2
+ import './global.css';
3
+ import { Inter } from 'next/font/google';
4
+
5
+ const inter = Inter({
6
+ subsets: ['latin'],
7
+ });
8
+
9
+ export default function Layout({ children }: LayoutProps<'/'>) {
10
+ return (
11
+ <html lang="en" className={inter.className} suppressHydrationWarning>
12
+ <body className="flex flex-col min-h-screen">
13
+ <RootProvider>{children}</RootProvider>
14
+ </body>
15
+ </html>
16
+ );
17
+ }
@@ -0,0 +1,10 @@
1
+ import { getLLMText, source } from '@/lib/source';
2
+
3
+ export const revalidate = false;
4
+
5
+ export async function GET() {
6
+ const scan = source.getPages().map(getLLMText);
7
+ const scanned = await Promise.all(scan);
8
+
9
+ return new Response(scanned.join('\n\n'));
10
+ }
@@ -0,0 +1,20 @@
1
+ import { getLLMText, source } from '@/lib/source';
2
+ import { notFound } from 'next/navigation';
3
+
4
+ export const revalidate = false;
5
+
6
+ export async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/docs/[[...slug]]'>) {
7
+ const { slug } = await params;
8
+ const page = source.getPage(slug);
9
+ if (!page) notFound();
10
+
11
+ return new Response(await getLLMText(page), {
12
+ headers: {
13
+ 'Content-Type': 'text/markdown',
14
+ },
15
+ });
16
+ }
17
+
18
+ export function generateStaticParams() {
19
+ return source.generateParams();
20
+ }
@@ -0,0 +1,13 @@
1
+ import { source } from '@/lib/source';
2
+
3
+ export const revalidate = false;
4
+
5
+ export async function GET() {
6
+ const lines: string[] = [];
7
+ lines.push('# Documentation');
8
+ lines.push('');
9
+ for (const page of source.getPages()) {
10
+ lines.push(`- [${page.data.title}](${page.url}): ${page.data.description}`);
11
+ }
12
+ return new Response(lines.join('\n'));
13
+ }
@@ -0,0 +1,27 @@
1
+ import { getPageImage, source } from '@/lib/source';
2
+ import { notFound } from 'next/navigation';
3
+ import { ImageResponse } from 'next/og';
4
+ import { generate as DefaultImage } from '@hanzo/docs-ui/og';
5
+
6
+ export const revalidate = false;
7
+
8
+ export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) {
9
+ const { slug } = await params;
10
+ const page = source.getPage(slug.slice(0, -1));
11
+ if (!page) notFound();
12
+
13
+ return new ImageResponse(
14
+ <DefaultImage title={page.data.title} description={page.data.description} site="My App" />,
15
+ {
16
+ width: 1200,
17
+ height: 630,
18
+ },
19
+ );
20
+ }
21
+
22
+ export function generateStaticParams() {
23
+ return source.getPages().map((page) => ({
24
+ lang: page.locale,
25
+ slug: getPageImage(page).segments,
26
+ }));
27
+ }