@heyo-sh/create-heyo-docs 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/deployments/cloudflare/astro/package.json +2 -1
  2. package/deployments/cloudflare/astro/src/env.d.ts +8 -0
  3. package/deployments/cloudflare/astro/src/pages/heyo-docs-internal/ai-chat.ts +32 -0
  4. package/deployments/cloudflare/next/app/heyo-docs-internal/ai-chat/route.ts +27 -0
  5. package/deployments/cloudflare/next/cloudflare-env.d.ts +7 -0
  6. package/deployments/cloudflare/react-router/app/cloudflare-env.d.ts +7 -0
  7. package/deployments/cloudflare/react-router/app/lib/cloudflare-context.ts +4 -0
  8. package/deployments/cloudflare/react-router/app/routes/ai-chat.ts +31 -0
  9. package/deployments/cloudflare/react-router/package.json +2 -1
  10. package/deployments/cloudflare/react-router/workers/app.ts +6 -2
  11. package/deployments/vercel/astro/package.json +1 -0
  12. package/dist/index.js +37 -16
  13. package/dist/project-name.d.ts +1 -1
  14. package/dist/project-name.d.ts.map +1 -1
  15. package/dist/scaffold.d.ts.map +1 -1
  16. package/dist/utils.d.ts.map +1 -1
  17. package/package.json +2 -2
  18. package/templates/astro/content/index.mdx +8 -0
  19. package/templates/astro/heyo-docs.config.ts +4 -48
  20. package/templates/astro/src/components/docs-app.tsx +30 -130
  21. package/templates/astro/src/heyo-docs-icons.tsx +3 -1
  22. package/templates/astro/src/layouts/docs-layout.astro +20 -504
  23. package/templates/astro/src/lib/docs.ts +3 -2
  24. package/templates/astro/src/lib/openapi-request.ts +6 -146
  25. package/templates/astro/src/pages/[...slug].astro +7 -15
  26. package/templates/astro/src/pages/[...slug].md.ts +4 -1
  27. package/templates/astro/src/pages/heyo-docs-internal/ai-chat.ts +10 -3
  28. package/templates/astro/src/pages/heyo-docs-internal/openapi-request.ts +6 -0
  29. package/templates/astro/src/pages/index.astro +18 -9
  30. package/templates/astro/src/pages/llms-full.txt.ts +1 -1
  31. package/templates/astro/src/pages/llms.txt.ts +1 -1
  32. package/templates/astro/src/pages/rss.xml.ts +1 -1
  33. package/templates/astro/src/pages/sitemap.xml.ts +2 -2
  34. package/templates/astro/src/virtual.d.ts +5 -5
  35. package/templates/next/app/[[...slug]]/page.tsx +10 -9
  36. package/templates/next/app/components/docs-app.tsx +28 -120
  37. package/templates/next/app/heyo-docs-icons.tsx +1 -1
  38. package/templates/next/app/heyo-docs-internal/ai-chat/route.ts +9 -2
  39. package/templates/next/app/heyo-docs-internal/markdown/[[...slug]]/route.ts +1 -1
  40. package/templates/next/app/layout.tsx +25 -444
  41. package/templates/next/app/lib/docs.ts +3 -3
  42. package/templates/next/app/lib/openapi-request.ts +4 -136
  43. package/templates/next/app/llms-full.txt/route.ts +1 -1
  44. package/templates/next/app/llms.txt/route.ts +1 -1
  45. package/templates/next/app/rss.xml/route.ts +1 -1
  46. package/templates/next/app/sitemap.xml/route.ts +1 -1
  47. package/templates/next/content/index.mdx +8 -0
  48. package/templates/next/heyo-docs.config.ts +3 -47
  49. package/templates/next/next.config.ts +7 -1
  50. package/templates/react-router/app/heyo-docs-icons.tsx +3 -1
  51. package/templates/react-router/app/root.tsx +28 -465
  52. package/templates/react-router/app/routes/ai-chat.ts +6 -2
  53. package/templates/react-router/app/routes/docs.tsx +22 -63
  54. package/templates/react-router/app/routes/home.tsx +6 -1
  55. package/templates/react-router/app/routes/llms-full.ts +1 -1
  56. package/templates/react-router/app/routes/llms.ts +1 -1
  57. package/templates/react-router/app/routes/markdown.ts +4 -1
  58. package/templates/react-router/app/routes/openapi-request.ts +11 -144
  59. package/templates/react-router/app/routes/rss.ts +1 -1
  60. package/templates/react-router/app/routes/sitemap.ts +5 -8
  61. package/templates/react-router/app/virtual.d.ts +5 -5
  62. package/templates/react-router/content/index.mdx +8 -0
  63. package/templates/react-router/heyo-docs.config.ts +4 -48
  64. package/templates/astro/content/api-overview.mdx +0 -20
  65. package/templates/astro/content/assets/local-architecture.svg +0 -22
  66. package/templates/astro/content/assets/quick-reference.txt +0 -5
  67. package/templates/astro/content/changelog.mdx +0 -38
  68. package/templates/astro/content/configuration.mdx +0 -117
  69. package/templates/astro/content/deploying.mdx +0 -57
  70. package/templates/astro/content/essentials/callouts.mdx +0 -34
  71. package/templates/astro/content/essentials/code-blocks.mdx +0 -43
  72. package/templates/astro/content/essentials/lists.mdx +0 -36
  73. package/templates/astro/content/essentials/tables.mdx +0 -30
  74. package/templates/astro/content/essentials/tabs.mdx +0 -40
  75. package/templates/astro/content/essentials/text-styling.mdx +0 -43
  76. package/templates/astro/content/getting-started.mdx +0 -16
  77. package/templates/astro/content/mdx-components.mdx +0 -44
  78. package/templates/astro/content/openapi-petstore.json +0 -160
  79. package/templates/astro/content/openapi.json +0 -278
  80. package/templates/astro/content/quickstart.mdx +0 -60
  81. package/templates/astro/src/components/theme-provider.tsx +0 -106
  82. package/templates/astro/src/lib/seo.ts +0 -221
  83. package/templates/astro/src/lib/theme.ts +0 -74
  84. package/templates/next/app/components/theme-provider.tsx +0 -93
  85. package/templates/next/app/lib/seo.ts +0 -189
  86. package/templates/next/app/lib/theme.ts +0 -61
  87. package/templates/next/content/api-overview.mdx +0 -20
  88. package/templates/next/content/assets/local-architecture.svg +0 -22
  89. package/templates/next/content/assets/quick-reference.txt +0 -5
  90. package/templates/next/content/changelog.mdx +0 -38
  91. package/templates/next/content/configuration.mdx +0 -117
  92. package/templates/next/content/deploying.mdx +0 -57
  93. package/templates/next/content/essentials/callouts.mdx +0 -34
  94. package/templates/next/content/essentials/code-blocks.mdx +0 -43
  95. package/templates/next/content/essentials/lists.mdx +0 -36
  96. package/templates/next/content/essentials/tables.mdx +0 -30
  97. package/templates/next/content/essentials/tabs.mdx +0 -40
  98. package/templates/next/content/essentials/text-styling.mdx +0 -43
  99. package/templates/next/content/getting-started.mdx +0 -16
  100. package/templates/next/content/mdx-components.mdx +0 -41
  101. package/templates/next/content/openapi-petstore.json +0 -160
  102. package/templates/next/content/openapi.json +0 -278
  103. package/templates/next/content/quickstart.mdx +0 -60
  104. package/templates/react-router/app/components/theme-provider.tsx +0 -106
  105. package/templates/react-router/app/lib/theme.ts +0 -74
  106. package/templates/react-router/content/api-overview.mdx +0 -20
  107. package/templates/react-router/content/assets/local-architecture.svg +0 -22
  108. package/templates/react-router/content/assets/quick-reference.txt +0 -5
  109. package/templates/react-router/content/changelog.mdx +0 -38
  110. package/templates/react-router/content/configuration.mdx +0 -117
  111. package/templates/react-router/content/deploying.mdx +0 -57
  112. package/templates/react-router/content/essentials/callouts.mdx +0 -34
  113. package/templates/react-router/content/essentials/code-blocks.mdx +0 -43
  114. package/templates/react-router/content/essentials/lists.mdx +0 -36
  115. package/templates/react-router/content/essentials/tables.mdx +0 -30
  116. package/templates/react-router/content/essentials/tabs.mdx +0 -40
  117. package/templates/react-router/content/essentials/text-styling.mdx +0 -43
  118. package/templates/react-router/content/getting-started.mdx +0 -16
  119. package/templates/react-router/content/mdx-components.mdx +0 -293
  120. package/templates/react-router/content/openapi-petstore.json +0 -160
  121. package/templates/react-router/content/openapi.json +0 -278
  122. package/templates/react-router/content/quickstart.mdx +0 -60
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "scripts": {
3
3
  "deploy": "wrangler deploy --config dist/server/wrangler.json",
4
- "cf-typegen": "wrangler types --config dist/server/wrangler.json"
4
+ "cf-typegen": "wrangler types",
5
+ "typecheck": "bun run cf-typegen && astro check"
5
6
  },
6
7
  "dependencies": {
7
8
  "@astrojs/cloudflare": "14.2.6"
@@ -0,0 +1,8 @@
1
+ declare namespace Cloudflare {
2
+ interface Env {
3
+ /** Preferred generic API-key binding; provider-specific auth stays in config. */
4
+ HEYO_DOCS_AI_API_KEY?: string;
5
+ /** @deprecated Use HEYO_DOCS_AI_API_KEY or config.ai.chat.auth. */
6
+ OPENAI_API_KEY?: string;
7
+ }
8
+ }
@@ -0,0 +1,32 @@
1
+ import type { APIRoute } from "astro";
2
+ import { env } from "cloudflare:workers";
3
+
4
+ import config from "../../../heyo-docs.config";
5
+ import { pages as markdownPages } from "virtual:heyo-docs-content/server";
6
+
7
+ export const prerender = false;
8
+
9
+ export const POST: APIRoute = async ({ request }) => {
10
+ if (!config.ai?.chat)
11
+ return Response.json(
12
+ { error: "AI chat is not configured." },
13
+ { status: 404 },
14
+ );
15
+
16
+ const token = env.HEYO_DOCS_AI_API_KEY ?? env.OPENAI_API_KEY;
17
+ const { createAiChatResponse } = await import("@heyo-sh/heyo-docs/ai");
18
+ return createAiChatResponse(request, {
19
+ ai: config.ai,
20
+ ...(config.ai?.chat.auth || !token
21
+ ? {}
22
+ : { auth: { type: "api-key" as const, token } }),
23
+ markdownPages,
24
+ pages: markdownPages.map((page) => ({
25
+ description: page.description,
26
+ searchContent: page.raw,
27
+ slug: page.slug,
28
+ title: page.title,
29
+ })),
30
+ title: config.title,
31
+ });
32
+ };
@@ -0,0 +1,27 @@
1
+ import { getCloudflareContext } from "@opennextjs/cloudflare";
2
+
3
+ import config from "../../../heyo-docs.config";
4
+ import { docsPages, markdownPages } from "../../_heyo-docs/server";
5
+
6
+ export const runtime = "nodejs";
7
+
8
+ export async function POST(request: Request) {
9
+ if (!config.ai?.chat)
10
+ return Response.json(
11
+ { error: "AI chat is not configured." },
12
+ { status: 404 },
13
+ );
14
+
15
+ const { env } = getCloudflareContext();
16
+ const token = env.HEYO_DOCS_AI_API_KEY ?? env.OPENAI_API_KEY;
17
+ const { createAiChatResponse } = await import("@heyo-sh/heyo-docs/ai");
18
+ return createAiChatResponse(request, {
19
+ ai: config.ai,
20
+ ...(config.ai?.chat.auth || !token
21
+ ? {}
22
+ : { auth: { type: "api-key" as const, token } }),
23
+ markdownPages,
24
+ pages: docsPages,
25
+ title: config.title,
26
+ });
27
+ }
@@ -0,0 +1,7 @@
1
+ /** Cloudflare Worker secret configured with `wrangler secret put`. */
2
+ interface CloudflareEnv {
3
+ /** Preferred generic API-key binding; provider-specific auth stays in config. */
4
+ HEYO_DOCS_AI_API_KEY?: string;
5
+ /** @deprecated Use HEYO_DOCS_AI_API_KEY or config.ai.chat.auth. */
6
+ OPENAI_API_KEY?: string;
7
+ }
@@ -0,0 +1,7 @@
1
+ /** Cloudflare Worker secret configured with `wrangler secret put`. */
2
+ interface Env {
3
+ /** Preferred generic API-key binding; provider-specific auth stays in config. */
4
+ HEYO_DOCS_AI_API_KEY?: string;
5
+ /** @deprecated Use HEYO_DOCS_AI_API_KEY or config.ai.chat.auth. */
6
+ OPENAI_API_KEY?: string;
7
+ }
@@ -0,0 +1,4 @@
1
+ import { createContext } from "react-router";
2
+
3
+ /** Cloudflare bindings supplied to the Worker for the current request. */
4
+ export const cloudflareContext = createContext<Env>();
@@ -0,0 +1,31 @@
1
+ import type { ActionFunctionArgs } from "react-router";
2
+
3
+ import config from "../../heyo-docs.config";
4
+ import { cloudflareContext } from "../lib/cloudflare-context";
5
+ import { pages } from "virtual:heyo-docs-content";
6
+ import { pages as markdownPages } from "virtual:heyo-docs-content/server";
7
+
8
+ export async function action({ context, request }: ActionFunctionArgs) {
9
+ if (request.method !== "POST")
10
+ return new Response("Method Not Allowed", {
11
+ status: 405,
12
+ headers: { Allow: "POST" },
13
+ });
14
+ if (!config.ai?.chat)
15
+ return Response.json(
16
+ { error: "AI chat is not configured." },
17
+ { status: 404 },
18
+ );
19
+ const bindings = context.get(cloudflareContext);
20
+ const token = bindings.HEYO_DOCS_AI_API_KEY ?? bindings.OPENAI_API_KEY;
21
+ const { createAiChatResponse } = await import("@heyo-sh/heyo-docs/ai");
22
+ return createAiChatResponse(request, {
23
+ ai: config.ai,
24
+ ...(config.ai?.chat.auth || !token
25
+ ? {}
26
+ : { auth: { type: "api-key" as const, token } }),
27
+ markdownPages,
28
+ pages,
29
+ title: config.title,
30
+ });
31
+ }
@@ -5,7 +5,8 @@
5
5
  },
6
6
  "scripts": {
7
7
  "deploy": "wrangler deploy",
8
- "cf-typegen": "wrangler types"
8
+ "cf-typegen": "wrangler types",
9
+ "typecheck": "bun run cf-typegen && react-router typegen && tsc -p tsconfig.json"
9
10
  },
10
11
  "devDependencies": {
11
12
  "@react-router/dev": "8.3.0",
@@ -1,12 +1,16 @@
1
1
  import { createRequestHandler, RouterContextProvider } from "react-router";
2
2
 
3
+ import { cloudflareContext } from "../app/lib/cloudflare-context";
4
+
3
5
  const handleRequest = createRequestHandler(
4
6
  () => import("virtual:react-router/server-build"),
5
7
  import.meta.env.MODE,
6
8
  );
7
9
 
8
10
  export default {
9
- fetch(request) {
10
- return handleRequest(request, new RouterContextProvider());
11
+ fetch(request, env) {
12
+ const context = new RouterContextProvider();
13
+ context.set(cloudflareContext, env);
14
+ return handleRequest(request, context);
11
15
  },
12
16
  } satisfies ExportedHandler<Env>;
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "scripts": {
3
+ "start": "vercel dev",
3
4
  "deploy": "vercel --prod"
4
5
  },
5
6
  "dependencies": {
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ function packageManagerRunCommand(manager, script) {
47
47
  // src/project-name.ts
48
48
  var PROJECT_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/i;
49
49
  function projectNameError(value) {
50
- if (!value.trim())
50
+ if (!value?.trim())
51
51
  return "Enter a project name.";
52
52
  if (!PROJECT_NAME_PATTERN.test(value))
53
53
  return "Use letters, numbers and hyphens only.";
@@ -77,7 +77,10 @@ import {
77
77
  } from "node:fs/promises";
78
78
  import { dirname, join } from "node:path";
79
79
  function replacePlaceholders(source, values) {
80
- return source.replace(/\{\{([A-Z0-9_]+)\}\}/g, (placeholder, key) => values[key] ?? placeholder);
80
+ return source.replace(/\{\{([A-Z0-9_]+)\}\}|__(HEYO_[A-Z0-9_]+)__/g, (placeholder, mustacheKey, tokenKey) => {
81
+ const key = mustacheKey ?? tokenKey;
82
+ return key ? values[key] ?? placeholder : placeholder;
83
+ });
81
84
  }
82
85
  function mergePackageJson(base, overlay) {
83
86
  const merged = { ...base };
@@ -96,13 +99,28 @@ async function copyTemplate(source, destination, placeholders) {
96
99
  }
97
100
  async function replacePlaceholdersAtPath(path, values) {
98
101
  if (!(await stat(path)).isDirectory()) {
99
- const contents = await readFile(path, "utf8");
100
- await writeFile(path, replacePlaceholders(contents, values));
102
+ const contents = await readFile(path);
103
+ if (!isTextFile(contents))
104
+ return;
105
+ const source = contents.toString("utf8");
106
+ if (!source.includes("{{") && !source.includes("__HEYO_"))
107
+ return;
108
+ await writeFile(path, replacePlaceholders(source, values));
101
109
  return;
102
110
  }
103
111
  const entries = await readdir(path, { withFileTypes: true });
104
112
  await Promise.all(entries.map((entry) => replacePlaceholdersAtPath(join(path, entry.name), values)));
105
113
  }
114
+ function isTextFile(contents) {
115
+ if (contents.includes(0))
116
+ return false;
117
+ try {
118
+ new TextDecoder("utf-8", { fatal: true }).decode(contents);
119
+ return true;
120
+ } catch {
121
+ return false;
122
+ }
123
+ }
106
124
  async function writeJson(path, data) {
107
125
  await mkdir(dirname(path), { recursive: true });
108
126
  await writeFile(path, `${JSON.stringify(data, null, 2)}
@@ -133,7 +151,9 @@ async function scaffoldProject(options) {
133
151
  PROJECT_NAME: projectName,
134
152
  HEYO_DOCS_VERSION: options.heyoDocsVersion ?? "latest",
135
153
  PACKAGE_MANAGER: packageManagerField(options.packageManager),
136
- THEME: options.theme
154
+ THEME: options.theme,
155
+ HEYO_THEME: options.theme,
156
+ HEYO_THEME_IDENTIFIER: `${options.theme}Theme`
137
157
  };
138
158
  const templatePath = join2(packageRoot, "templates", options.template);
139
159
  const deploymentPath = join2(packageRoot, "deployments", options.deployment, options.template);
@@ -289,14 +309,12 @@ function parseArguments(argv) {
289
309
  }
290
310
  async function askQuestions(defaults) {
291
311
  p.intro("Create Heyo Docs");
292
- const projectName = await p.text({
312
+ const projectName = promptValue(await p.text({
293
313
  message: "Project name",
294
314
  placeholder: "my-docs",
295
315
  defaultValue: "my-docs",
296
316
  validate: projectNameError
297
- });
298
- if (p.isCancel(projectName))
299
- cancelCreation();
317
+ }));
300
318
  const template = await selectAvailable("Template", TEMPLATE_OPTIONS, [
301
319
  "react-router",
302
320
  "next",
@@ -309,12 +327,10 @@ async function askQuestions(defaults) {
309
327
  "moss"
310
328
  ]);
311
329
  const packageManager = await selectAvailable("Package manager", PACKAGE_MANAGER_OPTIONS, ["bun", "pnpm", "npm", "yarn"], defaults.packageManager);
312
- const install = await p.confirm({
330
+ const install = promptValue(await p.confirm({
313
331
  message: "Install dependencies?",
314
332
  initialValue: true
315
- });
316
- if (p.isCancel(install))
317
- cancelCreation();
333
+ }));
318
334
  return {
319
335
  projectName,
320
336
  template,
@@ -334,14 +350,19 @@ async function selectDeployment(template, initialValue) {
334
350
  }
335
351
  async function selectAvailable(message, options, available, initialValue) {
336
352
  for (;; ) {
337
- const answer = await p.select({ message, options, initialValue });
338
- if (p.isCancel(answer))
339
- cancelCreation();
353
+ const answer = promptValue(await p.select({ message, options, initialValue }));
340
354
  if (isOneOf(answer, available))
341
355
  return answer;
342
356
  p.log.warn("That option is planned but not available in this MVP.");
343
357
  }
344
358
  }
359
+ function promptValue(value) {
360
+ if (typeof value !== "symbol")
361
+ return value;
362
+ if (p.isCancel(value))
363
+ cancelCreation();
364
+ throw new Error("Prompt did not return a value.");
365
+ }
345
366
  function isOneOf(value, values) {
346
367
  return values.some((candidate) => candidate === value);
347
368
  }
@@ -1,3 +1,3 @@
1
- export declare function projectNameError(value: string): string | undefined;
1
+ export declare function projectNameError(value: string | undefined): string | undefined;
2
2
  export declare function assertProjectName(value: string): string;
3
3
  //# sourceMappingURL=project-name.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-name.d.ts","sourceRoot":"","sources":["../src/project-name.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIlE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD"}
1
+ {"version":3,"file":"project-name.d.ts","sourceRoot":"","sources":["../src/project-name.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAIpB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,eAAO,MAAM,uCAAuC,+IAC0F,CAAC;AAE/I,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,YAAY,CAAC,GACtD,IAAI,CAGN;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAgDlC"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,eAAO,MAAM,uCAAuC,+IAC0F,CAAC;AAE/I,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,YAAY,CAAC,GACtD,IAAI,CAGN;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAkDlC"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAWA,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAKR;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,CAAC,CASH;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAOf;AAoBD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAE1D;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAWA,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAYR;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,CAAC,CASH;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAOf;AAwCD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAE1D;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyo-sh/create-heyo-docs",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Create a standalone Heyo Docs documentation project.",
5
5
  "homepage": "https://heyo.sh",
6
6
  "repository": {
@@ -27,7 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@clack/prompts": "0.10.0"
30
+ "@clack/prompts": "1.8.0"
31
31
  },
32
32
  "scripts": {
33
33
  "dev": "bun run build --watch",
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: "Welcome"
3
+ description: "Get started with {{PROJECT_NAME}}."
4
+ ---
5
+
6
+ # Welcome
7
+
8
+ This documentation is ready for your content. Edit this page or add Markdown and MDX files in `content/`.
@@ -1,56 +1,12 @@
1
- import { heyoDocs } from "@heyo-sh/heyo-docs";
1
+ import { heyoDocs } from "@heyo-sh/heyo-docs/config";
2
2
 
3
3
  export default heyoDocs({
4
4
  title: "{{PROJECT_NAME}}",
5
5
  description: "Developer documentation",
6
- content: "./content",
7
6
  theme: "{{THEME}}",
8
- mode: "system",
9
- groups: [
10
- {
11
- group: "Documentation",
12
- icon: "globe",
13
- sections: [
14
- {
15
- section: "Get Started",
16
- icon: "lightbulb",
17
- pages: ["quickstart", "configuration", "deploying"],
18
- },
19
- {
20
- section: "Essentials",
21
- icon: "book",
22
- pages: [
23
- "essentials/text-styling",
24
- "essentials/code-blocks",
25
- "essentials/callouts",
26
- "essentials/tabs",
27
- "essentials/lists",
28
- "essentials/tables",
29
- ],
30
- },
31
- ],
32
- },
33
- {
34
- group: "OpenAPI",
35
- icon: "code",
36
- sections: [
37
- {
38
- pages: ["api-overview"],
39
- },
40
- {
41
- schema: "./openapi.json",
42
- },
43
- ],
44
- },
45
- {
46
- group: "Changelog",
47
- description: "Mock release notes for the Heyo Docs demo.",
48
- icon: "changelog",
49
- type: "changelog",
50
- updates: ["changelog"],
51
- },
52
- ],
53
7
  branding: { name: "{{PROJECT_NAME}}", logo: "/logo.svg" },
54
- // Set this before deploying to publish canonical and absolute social URLs.
8
+ // Set this before deploying to publish canonical, sitemap, and social URLs.
55
9
  // siteUrl: "https://docs.example.com",
10
+ // Add analytics, consent, and support integrations here when you need them.
11
+ // integrations: { analytics: { ga4: { measurementId: "G-..." } } },
56
12
  });
@@ -1,62 +1,21 @@
1
- import {
2
- DocsApp,
3
- openApiEndpointDataPath,
4
- type OpenApiEndpoint,
5
- } from "@heyo-sh/heyo-docs";
6
- import {
7
- createContext,
8
- forwardRef,
9
- useCallback,
10
- useContext,
11
- useEffect,
12
- useRef,
13
- useState,
14
- type ComponentPropsWithoutRef,
15
- type MouseEvent,
16
- } from "react";
1
+ import { DocsApp } from "@heyo-sh/heyo-docs";
2
+ import type { DocsLinkProps } from "@heyo-sh/heyo-docs/link";
3
+ import type { OpenApiEndpoint } from "@heyo-sh/heyo-docs/types";
4
+ import { DEFAULT_THEME_STORAGE_KEY } from "@heyo-sh/heyo-docs/theme/script";
5
+ import { ThemeProvider, useDocsTheme } from "@heyo-sh/heyo-docs/theme/provider";
6
+ import { forwardRef } from "react";
7
+ import { __HEYO_THEME_IDENTIFIER__ } from "@heyo-sh/heyo-docs/theme/__HEYO_THEME__";
17
8
 
18
9
  import { iconSet } from "../heyo-docs-icons";
19
- import { THEME_STORAGE_KEY } from "../lib/theme";
20
10
  import { config } from "virtual:heyo-docs-config";
21
11
  import { openApiEndpoints } from "virtual:heyo-docs-openapi/index";
22
12
  import { pages } from "virtual:heyo-docs-content";
23
- import { ThemeProvider, useTheme } from "./theme-provider";
24
13
 
25
- type Navigate = (href: string) => void;
26
-
27
- const AstroNavigationContext = createContext<Navigate | undefined>(undefined);
28
-
29
- const AstroLink = forwardRef<HTMLAnchorElement, ComponentPropsWithoutRef<"a">>(
30
- function AstroLink({ href, onClick, target, ...props }, ref) {
31
- const navigate = useContext(AstroNavigationContext);
32
-
33
- const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {
34
- onClick?.(event);
35
- if (
36
- !navigate ||
37
- event.defaultPrevented ||
38
- event.button !== 0 ||
39
- event.metaKey ||
40
- event.altKey ||
41
- event.ctrlKey ||
42
- event.shiftKey ||
43
- target
44
- )
45
- return;
46
-
47
- event.preventDefault();
48
- navigate(href ?? "/");
49
- };
50
-
51
- return (
52
- <a
53
- {...props}
54
- href={href}
55
- onClick={handleClick}
56
- ref={ref}
57
- target={target}
58
- />
59
- );
14
+ // Astro uses ordinary document navigation for docs links. It preserves static
15
+ // page HTML and metadata instead of maintaining a second router in React.
16
+ const AstroLink = forwardRef<HTMLAnchorElement, DocsLinkProps>(
17
+ function AstroLink(props, ref) {
18
+ return <a {...props} ref={ref} />;
60
19
  },
61
20
  );
62
21
 
@@ -68,7 +27,10 @@ export function AstroDocsApp({
68
27
  pathname: string;
69
28
  }) {
70
29
  return (
71
- <ThemeProvider defaultTheme={config.mode} storageKey={THEME_STORAGE_KEY}>
30
+ <ThemeProvider
31
+ defaultTheme={config.mode}
32
+ storageKey={DEFAULT_THEME_STORAGE_KEY}
33
+ >
72
34
  <DocsShell
73
35
  currentOpenApiEndpoint={currentOpenApiEndpoint}
74
36
  pathname={pathname}
@@ -77,10 +39,6 @@ export function AstroDocsApp({
77
39
  );
78
40
  }
79
41
 
80
- /**
81
- * Content is imported in this island instead of crossing Astro's serialisation
82
- * boundary. MDX pages are React components and must stay module references.
83
- */
84
42
  function DocsShell({
85
43
  currentOpenApiEndpoint,
86
44
  pathname,
@@ -88,78 +46,20 @@ function DocsShell({
88
46
  currentOpenApiEndpoint?: OpenApiEndpoint;
89
47
  pathname: string;
90
48
  }) {
91
- const { mounted, resolvedTheme, setTheme } = useTheme();
92
- const [activePathname, setActivePathname] = useState(pathname);
93
- const [activeOpenApiEndpoint, setActiveOpenApiEndpoint] = useState(
94
- currentOpenApiEndpoint,
95
- );
96
- const navigationId = useRef(0);
97
-
98
- const navigate = useCallback(async (href: string, updateHistory = true) => {
99
- const destination = new URL(href, window.location.href);
100
- if (destination.origin !== window.location.origin) {
101
- window.location.assign(href);
102
- return;
103
- }
104
-
105
- const nextPathname = destination.pathname;
106
- const indexedEndpoint = openApiEndpoints.find(
107
- (endpoint) => endpoint.slug === nextPathname,
108
- );
109
- const page = pages.find((candidate) => candidate.slug === nextPathname);
110
- if (!indexedEndpoint && !page) {
111
- window.location.assign(href);
112
- return;
113
- }
114
-
115
- const currentNavigation = ++navigationId.current;
116
- let endpoint: OpenApiEndpoint | undefined;
117
- if (indexedEndpoint) {
118
- const response = await fetch(
119
- openApiEndpointDataPath(indexedEndpoint.slug),
120
- );
121
- if (!response.ok) {
122
- window.location.assign(href);
123
- return;
124
- }
125
- endpoint = (await response.json()) as OpenApiEndpoint;
126
- }
127
- if (currentNavigation !== navigationId.current) return;
128
-
129
- if (updateHistory) window.history.pushState({}, "", destination);
130
- document.title =
131
- page?.seo.title ?? `${indexedEndpoint!.title} | ${config.title}`;
132
- setActiveOpenApiEndpoint(endpoint);
133
- setActivePathname(nextPathname);
134
- }, []);
135
-
136
- useEffect(() => {
137
- const onPopState = () => {
138
- void navigate(window.location.href, false);
139
- };
140
-
141
- window.addEventListener("popstate", onPopState);
142
- return () => window.removeEventListener("popstate", onPopState);
143
- }, [navigate]);
144
-
49
+ const { mounted, resolvedTheme, toggleTheme } = useDocsTheme();
145
50
  return (
146
- <AstroNavigationContext.Provider value={navigate}>
147
- <DocsApp
148
- config={config}
149
- iconSet={iconSet}
150
- isDark={mounted ? resolvedTheme === "dark" : undefined}
151
- link={AstroLink}
152
- onThemeToggle={
153
- mounted
154
- ? () => setTheme(resolvedTheme === "dark" ? "light" : "dark")
155
- : undefined
156
- }
157
- currentOpenApiEndpoint={activeOpenApiEndpoint}
158
- openApiEndpoints={openApiEndpoints}
159
- openApiRequestUrl="/heyo-docs-internal/openapi-request"
160
- pages={pages}
161
- pathname={activePathname}
162
- />
163
- </AstroNavigationContext.Provider>
51
+ <DocsApp
52
+ config={config}
53
+ currentOpenApiEndpoint={currentOpenApiEndpoint}
54
+ iconSet={iconSet}
55
+ isDark={mounted ? resolvedTheme === "dark" : undefined}
56
+ link={AstroLink}
57
+ onThemeToggle={mounted ? toggleTheme : undefined}
58
+ openApiEndpoints={openApiEndpoints}
59
+ openApiRequestUrl="/heyo-docs-internal/openapi-request"
60
+ pages={pages}
61
+ pathname={pathname}
62
+ theme={__HEYO_THEME_IDENTIFIER__}
63
+ />
164
64
  );
165
65
  }
@@ -24,13 +24,14 @@ import {
24
24
  RiInformationLine,
25
25
  RiLightbulbLine,
26
26
  RiLoginBoxLine,
27
+ RiMenuLine,
27
28
  RiMoonLine,
28
29
  RiNewsLine,
29
30
  RiSearchLine,
30
31
  RiStarLine,
31
32
  RiSunLine,
32
33
  } from "@remixicon/react";
33
- import type { IconSet } from "@heyo-sh/heyo-docs";
34
+ import type { IconSet } from "@heyo-sh/heyo-docs/types";
34
35
 
35
36
  /**
36
37
  * This mapping is intentionally local to the generated application. Replace
@@ -51,6 +52,7 @@ const remixIconSet = {
51
52
  arrowRight: RiArrowRightLine,
52
53
  close: RiCloseLine,
53
54
  cornerDownLeft: RiCornerDownLeftLine,
55
+ menu: RiMenuLine,
54
56
  search: RiSearchLine,
55
57
  sun: RiSunLine,
56
58
  moon: RiMoonLine,