doccupine 0.0.108 → 0.0.110

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 (58) hide show
  1. package/dist/templates/components/SideBar.d.ts +1 -1
  2. package/dist/templates/components/SideBar.js +45 -3
  3. package/dist/templates/components/layout/DocsComponents.d.ts +1 -1
  4. package/dist/templates/components/layout/DocsComponents.js +2 -1
  5. package/dist/templates/mdx/accordion.mdx.d.ts +1 -1
  6. package/dist/templates/mdx/accordion.mdx.js +19 -21
  7. package/dist/templates/mdx/ai-assistant.mdx.d.ts +1 -1
  8. package/dist/templates/mdx/ai-assistant.mdx.js +8 -0
  9. package/dist/templates/mdx/analytics.mdx.d.ts +1 -1
  10. package/dist/templates/mdx/analytics.mdx.js +1 -1
  11. package/dist/templates/mdx/buttons.mdx.d.ts +1 -1
  12. package/dist/templates/mdx/buttons.mdx.js +6 -6
  13. package/dist/templates/mdx/callouts.mdx.d.ts +1 -1
  14. package/dist/templates/mdx/callouts.mdx.js +1 -9
  15. package/dist/templates/mdx/cards.mdx.d.ts +1 -1
  16. package/dist/templates/mdx/cards.mdx.js +2 -2
  17. package/dist/templates/mdx/code.mdx.d.ts +1 -1
  18. package/dist/templates/mdx/code.mdx.js +8 -8
  19. package/dist/templates/mdx/color-swatches.mdx.d.ts +1 -1
  20. package/dist/templates/mdx/color-swatches.mdx.js +2 -2
  21. package/dist/templates/mdx/columns.mdx.d.ts +1 -1
  22. package/dist/templates/mdx/columns.mdx.js +1 -3
  23. package/dist/templates/mdx/deployment-and-hosting.mdx.d.ts +1 -1
  24. package/dist/templates/mdx/deployment-and-hosting.mdx.js +2 -2
  25. package/dist/templates/mdx/fields.mdx.d.ts +1 -1
  26. package/dist/templates/mdx/fields.mdx.js +1 -1
  27. package/dist/templates/mdx/fonts.mdx.d.ts +1 -1
  28. package/dist/templates/mdx/fonts.mdx.js +1 -1
  29. package/dist/templates/mdx/footer-links.mdx.d.ts +1 -1
  30. package/dist/templates/mdx/footer-links.mdx.js +1 -1
  31. package/dist/templates/mdx/globals.mdx.d.ts +1 -1
  32. package/dist/templates/mdx/globals.mdx.js +1 -1
  33. package/dist/templates/mdx/icons.mdx.d.ts +1 -1
  34. package/dist/templates/mdx/icons.mdx.js +2 -2
  35. package/dist/templates/mdx/index.mdx.d.ts +1 -1
  36. package/dist/templates/mdx/index.mdx.js +1 -1
  37. package/dist/templates/mdx/media-and-assets.mdx.d.ts +1 -1
  38. package/dist/templates/mdx/media-and-assets.mdx.js +4 -4
  39. package/dist/templates/mdx/navigation.mdx.d.ts +1 -1
  40. package/dist/templates/mdx/navigation.mdx.js +1 -1
  41. package/dist/templates/mdx/platform/file-editor.mdx.d.ts +1 -1
  42. package/dist/templates/mdx/platform/file-editor.mdx.js +2 -2
  43. package/dist/templates/mdx/sections.mdx.d.ts +1 -1
  44. package/dist/templates/mdx/sections.mdx.js +1 -1
  45. package/dist/templates/mdx/steps.mdx.d.ts +1 -1
  46. package/dist/templates/mdx/steps.mdx.js +4 -8
  47. package/dist/templates/mdx/tabs.mdx.d.ts +1 -1
  48. package/dist/templates/mdx/tabs.mdx.js +8 -10
  49. package/dist/templates/mdx/theme.mdx.d.ts +1 -1
  50. package/dist/templates/mdx/theme.mdx.js +1 -1
  51. package/dist/templates/mdx/update.mdx.d.ts +1 -1
  52. package/dist/templates/mdx/update.mdx.js +13 -15
  53. package/dist/templates/package.js +2 -2
  54. package/dist/templates/prettierignore.d.ts +1 -1
  55. package/dist/templates/prettierignore.js +1 -0
  56. package/dist/templates/services/search.d.ts +1 -1
  57. package/dist/templates/services/search.js +28 -2
  58. package/package.json +3 -3
@@ -1 +1 @@
1
- export declare const themeMdxTemplate = "---\ntitle: \"Theme\"\ndescription: \"Customize the documentation UI colors with a theme.json file.\"\ndate: \"2026-02-19\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 5\n---\n\n# Theme\n\nDefine your site\u2019s color system with a `theme.json` file. This lets you tailor the look and feel of your documentation without changing content.\n\n## theme.json\n\nPlace a `theme.json` at your project root (the same folder where you execute `npx doccupine`). It supports multiple modes. Define a `default` mode and a `dark` mode.\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#93c5fd\",\n \"primary\": \"#2563eb\",\n \"primaryDark\": \"#1e40af\",\n \"secondaryLight\": \"#c4b5fd\",\n \"secondary\": \"#8b5cf6\",\n \"secondaryDark\": \"#5b21b6\",\n \"tertiaryLight\": \"#fbbf24\",\n \"tertiary\": \"#f59e0b\",\n \"tertiaryDark\": \"#d97706\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#9bcaff\",\n \"primary\": \"#1e7ae0\",\n \"primaryDark\": \"#033d7e\",\n \"secondaryLight\": \"#ddd6fe\",\n \"secondary\": \"#a78bfa\",\n \"secondaryDark\": \"#7c3aed\",\n \"tertiaryLight\": \"#fed7aa\",\n \"tertiary\": \"#fb923c\",\n \"tertiaryDark\": \"#ea580c\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n },\n \"logo\": {\n \"dark\": \"https://docs.doccupine.com/logo-dark.svg\",\n \"light\": \"https://docs.doccupine.com/logo-light.svg\"\n }\n}\n```\n\n## Modes\n\n- **default**: The base color palette for your site.\n- **dark**: Dark\u2011mode palette.\n\n## Fields\n\n- **primaryLight**: A lighter variant of your brand color, used for subtle accents and backgrounds.\n- **primary**: The main brand color.\n- **primaryDark**: A darker variant of your brand color for emphasis and hover states.\n- **secondaryLight**: A lighter variant of your secondary color, used for subtle accents and backgrounds.\n- **secondary**: The secondary brand color used for highlights and UI accents.\n- **secondaryDark**: A darker variant of your secondary color for emphasis and hover states.\n- **tertiaryLight**: A lighter variant of your tertiary color, used for subtle accents and backgrounds.\n- **tertiary**: The tertiary accent color.\n- **tertiaryDark**: A darker variant of your tertiary color for emphasis and hover states.\n- **grayLight**: Light gray for surfaces and borders.\n- **gray**: Neutral gray for text and UI elements.\n- **grayDark**: Dark gray for headings or high\u2011contrast text.\n- **success**: Positive/confirmation color.\n- **error**: Error/destructive color.\n- **warning**: Warning/attention color.\n- **info**: Informational/highlight color.\n- **dark**: The darkest/base color (often page background in dark mode).\n- **light**: The lightest/base color (often page background in light mode).\n- **logo.light**: Path or URL to the logo used on light backgrounds. Recommended size: 164\u00D730 px.\n- **logo.dark**: Path or URL to the logo used on dark backgrounds. Recommended size: 164\u00D730 px.\n\n## Behavior\n\n- **Placement**: Put `theme.json` in the project root alongside `config.json`.\n- **Partial palettes**: If a key is missing in a mode, consumers may fall back to the `default` value.\n- **Logo size**: Recommended dimensions are 164px width and 30px height.\n\n<Callout type=\"warning\">\n Use valid hex colors (e.g., `#22c55e`). Invalid color values may cause unexpected rendering.\n</Callout>\n\n## Tips\n\n- **Contrast**: Ensure sufficient contrast between text and backgrounds for readability.\n- **Branding**: Start with your brand\u2019s `primary` color, then derive `primaryLight` and `primaryDark`.\n- **Iterate**: Adjust colors and refresh the site to preview changes quickly.\n\n# Demo\n\nIn the following demos, you can see how the theme can be changed. To override the theme, create a `theme.json` file in the project root and copy paste the code below.\n\n<DemoTheme variant=\"purple\" />\n<DemoTheme variant=\"green\" />\n<DemoTheme variant=\"yellow\" />\n<DemoTheme />\n\n## Purple\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#c4b5fd\",\n \"primary\": \"#8b5cf6\",\n \"primaryDark\": \"#5b21b6\",\n \"secondaryLight\": \"#86efac\",\n \"secondary\": \"#22c55e\",\n \"secondaryDark\": \"#15803d\",\n \"tertiaryLight\": \"#fbbf24\",\n \"tertiary\": \"#f59e0b\",\n \"tertiaryDark\": \"#d97706\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#ddd6fe\",\n \"primary\": \"#a78bfa\",\n \"primaryDark\": \"#7c3aed\",\n \"secondaryLight\": \"#6ee7b7\",\n \"secondary\": \"#10b981\",\n \"secondaryDark\": \"#065f46\",\n \"tertiaryLight\": \"#fed7aa\",\n \"tertiary\": \"#fb923c\",\n \"tertiaryDark\": \"#ea580c\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n }\n}\n```\n\n<DemoTheme variant=\"purple\" />\n\n## Green\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#86efac\",\n \"primary\": \"#22c55e\",\n \"primaryDark\": \"#15803d\",\n \"secondaryLight\": \"#c4b5fd\",\n \"secondary\": \"#8b5cf6\",\n \"secondaryDark\": \"#5b21b6\",\n \"tertiaryLight\": \"#fbbf24\",\n \"tertiary\": \"#f59e0b\",\n \"tertiaryDark\": \"#d97706\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#6ee7b7\",\n \"primary\": \"#10b981\",\n \"primaryDark\": \"#065f46\",\n \"secondaryLight\": \"#ddd6fe\",\n \"secondary\": \"#a78bfa\",\n \"secondaryDark\": \"#7c3aed\",\n \"tertiaryLight\": \"#fed7aa\",\n \"tertiary\": \"#fb923c\",\n \"tertiaryDark\": \"#ea580c\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n }\n}\n```\n\n<DemoTheme variant=\"green\" />\n\n## Yellow\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#fbbf24\",\n \"primary\": \"#f59e0b\",\n \"primaryDark\": \"#d97706\",\n \"secondaryLight\": \"#c4b5fd\",\n \"secondary\": \"#8b5cf6\",\n \"secondaryDark\": \"#5b21b6\",\n \"tertiaryLight\": \"#86efac\",\n \"tertiary\": \"#22c55e\",\n \"tertiaryDark\": \"#15803d\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#fed7aa\",\n \"primary\": \"#fb923c\",\n \"primaryDark\": \"#ea580c\",\n \"secondaryLight\": \"#ddd6fe\",\n \"secondary\": \"#a78bfa\",\n \"secondaryDark\": \"#7c3aed\",\n \"tertiaryLight\": \"#6ee7b7\",\n \"tertiary\": \"#10b981\",\n \"tertiaryDark\": \"#065f46\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n }\n}\n```\n\n<DemoTheme variant=\"yellow\" />";
1
+ export declare const themeMdxTemplate = "---\ntitle: \"Theme\"\ndescription: \"Customize the documentation UI colors with a theme.json file.\"\ndate: \"2026-02-19\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 5\n---\n\n# Theme\n\nDefine your site\u2019s color system with a `theme.json` file. This lets you tailor the look and feel of your documentation without changing content.\n\n## theme.json\n\nPlace a `theme.json` at your project root (the same directory where you execute `npx doccupine`). It supports multiple modes. Define a `default` mode and a `dark` mode.\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#93c5fd\",\n \"primary\": \"#2563eb\",\n \"primaryDark\": \"#1e40af\",\n \"secondaryLight\": \"#c4b5fd\",\n \"secondary\": \"#8b5cf6\",\n \"secondaryDark\": \"#5b21b6\",\n \"tertiaryLight\": \"#fbbf24\",\n \"tertiary\": \"#f59e0b\",\n \"tertiaryDark\": \"#d97706\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#9bcaff\",\n \"primary\": \"#1e7ae0\",\n \"primaryDark\": \"#033d7e\",\n \"secondaryLight\": \"#ddd6fe\",\n \"secondary\": \"#a78bfa\",\n \"secondaryDark\": \"#7c3aed\",\n \"tertiaryLight\": \"#fed7aa\",\n \"tertiary\": \"#fb923c\",\n \"tertiaryDark\": \"#ea580c\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n },\n \"logo\": {\n \"dark\": \"https://docs.doccupine.com/logo-dark.svg\",\n \"light\": \"https://docs.doccupine.com/logo-light.svg\"\n }\n}\n```\n\n## Modes\n\n- **default**: The base color palette for your site.\n- **dark**: Dark\u2011mode palette.\n\n## Fields\n\n- **primaryLight**: A lighter variant of your brand color, used for subtle accents and backgrounds.\n- **primary**: The main brand color.\n- **primaryDark**: A darker variant of your brand color for emphasis and hover states.\n- **secondaryLight**: A lighter variant of your secondary color, used for subtle accents and backgrounds.\n- **secondary**: The secondary brand color used for highlights and UI accents.\n- **secondaryDark**: A darker variant of your secondary color for emphasis and hover states.\n- **tertiaryLight**: A lighter variant of your tertiary color, used for subtle accents and backgrounds.\n- **tertiary**: The tertiary accent color.\n- **tertiaryDark**: A darker variant of your tertiary color for emphasis and hover states.\n- **grayLight**: Light gray for surfaces and borders.\n- **gray**: Neutral gray for text and UI elements.\n- **grayDark**: Dark gray for headings or high\u2011contrast text.\n- **success**: Positive/confirmation color.\n- **error**: Error/destructive color.\n- **warning**: Warning/attention color.\n- **info**: Informational/highlight color.\n- **dark**: The darkest/base color (often page background in dark mode).\n- **light**: The lightest/base color (often page background in light mode).\n- **logo.light**: Path or URL to the logo used on light backgrounds. Recommended size: 164\u00D730 px.\n- **logo.dark**: Path or URL to the logo used on dark backgrounds. Recommended size: 164\u00D730 px.\n\n## Behavior\n\n- **Placement**: Put `theme.json` in the project root alongside `config.json`.\n- **Partial palettes**: If a key is missing in a mode, consumers may fall back to the `default` value.\n- **Logo size**: Recommended dimensions are 164px width and 30px height.\n\n<Callout type=\"warning\">\n Use valid hex colors (e.g., `#22c55e`). Invalid color values may cause unexpected rendering.\n</Callout>\n\n## Tips\n\n- **Contrast**: Ensure sufficient contrast between text and backgrounds for readability.\n- **Branding**: Start with your brand\u2019s `primary` color, then derive `primaryLight` and `primaryDark`.\n- **Iterate**: Adjust colors and refresh the site to preview changes quickly.\n\n# Demo\n\nIn the following demos, you can see how the theme can be changed. To override the theme, create a `theme.json` file in the project root and copy paste the code below.\n\n<DemoTheme variant=\"purple\" />\n<DemoTheme variant=\"green\" />\n<DemoTheme variant=\"yellow\" />\n<DemoTheme />\n\n## Purple\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#c4b5fd\",\n \"primary\": \"#8b5cf6\",\n \"primaryDark\": \"#5b21b6\",\n \"secondaryLight\": \"#86efac\",\n \"secondary\": \"#22c55e\",\n \"secondaryDark\": \"#15803d\",\n \"tertiaryLight\": \"#fbbf24\",\n \"tertiary\": \"#f59e0b\",\n \"tertiaryDark\": \"#d97706\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#ddd6fe\",\n \"primary\": \"#a78bfa\",\n \"primaryDark\": \"#7c3aed\",\n \"secondaryLight\": \"#6ee7b7\",\n \"secondary\": \"#10b981\",\n \"secondaryDark\": \"#065f46\",\n \"tertiaryLight\": \"#fed7aa\",\n \"tertiary\": \"#fb923c\",\n \"tertiaryDark\": \"#ea580c\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n }\n}\n```\n\n<DemoTheme variant=\"purple\" />\n\n## Green\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#86efac\",\n \"primary\": \"#22c55e\",\n \"primaryDark\": \"#15803d\",\n \"secondaryLight\": \"#c4b5fd\",\n \"secondary\": \"#8b5cf6\",\n \"secondaryDark\": \"#5b21b6\",\n \"tertiaryLight\": \"#fbbf24\",\n \"tertiary\": \"#f59e0b\",\n \"tertiaryDark\": \"#d97706\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#6ee7b7\",\n \"primary\": \"#10b981\",\n \"primaryDark\": \"#065f46\",\n \"secondaryLight\": \"#ddd6fe\",\n \"secondary\": \"#a78bfa\",\n \"secondaryDark\": \"#7c3aed\",\n \"tertiaryLight\": \"#fed7aa\",\n \"tertiary\": \"#fb923c\",\n \"tertiaryDark\": \"#ea580c\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n }\n}\n```\n\n<DemoTheme variant=\"green\" />\n\n## Yellow\n\n```json\n{\n \"default\": {\n \"primaryLight\": \"#fbbf24\",\n \"primary\": \"#f59e0b\",\n \"primaryDark\": \"#d97706\",\n \"secondaryLight\": \"#c4b5fd\",\n \"secondary\": \"#8b5cf6\",\n \"secondaryDark\": \"#5b21b6\",\n \"tertiaryLight\": \"#86efac\",\n \"tertiary\": \"#22c55e\",\n \"tertiaryDark\": \"#15803d\",\n \"grayLight\": \"#f3f4f6\",\n \"gray\": \"#9ca3af\",\n \"grayDark\": \"#374151\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#000000\",\n \"light\": \"#ffffff\"\n },\n \"dark\": {\n \"primaryLight\": \"#fed7aa\",\n \"primary\": \"#fb923c\",\n \"primaryDark\": \"#ea580c\",\n \"secondaryLight\": \"#ddd6fe\",\n \"secondary\": \"#a78bfa\",\n \"secondaryDark\": \"#7c3aed\",\n \"tertiaryLight\": \"#6ee7b7\",\n \"tertiary\": \"#10b981\",\n \"tertiaryDark\": \"#065f46\",\n \"grayLight\": \"#1f2937\",\n \"gray\": \"#6b7280\",\n \"grayDark\": \"#9ca3af\",\n \"success\": \"#10b981\",\n \"error\": \"#f43f5e\",\n \"warning\": \"#f59e0b\",\n \"info\": \"#3b82f6\",\n \"dark\": \"#ffffff\",\n \"light\": \"#000000\"\n }\n}\n```\n\n<DemoTheme variant=\"yellow\" />";
@@ -13,7 +13,7 @@ Define your site’s color system with a \`theme.json\` file. This lets you tail
13
13
 
14
14
  ## theme.json
15
15
 
16
- Place a \`theme.json\` at your project root (the same folder where you execute \`npx doccupine\`). It supports multiple modes. Define a \`default\` mode and a \`dark\` mode.
16
+ Place a \`theme.json\` at your project root (the same directory where you execute \`npx doccupine\`). It supports multiple modes. Define a \`default\` mode and a \`dark\` mode.
17
17
 
18
18
  \`\`\`json
19
19
  {
@@ -1 +1 @@
1
- export declare const updateMdxTemplate = "---\ntitle: \"Update\"\ndescription: \"Easily manage and present change history.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 12\n---\n\n# Update\n\nEasily manage and present change history.\n\nThe `Update` component helps you display release notes, version details, and changelogs in a standardized format.\n\nEach `Update` label is added to the \"On this page\" sidebar and gets its own anchor, so you can link directly to a specific entry.\n\n<Update label=\"v0.0.1\" description=\"Example\">\n ## Example entry\n\nYou can include anything here - images, code snippets, or a bullet list of modifications.\n\n![Demo Image](https://docs.doccupine.com/demo.png)\n\n### Key additions\n\n- Fully responsive layout\n- Individual anchor for each update\n- Automatic RSS feed entry generation\n\n</Update>\n\n## Update Usage\n\nYou can combine multiple `Update` components to build complete changelogs.\n\n```mdx\n<Update label=\"v0.0.1\" description=\"Example\">\n ## Example entry\n\nYou can include anything here - images, code snippets, or a bullet list of modifications.\n\n![Demo Image](https://docs.doccupine.com/demo.png)\n\n### Key additions\n\n- Fully responsive layout\n- Individual anchor for each update\n- Automatic RSS feed entry generation\n\n</Update>\n```\n\n## Properties\n\n<Field value=\"label\" type=\"string\" required>\n The label of the update. It also appears in the page's \"On this page\"\n navigation and acts as a deep-link anchor to this entry.\n</Field>\n\n<Field value=\"description\" type=\"string\" required>\n The description of the update.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the update.\n</Field>";
1
+ export declare const updateMdxTemplate = "---\ntitle: \"Update\"\ndescription: \"Easily manage and present change history.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 12\n---\n\n# Update\n\nEasily manage and present change history.\n\nThe `Update` component helps you display release notes, version details, and changelogs in a standardized format.\n\nEach `Update` label is added to the \"On this page\" sidebar and gets its own anchor, so you can link directly to a specific entry.\n\n<Update label=\"v0.0.1\" description=\"Example\">\n ## Example entry\n\n You can include anything here - images, code snippets, or a bullet list of modifications.\n\n ![Demo Image](https://docs.doccupine.com/demo.png)\n\n ### Key additions\n\n - Fully responsive layout\n - Individual anchor for each update\n - Automatic RSS feed entry generation\n</Update>\n\n## Update Usage\n\nYou can combine multiple `Update` components to build complete changelogs.\n\n```html\n<Update label=\"v0.0.1\" description=\"Example\">\n ## Example entry\n\n You can include anything here - images, code snippets, or a bullet list of modifications.\n\n ![Demo Image](https://docs.doccupine.com/demo.png)\n\n ### Key additions\n\n - Fully responsive layout\n - Individual anchor for each update\n - Automatic RSS feed entry generation\n</Update>\n```\n\n## Properties\n\n<Field value=\"label\" type=\"string\" required>\n The label of the update. It also appears in the page's \"On this page\"\n navigation and acts as a deep-link anchor to this entry.\n</Field>\n\n<Field value=\"description\" type=\"string\" required>\n The description of the update.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the update.\n</Field>";
@@ -18,36 +18,34 @@ Each \`Update\` label is added to the "On this page" sidebar and gets its own an
18
18
  <Update label="v0.0.1" description="Example">
19
19
  ## Example entry
20
20
 
21
- You can include anything here - images, code snippets, or a bullet list of modifications.
21
+ You can include anything here - images, code snippets, or a bullet list of modifications.
22
22
 
23
- ![Demo Image](https://docs.doccupine.com/demo.png)
23
+ ![Demo Image](https://docs.doccupine.com/demo.png)
24
24
 
25
- ### Key additions
26
-
27
- - Fully responsive layout
28
- - Individual anchor for each update
29
- - Automatic RSS feed entry generation
25
+ ### Key additions
30
26
 
27
+ - Fully responsive layout
28
+ - Individual anchor for each update
29
+ - Automatic RSS feed entry generation
31
30
  </Update>
32
31
 
33
32
  ## Update Usage
34
33
 
35
34
  You can combine multiple \`Update\` components to build complete changelogs.
36
35
 
37
- \`\`\`mdx
36
+ \`\`\`html
38
37
  <Update label="v0.0.1" description="Example">
39
38
  ## Example entry
40
39
 
41
- You can include anything here - images, code snippets, or a bullet list of modifications.
42
-
43
- ![Demo Image](https://docs.doccupine.com/demo.png)
40
+ You can include anything here - images, code snippets, or a bullet list of modifications.
44
41
 
45
- ### Key additions
42
+ ![Demo Image](https://docs.doccupine.com/demo.png)
46
43
 
47
- - Fully responsive layout
48
- - Individual anchor for each update
49
- - Automatic RSS feed entry generation
44
+ ### Key additions
50
45
 
46
+ - Fully responsive layout
47
+ - Individual anchor for each update
48
+ - Automatic RSS feed entry generation
51
49
  </Update>
52
50
  \`\`\`
53
51
 
@@ -23,8 +23,8 @@ export const packageJsonTemplate = JSON.stringify({
23
23
  minisearch: "^7.2.0",
24
24
  next: "16.2.10",
25
25
  "next-mdx-remote": "^6.0.0",
26
- "posthog-js": "^1.398.0",
27
- "posthog-node": "^5.39.4",
26
+ "posthog-js": "^1.398.4",
27
+ "posthog-node": "^5.40.0",
28
28
  react: "19.2.7",
29
29
  "react-dom": "19.2.7",
30
30
  "rehype-highlight": "^7.0.2",
@@ -1 +1 @@
1
- export declare const prettierignoreTemplate = "node_modules\nconvex/_generated\npackage.json\npackage-lock.json\npnpm-lock.yaml\npnpm-workspace.yaml\n";
1
+ export declare const prettierignoreTemplate = "node_modules\nconvex/_generated\npublic\npackage.json\npackage-lock.json\npnpm-lock.yaml\npnpm-workspace.yaml\n";
@@ -1,5 +1,6 @@
1
1
  export const prettierignoreTemplate = `node_modules
2
2
  convex/_generated
3
+ public
3
4
  package.json
4
5
  package-lock.json
5
6
  pnpm-lock.yaml
@@ -1 +1 @@
1
- export declare const searchServiceTemplate = "import MiniSearch from \"minisearch\";\nimport { listDocs } from \"@/services/mcp/tools\";\n\ninterface IndexedDoc {\n id: string;\n slug: string;\n title: string;\n content: string;\n}\n\nexport interface SearchHit {\n slug: string;\n snippet: string;\n}\n\nlet index: MiniSearch<IndexedDoc> | null = null;\nlet docs: IndexedDoc[] = [];\nlet buildPromise: Promise<void> | null = null;\n\nconst CONTEXT_BEFORE = 60;\nconst CONTEXT_AFTER = 90;\n\nasync function ensureIndex(): Promise<MiniSearch<IndexedDoc>> {\n if (index) return index;\n if (buildPromise) {\n await buildPromise;\n return index!;\n }\n\n buildPromise = (async () => {\n const resources = await listDocs();\n\n docs = resources.map((doc) => {\n // Strip the leading \"app/\", the \"/page.ext\" suffix, and any Next.js\n // route-group segments like \"(site)\" which never appear in URLs. This\n // must match the URL slug produced by toDocPath() in mcp/tools.ts and\n // the nav slugs in the layout, otherwise content hits fail to map back\n // to a page on the client and get silently dropped.\n const slug = doc.path\n .replace(/^app\\//, \"\")\n .replace(/\\/page\\.\\w+$/, \"\")\n .split(\"/\")\n .filter((seg) => !(seg.startsWith(\"(\") && seg.endsWith(\")\")))\n .join(\"/\");\n const cleanContent = doc.content\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .slice(0, 200_000);\n return {\n id: slug || \"__index__\",\n slug,\n title: doc.name,\n content: cleanContent,\n };\n });\n\n index = new MiniSearch<IndexedDoc>({\n fields: [\"title\", \"content\"],\n storeFields: [\"slug\", \"title\", \"content\"],\n searchOptions: {\n boost: { title: 3 },\n fuzzy: 0.2,\n prefix: true,\n },\n });\n\n index.addAll(docs);\n })();\n\n await buildPromise;\n return index!;\n}\n\nfunction extractSnippet(content: string, query: string): string {\n const lower = content.toLowerCase();\n const qLower = query.toLowerCase();\n const matchIdx = lower.indexOf(qLower);\n\n if (matchIdx === -1) {\n // Fuzzy match - no exact substring. Return start of content.\n const end = Math.min(content.length, CONTEXT_BEFORE + CONTEXT_AFTER);\n const raw = content.slice(0, end).trim();\n return raw.length < content.length ? raw + \"...\" : raw;\n }\n\n let start = Math.max(0, matchIdx - CONTEXT_BEFORE);\n let end = Math.min(content.length, matchIdx + query.length + CONTEXT_AFTER);\n\n // Align to word boundaries\n if (start > 0) {\n const space = content.indexOf(\" \", start);\n if (space !== -1 && space < matchIdx) start = space + 1;\n }\n if (end < content.length) {\n const space = content.lastIndexOf(\" \", end);\n if (space > matchIdx + query.length) end = space;\n }\n\n const prefix = start > 0 ? \"...\" : \"\";\n const suffix = end < content.length ? \"...\" : \"\";\n const snippet = content.slice(start, end).replace(/\\n+/g, \" \").trim();\n\n return prefix + snippet + suffix;\n}\n\nexport async function searchContent(\n query: string,\n limit = 10,\n): Promise<SearchHit[]> {\n const q = query.trim();\n if (!q) return [];\n\n const idx = await ensureIndex();\n const results = idx.search(q);\n\n return results.slice(0, limit).map((result) => {\n const doc = docs.find((d) => d.id === result.id);\n const content = doc?.content || \"\";\n return {\n slug: doc?.slug || \"\",\n snippet: extractSnippet(content, q),\n };\n });\n}\n";
1
+ export declare const searchServiceTemplate = "import MiniSearch from \"minisearch\";\nimport { listDocs } from \"@/services/mcp/tools\";\n\ninterface IndexedDoc {\n id: string;\n slug: string;\n title: string;\n content: string;\n}\n\nexport interface SearchHit {\n slug: string;\n snippet: string;\n}\n\nlet index: MiniSearch<IndexedDoc> | null = null;\nlet docs: IndexedDoc[] = [];\nlet buildPromise: Promise<void> | null = null;\n\nconst CONTEXT_BEFORE = 60;\nconst CONTEXT_AFTER = 90;\n\n/**\n * Convert raw MDX (as extracted from the generated page templates) into plain,\n * human-readable text for search snippets: undoes the template-literal escaping\n * and strips common Markdown syntax so inline code shows as Test rather than a\n * backtick-wrapped or backslash-escaped fragment.\n */\nfunction toPlainText(text: string): string {\n return (\n text\n // Undo the template-literal escaping from the generated page files so\n // escaped backticks, dollar-braces and backslashes read as plain text.\n .replace(/\\\\([\\s\\S])/g, \"$1\")\n // Images and links -> visible text only.\n .replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n // Bold markers.\n .replace(/\\*\\*([\\s\\S]*?)\\*\\*/g, \"$1\")\n // Line-leading markers: headings, blockquotes, list bullets.\n .replace(/^\\s{0,3}#{1,6}\\s+/gm, \"\")\n .replace(/^\\s{0,3}>\\s?/gm, \"\")\n .replace(/^\\s{0,3}[-*+]\\s+/gm, \"\")\n .replace(/^\\s{0,3}\\d+\\.\\s+/gm, \"\")\n // Inline code / escaped backticks -> plain text.\n .replace(/`/g, \"\")\n );\n}\n\nasync function ensureIndex(): Promise<MiniSearch<IndexedDoc>> {\n if (index) return index;\n if (buildPromise) {\n await buildPromise;\n return index!;\n }\n\n buildPromise = (async () => {\n const resources = await listDocs();\n\n docs = resources.map((doc) => {\n // Strip the leading \"app/\", the \"/page.ext\" suffix, and any Next.js\n // route-group segments like \"(site)\" which never appear in URLs. This\n // must match the URL slug produced by toDocPath() in mcp/tools.ts and\n // the nav slugs in the layout, otherwise content hits fail to map back\n // to a page on the client and get silently dropped.\n const slug = doc.path\n .replace(/^app\\//, \"\")\n .replace(/\\/page\\.\\w+$/, \"\")\n .split(\"/\")\n .filter((seg) => !(seg.startsWith(\"(\") && seg.endsWith(\")\")))\n .join(\"/\");\n const cleanContent = toPlainText(doc.content.replace(/\\r\\n/g, \"\\n\"))\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .slice(0, 200_000);\n return {\n id: slug || \"__index__\",\n slug,\n title: doc.name,\n content: cleanContent,\n };\n });\n\n index = new MiniSearch<IndexedDoc>({\n fields: [\"title\", \"content\"],\n storeFields: [\"slug\", \"title\", \"content\"],\n searchOptions: {\n boost: { title: 3 },\n fuzzy: 0.2,\n prefix: true,\n },\n });\n\n index.addAll(docs);\n })();\n\n await buildPromise;\n return index!;\n}\n\nfunction extractSnippet(content: string, query: string): string {\n const lower = content.toLowerCase();\n const qLower = query.toLowerCase();\n const matchIdx = lower.indexOf(qLower);\n\n if (matchIdx === -1) {\n // Fuzzy match - no exact substring. Return start of content.\n const end = Math.min(content.length, CONTEXT_BEFORE + CONTEXT_AFTER);\n const raw = content.slice(0, end).trim();\n return raw.length < content.length ? raw + \"...\" : raw;\n }\n\n let start = Math.max(0, matchIdx - CONTEXT_BEFORE);\n let end = Math.min(content.length, matchIdx + query.length + CONTEXT_AFTER);\n\n // Align to word boundaries\n if (start > 0) {\n const space = content.indexOf(\" \", start);\n if (space !== -1 && space < matchIdx) start = space + 1;\n }\n if (end < content.length) {\n const space = content.lastIndexOf(\" \", end);\n if (space > matchIdx + query.length) end = space;\n }\n\n const prefix = start > 0 ? \"...\" : \"\";\n const suffix = end < content.length ? \"...\" : \"\";\n const snippet = content.slice(start, end).replace(/\\n+/g, \" \").trim();\n\n return prefix + snippet + suffix;\n}\n\nexport async function searchContent(\n query: string,\n limit = 10,\n): Promise<SearchHit[]> {\n const q = query.trim();\n if (!q) return [];\n\n const idx = await ensureIndex();\n const results = idx.search(q);\n\n return results.slice(0, limit).map((result) => {\n const doc = docs.find((d) => d.id === result.id);\n const content = doc?.content || \"\";\n return {\n slug: doc?.slug || \"\",\n snippet: extractSnippet(content, q),\n };\n });\n}\n";
@@ -20,6 +20,33 @@ let buildPromise: Promise<void> | null = null;
20
20
  const CONTEXT_BEFORE = 60;
21
21
  const CONTEXT_AFTER = 90;
22
22
 
23
+ /**
24
+ * Convert raw MDX (as extracted from the generated page templates) into plain,
25
+ * human-readable text for search snippets: undoes the template-literal escaping
26
+ * and strips common Markdown syntax so inline code shows as Test rather than a
27
+ * backtick-wrapped or backslash-escaped fragment.
28
+ */
29
+ function toPlainText(text: string): string {
30
+ return (
31
+ text
32
+ // Undo the template-literal escaping from the generated page files so
33
+ // escaped backticks, dollar-braces and backslashes read as plain text.
34
+ .replace(/\\\\([\\s\\S])/g, "$1")
35
+ // Images and links -> visible text only.
36
+ .replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, "$1")
37
+ .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, "$1")
38
+ // Bold markers.
39
+ .replace(/\\*\\*([\\s\\S]*?)\\*\\*/g, "$1")
40
+ // Line-leading markers: headings, blockquotes, list bullets.
41
+ .replace(/^\\s{0,3}#{1,6}\\s+/gm, "")
42
+ .replace(/^\\s{0,3}>\\s?/gm, "")
43
+ .replace(/^\\s{0,3}[-*+]\\s+/gm, "")
44
+ .replace(/^\\s{0,3}\\d+\\.\\s+/gm, "")
45
+ // Inline code / escaped backticks -> plain text.
46
+ .replace(/\`/g, "")
47
+ );
48
+ }
49
+
23
50
  async function ensureIndex(): Promise<MiniSearch<IndexedDoc>> {
24
51
  if (index) return index;
25
52
  if (buildPromise) {
@@ -42,8 +69,7 @@ async function ensureIndex(): Promise<MiniSearch<IndexedDoc>> {
42
69
  .split("/")
43
70
  .filter((seg) => !(seg.startsWith("(") && seg.endsWith(")")))
44
71
  .join("/");
45
- const cleanContent = doc.content
46
- .replace(/\\r\\n/g, "\\n")
72
+ const cleanContent = toPlainText(doc.content.replace(/\\r\\n/g, "\\n"))
47
73
  .replace(/\\n{3,}/g, "\\n\\n")
48
74
  .slice(0, 200_000);
49
75
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doccupine",
3
- "version": "0.0.108",
3
+ "version": "0.0.110",
4
4
  "description": "Free and open-source documentation platform. Write MDX, get a production-ready site with AI chat, built-in components, and an MCP server - in one command.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -46,11 +46,11 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/fs-extra": "^11.0.4",
49
- "@types/node": "^26.1.0",
49
+ "@types/node": "^26.1.1",
50
50
  "@types/prompts": "^2.4.9",
51
51
  "prettier": "^3.9.4",
52
52
  "typescript": "^6.0.3",
53
- "vitest": "^4.1.9"
53
+ "vitest": "^4.1.10"
54
54
  },
55
55
  "files": [
56
56
  "dist/**/*"