convex-cms 0.0.7 → 0.0.9-alpha.1

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 (154) hide show
  1. package/README.md +16 -6
  2. package/admin/src/components/BulkActionBar.tsx +6 -5
  3. package/admin/src/components/ContentEntryEditor.tsx +10 -9
  4. package/admin/src/components/ContentTypeFormModal.tsx +4 -3
  5. package/admin/src/components/Sidebar.tsx +3 -2
  6. package/admin/src/components/TaxonomyEditor.tsx +4 -3
  7. package/admin/src/components/TermTree.tsx +8 -6
  8. package/admin/src/components/VersionCompare.tsx +3 -2
  9. package/admin/src/components/VersionHistory.tsx +4 -3
  10. package/admin/src/components/fields/CategoryField.tsx +3 -2
  11. package/admin/src/components/fields/MediaField.tsx +6 -5
  12. package/admin/src/components/fields/ReferenceField.tsx +6 -5
  13. package/admin/src/components/fields/TagField.tsx +5 -4
  14. package/admin/src/components/filters/TaxonomyFilter.tsx +4 -3
  15. package/admin/src/components/media/MediaAssetEditDialog.tsx +4 -3
  16. package/admin/src/components/media/MediaFolderEditDialog.tsx +3 -2
  17. package/admin/src/components/media/MediaMoveModal.tsx +4 -3
  18. package/admin/src/components/media/MediaTaxonomyPicker.tsx +6 -5
  19. package/admin/src/contexts/SettingsConfigContext.tsx +19 -5
  20. package/admin/src/embed/contexts/ApiContext.tsx +6 -2
  21. package/admin/src/routes/__root.tsx +7 -3
  22. package/admin-dist/nitro.json +1 -1
  23. package/admin-dist/public/assets/{CmsEmptyState-6-PLaXtD.js → CmsEmptyState-BM4e6N83.js} +1 -1
  24. package/admin-dist/public/assets/{CmsPageHeader-SoF4Epu9.js → CmsPageHeader-uor3DPIk.js} +1 -1
  25. package/admin-dist/public/assets/{CmsStatusBadge-D7kYaohx.js → CmsStatusBadge-D8N18LJx.js} +1 -1
  26. package/admin-dist/public/assets/{CmsSurface-BvksBm6W.js → CmsSurface-BEcY-WpI.js} +1 -1
  27. package/admin-dist/public/assets/{CmsToolbar-DlZPMe2B.js → CmsToolbar-DE-bu3W8.js} +1 -1
  28. package/admin-dist/public/assets/ContentEntryEditor-BdkIMCUk.js +4 -0
  29. package/admin-dist/public/assets/TaxonomyFilter-a1-O9DPs.js +1 -0
  30. package/admin-dist/public/assets/{_contentTypeId-DTv8UoTp.js → _contentTypeId-XIkYOLyY.js} +1 -1
  31. package/admin-dist/public/assets/{_entryId-D3lr5Dvy.js → _entryId-DyP15QpI.js} +1 -1
  32. package/admin-dist/public/assets/{alert-BAHTL6ao.js → alert-DHBQuuib.js} +1 -1
  33. package/admin-dist/public/assets/{badge-oJv4Eai8.js → badge-BOhWFWzb.js} +1 -1
  34. package/admin-dist/public/assets/{circle-check-big-3OHxNDhO.js → circle-check-big-DjTNapen.js} +1 -1
  35. package/admin-dist/public/assets/{command-DwgQs69u.js → command-BIc5_8gL.js} +1 -1
  36. package/admin-dist/public/assets/content-C3N8Ugra.js +1 -0
  37. package/admin-dist/public/assets/content-types-D0wh1eUF.js +1 -0
  38. package/admin-dist/public/assets/{index-DOkgTSx0.js → index-B-g3F_ri.js} +1 -1
  39. package/admin-dist/public/assets/main-BapBJgQD.js +102 -0
  40. package/admin-dist/public/assets/media-8uh1MwDi.js +1 -0
  41. package/admin-dist/public/assets/{new._contentTypeId-VF63rpic.js → new._contentTypeId-S96rFbgY.js} +1 -1
  42. package/admin-dist/public/assets/{pencil-CX1CiTDD.js → pencil-DgaZav4e.js} +1 -1
  43. package/admin-dist/public/assets/{refresh-cw-Cm-YOeFI.js → refresh-cw-BBut4hAU.js} +1 -1
  44. package/admin-dist/public/assets/{rotate-ccw-B45JsL5f.js → rotate-ccw-DVCkojZZ.js} +1 -1
  45. package/admin-dist/public/assets/{scroll-area-b3A1HHR7.js → scroll-area-DPC4uXzf.js} +1 -1
  46. package/admin-dist/public/assets/{search-DKKh_DdH.js → search-CSyHHglh.js} +1 -1
  47. package/admin-dist/public/assets/{settings-CGVDEV1r.js → settings-cEqPsoJ0.js} +1 -1
  48. package/admin-dist/public/assets/{switch-BTMY8Qnk.js → switch-O2BviO8Q.js} +1 -1
  49. package/admin-dist/public/assets/{tabs-DUQwUoIb.js → tabs-p1MWhOqY.js} +1 -1
  50. package/admin-dist/public/assets/{tanstack-adapter-f7AHmQ5L.js → tanstack-adapter-CDrxoPZD.js} +1 -1
  51. package/admin-dist/public/assets/taxonomies-DJ9UbjXW.js +1 -0
  52. package/admin-dist/public/assets/{trash-D7e0uKd9.js → trash-RnpP6lXF.js} +1 -1
  53. package/admin-dist/public/assets/{useBreadcrumbLabel-CF2KYwsw.js → useBreadcrumbLabel-zbIWXlkc.js} +1 -1
  54. package/admin-dist/public/assets/{usePermissions-DWBImEOW.js → usePermissions-4CTlK-vU.js} +1 -1
  55. package/admin-dist/server/_chunks/_libs/@floating-ui/core.mjs +71 -65
  56. package/admin-dist/server/_chunks/_libs/@floating-ui/dom.mjs +1 -1
  57. package/admin-dist/server/_chunks/_libs/@floating-ui/utils.mjs +8 -8
  58. package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +12 -30
  59. package/admin-dist/server/_chunks/_libs/@tanstack/react-store.mjs +1 -56
  60. package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +130 -114
  61. package/admin-dist/server/_chunks/_libs/@tanstack/store.mjs +1 -134
  62. package/admin-dist/server/_chunks/_libs/react-dom.mjs +5 -5
  63. package/admin-dist/server/_chunks/_libs/react.mjs +1 -1
  64. package/admin-dist/server/_libs/isbot.mjs +1 -1
  65. package/admin-dist/server/_libs/use-sync-external-store.mjs +1 -76
  66. package/admin-dist/server/_ssr/{CmsEmptyState-BM8DghTl.mjs → CmsEmptyState-BA0Lc5xs.mjs} +1 -1
  67. package/admin-dist/server/_ssr/{CmsPageHeader-BHUmrIWD.mjs → CmsPageHeader-PMyecILZ.mjs} +1 -1
  68. package/admin-dist/server/_ssr/{CmsStatusBadge-D0Zb0oRl.mjs → CmsStatusBadge-CInuN2bZ.mjs} +2 -2
  69. package/admin-dist/server/_ssr/{CmsSurface-B2eBr-47.mjs → CmsSurface-CH1PIfcS.mjs} +1 -1
  70. package/admin-dist/server/_ssr/{CmsToolbar-BCrwg7OL.mjs → CmsToolbar-IuhSA7gR.mjs} +1 -1
  71. package/admin-dist/server/_ssr/{ContentEntryEditor-Cjfm0uhr.mjs → ContentEntryEditor-Bzhir4fQ.mjs} +38 -31
  72. package/admin-dist/server/_ssr/{TaxonomyFilter-C4pD0kfM.mjs → TaxonomyFilter-r4izSMBh.mjs} +6 -5
  73. package/admin-dist/server/_ssr/{_contentTypeId-CiDiX-p7.mjs → _contentTypeId-BWEbjqxY.mjs} +11 -13
  74. package/admin-dist/server/_ssr/{_entryId-9GxatOkL.mjs → _entryId-B5xoXoJf.mjs} +12 -14
  75. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-CBTan6ii.mjs +4 -0
  76. package/admin-dist/server/_ssr/{badge-EI998zba.mjs → badge-DXrjBRqZ.mjs} +1 -1
  77. package/admin-dist/server/_ssr/{command-BLAWQhUw.mjs → command-Cj90OdCX.mjs} +1 -1
  78. package/admin-dist/server/_ssr/config.server-BOr7Jxr4.mjs +0 -3
  79. package/admin-dist/server/_ssr/{content-BHX39L4D.mjs → content-DKRI-YqL.mjs} +14 -15
  80. package/admin-dist/server/_ssr/{content-types-DCzrBhTH.mjs → content-types-BzgRcS8K.mjs} +7 -9
  81. package/admin-dist/server/_ssr/{index-DwM_5VNP.mjs → index-BPf6_agY.mjs} +4 -6
  82. package/admin-dist/server/_ssr/index.mjs +11 -10
  83. package/admin-dist/server/_ssr/{media-CbzgTRRQ.mjs → media-MpjxOZL8.mjs} +23 -21
  84. package/admin-dist/server/_ssr/{new._contentTypeId-6Ph-Gtlw.mjs → new._contentTypeId-DSb4qR9j.mjs} +11 -13
  85. package/admin-dist/server/_ssr/{router-vd1nySeP.mjs → router-Dk9ikPNc.mjs} +61 -47
  86. package/admin-dist/server/_ssr/{scroll-area--B9snFTJ.mjs → scroll-area-JwVD_6MZ.mjs} +1 -1
  87. package/admin-dist/server/_ssr/{settings-DlTO2JSj.mjs → settings-KVJNe0GM.mjs} +8 -10
  88. package/admin-dist/server/_ssr/{switch-C05NgNW0.mjs → switch-DvREvRv4.mjs} +1 -1
  89. package/admin-dist/server/_ssr/{tabs-DAk2J5xy.mjs → tabs-B0h57pFf.mjs} +1 -1
  90. package/admin-dist/server/_ssr/{tanstack-adapter-DWbaPByn.mjs → tanstack-adapter-gmM64LnW.mjs} +1 -1
  91. package/admin-dist/server/_ssr/{taxonomies-B8nqce6u.mjs → taxonomies-BbBNx260.mjs} +17 -16
  92. package/admin-dist/server/_ssr/{trash-zdlZgpTo.mjs → trash-JAzYGh7A.mjs} +8 -10
  93. package/admin-dist/server/_ssr/{useBreadcrumbLabel-DpEKyG1h.mjs → useBreadcrumbLabel-BWIujj97.mjs} +1 -1
  94. package/admin-dist/server/_ssr/{usePermissions-olYRd9S9.mjs → usePermissions-CcLDCSwa.mjs} +1 -1
  95. package/admin-dist/server/index.mjs +162 -162
  96. package/dist/cli/commands/init.d.ts.map +1 -1
  97. package/dist/cli/commands/init.js +18 -29
  98. package/dist/cli/commands/init.js.map +1 -1
  99. package/dist/cli/templates/admin.d.ts +4 -3
  100. package/dist/cli/templates/admin.d.ts.map +1 -1
  101. package/dist/cli/templates/admin.js +152 -195
  102. package/dist/cli/templates/admin.js.map +1 -1
  103. package/dist/cli/templates/cmsClient.d.ts +2 -2
  104. package/dist/cli/templates/cmsClient.d.ts.map +1 -1
  105. package/dist/cli/templates/cmsClient.js +58 -27
  106. package/dist/cli/templates/cmsClient.js.map +1 -1
  107. package/dist/cli/templates/content.d.ts +10 -0
  108. package/dist/cli/templates/content.d.ts.map +1 -0
  109. package/dist/cli/templates/content.js +257 -0
  110. package/dist/cli/templates/content.js.map +1 -0
  111. package/dist/cli/templates/index.d.ts +3 -2
  112. package/dist/cli/templates/index.d.ts.map +1 -1
  113. package/dist/cli/templates/index.js +3 -2
  114. package/dist/cli/templates/index.js.map +1 -1
  115. package/dist/cli/templates/schemas/blog.d.ts +4 -3
  116. package/dist/cli/templates/schemas/blog.d.ts.map +1 -1
  117. package/dist/cli/templates/schemas/blog.js +44 -13
  118. package/dist/cli/templates/schemas/blog.js.map +1 -1
  119. package/dist/cli/templates/schemas/docs.d.ts +4 -3
  120. package/dist/cli/templates/schemas/docs.d.ts.map +1 -1
  121. package/dist/cli/templates/schemas/docs.js +43 -12
  122. package/dist/cli/templates/schemas/docs.js.map +1 -1
  123. package/dist/cli/templates/schemas/index.d.ts +6 -4
  124. package/dist/cli/templates/schemas/index.d.ts.map +1 -1
  125. package/dist/cli/templates/schemas/index.js +6 -4
  126. package/dist/cli/templates/schemas/index.js.map +1 -1
  127. package/dist/cli/templates/schemas/landing.d.ts +4 -3
  128. package/dist/cli/templates/schemas/landing.d.ts.map +1 -1
  129. package/dist/cli/templates/schemas/landing.js +62 -15
  130. package/dist/cli/templates/schemas/landing.js.map +1 -1
  131. package/dist/cli/utils/fileUtils.d.ts.map +1 -1
  132. package/dist/cli/utils/fileUtils.js +6 -5
  133. package/dist/cli/utils/fileUtils.js.map +1 -1
  134. package/dist/client/admin/index.d.ts +2 -1
  135. package/dist/client/admin/index.d.ts.map +1 -1
  136. package/dist/client/admin/index.js.map +1 -1
  137. package/dist/client/admin/types.d.ts +14 -1
  138. package/dist/client/admin/types.d.ts.map +1 -1
  139. package/dist/client/index.d.ts +1 -1
  140. package/dist/client/index.d.ts.map +1 -1
  141. package/dist/client/index.js.map +1 -1
  142. package/dist/react/index.d.ts +176 -0
  143. package/dist/react/index.d.ts.map +1 -1
  144. package/dist/react/index.js +162 -0
  145. package/dist/react/index.js.map +1 -1
  146. package/package.json +2 -2
  147. package/admin-dist/public/assets/ContentEntryEditor-C6n9xLS9.js +0 -4
  148. package/admin-dist/public/assets/TaxonomyFilter-CFX1_g8s.js +0 -1
  149. package/admin-dist/public/assets/content-CKQ4QwW2.js +0 -1
  150. package/admin-dist/public/assets/content-types-BrttaLpc.js +0 -1
  151. package/admin-dist/public/assets/main-DV6oxWnU.js +0 -102
  152. package/admin-dist/public/assets/media-B2i-mCbx.js +0 -1
  153. package/admin-dist/public/assets/taxonomies-DvMppdiD.js +0 -1
  154. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-CC7UrHKE.mjs +0 -4
@@ -1,55 +1,86 @@
1
1
  /**
2
- * CMS Client template
2
+ * CMS Client template - Blank starter
3
3
  *
4
4
  * Generated by: npx convex-cms init
5
5
  */
6
6
  export const CMS_CLIENT_TEMPLATE = `/**
7
7
  * CMS Setup
8
8
  *
9
- * Uses the unified createCms API for type-safe content management.
10
- * Define content types with defineContent() and export the admin API.
9
+ * This file defines content types and creates typed helpers for type-safe access.
11
10
  *
12
- * @example
11
+ * Architecture:
12
+ * - defineContentType() creates schema definitions for the admin API
13
+ * - createTypedHelpers() creates type-safe CRUD helpers for programmatic access
14
+ * - Both work together: definitions go to admin API, helpers provide typed access
15
+ *
16
+ * @example Type-safe queries in Convex functions
13
17
  * \`\`\`typescript
14
- * import { blogPost, admin } from "./cms";
18
+ * import { content } from "./cms";
15
19
  *
16
- * // Use in a mutation (typed helpers)
17
- * export const createPost = mutation({
18
- * args: { title: v.string() },
19
- * handler: async (ctx, args) => {
20
- * return await blogPost.create(ctx, {
21
- * data: { title: args.title },
22
- * });
23
- * },
24
- * });
20
+ * // Fully typed - data fields have correct types
21
+ * const items = await content.blog.list(ctx, { status: "published" });
22
+ * items.page[0].data.title; // string
25
23
  * \`\`\`
26
24
  */
27
25
 
28
- import { createCms } from "convex-cms";
29
- import { v } from "convex/values";
26
+ import { defineContentType, createTypedHelpers } from "convex-cms";
30
27
  import { components } from "./_generated/api";
31
- import cmsConfig from "./cms.config";
28
+ import { v } from "convex/values";
32
29
 
33
- const cms = createCms(components.convexCms, cmsConfig);
30
+ // =============================================================================
31
+ // CONTENT TYPE DEFINITIONS
32
+ // =============================================================================
33
+ // Define your content types here. These are automatically registered and
34
+ // available in the admin API. Code-defined types show as "Native Fields"
35
+ // and cannot be edited/deleted through the admin UI.
34
36
 
35
- // Define your content types here
36
- export const blogPost = cms.defineContent({
37
+ export const blogPost = defineContentType({
37
38
  name: "Blog Post",
38
- fields: v.object({
39
+ validator: v.object({
39
40
  title: v.string(),
41
+ slug: v.string(),
40
42
  content: v.string(),
43
+ excerpt: v.optional(v.string()),
41
44
  publishedAt: v.optional(v.number()),
42
45
  }),
43
- display: {
46
+ meta: {
47
+ displayName: "Blog Post",
44
48
  titleField: "title",
45
- icon: "📝",
49
+ slugField: "slug",
50
+ fields: {
51
+ title: {
52
+ label: "Title",
53
+ maxLength: 200,
54
+ searchable: true,
55
+ },
56
+ slug: {
57
+ label: "URL Slug",
58
+ description: "URL-friendly identifier",
59
+ },
60
+ content: {
61
+ label: "Content",
62
+ renderAs: "richText",
63
+ },
64
+ excerpt: {
65
+ label: "Excerpt",
66
+ maxLength: 300,
67
+ },
68
+ publishedAt: {
69
+ label: "Publish Date",
70
+ renderAs: "datetime",
71
+ },
72
+ },
46
73
  },
47
74
  });
48
75
 
49
- // Export admin API for the admin UI
50
- export const admin = cms.admin;
76
+ // =============================================================================
77
+ // TYPED HELPERS
78
+ // =============================================================================
79
+ // Create type-safe CRUD helpers for programmatic access.
80
+ // Use these in Convex functions for fully typed data access.
51
81
 
52
- // For advanced usage, you can also access CmsClient namespaces:
53
- // cms.contentTypes, cms.contentEntries, cms.versions, etc.
82
+ export const content = createTypedHelpers(components.cms, {
83
+ blog: blogPost,
84
+ });
54
85
  `;
55
86
  //# sourceMappingURL=cmsClient.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cmsClient.js","sourceRoot":"","sources":["../../../src/cli/templates/cmsClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDlC,CAAC"}
1
+ {"version":3,"file":"cmsClient.js","sourceRoot":"","sources":["../../../src/cli/templates/cmsClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+ElC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Content queries template
3
+ *
4
+ * Generated by: npx convex-cms init
5
+ *
6
+ * Shows how to use typed helpers from cms.ts in public queries.
7
+ */
8
+ import type { SchemaTemplate } from "./schemas/index.js";
9
+ export declare function getContentTemplate(template: SchemaTemplate): string;
10
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/content.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAYnE"}
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Content queries template
3
+ *
4
+ * Generated by: npx convex-cms init
5
+ *
6
+ * Shows how to use typed helpers from cms.ts in public queries.
7
+ */
8
+ export function getContentTemplate(template) {
9
+ switch (template) {
10
+ case "blog":
11
+ return CONTENT_BLOG_TEMPLATE;
12
+ case "docs":
13
+ return CONTENT_DOCS_TEMPLATE;
14
+ case "landing":
15
+ return CONTENT_LANDING_TEMPLATE;
16
+ case "blank":
17
+ default:
18
+ return CONTENT_BLANK_TEMPLATE;
19
+ }
20
+ }
21
+ const CONTENT_BLANK_TEMPLATE = `/**
22
+ * Public content queries for the frontend
23
+ *
24
+ * These queries use the typed helpers from cms.ts for type-safe data access.
25
+ * The content helpers provide full TypeScript inference for all fields.
26
+ */
27
+
28
+ import { query } from "./_generated/server";
29
+ import { content } from "./cms";
30
+
31
+ export const getBlogPosts = query({
32
+ args: {},
33
+ handler: async (ctx) => {
34
+ // Using typed helper - result.page[].data is fully typed
35
+ const result = await content.blog.list(ctx, { status: "published" });
36
+
37
+ // Return entries with data flattened for easier frontend consumption
38
+ return result.page.map((entry) => ({
39
+ _id: entry._id,
40
+ ...entry.data,
41
+ }));
42
+ },
43
+ });
44
+ `;
45
+ const CONTENT_BLOG_TEMPLATE = `/**
46
+ * Public content queries for the frontend - Blog Template
47
+ *
48
+ * These queries use the typed helpers from cms.ts for type-safe data access.
49
+ * The content helpers provide full TypeScript inference for all fields.
50
+ */
51
+
52
+ import { query } from "./_generated/server";
53
+ import { v } from "convex/values";
54
+ import { content } from "./cms";
55
+
56
+ export const getBlogPosts = query({
57
+ args: {},
58
+ handler: async (ctx) => {
59
+ const result = await content.blog.list(ctx, { status: "published" });
60
+
61
+ return result.page.map((entry) => ({
62
+ _id: entry._id,
63
+ ...entry.data,
64
+ }));
65
+ },
66
+ });
67
+
68
+ export const getBlogPostBySlug = query({
69
+ args: { slug: v.string() },
70
+ handler: async (ctx, { slug }) => {
71
+ const result = await content.blog.list(ctx, { status: "published" });
72
+
73
+ const post = result.page.find((entry) => entry.data.slug === slug);
74
+ if (!post) return null;
75
+
76
+ return {
77
+ _id: post._id,
78
+ ...post.data,
79
+ };
80
+ },
81
+ });
82
+
83
+ export const getAuthors = query({
84
+ args: {},
85
+ handler: async (ctx) => {
86
+ const result = await content.author.list(ctx, { status: "published" });
87
+
88
+ return result.page.map((entry) => ({
89
+ _id: entry._id,
90
+ ...entry.data,
91
+ }));
92
+ },
93
+ });
94
+
95
+ export const getCategories = query({
96
+ args: {},
97
+ handler: async (ctx) => {
98
+ const result = await content.category.list(ctx, { status: "published" });
99
+
100
+ return result.page.map((entry) => ({
101
+ _id: entry._id,
102
+ ...entry.data,
103
+ }));
104
+ },
105
+ });
106
+ `;
107
+ const CONTENT_DOCS_TEMPLATE = `/**
108
+ * Public content queries for the frontend - Documentation Template
109
+ *
110
+ * These queries use the typed helpers from cms.ts for type-safe data access.
111
+ * The content helpers provide full TypeScript inference for all fields.
112
+ */
113
+
114
+ import { query } from "./_generated/server";
115
+ import { v } from "convex/values";
116
+ import { content } from "./cms";
117
+
118
+ export const getDocPages = query({
119
+ args: {},
120
+ handler: async (ctx) => {
121
+ const result = await content.docPage.list(ctx, { status: "published" });
122
+
123
+ return result.page.map((entry) => ({
124
+ _id: entry._id,
125
+ ...entry.data,
126
+ }));
127
+ },
128
+ });
129
+
130
+ export const getDocPageBySlug = query({
131
+ args: { slug: v.string() },
132
+ handler: async (ctx, { slug }) => {
133
+ const result = await content.docPage.list(ctx, { status: "published" });
134
+
135
+ const page = result.page.find((entry) => entry.data.slug === slug);
136
+ if (!page) return null;
137
+
138
+ return {
139
+ _id: page._id,
140
+ ...page.data,
141
+ };
142
+ },
143
+ });
144
+
145
+ export const getDocSections = query({
146
+ args: {},
147
+ handler: async (ctx) => {
148
+ const result = await content.docSection.list(ctx, { status: "published" });
149
+
150
+ // Sort by order
151
+ return result.page
152
+ .map((entry) => ({
153
+ _id: entry._id,
154
+ ...entry.data,
155
+ }))
156
+ .sort((a, b) => a.order - b.order);
157
+ },
158
+ });
159
+
160
+ export const getDocNavigation = query({
161
+ args: {},
162
+ handler: async (ctx) => {
163
+ const result = await content.docNavigation.list(ctx, { status: "published" });
164
+
165
+ // Find the default navigation
166
+ const defaultNav = result.page.find((entry) => entry.data.isDefault);
167
+ if (!defaultNav) {
168
+ // Return first nav if no default
169
+ const first = result.page[0];
170
+ if (!first) return null;
171
+ return { _id: first._id, ...first.data };
172
+ }
173
+
174
+ return {
175
+ _id: defaultNav._id,
176
+ ...defaultNav.data,
177
+ };
178
+ },
179
+ });
180
+ `;
181
+ const CONTENT_LANDING_TEMPLATE = `/**
182
+ * Public content queries for the frontend - Landing Page Template
183
+ *
184
+ * These queries use the typed helpers from cms.ts for type-safe data access.
185
+ * The content helpers provide full TypeScript inference for all fields.
186
+ */
187
+
188
+ import { query } from "./_generated/server";
189
+ import { content } from "./cms";
190
+
191
+ export const getHeroSections = query({
192
+ args: {},
193
+ handler: async (ctx) => {
194
+ const result = await content.hero.list(ctx, { status: "published" });
195
+
196
+ return result.page.map((entry) => ({
197
+ _id: entry._id,
198
+ ...entry.data,
199
+ }));
200
+ },
201
+ });
202
+
203
+ export const getFeatureBlocks = query({
204
+ args: {},
205
+ handler: async (ctx) => {
206
+ const result = await content.feature.list(ctx, { status: "published" });
207
+
208
+ // Sort by order
209
+ return result.page
210
+ .map((entry) => ({
211
+ _id: entry._id,
212
+ ...entry.data,
213
+ }))
214
+ .sort((a, b) => a.order - b.order);
215
+ },
216
+ });
217
+
218
+ export const getTestimonials = query({
219
+ args: {},
220
+ handler: async (ctx) => {
221
+ const result = await content.testimonial.list(ctx, { status: "published" });
222
+
223
+ return result.page.map((entry) => ({
224
+ _id: entry._id,
225
+ ...entry.data,
226
+ }));
227
+ },
228
+ });
229
+
230
+ export const getFeaturedTestimonials = query({
231
+ args: {},
232
+ handler: async (ctx) => {
233
+ const result = await content.testimonial.list(ctx, { status: "published" });
234
+
235
+ // Filter to featured only
236
+ return result.page
237
+ .filter((entry) => entry.data.featured)
238
+ .map((entry) => ({
239
+ _id: entry._id,
240
+ ...entry.data,
241
+ }));
242
+ },
243
+ });
244
+
245
+ export const getCtaSections = query({
246
+ args: {},
247
+ handler: async (ctx) => {
248
+ const result = await content.cta.list(ctx, { status: "published" });
249
+
250
+ return result.page.map((entry) => ({
251
+ _id: entry._id,
252
+ ...entry.data,
253
+ }));
254
+ },
255
+ });
256
+ `;
257
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/cli/templates/content.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,UAAU,kBAAkB,CAAC,QAAwB;IACzD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM;YACT,OAAO,qBAAqB,CAAC;QAC/B,KAAK,MAAM;YACT,OAAO,qBAAqB,CAAC;QAC/B,KAAK,SAAS;YACZ,OAAO,wBAAwB,CAAC;QAClC,KAAK,OAAO,CAAC;QACb;YACE,OAAO,sBAAsB,CAAC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuB9B,CAAC;AAEF,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D7B,CAAC;AAEF,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyE7B,CAAC;AAEF,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EhC,CAAC"}
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * All templates for the init command.
5
5
  */
6
- export { ADMIN_TEMPLATE } from "./admin.js";
6
+ export { ADMIN_TEMPLATE, getAdminTemplate } from "./admin.js";
7
7
  export { CMS_CONFIG_TEMPLATE } from "./cmsConfig.js";
8
8
  export { CMS_CLIENT_TEMPLATE } from "./cmsClient.js";
9
- export { BLOG_SCHEMA_TEMPLATE, DOCS_SCHEMA_TEMPLATE, LANDING_SCHEMA_TEMPLATE, type SchemaTemplate, } from "./schemas/index.js";
9
+ export { getContentTemplate } from "./content.js";
10
+ export { CMS_BLOG_TEMPLATE, CMS_DOCS_TEMPLATE, CMS_LANDING_TEMPLATE, type SchemaTemplate, } from "./schemas/index.js";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC"}
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * All templates for the init command.
5
5
  */
6
- export { ADMIN_TEMPLATE } from "./admin.js";
6
+ export { ADMIN_TEMPLATE, getAdminTemplate } from "./admin.js";
7
7
  export { CMS_CONFIG_TEMPLATE } from "./cmsConfig.js";
8
8
  export { CMS_CLIENT_TEMPLATE } from "./cmsClient.js";
9
- export { BLOG_SCHEMA_TEMPLATE, DOCS_SCHEMA_TEMPLATE, LANDING_SCHEMA_TEMPLATE, } from "./schemas/index.js";
9
+ export { getContentTemplate } from "./content.js";
10
+ export { CMS_BLOG_TEMPLATE, CMS_DOCS_TEMPLATE, CMS_LANDING_TEMPLATE, } from "./schemas/index.js";
10
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,GAExB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,oBAAoB,CAAC"}
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Blog schema template
2
+ * Blog cms.ts template
3
3
  *
4
- * Content types: blog_post, author, category
4
+ * Content types: Blog Post, Author, Category
5
+ * Includes typed helpers for programmatic access
5
6
  */
6
- export declare const BLOG_SCHEMA_TEMPLATE = "/**\n * Blog Content Types\n *\n * Defines the content structure for a blog with posts, authors, and categories.\n * These definitions are code-first and type-safe using Convex validators.\n *\n * Generated by: npx convex-cms init --template blog\n */\n\nimport { v } from \"convex/values\";\nimport { defineContentType } from \"convex-cms\";\n\nexport const blogPost = defineContentType({\n name: \"blog_post\",\n validator: v.object({\n title: v.string(),\n slug: v.string(),\n excerpt: v.optional(v.string()),\n content: v.string(),\n featuredImage: v.optional(v.string()),\n publishedAt: v.optional(v.number()),\n author: v.optional(v.string()),\n tags: v.optional(v.array(v.string())),\n }),\n meta: {\n displayName: \"Blog Post\",\n titleField: \"title\",\n slugField: \"slug\",\n fields: {\n title: { label: \"Title\", maxLength: 200 },\n slug: { label: \"URL Slug\", description: \"URL-friendly identifier\" },\n excerpt: { label: \"Excerpt\", maxLength: 300 },\n content: { label: \"Content\", renderAs: \"richText\" },\n featuredImage: { label: \"Featured Image\", renderAs: \"media\" },\n publishedAt: { label: \"Publish Date\", renderAs: \"datetime\" },\n author: { label: \"Author\" },\n tags: { label: \"Tags\", renderAs: \"tags\" },\n },\n },\n});\n\nexport const author = defineContentType({\n name: \"author\",\n validator: v.object({\n name: v.string(),\n slug: v.string(),\n bio: v.optional(v.string()),\n avatar: v.optional(v.string()),\n email: v.optional(v.string()),\n socialLinks: v.optional(\n v.object({\n twitter: v.optional(v.string()),\n linkedin: v.optional(v.string()),\n github: v.optional(v.string()),\n website: v.optional(v.string()),\n })\n ),\n }),\n meta: {\n displayName: \"Author\",\n titleField: \"name\",\n slugField: \"slug\",\n fields: {\n name: { label: \"Full Name\" },\n slug: { label: \"URL Slug\" },\n bio: { label: \"Biography\", renderAs: \"richText\" },\n avatar: { label: \"Profile Photo\", renderAs: \"media\" },\n email: { label: \"Email Address\" },\n socialLinks: { label: \"Social Links\", renderAs: \"json\" },\n },\n },\n});\n\nexport const category = defineContentType({\n name: \"category\",\n validator: v.object({\n name: v.string(),\n slug: v.string(),\n description: v.optional(v.string()),\n color: v.optional(v.string()),\n parentCategory: v.optional(v.string()),\n }),\n meta: {\n displayName: \"Category\",\n titleField: \"name\",\n slugField: \"slug\",\n fields: {\n name: { label: \"Category Name\" },\n slug: { label: \"URL Slug\" },\n description: { label: \"Description\" },\n color: { label: \"Color\", description: \"Hex color for UI display\" },\n parentCategory: { label: \"Parent Category\" },\n },\n },\n});\n";
7
+ export declare const CMS_BLOG_TEMPLATE = "/**\n * CMS Setup - Blog Template\n *\n * This file defines content types and creates typed helpers for type-safe access.\n *\n * Architecture:\n * - defineContentType() creates schema definitions for the admin API\n * - createTypedHelpers() creates type-safe CRUD helpers for programmatic access\n * - Both work together: definitions go to admin API, helpers provide typed access\n *\n * @example Type-safe queries in Convex functions\n * ```typescript\n * import { content } from \"./cms\";\n *\n * // Fully typed - data fields have correct types\n * const posts = await content.blog.list(ctx, { status: \"published\" });\n * posts.page[0].data.title; // string\n * ```\n *\n * Generated by: npx convex-cms init --template blog\n */\n\nimport { defineContentType, createTypedHelpers } from \"convex-cms\";\nimport { components } from \"./_generated/api\";\nimport { v } from \"convex/values\";\n\n// =============================================================================\n// CONTENT TYPE DEFINITIONS\n// =============================================================================\n\nexport const blogPost = defineContentType({\n name: \"Blog Post\",\n validator: v.object({\n title: v.string(),\n slug: v.string(),\n excerpt: v.optional(v.string()),\n content: v.string(),\n featuredImage: v.optional(v.string()),\n publishedAt: v.optional(v.number()),\n author: v.optional(v.string()),\n tags: v.optional(v.array(v.string())),\n }),\n meta: {\n displayName: \"Blog Post\",\n titleField: \"title\",\n slugField: \"slug\",\n fields: {\n title: { label: \"Title\", maxLength: 200, searchable: true },\n slug: { label: \"URL Slug\", description: \"URL-friendly identifier\" },\n excerpt: { label: \"Excerpt\", maxLength: 300 },\n content: { label: \"Content\", renderAs: \"richText\" },\n featuredImage: { label: \"Featured Image\", renderAs: \"media\" },\n publishedAt: { label: \"Publish Date\", renderAs: \"datetime\" },\n author: { label: \"Author\" },\n tags: { label: \"Tags\", renderAs: \"tags\" },\n },\n },\n});\n\nexport const author = defineContentType({\n name: \"Author\",\n validator: v.object({\n name: v.string(),\n slug: v.string(),\n bio: v.optional(v.string()),\n avatar: v.optional(v.string()),\n email: v.optional(v.string()),\n socialLinks: v.optional(\n v.object({\n twitter: v.optional(v.string()),\n linkedin: v.optional(v.string()),\n github: v.optional(v.string()),\n website: v.optional(v.string()),\n })\n ),\n }),\n meta: {\n displayName: \"Author\",\n titleField: \"name\",\n slugField: \"slug\",\n fields: {\n name: { label: \"Full Name\", searchable: true },\n slug: { label: \"URL Slug\" },\n bio: { label: \"Biography\", renderAs: \"richText\" },\n avatar: { label: \"Profile Photo\", renderAs: \"media\" },\n email: { label: \"Email Address\" },\n socialLinks: { label: \"Social Links\", renderAs: \"json\" },\n },\n },\n});\n\nexport const category = defineContentType({\n name: \"Category\",\n validator: v.object({\n name: v.string(),\n slug: v.string(),\n description: v.optional(v.string()),\n color: v.optional(v.string()),\n parentCategory: v.optional(v.string()),\n }),\n meta: {\n displayName: \"Category\",\n titleField: \"name\",\n slugField: \"slug\",\n fields: {\n name: { label: \"Category Name\", searchable: true },\n slug: { label: \"URL Slug\" },\n description: { label: \"Description\" },\n color: { label: \"Color\", description: \"Hex color for UI display\" },\n parentCategory: { label: \"Parent Category\" },\n },\n },\n});\n\n// =============================================================================\n// TYPED HELPERS\n// =============================================================================\n// Create type-safe CRUD helpers for programmatic access.\n// Use these in Convex functions for fully typed data access.\n\nexport const content = createTypedHelpers(components.cms, {\n blog: blogPost,\n author: author,\n category: category,\n});\n";
7
8
  export declare const BLOG_SCHEMA_DESCRIPTION = "Blog (post, author, category)";
8
9
  //# sourceMappingURL=blog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../../../../src/cli/templates/schemas/blog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,oBAAoB,o4FA+FhC,CAAC;AAEF,eAAO,MAAM,uBAAuB,kCAAkC,CAAC"}
1
+ {"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../../../../src/cli/templates/schemas/blog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,iBAAiB,0lIA6H7B,CAAC;AAEF,eAAO,MAAM,uBAAuB,kCAAkC,CAAC"}
@@ -1,22 +1,41 @@
1
1
  /**
2
- * Blog schema template
2
+ * Blog cms.ts template
3
3
  *
4
- * Content types: blog_post, author, category
4
+ * Content types: Blog Post, Author, Category
5
+ * Includes typed helpers for programmatic access
5
6
  */
6
- export const BLOG_SCHEMA_TEMPLATE = `/**
7
- * Blog Content Types
7
+ export const CMS_BLOG_TEMPLATE = `/**
8
+ * CMS Setup - Blog Template
8
9
  *
9
- * Defines the content structure for a blog with posts, authors, and categories.
10
- * These definitions are code-first and type-safe using Convex validators.
10
+ * This file defines content types and creates typed helpers for type-safe access.
11
+ *
12
+ * Architecture:
13
+ * - defineContentType() creates schema definitions for the admin API
14
+ * - createTypedHelpers() creates type-safe CRUD helpers for programmatic access
15
+ * - Both work together: definitions go to admin API, helpers provide typed access
16
+ *
17
+ * @example Type-safe queries in Convex functions
18
+ * \`\`\`typescript
19
+ * import { content } from "./cms";
20
+ *
21
+ * // Fully typed - data fields have correct types
22
+ * const posts = await content.blog.list(ctx, { status: "published" });
23
+ * posts.page[0].data.title; // string
24
+ * \`\`\`
11
25
  *
12
26
  * Generated by: npx convex-cms init --template blog
13
27
  */
14
28
 
29
+ import { defineContentType, createTypedHelpers } from "convex-cms";
30
+ import { components } from "./_generated/api";
15
31
  import { v } from "convex/values";
16
- import { defineContentType } from "convex-cms";
32
+
33
+ // =============================================================================
34
+ // CONTENT TYPE DEFINITIONS
35
+ // =============================================================================
17
36
 
18
37
  export const blogPost = defineContentType({
19
- name: "blog_post",
38
+ name: "Blog Post",
20
39
  validator: v.object({
21
40
  title: v.string(),
22
41
  slug: v.string(),
@@ -32,7 +51,7 @@ export const blogPost = defineContentType({
32
51
  titleField: "title",
33
52
  slugField: "slug",
34
53
  fields: {
35
- title: { label: "Title", maxLength: 200 },
54
+ title: { label: "Title", maxLength: 200, searchable: true },
36
55
  slug: { label: "URL Slug", description: "URL-friendly identifier" },
37
56
  excerpt: { label: "Excerpt", maxLength: 300 },
38
57
  content: { label: "Content", renderAs: "richText" },
@@ -45,7 +64,7 @@ export const blogPost = defineContentType({
45
64
  });
46
65
 
47
66
  export const author = defineContentType({
48
- name: "author",
67
+ name: "Author",
49
68
  validator: v.object({
50
69
  name: v.string(),
51
70
  slug: v.string(),
@@ -66,7 +85,7 @@ export const author = defineContentType({
66
85
  titleField: "name",
67
86
  slugField: "slug",
68
87
  fields: {
69
- name: { label: "Full Name" },
88
+ name: { label: "Full Name", searchable: true },
70
89
  slug: { label: "URL Slug" },
71
90
  bio: { label: "Biography", renderAs: "richText" },
72
91
  avatar: { label: "Profile Photo", renderAs: "media" },
@@ -77,7 +96,7 @@ export const author = defineContentType({
77
96
  });
78
97
 
79
98
  export const category = defineContentType({
80
- name: "category",
99
+ name: "Category",
81
100
  validator: v.object({
82
101
  name: v.string(),
83
102
  slug: v.string(),
@@ -90,7 +109,7 @@ export const category = defineContentType({
90
109
  titleField: "name",
91
110
  slugField: "slug",
92
111
  fields: {
93
- name: { label: "Category Name" },
112
+ name: { label: "Category Name", searchable: true },
94
113
  slug: { label: "URL Slug" },
95
114
  description: { label: "Description" },
96
115
  color: { label: "Color", description: "Hex color for UI display" },
@@ -98,6 +117,18 @@ export const category = defineContentType({
98
117
  },
99
118
  },
100
119
  });
120
+
121
+ // =============================================================================
122
+ // TYPED HELPERS
123
+ // =============================================================================
124
+ // Create type-safe CRUD helpers for programmatic access.
125
+ // Use these in Convex functions for fully typed data access.
126
+
127
+ export const content = createTypedHelpers(components.cms, {
128
+ blog: blogPost,
129
+ author: author,
130
+ category: category,
131
+ });
101
132
  `;
102
133
  export const BLOG_SCHEMA_DESCRIPTION = "Blog (post, author, category)";
103
134
  //# sourceMappingURL=blog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blog.js","sourceRoot":"","sources":["../../../../src/cli/templates/schemas/blog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FnC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,+BAA+B,CAAC"}
1
+ {"version":3,"file":"blog.js","sourceRoot":"","sources":["../../../../src/cli/templates/schemas/blog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6HhC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,+BAA+B,CAAC"}
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Documentation schema template
2
+ * Documentation cms.ts template
3
3
  *
4
- * Content types: doc_page, doc_section, doc_navigation
4
+ * Content types: Documentation Page, Documentation Section, Navigation Tree
5
+ * Includes typed helpers for programmatic access
5
6
  */
6
- export declare const DOCS_SCHEMA_TEMPLATE = "/**\n * Documentation Content Types\n *\n * Defines the content structure for technical documentation with pages,\n * sections, and navigation. Supports hierarchical organization.\n *\n * Generated by: npx convex-cms init --template docs\n */\n\nimport { v } from \"convex/values\";\nimport { defineContentType } from \"convex-cms\";\n\nexport const docPage = defineContentType({\n name: \"doc_page\",\n validator: v.object({\n title: v.string(),\n slug: v.string(),\n content: v.string(),\n order: v.number(),\n sectionId: v.optional(v.string()),\n parentPageId: v.optional(v.string()),\n description: v.optional(v.string()),\n lastUpdatedBy: v.optional(v.string()),\n tags: v.optional(v.array(v.string())),\n relatedPages: v.optional(v.array(v.string())),\n }),\n meta: {\n displayName: \"Documentation Page\",\n titleField: \"title\",\n slugField: \"slug\",\n fields: {\n title: { label: \"Page Title\", searchable: true },\n slug: { label: \"URL Slug\" },\n content: { label: \"Content\", renderAs: \"richText\", searchable: true },\n order: { label: \"Display Order\" },\n sectionId: { label: \"Section\" },\n parentPageId: { label: \"Parent Page\" },\n description: { label: \"Meta Description\", maxLength: 160 },\n lastUpdatedBy: { label: \"Last Updated By\" },\n tags: { label: \"Tags\", renderAs: \"tags\" },\n relatedPages: { label: \"Related Pages\", renderAs: \"json\" },\n },\n },\n});\n\nexport const docSection = defineContentType({\n name: \"doc_section\",\n validator: v.object({\n name: v.string(),\n slug: v.string(),\n order: v.number(),\n description: v.optional(v.string()),\n icon: v.optional(v.string()),\n isCollapsible: v.optional(v.boolean()),\n defaultExpanded: v.optional(v.boolean()),\n }),\n meta: {\n displayName: \"Documentation Section\",\n titleField: \"name\",\n slugField: \"slug\",\n fields: {\n name: { label: \"Section Name\" },\n slug: { label: \"URL Slug\" },\n order: { label: \"Display Order\" },\n description: { label: \"Description\" },\n icon: { label: \"Icon\", description: \"Icon name or emoji\" },\n isCollapsible: { label: \"Collapsible\" },\n defaultExpanded: { label: \"Expanded by Default\" },\n },\n },\n});\n\nexport const docNavigation = defineContentType({\n name: \"doc_navigation\",\n validator: v.object({\n name: v.string(),\n items: v.array(\n v.object({\n type: v.union(\n v.literal(\"page\"),\n v.literal(\"section\"),\n v.literal(\"link\"),\n v.literal(\"divider\")\n ),\n label: v.optional(v.string()),\n targetId: v.optional(v.string()),\n url: v.optional(v.string()),\n children: v.optional(v.array(v.string())),\n })\n ),\n isDefault: v.optional(v.boolean()),\n }),\n meta: {\n displayName: \"Navigation Tree\",\n titleField: \"name\",\n fields: {\n name: { label: \"Navigation Name\" },\n items: { label: \"Navigation Items\", renderAs: \"json\" },\n isDefault: { label: \"Default Navigation\" },\n },\n },\n});\n";
7
+ export declare const CMS_DOCS_TEMPLATE = "/**\n * CMS Setup - Documentation Template\n *\n * This file defines content types and creates typed helpers for type-safe access.\n *\n * Architecture:\n * - defineContentType() creates schema definitions for the admin API\n * - createTypedHelpers() creates type-safe CRUD helpers for programmatic access\n * - Both work together: definitions go to admin API, helpers provide typed access\n *\n * @example Type-safe queries in Convex functions\n * ```typescript\n * import { content } from \"./cms\";\n *\n * // Fully typed - data fields have correct types\n * const pages = await content.docPage.list(ctx, { status: \"published\" });\n * pages.page[0].data.title; // string\n * ```\n *\n * Generated by: npx convex-cms init --template docs\n */\n\nimport { defineContentType, createTypedHelpers } from \"convex-cms\";\nimport { components } from \"./_generated/api\";\nimport { v } from \"convex/values\";\n\n// =============================================================================\n// CONTENT TYPE DEFINITIONS\n// =============================================================================\n\nexport const docPage = defineContentType({\n name: \"Documentation Page\",\n validator: v.object({\n title: v.string(),\n slug: v.string(),\n content: v.string(),\n order: v.number(),\n sectionId: v.optional(v.string()),\n parentPageId: v.optional(v.string()),\n description: v.optional(v.string()),\n lastUpdatedBy: v.optional(v.string()),\n tags: v.optional(v.array(v.string())),\n relatedPages: v.optional(v.array(v.string())),\n }),\n meta: {\n displayName: \"Documentation Page\",\n titleField: \"title\",\n slugField: \"slug\",\n fields: {\n title: { label: \"Page Title\", searchable: true },\n slug: { label: \"URL Slug\" },\n content: { label: \"Content\", renderAs: \"richText\", searchable: true },\n order: { label: \"Display Order\" },\n sectionId: { label: \"Section\" },\n parentPageId: { label: \"Parent Page\" },\n description: { label: \"Meta Description\", maxLength: 160 },\n lastUpdatedBy: { label: \"Last Updated By\" },\n tags: { label: \"Tags\", renderAs: \"tags\" },\n relatedPages: { label: \"Related Pages\", renderAs: \"json\" },\n },\n },\n});\n\nexport const docSection = defineContentType({\n name: \"Documentation Section\",\n validator: v.object({\n name: v.string(),\n slug: v.string(),\n order: v.number(),\n description: v.optional(v.string()),\n icon: v.optional(v.string()),\n isCollapsible: v.optional(v.boolean()),\n defaultExpanded: v.optional(v.boolean()),\n }),\n meta: {\n displayName: \"Documentation Section\",\n titleField: \"name\",\n slugField: \"slug\",\n fields: {\n name: { label: \"Section Name\", searchable: true },\n slug: { label: \"URL Slug\" },\n order: { label: \"Display Order\" },\n description: { label: \"Description\" },\n icon: { label: \"Icon\", description: \"Icon name or emoji\" },\n isCollapsible: { label: \"Collapsible\" },\n defaultExpanded: { label: \"Expanded by Default\" },\n },\n },\n});\n\nexport const docNavigation = defineContentType({\n name: \"Navigation Tree\",\n validator: v.object({\n name: v.string(),\n items: v.array(\n v.object({\n type: v.union(\n v.literal(\"page\"),\n v.literal(\"section\"),\n v.literal(\"link\"),\n v.literal(\"divider\")\n ),\n label: v.optional(v.string()),\n targetId: v.optional(v.string()),\n url: v.optional(v.string()),\n children: v.optional(v.array(v.string())),\n })\n ),\n isDefault: v.optional(v.boolean()),\n }),\n meta: {\n displayName: \"Navigation Tree\",\n titleField: \"name\",\n fields: {\n name: { label: \"Navigation Name\", searchable: true },\n items: { label: \"Navigation Items\", renderAs: \"json\" },\n isDefault: { label: \"Default Navigation\" },\n },\n },\n});\n\n// =============================================================================\n// TYPED HELPERS\n// =============================================================================\n// Create type-safe CRUD helpers for programmatic access.\n// Use these in Convex functions for fully typed data access.\n\nexport const content = createTypedHelpers(components.cms, {\n docPage: docPage,\n docSection: docSection,\n docNavigation: docNavigation,\n});\n";
7
8
  export declare const DOCS_SCHEMA_DESCRIPTION = "Documentation (page, section, navigation)";
8
9
  //# sourceMappingURL=docs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../../src/cli/templates/schemas/docs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,oBAAoB,goGAsGhC,CAAC;AAEF,eAAO,MAAM,uBAAuB,8CAA8C,CAAC"}
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../../src/cli/templates/schemas/docs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,iBAAiB,k4IAoI7B,CAAC;AAEF,eAAO,MAAM,uBAAuB,8CAA8C,CAAC"}