@agility/create-next-app 1.0.0-beta.2

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 (213) hide show
  1. package/.claude/settings.json +7 -0
  2. package/.claude/settings.local.json +24 -0
  3. package/FEATURE_ROADMAP.md +343 -0
  4. package/README.md +205 -0
  5. package/TESTING.md +131 -0
  6. package/bin/create-agility-app.js +48 -0
  7. package/dist/agility/api-keys/generateApiKeys.d.ts +9 -0
  8. package/dist/agility/api-keys/generateApiKeys.d.ts.map +1 -0
  9. package/dist/agility/api-keys/generateApiKeys.js +99 -0
  10. package/dist/agility/api-keys/generateApiKeys.js.map +1 -0
  11. package/dist/agility/api-keys/getApiKeys.d.ts +9 -0
  12. package/dist/agility/api-keys/getApiKeys.d.ts.map +1 -0
  13. package/dist/agility/api-keys/getApiKeys.js +14 -0
  14. package/dist/agility/api-keys/getApiKeys.js.map +1 -0
  15. package/dist/agility/index.d.ts +3 -0
  16. package/dist/agility/index.d.ts.map +1 -0
  17. package/dist/agility/index.js +8 -0
  18. package/dist/agility/index.js.map +1 -0
  19. package/dist/agility/instance/createNewInstance.d.ts +8 -0
  20. package/dist/agility/instance/createNewInstance.d.ts.map +1 -0
  21. package/dist/agility/instance/createNewInstance.js +65 -0
  22. package/dist/agility/instance/createNewInstance.js.map +1 -0
  23. package/dist/agility/instance/getAvailableInstances.d.ts +8 -0
  24. package/dist/agility/instance/getAvailableInstances.d.ts.map +1 -0
  25. package/dist/agility/instance/getAvailableInstances.js +43 -0
  26. package/dist/agility/instance/getAvailableInstances.js.map +1 -0
  27. package/dist/agility/instance/manageInstance.d.ts +9 -0
  28. package/dist/agility/instance/manageInstance.d.ts.map +1 -0
  29. package/dist/agility/instance/manageInstance.js +82 -0
  30. package/dist/agility/instance/manageInstance.js.map +1 -0
  31. package/dist/agility/utils/getMgmtAPIUrl.d.ts +20 -0
  32. package/dist/agility/utils/getMgmtAPIUrl.d.ts.map +1 -0
  33. package/dist/agility/utils/getMgmtAPIUrl.js +61 -0
  34. package/dist/agility/utils/getMgmtAPIUrl.js.map +1 -0
  35. package/dist/auth/api-key/authenticateWithApiKey.d.ts +6 -0
  36. package/dist/auth/api-key/authenticateWithApiKey.d.ts.map +1 -0
  37. package/dist/auth/api-key/authenticateWithApiKey.js +28 -0
  38. package/dist/auth/api-key/authenticateWithApiKey.js.map +1 -0
  39. package/dist/auth/index.d.ts +3 -0
  40. package/dist/auth/index.d.ts.map +1 -0
  41. package/dist/auth/index.js +8 -0
  42. package/dist/auth/index.js.map +1 -0
  43. package/dist/auth/oauth/authenticate.d.ts +6 -0
  44. package/dist/auth/oauth/authenticate.d.ts.map +1 -0
  45. package/dist/auth/oauth/authenticate.js +162 -0
  46. package/dist/auth/oauth/authenticate.js.map +1 -0
  47. package/dist/auth/oauth/constants.d.ts +5 -0
  48. package/dist/auth/oauth/constants.d.ts.map +1 -0
  49. package/dist/auth/oauth/constants.js +9 -0
  50. package/dist/auth/oauth/constants.js.map +1 -0
  51. package/dist/auth/oauth/exchangeCodeForToken.d.ts +7 -0
  52. package/dist/auth/oauth/exchangeCodeForToken.d.ts.map +1 -0
  53. package/dist/auth/oauth/exchangeCodeForToken.js +39 -0
  54. package/dist/auth/oauth/exchangeCodeForToken.js.map +1 -0
  55. package/dist/cli/index.d.ts +3 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +290 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/cli/promptForMissingOptions.d.ts +8 -0
  60. package/dist/cli/promptForMissingOptions.d.ts.map +1 -0
  61. package/dist/cli/promptForMissingOptions.js +92 -0
  62. package/dist/cli/promptForMissingOptions.js.map +1 -0
  63. package/dist/config/env/createEnvFile.d.ts +6 -0
  64. package/dist/config/env/createEnvFile.d.ts.map +1 -0
  65. package/dist/config/env/createEnvFile.js +31 -0
  66. package/dist/config/env/createEnvFile.js.map +1 -0
  67. package/dist/config/index.d.ts +2 -0
  68. package/dist/config/index.d.ts.map +1 -0
  69. package/dist/config/index.js +6 -0
  70. package/dist/config/index.js.map +1 -0
  71. package/dist/config/mcp/createMcpConfig.d.ts +5 -0
  72. package/dist/config/mcp/createMcpConfig.d.ts.map +1 -0
  73. package/dist/config/mcp/createMcpConfig.js +32 -0
  74. package/dist/config/mcp/createMcpConfig.js.map +1 -0
  75. package/dist/config/packages/installAgilityPackages.d.ts +6 -0
  76. package/dist/config/packages/installAgilityPackages.d.ts.map +1 -0
  77. package/dist/config/packages/installAgilityPackages.js +61 -0
  78. package/dist/config/packages/installAgilityPackages.js.map +1 -0
  79. package/dist/config/setupProject.d.ts +8 -0
  80. package/dist/config/setupProject.d.ts.map +1 -0
  81. package/dist/config/setupProject.js +32 -0
  82. package/dist/config/setupProject.js.map +1 -0
  83. package/dist/create-next-app/createNextApp.d.ts +9 -0
  84. package/dist/create-next-app/createNextApp.d.ts.map +1 -0
  85. package/dist/create-next-app/createNextApp.js +83 -0
  86. package/dist/create-next-app/createNextApp.js.map +1 -0
  87. package/dist/create-next-app/index.d.ts +3 -0
  88. package/dist/create-next-app/index.d.ts.map +1 -0
  89. package/dist/create-next-app/index.js +8 -0
  90. package/dist/create-next-app/index.js.map +1 -0
  91. package/dist/scaffold/components/createPageComponents.d.ts +6 -0
  92. package/dist/scaffold/components/createPageComponents.d.ts.map +1 -0
  93. package/dist/scaffold/components/createPageComponents.js +62 -0
  94. package/dist/scaffold/components/createPageComponents.js.map +1 -0
  95. package/dist/scaffold/containers/createContainers.d.ts +6 -0
  96. package/dist/scaffold/containers/createContainers.d.ts.map +1 -0
  97. package/dist/scaffold/containers/createContainers.js +48 -0
  98. package/dist/scaffold/containers/createContainers.js.map +1 -0
  99. package/dist/scaffold/index.d.ts +2 -0
  100. package/dist/scaffold/index.d.ts.map +1 -0
  101. package/dist/scaffold/index.js +6 -0
  102. package/dist/scaffold/index.js.map +1 -0
  103. package/dist/scaffold/instance/createBlankInstance.d.ts +8 -0
  104. package/dist/scaffold/instance/createBlankInstance.d.ts.map +1 -0
  105. package/dist/scaffold/instance/createBlankInstance.js +51 -0
  106. package/dist/scaffold/instance/createBlankInstance.js.map +1 -0
  107. package/dist/scaffold/models/createContentModels.d.ts +6 -0
  108. package/dist/scaffold/models/createContentModels.d.ts.map +1 -0
  109. package/dist/scaffold/models/createContentModels.js +70 -0
  110. package/dist/scaffold/models/createContentModels.js.map +1 -0
  111. package/dist/templates/copyDirectory.d.ts +5 -0
  112. package/dist/templates/copyDirectory.d.ts.map +1 -0
  113. package/dist/templates/copyDirectory.js +28 -0
  114. package/dist/templates/copyDirectory.js.map +1 -0
  115. package/dist/templates/copyTemplates.d.ts +8 -0
  116. package/dist/templates/copyTemplates.d.ts.map +1 -0
  117. package/dist/templates/copyTemplates.js +58 -0
  118. package/dist/templates/copyTemplates.js.map +1 -0
  119. package/dist/templates/index.d.ts +2 -0
  120. package/dist/templates/index.d.ts.map +1 -0
  121. package/dist/templates/index.js +6 -0
  122. package/dist/templates/index.js.map +1 -0
  123. package/dist/types/index.d.ts +50 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/index.js +3 -0
  126. package/dist/types/index.js.map +1 -0
  127. package/dist/utils/git.d.ts +9 -0
  128. package/dist/utils/git.d.ts.map +1 -0
  129. package/dist/utils/git.js +71 -0
  130. package/dist/utils/git.js.map +1 -0
  131. package/dist/utils/validation.d.ts +45 -0
  132. package/dist/utils/validation.d.ts.map +1 -0
  133. package/dist/utils/validation.js +180 -0
  134. package/dist/utils/validation.js.map +1 -0
  135. package/package.json +45 -0
  136. package/src/agility/api-keys/generateApiKeys.ts +100 -0
  137. package/src/agility/api-keys/getApiKeys.ts +13 -0
  138. package/src/agility/index.ts +3 -0
  139. package/src/agility/instance/createNewInstance.ts +67 -0
  140. package/src/agility/instance/getAvailableInstances.ts +49 -0
  141. package/src/agility/instance/manageInstance.ts +90 -0
  142. package/src/agility/utils/getMgmtAPIUrl.ts +68 -0
  143. package/src/auth/api-key/authenticateWithApiKey.ts +24 -0
  144. package/src/auth/index.ts +3 -0
  145. package/src/auth/oauth/authenticate.ts +165 -0
  146. package/src/auth/oauth/constants.ts +6 -0
  147. package/src/auth/oauth/exchangeCodeForToken.ts +43 -0
  148. package/src/cli/index.ts +281 -0
  149. package/src/cli/promptForMissingOptions.ts +104 -0
  150. package/src/config/env/createEnvFile.ts +30 -0
  151. package/src/config/index.ts +2 -0
  152. package/src/config/mcp/createMcpConfig.ts +30 -0
  153. package/src/config/packages/installAgilityPackages.ts +63 -0
  154. package/src/config/setupProject.ts +31 -0
  155. package/src/create-next-app/createNextApp.ts +75 -0
  156. package/src/create-next-app/index.ts +3 -0
  157. package/src/scaffold/components/createPageComponents.ts +74 -0
  158. package/src/scaffold/containers/createContainers.ts +55 -0
  159. package/src/scaffold/index.ts +2 -0
  160. package/src/scaffold/instance/createBlankInstance.ts +55 -0
  161. package/src/scaffold/models/createContentModels.ts +83 -0
  162. package/src/templates/copyDirectory.ts +24 -0
  163. package/src/templates/copyTemplates.ts +57 -0
  164. package/src/templates/index.ts +2 -0
  165. package/src/types/index.ts +55 -0
  166. package/src/utils/git.ts +74 -0
  167. package/src/utils/validation.ts +184 -0
  168. package/templates/.claude/QUICK-START.md +230 -0
  169. package/templates/.claude/README.md +32 -0
  170. package/templates/.claude/settings.json +8 -0
  171. package/templates/BLANK-INSTANCE-SETUP.md +375 -0
  172. package/templates/DEVELOPMENT.md +160 -0
  173. package/templates/EXAMPLE-PROMPTS.md +643 -0
  174. package/templates/PROMPTS.md +410 -0
  175. package/templates/README.md +281 -0
  176. package/templates/agents.md +429 -0
  177. package/templates/app/[locale]/[...slug]/error.tsx +17 -0
  178. package/templates/app/[locale]/[...slug]/not-found.tsx +9 -0
  179. package/templates/app/[locale]/[...slug]/page.tsx +102 -0
  180. package/templates/app/[locale]/layout.tsx +22 -0
  181. package/templates/app/[locale]/page.tsx +12 -0
  182. package/templates/app/api/dynamic-redirect/route.ts +24 -0
  183. package/templates/app/api/preview/exit/route.ts +34 -0
  184. package/templates/app/api/preview/route.ts +63 -0
  185. package/templates/app/api/revalidate/route.ts +118 -0
  186. package/templates/components/agility-components/RichTextArea.tsx +66 -0
  187. package/templates/components/agility-components/index.ts +30 -0
  188. package/templates/components/agility-pages/MainTemplate.tsx +36 -0
  189. package/templates/components/agility-pages/index.ts +11 -0
  190. package/templates/docs/01-agility-cms-overview.md +139 -0
  191. package/templates/docs/02-page-routing.md +251 -0
  192. package/templates/docs/03-creating-components.md +462 -0
  193. package/templates/docs/04-data-fetching.md +484 -0
  194. package/templates/docs/05-containers-and-lists.md +596 -0
  195. package/templates/docs/06-localization.md +561 -0
  196. package/templates/docs/07-caching-strategies.md +410 -0
  197. package/templates/docs/08-common-components.md +756 -0
  198. package/templates/docs/09-whats-included.md +279 -0
  199. package/templates/docs/10-mcp-server-setup.md +153 -0
  200. package/templates/docs/11-linked-nested-content.md +611 -0
  201. package/templates/docs/README.md +164 -0
  202. package/templates/lib/cms/getAgilityContext.ts +28 -0
  203. package/templates/lib/cms/getAgilityPage.ts +51 -0
  204. package/templates/lib/cms/getAgilitySDK.ts +22 -0
  205. package/templates/lib/cms/getContentItem.ts +20 -0
  206. package/templates/lib/cms/getContentList.ts +19 -0
  207. package/templates/lib/cms/getRedirections.ts +85 -0
  208. package/templates/lib/cms/getSitemapFlat.ts +19 -0
  209. package/templates/lib/cms/getSitemapNested.ts +19 -0
  210. package/templates/lib/env.ts +99 -0
  211. package/templates/lib/i18n/config.ts +28 -0
  212. package/templates/proxy.ts +101 -0
  213. package/tsconfig.json +21 -0
@@ -0,0 +1,63 @@
1
+ import { localizeUrl } from "@/lib/i18n/localizeUrl";
2
+ import { validatePreview, getDynamicPageURL } from "@agility/nextjs/node";
3
+ import { draftMode } from 'next/headers'
4
+ import { NextRequest, NextResponse } from "next/server";
5
+
6
+
7
+ /**
8
+ * This endpoint is used as a rewrite for preview requests from middleware.
9
+ * Therefore, the URL will be the original preview request url...
10
+ * @param request
11
+ * @param res
12
+ * @returns
13
+ */
14
+ export async function GET(request: NextRequest) {
15
+
16
+ const searchParams = request.nextUrl.searchParams
17
+
18
+ const agilityPreviewKey = searchParams.get("agilitypreviewkey") || ""
19
+
20
+ //locale is also passed in the querystring on preview requests
21
+ const locale = searchParams.get("locale") || searchParams.get("lang")
22
+ const slug = searchParams.get("slug") || "/"
23
+
24
+ const ContentID = searchParams.get('ContentID')
25
+
26
+ //validate our preview key, also validate the requested page to preview exists
27
+ const validationResp = await validatePreview({
28
+ agilityPreviewKey,
29
+ slug
30
+ });
31
+
32
+
33
+ if (validationResp.error) {
34
+ return NextResponse.json({ message: validationResp.message }, { status: 401 });
35
+ }
36
+
37
+ let previewUrl = slug
38
+ if (locale) previewUrl = localizeUrl(slug, locale);
39
+
40
+ //if we have a content id, get the dynamic page url for it
41
+ if (ContentID) {
42
+ const dynamicPath = await getDynamicPageURL({ contentID: Number(ContentID), preview: true, slug: slug || undefined });
43
+ if (dynamicPath) {
44
+ previewUrl = dynamicPath;
45
+ }
46
+
47
+ }
48
+
49
+ //enable draft/preview mode
50
+ (await draftMode()).enable()
51
+
52
+ // Redirect to the slug
53
+ // Construct an absolute URL for the redirect
54
+ const baseUrl = `${request.nextUrl.protocol}//${request.nextUrl.host}`;
55
+ let url = `${baseUrl}${previewUrl}`;
56
+ if (url.includes("?")) {
57
+ url = `${url}&preview=1`;
58
+ } else {
59
+ url = `${url}?preview=1`;
60
+ }
61
+
62
+ return NextResponse.redirect(url, 307);
63
+ }
@@ -0,0 +1,118 @@
1
+
2
+
3
+ import { revalidatePath, revalidateTag } from "next/cache";
4
+ import { NextRequest, NextResponse } from "next/server";
5
+ import agilitySDK from "@agility/content-fetch"
6
+ import type { SitemapNode } from "@/lib/types/SitemapNode";
7
+
8
+ interface IRevalidateRequest {
9
+ state: string,
10
+ instanceGuid: string
11
+ languageCode?: string
12
+ referenceName?: string
13
+ contentID?: number
14
+ contentVersionID?: number
15
+ pageID?: number
16
+ pageVersionID?: number
17
+ changeDateUTC?: string
18
+ }
19
+
20
+ export async function POST(req: NextRequest) {
21
+
22
+ //parse the body
23
+ const data = await req.json() as IRevalidateRequest
24
+
25
+
26
+ //only process publish events
27
+ if (data.state === "Published") {
28
+
29
+ let sitemapFlat: {
30
+ [path: string]: SitemapNode
31
+ } = {}
32
+
33
+ //grab the sitemap flat so we can revalidate the full path if needed
34
+ if (data.contentID || data.pageID) {
35
+ const apiKey = process.env.AGILITY_API_FETCH_KEY
36
+
37
+ const agilityClient = agilitySDK.getApi({
38
+ guid: process.env.AGILITY_GUID,
39
+ apiKey
40
+ })
41
+
42
+ const languageCode = process.env.AGILITY_LOCALES || "en-us"
43
+
44
+ //don't cache the sitemap here... we want to get the latest
45
+ agilityClient.config.fetchConfig = {
46
+ cache: "no-store"
47
+ }
48
+
49
+
50
+ sitemapFlat = await agilityClient.getSitemapFlat({
51
+ channelName: process.env.AGILITY_SITEMAP || "website",
52
+ languageCode
53
+ })
54
+ }
55
+
56
+ //revalidate the correct tags based on what changed
57
+ if (data.referenceName) {
58
+ //content item change
59
+ const itemTag = `agility-content-${data.referenceName.toLowerCase()}-${data.languageCode}`
60
+ const listTag = `agility-content-${data.contentID}-${data.languageCode}`
61
+ revalidateTag(itemTag)
62
+ revalidateTag(listTag)
63
+
64
+ console.info("Revalidating content tags:", itemTag, listTag)
65
+
66
+ //grab the sitemap and check if this content is in there so we can revalidate a full path
67
+ if (sitemapFlat) {
68
+ const sitemapNode = Object.values(sitemapFlat).find(s => s.contentID === data.contentID)
69
+ if (sitemapNode) {
70
+ const path = sitemapNode.path
71
+ revalidatePath(path)
72
+ console.info("Revalidating path:", path)
73
+
74
+ }
75
+ }
76
+
77
+
78
+ } else if (data.pageID !== undefined && data.pageID > 0) {
79
+ //page change
80
+ const pageTag = `agility-page-${data.pageID}-${data.languageCode}`
81
+ revalidateTag(pageTag)
82
+
83
+
84
+ //also revalidate the sitemaps
85
+ const sitemapTagFlat = `agility-sitemap-flat-${data.languageCode}`
86
+ const sitemapTagNested = `agility-sitemap-nested-${data.languageCode}`
87
+ revalidateTag(sitemapTagFlat)
88
+ revalidateTag(sitemapTagNested)
89
+
90
+ console.info("Revalidating page and sitemap tags:", pageTag, sitemapTagFlat, sitemapTagNested)
91
+
92
+ if (sitemapFlat) {
93
+ const sitemapNode = Object.values(sitemapFlat).find(s => s.pageID === data.pageID)
94
+ if (sitemapNode) {
95
+ const path = sitemapNode.path
96
+ revalidatePath(path)
97
+ console.info("Revalidating path:", path)
98
+
99
+ }
100
+ }
101
+ }
102
+ } else if (data.contentID === undefined && data.pageID === undefined) {
103
+ //if no content or page id is provided, it's for a URL redirection
104
+ //trigger the rebuild hook for netlify's rebuild...
105
+ const hookUrl = process.env.BUILD_HOOK_URL
106
+ if (hookUrl) {
107
+ await fetch(hookUrl, {
108
+ method: 'POST'
109
+ })
110
+ }
111
+ }
112
+
113
+ return new Response(`OK`, {
114
+ status: 200
115
+ })
116
+
117
+
118
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * RichTextArea Component
3
+ *
4
+ * An Agility CMS module component that displays rich text content.
5
+ * This component fetches a content item from Agility CMS and renders
6
+ * the HTML content with proper styling and Agility CMS data attributes
7
+ * for in-context editing.
8
+ */
9
+
10
+ import { getContentItem } from "@/lib/cms/getContentItem"
11
+ import { renderHTML, type UnloadedModuleProps } from "@agility/nextjs"
12
+
13
+ /**
14
+ * Interface defining the structure of the RichText content item fields.
15
+ * The field name must match the field reference name in Agility CMS.
16
+ */
17
+ export interface RichText {
18
+ textblob: string
19
+ }
20
+
21
+ /**
22
+ * RichTextArea Component
23
+ *
24
+ * Fetches and renders rich text content from Agility CMS.
25
+ *
26
+ * @param module - The Agility CMS module object containing contentID
27
+ * @param languageCode - The language code for localized content
28
+ * @returns A section element with the rendered rich text content
29
+ *
30
+ * @remarks
31
+ * - Uses `data-agility-component` attribute for Agility CMS component identification
32
+ * - Uses `data-agility-field` and `data-agility-html` attributes for in-context editing
33
+ * - Applies Tailwind CSS prose classes for typography styling
34
+ * - Supports responsive typography sizing (sm, lg, xl)
35
+ * - Includes dark mode support via `dark:prose-invert`
36
+ */
37
+ const RichTextArea = async ({ module, languageCode }: UnloadedModuleProps) => {
38
+ // Fetch the content item from Agility CMS
39
+ const {
40
+ fields: { textblob },
41
+ contentID,
42
+ } = await getContentItem<RichText>({
43
+ contentID: module.contentid,
44
+ languageCode,
45
+ })
46
+
47
+ return (
48
+ <section id={`${contentID}`} className="relative px-8" data-agility-component={contentID}>
49
+ <div className="max-w-2xl mx-auto my-12 md:mt-18 lg:mt-20">
50
+ {/*
51
+ Rich text content container with Agility CMS editing attributes.
52
+ The renderHTML function sanitizes and prepares the HTML for safe rendering.
53
+ */}
54
+ <div
55
+ data-agility-field="textblob"
56
+ data-agility-html
57
+ className="my-6 prose prose-sm sm:prose lg:prose-lg xl:prose-xl max-w-full dark:prose-invert"
58
+ dangerouslySetInnerHTML={renderHTML(textblob)}
59
+ ></div>
60
+ </div>
61
+ </section>
62
+ )
63
+ }
64
+
65
+ export default RichTextArea
66
+
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Agility CMS Module Components
3
+ *
4
+ * This file exports a getModule function that maps Agility CMS module names
5
+ * to their corresponding React components. When a module is rendered in a
6
+ * ContentZone, this function is called to retrieve the appropriate component.
7
+ *
8
+ * To add a new module component:
9
+ * 1. Create a new component file in this directory (e.g., MyComponent.tsx)
10
+ * 2. Import it at the top of this file
11
+ * 3. Add a case in the switch statement below with the module's reference name
12
+ */
13
+
14
+ import RichTextArea from "./RichTextArea"
15
+
16
+ /**
17
+ * Returns the React component for a given Agility CMS module name.
18
+ *
19
+ * @param moduleName - The reference name of the module as defined in Agility CMS
20
+ * @returns The React component for the module, or null if not found
21
+ */
22
+ export const getModule = (moduleName: string) => {
23
+ switch (moduleName) {
24
+ case "RichTextArea":
25
+ return RichTextArea
26
+ default:
27
+ return null
28
+ }
29
+ }
30
+
@@ -0,0 +1,36 @@
1
+ /**
2
+ * MainTemplate Component
3
+ *
4
+ * The default page template for Agility CMS pages. This template defines
5
+ * the main content zone where modules can be added and rendered.
6
+ *
7
+ * The ContentZone component handles the rendering of all modules added to
8
+ * the "main-content-zone" in Agility CMS, using the getModule function to
9
+ * map module names to their corresponding React components.
10
+ */
11
+
12
+ import React from "react"
13
+ import { ContentZone } from "@agility/nextjs"
14
+ import { getModule } from "../agility-components"
15
+
16
+ /**
17
+ * MainTemplate Component
18
+ *
19
+ * Renders the main content zone for an Agility CMS page.
20
+ *
21
+ * @param props - Agility CMS page props including page data, sitemap, etc.
22
+ * @returns A ContentZone component that renders all modules in the main-content-zone
23
+ *
24
+ * @remarks
25
+ * - The ContentZone name "main-content-zone" must match the zone name in Agility CMS
26
+ * - The getModule function is used to resolve module components by their reference name
27
+ * - All props are spread to the ContentZone for proper context passing
28
+ */
29
+ const MainTemplate = (props: any) => {
30
+ return (
31
+ <ContentZone name="main-content-zone" {...props} getModule={getModule} />
32
+ )
33
+ }
34
+
35
+ export default MainTemplate
36
+
@@ -0,0 +1,11 @@
1
+ import MainTemplate from "./MainTemplate"
2
+
3
+ export const getPageTemplate = (templateName: string) => {
4
+ switch (templateName) {
5
+ case "MainTemplate":
6
+ return MainTemplate
7
+ default:
8
+ return MainTemplate
9
+ }
10
+ }
11
+
@@ -0,0 +1,139 @@
1
+ # Agility CMS Overview
2
+
3
+ This Next.js project is integrated with Agility CMS, a headless content management system. This document provides an overview of how Agility CMS works in this project.
4
+
5
+ ## What is Agility CMS?
6
+
7
+ Agility CMS is a headless CMS that provides:
8
+ - **Content Management**: Create and manage content using a web-based interface
9
+ - **Page Management**: Build pages by combining components (called "modules" in CMS)
10
+ - **Multi-locale Support**: Manage content in multiple languages
11
+ - **API Access**: Fetch content via REST API or SDK
12
+ - **Preview Mode**: Preview draft content before publishing
13
+
14
+ ## Key Concepts
15
+
16
+ ### 1. Pages
17
+ Pages in Agility CMS are composed of:
18
+ - **Title and SEO**: Meta title, description, keywords
19
+ - **Template**: Defines the layout structure (e.g., MainTemplate, TwoColumnTemplate)
20
+ - **Zones**: Areas where components (modules) can be added (e.g., "main-content-zone", "sidebar")
21
+ - **Path**: The URL path for the page (e.g., `/about`, `/blog/post-1`)
22
+
23
+ ### 2. Page Templates
24
+ Templates define the layout structure of a page. Each template has:
25
+ - **Named Zones**: ContentZone components where components (modules) are placed
26
+ - **Layout Structure**: Header, footer, sidebars, etc.
27
+ - **React Component**: A server component that renders the zones
28
+
29
+ Example: `MainTemplate.tsx` has a single zone called "main-content-zone"
30
+
31
+ ### 3. Components (Called "Modules" in CMS)
32
+ **Components** (referred to as "modules" in the Agility CMS interface) are reusable building blocks that can be added to page zones:
33
+ - **Reference Name**: Unique identifier (e.g., "RichTextArea", "Hero", "PostListing")
34
+ - **Fields**: Content fields defined in Agility CMS
35
+ - **React Component**: The implementation that renders the component
36
+
37
+ **Note**: While these are called "modules" in the CMS, we refer to them as "components" in code to align with React terminology.
38
+
39
+ ### 4. Content Items
40
+ Standalone content that can be:
41
+ - **Referenced by Components**: A component can reference a content item by ID or reference name
42
+ - **Listed in Collections**: Grouped content (e.g., blog posts, team members)
43
+ - **Shared Across Pages**: Reusable content (e.g., site settings, navigation)
44
+
45
+ ### 5. Content Lists
46
+ Collections of content items:
47
+ - **Reference Name**: Identifier for the list (e.g., "posts", "testimonials")
48
+ - **Content Type**: Type of items in the list (e.g., "BlogPost", "Testimonial")
49
+ - **Pagination**: Support for paginated lists
50
+
51
+ ## How This Project Works
52
+
53
+ ### Data Flow
54
+ ```
55
+ Agility CMS → API Fetch → Next.js Page → Page Template → Components
56
+ ```
57
+
58
+ 1. **User visits a page**: Next.js receives the request
59
+ 2. **Middleware processes**: Handles preview, redirects, locale routing
60
+ 3. **Page fetches data**: `getAgilityPage()` fetches page data from Agility CMS
61
+ 4. **Template renders**: The appropriate page template component is selected
62
+ 5. **Components render**: ContentZone renders each component in order
63
+ 6. **Component receives data**: Each component receives its data and renders
64
+
65
+ ### File Organization
66
+
67
+ ```
68
+ src/
69
+ ├── app/
70
+ │ └── [locale]/
71
+ │ └── [...slug]/
72
+ │ └── page.tsx # Dynamic page route
73
+ ├── components/
74
+ │ ├── agility-pages/ # Page templates
75
+ │ │ ├── index.ts # Template registry
76
+ │ │ └── MainTemplate.tsx # Main page template
77
+ │ └── agility-components/ # CMS components (called "modules" in CMS)
78
+ │ ├── index.ts # Component registry
79
+ │ └── RichTextArea.tsx # Example component
80
+ └── lib/
81
+ └── cms/ # CMS helper functions
82
+ ├── getAgilitySDK.ts # Initialize SDK
83
+ ├── getAgilityPage.ts # Fetch page data
84
+ ├── getContentItem.ts # Fetch single content
85
+ ├── getContentList.ts # Fetch content lists
86
+ ├── getSitemapFlat.ts # Fetch flat sitemap
87
+ ├── getSitemapNested.ts # Fetch nested sitemap
88
+ └── getRedirections.ts # Fetch redirects
89
+ ```
90
+
91
+ ## Environment Configuration
92
+
93
+ Required environment variables (in `.env.local`):
94
+
95
+ ```env
96
+ # Agility Instance
97
+ AGILITY_GUID=your-instance-guid
98
+
99
+ # API Keys
100
+ AGILITY_API_FETCH_KEY=your-fetch-key # Published content
101
+ AGILITY_API_PREVIEW_KEY=your-preview-key # Draft content
102
+
103
+ # Security
104
+ AGILITY_SECURITY_KEY=your-security-key # For webhooks
105
+
106
+ # Locale Settings
107
+ AGILITY_LOCALES=en-us # Comma-separated (e.g., "en-us,fr,es")
108
+ AGILITY_SITEMAP=website # Sitemap name
109
+
110
+ # Caching
111
+ AGILITY_FETCH_CACHE_DURATION=60 # Seconds
112
+ AGILITY_PATH_REVALIDATE_DURATION=60 # Seconds
113
+ ```
114
+
115
+ ## Preview Mode
116
+
117
+ To preview draft content:
118
+ 1. Add `?agilitypreviewkey=your-preview-key` to any URL
119
+ 2. The middleware redirects to `/api/preview`
120
+ 3. A cookie is set to enable preview mode
121
+ 4. All subsequent requests use the preview API key
122
+
123
+ To exit preview mode:
124
+ 1. Add `?AgilityPreview=0` to any URL
125
+ 2. The preview cookie is cleared
126
+
127
+ ## Caching Strategy
128
+
129
+ The project uses Next.js caching with Agility CMS:
130
+
131
+ 1. **Time-based Revalidation**: Pages revalidate every 60 seconds (configurable)
132
+ 2. **Cache Tags**: Each piece of content has a tag (e.g., `agility-content-123-en-us`)
133
+ 3. **On-demand Revalidation**: Webhook can revalidate specific content via `/api/revalidate`
134
+
135
+ ## Next Steps
136
+
137
+ - Read [02-page-routing.md](./02-page-routing.md) to understand page routing
138
+ - Read [03-creating-components.md](./03-creating-components.md) to create new components
139
+ - Read [04-data-fetching.md](./04-data-fetching.md) to fetch content from Agility CMS