convex-cms 0.0.8 → 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.
- package/README.md +11 -1
- package/admin/src/components/BulkActionBar.tsx +6 -5
- package/admin/src/components/ContentEntryEditor.tsx +10 -9
- package/admin/src/components/ContentTypeFormModal.tsx +4 -3
- package/admin/src/components/Sidebar.tsx +3 -2
- package/admin/src/components/TaxonomyEditor.tsx +4 -3
- package/admin/src/components/TermTree.tsx +8 -6
- package/admin/src/components/VersionCompare.tsx +3 -2
- package/admin/src/components/VersionHistory.tsx +4 -3
- package/admin/src/components/fields/CategoryField.tsx +3 -2
- package/admin/src/components/fields/MediaField.tsx +6 -5
- package/admin/src/components/fields/ReferenceField.tsx +6 -5
- package/admin/src/components/fields/TagField.tsx +5 -4
- package/admin/src/components/filters/TaxonomyFilter.tsx +4 -3
- package/admin/src/components/media/MediaAssetEditDialog.tsx +4 -3
- package/admin/src/components/media/MediaFolderEditDialog.tsx +3 -2
- package/admin/src/components/media/MediaMoveModal.tsx +4 -3
- package/admin/src/components/media/MediaTaxonomyPicker.tsx +6 -5
- package/admin/src/contexts/SettingsConfigContext.tsx +19 -5
- package/admin/src/embed/contexts/ApiContext.tsx +6 -2
- package/admin/src/routes/__root.tsx +7 -3
- package/admin-dist/nitro.json +1 -1
- package/admin-dist/public/assets/{CmsEmptyState-6-PLaXtD.js → CmsEmptyState-BM4e6N83.js} +1 -1
- package/admin-dist/public/assets/{CmsPageHeader-SoF4Epu9.js → CmsPageHeader-uor3DPIk.js} +1 -1
- package/admin-dist/public/assets/{CmsStatusBadge-D7kYaohx.js → CmsStatusBadge-D8N18LJx.js} +1 -1
- package/admin-dist/public/assets/{CmsSurface-BvksBm6W.js → CmsSurface-BEcY-WpI.js} +1 -1
- package/admin-dist/public/assets/{CmsToolbar-DlZPMe2B.js → CmsToolbar-DE-bu3W8.js} +1 -1
- package/admin-dist/public/assets/ContentEntryEditor-BdkIMCUk.js +4 -0
- package/admin-dist/public/assets/TaxonomyFilter-a1-O9DPs.js +1 -0
- package/admin-dist/public/assets/{_contentTypeId-DTv8UoTp.js → _contentTypeId-XIkYOLyY.js} +1 -1
- package/admin-dist/public/assets/{_entryId-D3lr5Dvy.js → _entryId-DyP15QpI.js} +1 -1
- package/admin-dist/public/assets/{alert-BAHTL6ao.js → alert-DHBQuuib.js} +1 -1
- package/admin-dist/public/assets/{badge-oJv4Eai8.js → badge-BOhWFWzb.js} +1 -1
- package/admin-dist/public/assets/{circle-check-big-3OHxNDhO.js → circle-check-big-DjTNapen.js} +1 -1
- package/admin-dist/public/assets/{command-DwgQs69u.js → command-BIc5_8gL.js} +1 -1
- package/admin-dist/public/assets/content-C3N8Ugra.js +1 -0
- package/admin-dist/public/assets/content-types-D0wh1eUF.js +1 -0
- package/admin-dist/public/assets/{index-DOkgTSx0.js → index-B-g3F_ri.js} +1 -1
- package/admin-dist/public/assets/main-BapBJgQD.js +102 -0
- package/admin-dist/public/assets/media-8uh1MwDi.js +1 -0
- package/admin-dist/public/assets/{new._contentTypeId-VF63rpic.js → new._contentTypeId-S96rFbgY.js} +1 -1
- package/admin-dist/public/assets/{pencil-CX1CiTDD.js → pencil-DgaZav4e.js} +1 -1
- package/admin-dist/public/assets/{refresh-cw-Cm-YOeFI.js → refresh-cw-BBut4hAU.js} +1 -1
- package/admin-dist/public/assets/{rotate-ccw-B45JsL5f.js → rotate-ccw-DVCkojZZ.js} +1 -1
- package/admin-dist/public/assets/{scroll-area-b3A1HHR7.js → scroll-area-DPC4uXzf.js} +1 -1
- package/admin-dist/public/assets/{search-DKKh_DdH.js → search-CSyHHglh.js} +1 -1
- package/admin-dist/public/assets/{settings-CGVDEV1r.js → settings-cEqPsoJ0.js} +1 -1
- package/admin-dist/public/assets/{switch-BTMY8Qnk.js → switch-O2BviO8Q.js} +1 -1
- package/admin-dist/public/assets/{tabs-DUQwUoIb.js → tabs-p1MWhOqY.js} +1 -1
- package/admin-dist/public/assets/{tanstack-adapter-f7AHmQ5L.js → tanstack-adapter-CDrxoPZD.js} +1 -1
- package/admin-dist/public/assets/taxonomies-DJ9UbjXW.js +1 -0
- package/admin-dist/public/assets/{trash-D7e0uKd9.js → trash-RnpP6lXF.js} +1 -1
- package/admin-dist/public/assets/{useBreadcrumbLabel-CF2KYwsw.js → useBreadcrumbLabel-zbIWXlkc.js} +1 -1
- package/admin-dist/public/assets/{usePermissions-DWBImEOW.js → usePermissions-4CTlK-vU.js} +1 -1
- package/admin-dist/server/_chunks/_libs/@floating-ui/core.mjs +71 -65
- package/admin-dist/server/_chunks/_libs/@floating-ui/dom.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@floating-ui/utils.mjs +8 -8
- package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +12 -30
- package/admin-dist/server/_chunks/_libs/@tanstack/react-store.mjs +1 -56
- package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +130 -114
- package/admin-dist/server/_chunks/_libs/@tanstack/store.mjs +1 -134
- package/admin-dist/server/_chunks/_libs/react-dom.mjs +5 -5
- package/admin-dist/server/_chunks/_libs/react.mjs +1 -1
- package/admin-dist/server/_libs/isbot.mjs +1 -1
- package/admin-dist/server/_libs/use-sync-external-store.mjs +1 -76
- package/admin-dist/server/_ssr/{CmsEmptyState-BM8DghTl.mjs → CmsEmptyState-BA0Lc5xs.mjs} +1 -1
- package/admin-dist/server/_ssr/{CmsPageHeader-BHUmrIWD.mjs → CmsPageHeader-PMyecILZ.mjs} +1 -1
- package/admin-dist/server/_ssr/{CmsStatusBadge-D0Zb0oRl.mjs → CmsStatusBadge-CInuN2bZ.mjs} +2 -2
- package/admin-dist/server/_ssr/{CmsSurface-B2eBr-47.mjs → CmsSurface-CH1PIfcS.mjs} +1 -1
- package/admin-dist/server/_ssr/{CmsToolbar-BCrwg7OL.mjs → CmsToolbar-IuhSA7gR.mjs} +1 -1
- package/admin-dist/server/_ssr/{ContentEntryEditor-Cjfm0uhr.mjs → ContentEntryEditor-Bzhir4fQ.mjs} +38 -31
- package/admin-dist/server/_ssr/{TaxonomyFilter-C4pD0kfM.mjs → TaxonomyFilter-r4izSMBh.mjs} +6 -5
- package/admin-dist/server/_ssr/{_contentTypeId-CiDiX-p7.mjs → _contentTypeId-BWEbjqxY.mjs} +11 -13
- package/admin-dist/server/_ssr/{_entryId-9GxatOkL.mjs → _entryId-B5xoXoJf.mjs} +12 -14
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-CBTan6ii.mjs +4 -0
- package/admin-dist/server/_ssr/{badge-EI998zba.mjs → badge-DXrjBRqZ.mjs} +1 -1
- package/admin-dist/server/_ssr/{command-BLAWQhUw.mjs → command-Cj90OdCX.mjs} +1 -1
- package/admin-dist/server/_ssr/config.server-BOr7Jxr4.mjs +0 -3
- package/admin-dist/server/_ssr/{content-BHX39L4D.mjs → content-DKRI-YqL.mjs} +14 -15
- package/admin-dist/server/_ssr/{content-types-DCzrBhTH.mjs → content-types-BzgRcS8K.mjs} +7 -9
- package/admin-dist/server/_ssr/{index-DwM_5VNP.mjs → index-BPf6_agY.mjs} +4 -6
- package/admin-dist/server/_ssr/index.mjs +11 -10
- package/admin-dist/server/_ssr/{media-CbzgTRRQ.mjs → media-MpjxOZL8.mjs} +23 -21
- package/admin-dist/server/_ssr/{new._contentTypeId-6Ph-Gtlw.mjs → new._contentTypeId-DSb4qR9j.mjs} +11 -13
- package/admin-dist/server/_ssr/{router-vd1nySeP.mjs → router-Dk9ikPNc.mjs} +61 -47
- package/admin-dist/server/_ssr/{scroll-area--B9snFTJ.mjs → scroll-area-JwVD_6MZ.mjs} +1 -1
- package/admin-dist/server/_ssr/{settings-DlTO2JSj.mjs → settings-KVJNe0GM.mjs} +8 -10
- package/admin-dist/server/_ssr/{switch-C05NgNW0.mjs → switch-DvREvRv4.mjs} +1 -1
- package/admin-dist/server/_ssr/{tabs-DAk2J5xy.mjs → tabs-B0h57pFf.mjs} +1 -1
- package/admin-dist/server/_ssr/{tanstack-adapter-DWbaPByn.mjs → tanstack-adapter-gmM64LnW.mjs} +1 -1
- package/admin-dist/server/_ssr/{taxonomies-B8nqce6u.mjs → taxonomies-BbBNx260.mjs} +17 -16
- package/admin-dist/server/_ssr/{trash-zdlZgpTo.mjs → trash-JAzYGh7A.mjs} +8 -10
- package/admin-dist/server/_ssr/{useBreadcrumbLabel-DpEKyG1h.mjs → useBreadcrumbLabel-BWIujj97.mjs} +1 -1
- package/admin-dist/server/_ssr/{usePermissions-olYRd9S9.mjs → usePermissions-CcLDCSwa.mjs} +1 -1
- package/admin-dist/server/index.mjs +162 -162
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +18 -29
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/templates/admin.d.ts +4 -3
- package/dist/cli/templates/admin.d.ts.map +1 -1
- package/dist/cli/templates/admin.js +152 -195
- package/dist/cli/templates/admin.js.map +1 -1
- package/dist/cli/templates/cmsClient.d.ts +2 -2
- package/dist/cli/templates/cmsClient.d.ts.map +1 -1
- package/dist/cli/templates/cmsClient.js +58 -27
- package/dist/cli/templates/cmsClient.js.map +1 -1
- package/dist/cli/templates/content.d.ts +10 -0
- package/dist/cli/templates/content.d.ts.map +1 -0
- package/dist/cli/templates/content.js +257 -0
- package/dist/cli/templates/content.js.map +1 -0
- package/dist/cli/templates/index.d.ts +3 -2
- package/dist/cli/templates/index.d.ts.map +1 -1
- package/dist/cli/templates/index.js +3 -2
- package/dist/cli/templates/index.js.map +1 -1
- package/dist/cli/templates/schemas/blog.d.ts +4 -3
- package/dist/cli/templates/schemas/blog.d.ts.map +1 -1
- package/dist/cli/templates/schemas/blog.js +44 -13
- package/dist/cli/templates/schemas/blog.js.map +1 -1
- package/dist/cli/templates/schemas/docs.d.ts +4 -3
- package/dist/cli/templates/schemas/docs.d.ts.map +1 -1
- package/dist/cli/templates/schemas/docs.js +43 -12
- package/dist/cli/templates/schemas/docs.js.map +1 -1
- package/dist/cli/templates/schemas/index.d.ts +6 -4
- package/dist/cli/templates/schemas/index.d.ts.map +1 -1
- package/dist/cli/templates/schemas/index.js +6 -4
- package/dist/cli/templates/schemas/index.js.map +1 -1
- package/dist/cli/templates/schemas/landing.d.ts +4 -3
- package/dist/cli/templates/schemas/landing.d.ts.map +1 -1
- package/dist/cli/templates/schemas/landing.js +62 -15
- package/dist/cli/templates/schemas/landing.js.map +1 -1
- package/dist/cli/utils/fileUtils.d.ts.map +1 -1
- package/dist/cli/utils/fileUtils.js +6 -5
- package/dist/cli/utils/fileUtils.js.map +1 -1
- package/dist/client/admin/index.d.ts +2 -1
- package/dist/client/admin/index.d.ts.map +1 -1
- package/dist/client/admin/index.js.map +1 -1
- package/dist/client/admin/types.d.ts +14 -1
- package/dist/client/admin/types.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/react/index.d.ts +176 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +162 -0
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
- package/admin-dist/public/assets/ContentEntryEditor-C6n9xLS9.js +0 -4
- package/admin-dist/public/assets/TaxonomyFilter-CFX1_g8s.js +0 -1
- package/admin-dist/public/assets/content-CKQ4QwW2.js +0 -1
- package/admin-dist/public/assets/content-types-BrttaLpc.js +0 -1
- package/admin-dist/public/assets/main-DV6oxWnU.js +0 -102
- package/admin-dist/public/assets/media-B2i-mCbx.js +0 -1
- package/admin-dist/public/assets/taxonomies-DvMppdiD.js +0 -1
- 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
|
-
*
|
|
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
|
-
*
|
|
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 {
|
|
18
|
+
* import { content } from "./cms";
|
|
15
19
|
*
|
|
16
|
-
* //
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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 {
|
|
29
|
-
import { v } from "convex/values";
|
|
26
|
+
import { defineContentType, createTypedHelpers } from "convex-cms";
|
|
30
27
|
import { components } from "./_generated/api";
|
|
31
|
-
import
|
|
28
|
+
import { v } from "convex/values";
|
|
32
29
|
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
export const blogPost = cms.defineContent({
|
|
37
|
+
export const blogPost = defineContentType({
|
|
37
38
|
name: "Blog Post",
|
|
38
|
-
|
|
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
|
-
|
|
46
|
+
meta: {
|
|
47
|
+
displayName: "Blog Post",
|
|
44
48
|
titleField: "title",
|
|
45
|
-
|
|
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
|
-
//
|
|
50
|
-
|
|
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
|
-
|
|
53
|
-
|
|
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
|
|
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 {
|
|
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;
|
|
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 {
|
|
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;
|
|
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
|
|
2
|
+
* Blog cms.ts template
|
|
3
3
|
*
|
|
4
|
-
* Content types:
|
|
4
|
+
* Content types: Blog Post, Author, Category
|
|
5
|
+
* Includes typed helpers for programmatic access
|
|
5
6
|
*/
|
|
6
|
-
export declare const
|
|
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
|
|
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
|
|
2
|
+
* Blog cms.ts template
|
|
3
3
|
*
|
|
4
|
-
* Content types:
|
|
4
|
+
* Content types: Blog Post, Author, Category
|
|
5
|
+
* Includes typed helpers for programmatic access
|
|
5
6
|
*/
|
|
6
|
-
export const
|
|
7
|
-
* Blog
|
|
7
|
+
export const CMS_BLOG_TEMPLATE = `/**
|
|
8
|
+
* CMS Setup - Blog Template
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// CONTENT TYPE DEFINITIONS
|
|
35
|
+
// =============================================================================
|
|
17
36
|
|
|
18
37
|
export const blogPost = defineContentType({
|
|
19
|
-
name: "
|
|
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: "
|
|
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: "
|
|
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
|
|
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
|
|
2
|
+
* Documentation cms.ts template
|
|
3
3
|
*
|
|
4
|
-
* Content types:
|
|
4
|
+
* Content types: Documentation Page, Documentation Section, Navigation Tree
|
|
5
|
+
* Includes typed helpers for programmatic access
|
|
5
6
|
*/
|
|
6
|
-
export declare const
|
|
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
|
|
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"}
|