@heyo-sh/create-heyo-docs 1.0.1 → 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 (118) hide show
  1. package/deployments/cloudflare/astro/package.json +2 -1
  2. package/deployments/cloudflare/astro/src/env.d.ts +4 -1
  3. package/deployments/cloudflare/astro/src/pages/heyo-docs-internal/ai-chat.ts +9 -7
  4. package/deployments/cloudflare/next/app/heyo-docs-internal/ai-chat/route.ts +9 -7
  5. package/deployments/cloudflare/next/cloudflare-env.d.ts +4 -1
  6. package/deployments/cloudflare/react-router/app/cloudflare-env.d.ts +4 -1
  7. package/deployments/cloudflare/react-router/app/routes/ai-chat.ts +9 -8
  8. package/deployments/cloudflare/react-router/package.json +2 -1
  9. package/deployments/vercel/astro/package.json +1 -0
  10. package/dist/index.js +24 -4
  11. package/dist/scaffold.d.ts.map +1 -1
  12. package/dist/utils.d.ts.map +1 -1
  13. package/package.json +1 -1
  14. package/templates/astro/content/index.mdx +8 -0
  15. package/templates/astro/heyo-docs.config.ts +4 -48
  16. package/templates/astro/src/components/docs-app.tsx +30 -130
  17. package/templates/astro/src/heyo-docs-icons.tsx +3 -1
  18. package/templates/astro/src/layouts/docs-layout.astro +10 -436
  19. package/templates/astro/src/lib/docs.ts +3 -2
  20. package/templates/astro/src/lib/openapi-request.ts +6 -146
  21. package/templates/astro/src/pages/[...slug].astro +7 -15
  22. package/templates/astro/src/pages/[...slug].md.ts +4 -1
  23. package/templates/astro/src/pages/heyo-docs-internal/ai-chat.ts +5 -7
  24. package/templates/astro/src/pages/heyo-docs-internal/openapi-request.ts +6 -0
  25. package/templates/astro/src/pages/index.astro +18 -9
  26. package/templates/astro/src/pages/llms-full.txt.ts +1 -1
  27. package/templates/astro/src/pages/llms.txt.ts +1 -1
  28. package/templates/astro/src/pages/rss.xml.ts +1 -1
  29. package/templates/astro/src/pages/sitemap.xml.ts +2 -2
  30. package/templates/astro/src/virtual.d.ts +5 -5
  31. package/templates/next/app/[[...slug]]/page.tsx +10 -9
  32. package/templates/next/app/components/docs-app.tsx +28 -120
  33. package/templates/next/app/heyo-docs-icons.tsx +1 -1
  34. package/templates/next/app/heyo-docs-internal/ai-chat/route.ts +6 -7
  35. package/templates/next/app/heyo-docs-internal/markdown/[[...slug]]/route.ts +1 -1
  36. package/templates/next/app/layout.tsx +25 -444
  37. package/templates/next/app/lib/docs.ts +3 -3
  38. package/templates/next/app/lib/openapi-request.ts +4 -136
  39. package/templates/next/app/llms-full.txt/route.ts +1 -1
  40. package/templates/next/app/llms.txt/route.ts +1 -1
  41. package/templates/next/app/rss.xml/route.ts +1 -1
  42. package/templates/next/app/sitemap.xml/route.ts +1 -1
  43. package/templates/next/content/index.mdx +8 -0
  44. package/templates/next/heyo-docs.config.ts +3 -47
  45. package/templates/next/next.config.ts +7 -1
  46. package/templates/react-router/app/heyo-docs-icons.tsx +3 -1
  47. package/templates/react-router/app/root.tsx +28 -465
  48. package/templates/react-router/app/routes/ai-chat.ts +4 -8
  49. package/templates/react-router/app/routes/docs.tsx +22 -63
  50. package/templates/react-router/app/routes/home.tsx +6 -1
  51. package/templates/react-router/app/routes/llms-full.ts +1 -1
  52. package/templates/react-router/app/routes/llms.ts +1 -1
  53. package/templates/react-router/app/routes/markdown.ts +4 -1
  54. package/templates/react-router/app/routes/openapi-request.ts +11 -144
  55. package/templates/react-router/app/routes/rss.ts +1 -1
  56. package/templates/react-router/app/routes/sitemap.ts +5 -8
  57. package/templates/react-router/app/virtual.d.ts +5 -5
  58. package/templates/react-router/content/index.mdx +8 -0
  59. package/templates/react-router/heyo-docs.config.ts +4 -48
  60. package/templates/astro/content/api-overview.mdx +0 -20
  61. package/templates/astro/content/assets/local-architecture.svg +0 -22
  62. package/templates/astro/content/assets/quick-reference.txt +0 -5
  63. package/templates/astro/content/changelog.mdx +0 -38
  64. package/templates/astro/content/configuration.mdx +0 -117
  65. package/templates/astro/content/deploying.mdx +0 -70
  66. package/templates/astro/content/essentials/callouts.mdx +0 -34
  67. package/templates/astro/content/essentials/code-blocks.mdx +0 -43
  68. package/templates/astro/content/essentials/lists.mdx +0 -36
  69. package/templates/astro/content/essentials/tables.mdx +0 -30
  70. package/templates/astro/content/essentials/tabs.mdx +0 -40
  71. package/templates/astro/content/essentials/text-styling.mdx +0 -43
  72. package/templates/astro/content/getting-started.mdx +0 -16
  73. package/templates/astro/content/mdx-components.mdx +0 -44
  74. package/templates/astro/content/openapi-petstore.json +0 -160
  75. package/templates/astro/content/openapi.json +0 -278
  76. package/templates/astro/content/quickstart.mdx +0 -60
  77. package/templates/astro/src/components/theme-provider.tsx +0 -106
  78. package/templates/astro/src/lib/seo.ts +0 -221
  79. package/templates/astro/src/lib/theme.ts +0 -74
  80. package/templates/next/app/components/theme-provider.tsx +0 -93
  81. package/templates/next/app/lib/seo.ts +0 -189
  82. package/templates/next/app/lib/theme.ts +0 -61
  83. package/templates/next/content/api-overview.mdx +0 -20
  84. package/templates/next/content/assets/local-architecture.svg +0 -22
  85. package/templates/next/content/assets/quick-reference.txt +0 -5
  86. package/templates/next/content/changelog.mdx +0 -38
  87. package/templates/next/content/configuration.mdx +0 -117
  88. package/templates/next/content/deploying.mdx +0 -70
  89. package/templates/next/content/essentials/callouts.mdx +0 -34
  90. package/templates/next/content/essentials/code-blocks.mdx +0 -43
  91. package/templates/next/content/essentials/lists.mdx +0 -36
  92. package/templates/next/content/essentials/tables.mdx +0 -30
  93. package/templates/next/content/essentials/tabs.mdx +0 -40
  94. package/templates/next/content/essentials/text-styling.mdx +0 -43
  95. package/templates/next/content/getting-started.mdx +0 -16
  96. package/templates/next/content/mdx-components.mdx +0 -41
  97. package/templates/next/content/openapi-petstore.json +0 -160
  98. package/templates/next/content/openapi.json +0 -278
  99. package/templates/next/content/quickstart.mdx +0 -60
  100. package/templates/react-router/app/components/theme-provider.tsx +0 -106
  101. package/templates/react-router/app/lib/theme.ts +0 -74
  102. package/templates/react-router/content/api-overview.mdx +0 -20
  103. package/templates/react-router/content/assets/local-architecture.svg +0 -22
  104. package/templates/react-router/content/assets/quick-reference.txt +0 -5
  105. package/templates/react-router/content/changelog.mdx +0 -38
  106. package/templates/react-router/content/configuration.mdx +0 -117
  107. package/templates/react-router/content/deploying.mdx +0 -70
  108. package/templates/react-router/content/essentials/callouts.mdx +0 -34
  109. package/templates/react-router/content/essentials/code-blocks.mdx +0 -43
  110. package/templates/react-router/content/essentials/lists.mdx +0 -36
  111. package/templates/react-router/content/essentials/tables.mdx +0 -30
  112. package/templates/react-router/content/essentials/tabs.mdx +0 -40
  113. package/templates/react-router/content/essentials/text-styling.mdx +0 -43
  114. package/templates/react-router/content/getting-started.mdx +0 -16
  115. package/templates/react-router/content/mdx-components.mdx +0 -293
  116. package/templates/react-router/content/openapi-petstore.json +0 -160
  117. package/templates/react-router/content/openapi.json +0 -278
  118. 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"
@@ -1,5 +1,8 @@
1
1
  declare namespace Cloudflare {
2
2
  interface Env {
3
- OPENAI_API_KEY: string;
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;
4
7
  }
5
8
  }
@@ -1,4 +1,3 @@
1
- import { createAiChatResponse } from "@heyo-sh/heyo-docs/ai";
2
1
  import type { APIRoute } from "astro";
3
2
  import { env } from "cloudflare:workers";
4
3
 
@@ -7,17 +6,20 @@ import { pages as markdownPages } from "virtual:heyo-docs-content/server";
7
6
 
8
7
  export const prerender = false;
9
8
 
10
- export const POST: APIRoute = ({ request }) => {
11
- const apiKey = env.OPENAI_API_KEY;
12
- if (!apiKey)
9
+ export const POST: APIRoute = async ({ request }) => {
10
+ if (!config.ai?.chat)
13
11
  return Response.json(
14
- { error: "The OPENAI_API_KEY Worker secret is not configured." },
15
- { status: 500 },
12
+ { error: "AI chat is not configured." },
13
+ { status: 404 },
16
14
  );
17
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
18
  return createAiChatResponse(request, {
19
19
  ai: config.ai,
20
- auth: { type: "api-key", token: apiKey },
20
+ ...(config.ai?.chat.auth || !token
21
+ ? {}
22
+ : { auth: { type: "api-key" as const, token } }),
21
23
  markdownPages,
22
24
  pages: markdownPages.map((page) => ({
23
25
  description: page.description,
@@ -1,4 +1,3 @@
1
- import { createAiChatResponse } from "@heyo-sh/heyo-docs/ai";
2
1
  import { getCloudflareContext } from "@opennextjs/cloudflare";
3
2
 
4
3
  import config from "../../../heyo-docs.config";
@@ -7,17 +6,20 @@ import { docsPages, markdownPages } from "../../_heyo-docs/server";
7
6
  export const runtime = "nodejs";
8
7
 
9
8
  export async function POST(request: Request) {
10
- const { env } = getCloudflareContext();
11
- const apiKey = env.OPENAI_API_KEY;
12
- if (!apiKey)
9
+ if (!config.ai?.chat)
13
10
  return Response.json(
14
- { error: "The OPENAI_API_KEY Worker secret is not configured." },
15
- { status: 500 },
11
+ { error: "AI chat is not configured." },
12
+ { status: 404 },
16
13
  );
17
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
18
  return createAiChatResponse(request, {
19
19
  ai: config.ai,
20
- auth: { type: "api-key", token: apiKey },
20
+ ...(config.ai?.chat.auth || !token
21
+ ? {}
22
+ : { auth: { type: "api-key" as const, token } }),
21
23
  markdownPages,
22
24
  pages: docsPages,
23
25
  title: config.title,
@@ -1,4 +1,7 @@
1
1
  /** Cloudflare Worker secret configured with `wrangler secret put`. */
2
2
  interface CloudflareEnv {
3
- OPENAI_API_KEY: string;
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;
4
7
  }
@@ -1,4 +1,7 @@
1
1
  /** Cloudflare Worker secret configured with `wrangler secret put`. */
2
2
  interface Env {
3
- OPENAI_API_KEY: string;
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;
4
7
  }
@@ -8,21 +8,22 @@ import { pages as markdownPages } from "virtual:heyo-docs-content/server";
8
8
  export async function action({ context, request }: ActionFunctionArgs) {
9
9
  if (request.method !== "POST")
10
10
  return new Response("Method Not Allowed", {
11
- headers: { Allow: "POST" },
12
11
  status: 405,
12
+ headers: { Allow: "POST" },
13
13
  });
14
-
15
- const apiKey = context.get(cloudflareContext).OPENAI_API_KEY;
16
- if (!apiKey)
14
+ if (!config.ai?.chat)
17
15
  return Response.json(
18
- { error: "The OPENAI_API_KEY Worker secret is not configured." },
19
- { status: 500 },
16
+ { error: "AI chat is not configured." },
17
+ { status: 404 },
20
18
  );
21
-
19
+ const bindings = context.get(cloudflareContext);
20
+ const token = bindings.HEYO_DOCS_AI_API_KEY ?? bindings.OPENAI_API_KEY;
22
21
  const { createAiChatResponse } = await import("@heyo-sh/heyo-docs/ai");
23
22
  return createAiChatResponse(request, {
24
23
  ai: config.ai,
25
- auth: { type: "api-key", token: apiKey },
24
+ ...(config.ai?.chat.auth || !token
25
+ ? {}
26
+ : { auth: { type: "api-key" as const, token } }),
26
27
  markdownPages,
27
28
  pages,
28
29
  title: config.title,
@@ -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,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
@@ -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);
@@ -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.1",
3
+ "version": "2.0.0",
4
4
  "description": "Create a standalone Heyo Docs documentation project.",
5
5
  "homepage": "https://heyo.sh",
6
6
  "repository": {
@@ -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,