create-agntcms-app 0.2.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 (197) hide show
  1. package/README.md +39 -0
  2. package/dist/index.mjs +297 -0
  3. package/dist/template/.claude/settings.json +6 -0
  4. package/dist/template/.claude/skills/.gitkeep +0 -0
  5. package/dist/template/.claude-plugin/channel/server.mjs +254 -0
  6. package/dist/template/.claude-plugin/channel/server.ts +369 -0
  7. package/dist/template/.claude-plugin/plugin.json +17 -0
  8. package/dist/template/.mcp.json +8 -0
  9. package/dist/template/BRAND.md +49 -0
  10. package/dist/template/CLAUDE.md +157 -0
  11. package/dist/template/agntcms/config.ts +49 -0
  12. package/dist/template/agntcms/sections/ArticleBody/component.tsx +32 -0
  13. package/dist/template/agntcms/sections/ArticleBody/index.ts +10 -0
  14. package/dist/template/agntcms/sections/ArticleBody/schema.ts +5 -0
  15. package/dist/template/agntcms/sections/ArticleHero/component.tsx +87 -0
  16. package/dist/template/agntcms/sections/ArticleHero/index.ts +10 -0
  17. package/dist/template/agntcms/sections/ArticleHero/schema.ts +12 -0
  18. package/dist/template/agntcms/sections/Banner/component.tsx +83 -0
  19. package/dist/template/agntcms/sections/Banner/index.ts +10 -0
  20. package/dist/template/agntcms/sections/Banner/schema.ts +9 -0
  21. package/dist/template/agntcms/sections/BlogIndex/component.tsx +173 -0
  22. package/dist/template/agntcms/sections/BlogIndex/index.ts +10 -0
  23. package/dist/template/agntcms/sections/BlogIndex/schema.ts +33 -0
  24. package/dist/template/agntcms/sections/BlogIndexHeader/component.tsx +44 -0
  25. package/dist/template/agntcms/sections/BlogIndexHeader/index.ts +10 -0
  26. package/dist/template/agntcms/sections/BlogIndexHeader/schema.ts +8 -0
  27. package/dist/template/agntcms/sections/BlogPostBody/component.tsx +50 -0
  28. package/dist/template/agntcms/sections/BlogPostBody/index.ts +10 -0
  29. package/dist/template/agntcms/sections/BlogPostBody/schema.ts +10 -0
  30. package/dist/template/agntcms/sections/BlogPostHero/component.tsx +88 -0
  31. package/dist/template/agntcms/sections/BlogPostHero/index.ts +10 -0
  32. package/dist/template/agntcms/sections/BlogPostHero/schema.ts +35 -0
  33. package/dist/template/agntcms/sections/CaseStudies/component.tsx +92 -0
  34. package/dist/template/agntcms/sections/CaseStudies/index.ts +10 -0
  35. package/dist/template/agntcms/sections/CaseStudies/schema.ts +17 -0
  36. package/dist/template/agntcms/sections/ContactForm/component.tsx +119 -0
  37. package/dist/template/agntcms/sections/ContactForm/index.ts +10 -0
  38. package/dist/template/agntcms/sections/ContactForm/schema.ts +15 -0
  39. package/dist/template/agntcms/sections/DocsArticle/component.tsx +266 -0
  40. package/dist/template/agntcms/sections/DocsArticle/index.ts +10 -0
  41. package/dist/template/agntcms/sections/DocsArticle/schema.ts +33 -0
  42. package/dist/template/agntcms/sections/FAQ/component.tsx +57 -0
  43. package/dist/template/agntcms/sections/FAQ/index.ts +10 -0
  44. package/dist/template/agntcms/sections/FAQ/schema.ts +11 -0
  45. package/dist/template/agntcms/sections/FeatureGrid/component.tsx +117 -0
  46. package/dist/template/agntcms/sections/FeatureGrid/index.ts +10 -0
  47. package/dist/template/agntcms/sections/FeatureGrid/schema.ts +21 -0
  48. package/dist/template/agntcms/sections/FeaturedArticles/component.tsx +99 -0
  49. package/dist/template/agntcms/sections/FeaturedArticles/index.ts +10 -0
  50. package/dist/template/agntcms/sections/FeaturedArticles/schema.ts +17 -0
  51. package/dist/template/agntcms/sections/GettingStarted/component.tsx +116 -0
  52. package/dist/template/agntcms/sections/GettingStarted/index.ts +10 -0
  53. package/dist/template/agntcms/sections/GettingStarted/schema.ts +11 -0
  54. package/dist/template/agntcms/sections/Hero/component.tsx +148 -0
  55. package/dist/template/agntcms/sections/Hero/index.ts +10 -0
  56. package/dist/template/agntcms/sections/Hero/schema.ts +16 -0
  57. package/dist/template/agntcms/sections/HowItWorks/component.tsx +57 -0
  58. package/dist/template/agntcms/sections/HowItWorks/index.ts +10 -0
  59. package/dist/template/agntcms/sections/HowItWorks/schema.ts +11 -0
  60. package/dist/template/agntcms/sections/ImageText/component.tsx +110 -0
  61. package/dist/template/agntcms/sections/ImageText/index.ts +10 -0
  62. package/dist/template/agntcms/sections/ImageText/schema.ts +14 -0
  63. package/dist/template/agntcms/sections/LogoStrip/component.tsx +37 -0
  64. package/dist/template/agntcms/sections/LogoStrip/index.ts +10 -0
  65. package/dist/template/agntcms/sections/LogoStrip/schema.ts +6 -0
  66. package/dist/template/agntcms/sections/Newsletter/component.tsx +48 -0
  67. package/dist/template/agntcms/sections/Newsletter/index.ts +10 -0
  68. package/dist/template/agntcms/sections/Newsletter/schema.ts +8 -0
  69. package/dist/template/agntcms/sections/OpenSource/component.tsx +99 -0
  70. package/dist/template/agntcms/sections/OpenSource/index.ts +10 -0
  71. package/dist/template/agntcms/sections/OpenSource/schema.ts +13 -0
  72. package/dist/template/agntcms/sections/PainAnswer/component.tsx +81 -0
  73. package/dist/template/agntcms/sections/PainAnswer/index.ts +10 -0
  74. package/dist/template/agntcms/sections/PainAnswer/schema.ts +15 -0
  75. package/dist/template/agntcms/sections/PricingPlans/component.tsx +100 -0
  76. package/dist/template/agntcms/sections/PricingPlans/index.ts +10 -0
  77. package/dist/template/agntcms/sections/PricingPlans/schema.ts +13 -0
  78. package/dist/template/agntcms/sections/Problem/component.tsx +49 -0
  79. package/dist/template/agntcms/sections/Problem/index.ts +10 -0
  80. package/dist/template/agntcms/sections/Problem/schema.ts +12 -0
  81. package/dist/template/agntcms/sections/SiteFooter/component.tsx +88 -0
  82. package/dist/template/agntcms/sections/SiteFooter/index.ts +10 -0
  83. package/dist/template/agntcms/sections/SiteFooter/schema.ts +13 -0
  84. package/dist/template/agntcms/sections/SiteHeader/component.tsx +99 -0
  85. package/dist/template/agntcms/sections/SiteHeader/index.ts +10 -0
  86. package/dist/template/agntcms/sections/SiteHeader/schema.ts +14 -0
  87. package/dist/template/agntcms/sections/SiteMeta/component.tsx +26 -0
  88. package/dist/template/agntcms/sections/SiteMeta/index.ts +13 -0
  89. package/dist/template/agntcms/sections/SiteMeta/schema.ts +18 -0
  90. package/dist/template/agntcms/sections/TabbedFeatures/component.tsx +120 -0
  91. package/dist/template/agntcms/sections/TabbedFeatures/index.ts +10 -0
  92. package/dist/template/agntcms/sections/TabbedFeatures/schema.ts +13 -0
  93. package/dist/template/agntcms/sections/TeamGrid/component.tsx +77 -0
  94. package/dist/template/agntcms/sections/TeamGrid/index.ts +10 -0
  95. package/dist/template/agntcms/sections/TeamGrid/schema.ts +14 -0
  96. package/dist/template/agntcms/sections/Testimonials/component.tsx +76 -0
  97. package/dist/template/agntcms/sections/Testimonials/index.ts +10 -0
  98. package/dist/template/agntcms/sections/Testimonials/schema.ts +12 -0
  99. package/dist/template/agntcms/sections/WhatIsBuilt/component.tsx +86 -0
  100. package/dist/template/agntcms/sections/WhatIsBuilt/index.ts +10 -0
  101. package/dist/template/agntcms/sections/WhatIsBuilt/schema.ts +20 -0
  102. package/dist/template/agntcms/site-meta.ts +81 -0
  103. package/dist/template/app/[[...slug]]/page.tsx +123 -0
  104. package/dist/template/app/admin/AdminPageClient.tsx +77 -0
  105. package/dist/template/app/admin/AdminPageDynamic.tsx +24 -0
  106. package/dist/template/app/admin/page.tsx +14 -0
  107. package/dist/template/app/api/agntcms/_shared.ts +80 -0
  108. package/dist/template/app/api/agntcms/assets/route.ts +11 -0
  109. package/dist/template/app/api/agntcms/assets/upload/route.ts +11 -0
  110. package/dist/template/app/api/agntcms/draft/discard/route.ts +12 -0
  111. package/dist/template/app/api/agntcms/draft/list/route.ts +11 -0
  112. package/dist/template/app/api/agntcms/draft/publish/route.ts +11 -0
  113. package/dist/template/app/api/agntcms/draft/reorder/route.ts +10 -0
  114. package/dist/template/app/api/agntcms/draft/save/route.ts +11 -0
  115. package/dist/template/app/api/agntcms/events/route.ts +12 -0
  116. package/dist/template/app/api/agntcms/forms/delete/route.ts +17 -0
  117. package/dist/template/app/api/agntcms/forms/list/route.ts +24 -0
  118. package/dist/template/app/api/agntcms/forms/read/route.ts +23 -0
  119. package/dist/template/app/api/agntcms/forms/submit/route.ts +17 -0
  120. package/dist/template/app/api/agntcms/global/delete/route.ts +13 -0
  121. package/dist/template/app/api/agntcms/global/history/route.ts +10 -0
  122. package/dist/template/app/api/agntcms/global/list/route.ts +14 -0
  123. package/dist/template/app/api/agntcms/global/read/route.ts +11 -0
  124. package/dist/template/app/api/agntcms/global/rollback/route.ts +10 -0
  125. package/dist/template/app/api/agntcms/global/save/route.ts +14 -0
  126. package/dist/template/app/api/agntcms/mcp/route.ts +12 -0
  127. package/dist/template/app/api/agntcms/page/delete/route.ts +10 -0
  128. package/dist/template/app/api/agntcms/page/duplicate/route.ts +11 -0
  129. package/dist/template/app/api/agntcms/page/history/route.ts +10 -0
  130. package/dist/template/app/api/agntcms/page/list/route.ts +10 -0
  131. package/dist/template/app/api/agntcms/page/read/route.ts +11 -0
  132. package/dist/template/app/api/agntcms/page/rename/route.ts +10 -0
  133. package/dist/template/app/api/agntcms/page/rollback/route.ts +10 -0
  134. package/dist/template/app/api/agntcms/page/unpublish/route.ts +11 -0
  135. package/dist/template/app/api/agntcms/preview/enter/route.ts +13 -0
  136. package/dist/template/app/api/agntcms/preview/exit/route.ts +10 -0
  137. package/dist/template/app/api/agntcms/preview/issue/route.ts +12 -0
  138. package/dist/template/app/api/agntcms/template/list/route.ts +15 -0
  139. package/dist/template/app/apple-icon.svg +9 -0
  140. package/dist/template/app/icon.svg +9 -0
  141. package/dist/template/app/layout.tsx +107 -0
  142. package/dist/template/app/not-found.tsx +75 -0
  143. package/dist/template/app/robots.ts +33 -0
  144. package/dist/template/app/sitemap.ts +49 -0
  145. package/dist/template/content/globals/site-footer.json +53 -0
  146. package/dist/template/content/globals/site-header.json +18 -0
  147. package/dist/template/content/globals/site-meta.json +13 -0
  148. package/dist/template/content/pages/404.json +34 -0
  149. package/dist/template/content/pages/about.json +307 -0
  150. package/dist/template/content/pages/article-editor.json +61 -0
  151. package/dist/template/content/pages/article-schemas.json +61 -0
  152. package/dist/template/content/pages/blog.json +162 -0
  153. package/dist/template/content/pages/contact.json +29 -0
  154. package/dist/template/content/pages/home.json +243 -0
  155. package/dist/template/content/pages/pricing.json +219 -0
  156. package/dist/template/content/pages/services.json +177 -0
  157. package/dist/template/fonts/Satoshi-Medium.woff2 +0 -0
  158. package/dist/template/fonts/Satoshi-Regular.woff2 +0 -0
  159. package/dist/template/next.config.ts +6 -0
  160. package/dist/template/package.json +36 -0
  161. package/dist/template/postcss.config.mjs +5 -0
  162. package/dist/template/public/assets/.gitkeep +0 -0
  163. package/dist/template/public/assets/0418d7ed21f57e7b9e0546725c92b8419daeaa355675d9070fab0c2013cf1524.jpg +0 -0
  164. package/dist/template/public/assets/0d0475f21aa96435a8ed3cdb2fddcc6278492e76ae842f569432454f4d33631a.jpg +0 -0
  165. package/dist/template/public/assets/27457a1adee2372030d9876b0d52c44d46be98843999935eaef2526b9b961f12.jpg +0 -0
  166. package/dist/template/public/assets/3855d91192f0c6120b01427b78ef84e52baa9f4b5a17d4271e41c1bfd95a5b0c.jpg +0 -0
  167. package/dist/template/public/assets/3b3b90c5084635b746be673ede92a328f002f5621a42c9a5cb89c5e2435652cb.jpg +0 -0
  168. package/dist/template/public/assets/3e76165a78fd3e7b8ed1e93dee50803ae11110c756c8c1c89229a2dec2bc0abf.jpg +0 -0
  169. package/dist/template/public/assets/4a3e28f85dc850c347ea0fd931696aa936a6bd45f193e7f1c9328b5896fb272c.jpg +0 -0
  170. package/dist/template/public/assets/579f67d5fd4c9106c6cdf2ef29f50df934ad0fc2b7849bac1e1cfb1e3f92303b.jpg +0 -0
  171. package/dist/template/public/assets/5b95209269661bb60fb250f1da682e05b9efa64dd42f350608b299e6bf1f2f35.jpg +0 -0
  172. package/dist/template/public/assets/5e04b46f8317ef95a7ddf85aedfe5c098a755f05056325d0251eccf95ce51172.jpg +0 -0
  173. package/dist/template/public/assets/6167a9164be2cf1183bdfdd4946bf9b908570e79e92a2380c25f0bb702422bbd.jpg +0 -0
  174. package/dist/template/public/assets/75e723ec316de28247924e5dfb73a4b266e10de605e749f150883d280ed8ed16.jpg +0 -0
  175. package/dist/template/public/assets/816a11e6a7245feaf51bbebf09d1bda3f125b334bc24fc3b8f47b5380a7b4294.jpg +0 -0
  176. package/dist/template/public/assets/81eba6f5654b8746a9b0cba1a9521a67f2b4afaaefc7c88d66dfab1461270d8f.jpg +0 -0
  177. package/dist/template/public/assets/82a2ce9e49361098f77a28755779dc5a7c026831cbd135175749c1304e21dacc.jpg +0 -0
  178. package/dist/template/public/assets/8d7b02ba277ba56bdafdbd47b01f7df6d993c714b4dc2305eb65a1307c09647d.jpg +0 -0
  179. package/dist/template/public/assets/b303185b471678e4d62f678a1549ee26022f4745407d08cae44ecb1c25352293.jpg +0 -0
  180. package/dist/template/public/assets/b69b49169c11546100d6dd5280073bc0d84cbbcc6d33fa01ecf6a5866fa42237.jpg +0 -0
  181. package/dist/template/public/assets/c4d2f0d1a310e457ac722a399693652e3c86c55b294243d5ffc679394e12f9d1.jpg +0 -0
  182. package/dist/template/public/assets/cae09f4729f8a348b67267c2f2a550be0f3bfa420689afe1a5cf8b7e2b146238.png +0 -0
  183. package/dist/template/public/assets/cb3acf58b57417a4b26474ba04c096af7103c4320ed2f4f3683f79d7670a055c.jpg +0 -0
  184. package/dist/template/public/assets/d5a0701b2d156284e0ce851cd2534ec632db34f91fbcbee3b8a7784d45ce78d2.jpg +0 -0
  185. package/dist/template/public/assets/d6ef1c3f48b0e488521794fb60701da1fd2c3a1621d6ac5f17ccfd4909d3be60.jpg +0 -0
  186. package/dist/template/public/assets/de249ff9be2539cf0d1ce092de3c57001839b6c3e14fcee3fc31a7b7673ae007.jpg +0 -0
  187. package/dist/template/public/assets/eac45438956be187b010e24b3289757aa00f227c190d49ee99fea510552dd2ba.jpg +0 -0
  188. package/dist/template/public/assets/f8b9200065b5436c6a88361839edc2b89be88d3037c84a80d3ee95c32891510b.jpg +0 -0
  189. package/dist/template/public/assets/placeholder.png +0 -0
  190. package/dist/template/public/brand/mark.svg +6 -0
  191. package/dist/template/public/brand/wordmark-light.svg +6 -0
  192. package/dist/template/public/brand/wordmark.svg +6 -0
  193. package/dist/template/styles/globals.css +69 -0
  194. package/dist/template/styles/theme.css +492 -0
  195. package/dist/template/styles/typography.css +469 -0
  196. package/dist/template/tsconfig.json +30 -0
  197. package/package.json +30 -0
@@ -0,0 +1,81 @@
1
+ 'use client'
2
+
3
+ import { EditableRichText, EditableList } from '@agntcms/next/client'
4
+ import type { EditableSlot, SlotItem } from '@agntcms/next/client'
5
+ import { schema } from './schema'
6
+
7
+ type Row = SlotItem<typeof schema.rows.itemSchema>
8
+
9
+ interface Props {
10
+ readonly eyebrow: EditableSlot<'richText', string>
11
+ readonly headline: EditableSlot<'richText', string>
12
+ readonly intro: EditableSlot<'richText', string>
13
+ readonly painLabel: EditableSlot<'richText', string>
14
+ readonly oursLabel: EditableSlot<'richText', string>
15
+ readonly rows: EditableSlot<'list', ReadonlyArray<Row>>
16
+ }
17
+
18
+ export function PainAnswerComponent({ eyebrow, headline, intro, painLabel, oursLabel, rows }: Props) {
19
+ return (
20
+ <section id="vs" className="bg-bg-primary">
21
+ <div className="mx-auto max-w-[1080px] px-8 py-16 border-t-[0.5px] border-border-secondary">
22
+ <EditableRichText
23
+ field={eyebrow}
24
+ className="prose mb-3.5 [&_p]:text-[11px] [&_p]:font-medium [&_p]:tracking-[0.10em] [&_p]:uppercase [&_p]:text-text-brand-primary [&_p]:m-0"
25
+ />
26
+ <EditableRichText
27
+ field={headline}
28
+ className="mb-6
29
+ [&_h2]:font-display [&_h2]:font-medium [&_h2]:text-text-primary [&_h2]:m-0
30
+ [&_h2]:max-w-[22ch]
31
+ [&_h2]:!text-[clamp(28px,3.6vw,40px)] [&_h2]:!leading-[1.1] [&_h2]:!tracking-[-0.02em]"
32
+ />
33
+ <EditableRichText
34
+ field={intro}
35
+ className="prose max-w-[60ch] mb-9 [&_p]:text-text-primary [&_p]:m-0"
36
+ />
37
+
38
+ <div className="border-t-[0.5px] border-border-primary mt-2">
39
+ {/* Header row */}
40
+ <div className="hidden sm:grid grid-cols-2 border-b-[0.5px] border-border-primary">
41
+ <EditableRichText
42
+ field={painLabel}
43
+ className="prose px-6 py-3.5 [&_p]:text-[11px] [&_p]:font-medium [&_p]:tracking-[0.10em] [&_p]:uppercase [&_p]:text-text-secondary [&_p]:m-0"
44
+ />
45
+ <EditableRichText
46
+ field={oursLabel}
47
+ className="prose px-6 py-3.5 border-l-[0.5px] border-border-primary [&_p]:text-[11px] [&_p]:font-medium [&_p]:tracking-[0.10em] [&_p]:uppercase [&_p]:text-text-brand-primary [&_p]:m-0"
48
+ />
49
+ </div>
50
+
51
+ <EditableList
52
+ field={rows}
53
+ itemSchema={schema.rows.itemSchema}
54
+ className="contents"
55
+ renderItem={(row, index) => {
56
+ const num = String(index + 1).padStart(2, '0')
57
+ return (
58
+ <div className="grid grid-cols-1 sm:grid-cols-2 border-b-[0.5px] border-border-primary">
59
+ <div className="flex gap-[18px] px-6 py-6 items-start text-text-tertiary">
60
+ <div className="font-mono text-[11px] tracking-[0.06em] text-text-tertiary mt-[3px] shrink-0 w-[18px]">{num}</div>
61
+ <EditableRichText
62
+ field={row.pain}
63
+ className="prose [&_p]:m-0 [&_p]:text-[15px] [&_p]:leading-[1.55] [&_p]:line-through [&_p]:decoration-text-tertiary [&_p]:decoration-[0.5px]"
64
+ />
65
+ </div>
66
+ <div className="flex gap-[18px] px-6 py-6 items-start bg-bg-secondary border-t-[0.5px] sm:border-t-0 sm:border-l-[0.5px] border-border-primary">
67
+ <div className="font-mono text-[11px] tracking-[0.06em] text-text-brand-primary mt-[3px] shrink-0 w-[18px]">→</div>
68
+ <EditableRichText
69
+ field={row.ours}
70
+ className="prose [&_p]:m-0 [&_p]:text-[15px] [&_p]:leading-[1.55] [&_p]:text-text-primary"
71
+ />
72
+ </div>
73
+ </div>
74
+ )
75
+ }}
76
+ />
77
+ </div>
78
+ </div>
79
+ </section>
80
+ )
81
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { PainAnswerComponent } from './component'
4
+
5
+ export const PainAnswer = defineSection({
6
+ name: 'PainAnswer',
7
+ category: 'Content',
8
+ schema,
9
+ component: PainAnswerComponent,
10
+ })
@@ -0,0 +1,15 @@
1
+ import { RichTextField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ eyebrow: RichTextField,
5
+ headline: RichTextField,
6
+ intro: RichTextField,
7
+ // Header labels for the two columns.
8
+ painLabel: RichTextField,
9
+ oursLabel: RichTextField,
10
+ // Each row pairs a "pain" statement with an "ours" answer.
11
+ rows: ListField({
12
+ pain: RichTextField,
13
+ ours: RichTextField,
14
+ }),
15
+ }
@@ -0,0 +1,100 @@
1
+ 'use client'
2
+
3
+ import {
4
+ EditableRichText,
5
+ EditableText,
6
+ EditableLink,
7
+ EditableList,
8
+ read,
9
+ isSlotInPreview,
10
+ } from '@agntcms/next/client'
11
+ import type { EditableSlot, SlotItem } from '@agntcms/next/client'
12
+ import { hrefOf, isExternalLink } from '@agntcms/next'
13
+ import { schema } from './schema'
14
+
15
+ type Plan = SlotItem<typeof schema.plans.itemSchema>
16
+
17
+ interface Props {
18
+ readonly plans: EditableSlot<'list', ReadonlyArray<Plan>>
19
+ }
20
+
21
+ export function PricingPlansComponent({ plans }: Props) {
22
+ return (
23
+ <section className="bg-paper">
24
+ <div className="mx-auto w-full max-w-[1280px] px-8 py-24">
25
+ <EditableList
26
+ field={plans}
27
+ itemSchema={schema.plans.itemSchema}
28
+ className="grid grid-cols-1 gap-5 lg:grid-cols-3"
29
+ renderItem={(plan) => {
30
+ const featured = read(plan.featured)
31
+ const cta = read(plan.cta)
32
+ const ctaHref = hrefOf(cta)
33
+ const showCta = Boolean(ctaHref) || isSlotInPreview(plan.cta)
34
+ const borderClass = featured ? 'border-ink' : 'border-hairline'
35
+ const ctaStyles = featured
36
+ ? 'bg-ink text-paper border-ink hover:bg-ink-2 hover:border-ink-2'
37
+ : 'bg-transparent text-ink border-hairline-2 hover:border-ink'
38
+ return (
39
+ <div className={`relative border bg-transparent p-8 ${borderClass}`}>
40
+ {featured ? (
41
+ <span className="absolute -top-px -left-px bg-ink px-2.5 py-[5px] font-mono text-[10px] font-medium tracking-[0.07em] uppercase text-paper">
42
+ most popular
43
+ </span>
44
+ ) : null}
45
+ <EditableText
46
+ field={plan.name}
47
+ as="h3"
48
+ className={`m-0 font-mono text-[16px] font-medium tracking-[0.04em] uppercase text-ink-3 ${featured ? 'mt-5' : ''}`}
49
+ />
50
+ <div className="mt-3.5 flex items-baseline gap-2">
51
+ <EditableText
52
+ field={plan.price}
53
+ as="span"
54
+ className="font-display text-[56px] font-semibold leading-none tracking-[-0.03em] text-ink"
55
+ />
56
+ <EditableText
57
+ field={plan.priceSub}
58
+ as="span"
59
+ className="font-mono text-[13px] text-ink-3"
60
+ />
61
+ </div>
62
+ <EditableRichText
63
+ field={plan.pitch}
64
+ className="mt-2.5 [&_p]:m-0 [&_p]:text-[14.5px] [&_p]:leading-[1.55] [&_p]:text-ink-3"
65
+ />
66
+ {showCta && (
67
+ <a
68
+ href={ctaHref || '#'}
69
+ target={isExternalLink(cta) ? '_blank' : undefined}
70
+ rel={isExternalLink(cta) ? 'noreferrer' : undefined}
71
+ className="mt-6 block"
72
+ >
73
+ <EditableLink
74
+ field={plan.cta}
75
+ className={`inline-flex w-full items-center justify-center gap-2 whitespace-nowrap rounded-sm border px-[22px] py-[13px] text-[15px] font-medium no-underline transition-colors duration-200 ease-out ${ctaStyles}`}
76
+ />
77
+ </a>
78
+ )}
79
+ <EditableList
80
+ field={plan.features}
81
+ itemSchema={schema.plans.itemSchema.features.itemSchema}
82
+ className="mt-7 flex list-none flex-col gap-2.5 border-t border-hairline p-0 pt-6"
83
+ renderItem={(f) => (
84
+ <div className="flex items-start gap-3 text-[14.5px] leading-[1.55] text-ink-2">
85
+ <span className="flex-shrink-0 font-mono text-ink-3">→</span>
86
+ <EditableRichText
87
+ field={f.item}
88
+ className="[&_p]:m-0 [&_p]:text-[14.5px] [&_p]:leading-[1.55] [&_p]:text-ink-2"
89
+ />
90
+ </div>
91
+ )}
92
+ />
93
+ </div>
94
+ )
95
+ }}
96
+ />
97
+ </div>
98
+ </section>
99
+ )
100
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { PricingPlansComponent } from './component'
4
+
5
+ export const PricingPlans = defineSection({
6
+ name: 'PricingPlans',
7
+ category: 'Pricing',
8
+ schema,
9
+ component: PricingPlansComponent,
10
+ })
@@ -0,0 +1,13 @@
1
+ import { RichTextField, TextField, LinkField, BooleanField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ plans: ListField({
5
+ name: TextField,
6
+ price: TextField,
7
+ priceSub: TextField,
8
+ featured: BooleanField,
9
+ pitch: RichTextField,
10
+ features: ListField({ item: RichTextField }),
11
+ cta: LinkField,
12
+ }),
13
+ }
@@ -0,0 +1,49 @@
1
+ 'use client'
2
+
3
+ import { EditableRichText } from '@agntcms/next/client'
4
+ import type { EditableSlot } from '@agntcms/next/client'
5
+
6
+ interface Props {
7
+ readonly eyebrow: EditableSlot<'richText', string>
8
+ readonly headline: EditableSlot<'richText', string>
9
+ readonly body: EditableSlot<'richText', string>
10
+ readonly messageEyebrow: EditableSlot<'richText', string>
11
+ readonly message: EditableSlot<'richText', string>
12
+ }
13
+
14
+ export function ProblemComponent({ eyebrow, headline, body, messageEyebrow, message }: Props) {
15
+ return (
16
+ <section id="problem" className="bg-bg-primary">
17
+ <div className="mx-auto max-w-[1080px] px-8 py-16 border-t-[0.5px] border-border-secondary">
18
+ <EditableRichText
19
+ field={eyebrow}
20
+ className="prose mb-3.5 [&_p]:text-[11px] [&_p]:font-medium [&_p]:tracking-[0.10em] [&_p]:uppercase [&_p]:text-text-brand-primary [&_p]:m-0"
21
+ />
22
+ <EditableRichText
23
+ field={headline}
24
+ className="mb-6
25
+ [&_h2]:font-display [&_h2]:font-medium [&_h2]:text-text-primary [&_h2]:m-0
26
+ [&_h2]:max-w-[22ch]
27
+ [&_h2]:!text-[clamp(28px,3.6vw,40px)] [&_h2]:!leading-[1.1] [&_h2]:!tracking-[-0.02em]"
28
+ />
29
+ <EditableRichText
30
+ field={body}
31
+ className="prose max-w-[60ch]
32
+ [&_p]:text-text-primary [&_p]:m-0 [&_p]:mb-4 [&_p:last-child]:mb-0"
33
+ />
34
+ <div className="bg-bg-secondary border-[0.5px] border-border-primary border-l-2 border-l-border-brand rounded-r-lg py-[18px] px-[22px] my-6 max-w-[60ch]">
35
+ <EditableRichText
36
+ field={messageEyebrow}
37
+ className="prose mb-2 [&_p]:text-[11px] [&_p]:font-medium [&_p]:tracking-[0.10em] [&_p]:uppercase [&_p]:text-text-brand-primary [&_p]:m-0"
38
+ />
39
+ <EditableRichText
40
+ field={message}
41
+ className="prose
42
+ [&_p]:font-display [&_p]:font-medium [&_p]:text-[22px] [&_p]:leading-[1.35]
43
+ [&_p]:tracking-[-0.02em] [&_p]:text-text-primary [&_p]:m-0"
44
+ />
45
+ </div>
46
+ </div>
47
+ </section>
48
+ )
49
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { ProblemComponent } from './component'
4
+
5
+ export const Problem = defineSection({
6
+ name: 'Problem',
7
+ category: 'Content',
8
+ schema,
9
+ component: ProblemComponent,
10
+ })
@@ -0,0 +1,12 @@
1
+ import { RichTextField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ eyebrow: RichTextField,
5
+ headline: RichTextField,
6
+ // Long-form prose rendered as a stack of paragraphs (markdown).
7
+ body: RichTextField,
8
+ // Eyebrow inside the highlight message block.
9
+ messageEyebrow: RichTextField,
10
+ // Highlight statement inside the teal-bordered message block.
11
+ message: RichTextField,
12
+ }
@@ -0,0 +1,88 @@
1
+ 'use client'
2
+
3
+ import { EditableText, EditableRichText, EditableList, read } from '@agntcms/next/client'
4
+ import { hrefOf, isExternalLink } from '@agntcms/next'
5
+ import type { EditableSlot, SlotItem } from '@agntcms/next/client'
6
+ import { schema } from './schema'
7
+
8
+ type Column = SlotItem<typeof schema.columns.itemSchema>
9
+
10
+ interface Props {
11
+ readonly brandName: EditableSlot<'text', string>
12
+ readonly showCaret: EditableSlot<'boolean', boolean>
13
+ readonly tagline: EditableSlot<'richText', string>
14
+ readonly columns: EditableSlot<'list', ReadonlyArray<Column>>
15
+ readonly copyright: EditableSlot<'text', string>
16
+ readonly versionLine: EditableSlot<'text', string>
17
+ }
18
+
19
+ export function SiteFooterComponent({
20
+ brandName,
21
+ showCaret,
22
+ tagline,
23
+ columns,
24
+ copyright,
25
+ versionLine,
26
+ }: Props) {
27
+ const caret = read(showCaret)
28
+ return (
29
+ <footer className="bg-paper">
30
+ <div className="mx-auto w-full max-w-[1280px] px-8 pt-20 pb-10">
31
+ <div className="grid grid-cols-1 gap-12 md:grid-cols-5">
32
+ <div className="md:col-span-2">
33
+ <span className="inline-flex items-center font-mono text-[18px] font-semibold tracking-[-0.01em] text-ink">
34
+ <EditableText field={brandName} as="span" />
35
+ {caret ? (
36
+ <span
37
+ aria-hidden="true"
38
+ className="ml-1 inline-block h-[14px] w-[7px] bg-teal animate-caret-blink"
39
+ />
40
+ ) : null}
41
+ </span>
42
+ <EditableRichText
43
+ field={tagline}
44
+ className="mt-3.5 max-w-[280px] [&_p]:m-0 [&_p]:text-sm [&_p]:leading-[1.6] [&_p]:text-ink-3"
45
+ />
46
+ </div>
47
+ <EditableList
48
+ field={columns}
49
+ itemSchema={schema.columns.itemSchema}
50
+ className="contents"
51
+ renderItem={(col) => (
52
+ <div>
53
+ <EditableText
54
+ field={col.heading}
55
+ as="div"
56
+ className="mb-3 font-mono text-[11px] font-medium tracking-[0.07em] uppercase text-ink-3"
57
+ />
58
+ <EditableList
59
+ field={col.links}
60
+ itemSchema={schema.columns.itemSchema.links.itemSchema}
61
+ className="flex flex-col gap-2"
62
+ renderItem={(item) => {
63
+ const link = read(item.link)
64
+ const href = hrefOf(link) || '#'
65
+ return (
66
+ <a
67
+ href={href}
68
+ target={isExternalLink(link) ? '_blank' : undefined}
69
+ rel={isExternalLink(link) ? 'noreferrer' : undefined}
70
+ className="text-sm text-ink-2 no-underline hover:text-ink"
71
+ >
72
+ <EditableText field={item.label} as="span" />
73
+ </a>
74
+ )
75
+ }}
76
+ />
77
+ </div>
78
+ )}
79
+ />
80
+ </div>
81
+ <div className="mt-16 flex flex-col gap-2 border-t border-hairline pt-6 font-mono text-xs text-ink-3 md:flex-row md:justify-between md:items-center">
82
+ <EditableText field={copyright} as="span" />
83
+ <EditableText field={versionLine} as="span" />
84
+ </div>
85
+ </div>
86
+ </footer>
87
+ )
88
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { SiteFooterComponent } from './component'
4
+
5
+ export const SiteFooter = defineSection({
6
+ name: 'SiteFooter',
7
+ category: 'Layout',
8
+ schema,
9
+ component: SiteFooterComponent,
10
+ })
@@ -0,0 +1,13 @@
1
+ import { TextField, RichTextField, LinkField, BooleanField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ brandName: TextField,
5
+ showCaret: BooleanField,
6
+ tagline: RichTextField,
7
+ columns: ListField({
8
+ heading: TextField,
9
+ links: ListField({ label: TextField, link: LinkField }),
10
+ }),
11
+ copyright: TextField,
12
+ versionLine: TextField,
13
+ }
@@ -0,0 +1,99 @@
1
+ 'use client'
2
+
3
+ import { EditableText, EditableLink, EditableList, read, isSlotInPreview } from '@agntcms/next/client'
4
+ import type { EditableSlot, SlotItem } from '@agntcms/next/client'
5
+ import { hrefOf, isExternalLink } from '@agntcms/next'
6
+ import type { LinkValue } from '@agntcms/next'
7
+ import { schema } from './schema'
8
+
9
+ type NavItem = SlotItem<typeof schema.navItems.itemSchema>
10
+
11
+ interface Props {
12
+ readonly brandName: EditableSlot<'text', string>
13
+ readonly showCaret: EditableSlot<'boolean', boolean>
14
+ readonly navItems: EditableSlot<'list', ReadonlyArray<NavItem>>
15
+ readonly signInCta: EditableSlot<'link', LinkValue>
16
+ readonly primaryCta: EditableSlot<'link', LinkValue>
17
+ }
18
+
19
+ function HeaderCta({
20
+ field,
21
+ variant,
22
+ }: {
23
+ field: EditableSlot<'link', LinkValue>
24
+ variant: 'ghost' | 'primary'
25
+ }) {
26
+ const link = read(field)
27
+ const href = hrefOf(link)
28
+ const show = Boolean(href) || isSlotInPreview(field)
29
+ if (!show) return null
30
+ const styles =
31
+ variant === 'primary'
32
+ ? 'bg-ink text-paper border-ink hover:bg-ink-2 hover:border-ink-2'
33
+ : 'bg-transparent text-ink border-transparent hover:text-ink-3'
34
+ return (
35
+ <a
36
+ href={href || '#'}
37
+ target={isExternalLink(link) ? '_blank' : undefined}
38
+ rel={isExternalLink(link) ? 'noreferrer' : undefined}
39
+ >
40
+ <EditableLink
41
+ field={field}
42
+ className={`inline-flex items-center gap-1.5 whitespace-nowrap rounded-sm border px-3 py-[7px] text-[13px] font-medium no-underline transition-colors duration-200 ease-out ${styles}`}
43
+ />
44
+ </a>
45
+ )
46
+ }
47
+
48
+ export function SiteHeaderComponent({
49
+ brandName,
50
+ showCaret,
51
+ navItems,
52
+ signInCta,
53
+ primaryCta,
54
+ }: Props) {
55
+ const caret = read(showCaret)
56
+ return (
57
+ <header className="sticky top-0 z-50 bg-paper">
58
+ <div className="mx-auto w-full max-w-[1280px] px-8">
59
+ <div className="flex items-center gap-7 py-[18px]">
60
+ <a
61
+ href="/"
62
+ aria-label="Home"
63
+ className="inline-flex items-center font-mono text-[18px] font-semibold tracking-[-0.01em] text-ink no-underline"
64
+ >
65
+ <EditableText field={brandName} as="span" />
66
+ {caret ? (
67
+ <span
68
+ aria-hidden="true"
69
+ className="ml-1 inline-block h-[14px] w-[7px] bg-teal animate-caret-blink"
70
+ />
71
+ ) : null}
72
+ </a>
73
+ <EditableList
74
+ field={navItems}
75
+ itemSchema={schema.navItems.itemSchema}
76
+ className="hidden md:flex items-center gap-[22px] ml-3"
77
+ renderItem={(item) => {
78
+ const link = read(item.link)
79
+ const href = hrefOf(link)
80
+ return (
81
+ <a
82
+ href={href || '#'}
83
+ target={isExternalLink(link) ? '_blank' : undefined}
84
+ rel={isExternalLink(link) ? 'noreferrer' : undefined}
85
+ className="border-b border-transparent pb-0.5 text-sm font-medium text-ink-3 no-underline hover:text-ink"
86
+ >
87
+ <EditableText field={item.label} as="span" />
88
+ </a>
89
+ )
90
+ }}
91
+ />
92
+ <div className="flex-1" />
93
+ <HeaderCta field={signInCta} variant="ghost" />
94
+ <HeaderCta field={primaryCta} variant="primary" />
95
+ </div>
96
+ </div>
97
+ </header>
98
+ )
99
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { SiteHeaderComponent } from './component'
4
+
5
+ export const SiteHeader = defineSection({
6
+ name: 'SiteHeader',
7
+ category: 'Layout',
8
+ schema,
9
+ component: SiteHeaderComponent,
10
+ })
@@ -0,0 +1,14 @@
1
+ import { TextField, LinkField, BooleanField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ // Wordmark text (lowercase mono).
5
+ brandName: TextField,
6
+ // When true, render the teal blinking caret after the wordmark.
7
+ showCaret: BooleanField,
8
+ // Primary navigation.
9
+ navItems: ListField({ label: TextField, link: LinkField }),
10
+ // "Sign in"-style secondary header CTA.
11
+ signInCta: LinkField,
12
+ // "Start building"-style primary header CTA.
13
+ primaryCta: LinkField,
14
+ }
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ // SiteMeta is a data-only global: it holds SEO defaults (siteName,
4
+ // baseUrl, defaultOgImage, defaultDescription). It is consumed at the
5
+ // server layer by generateMetadata in app/[[...slug]]/page.tsx and by
6
+ // app/layout.tsx; it is never rendered as a visible section.
7
+ //
8
+ // The component is intentionally a no-op. GlobalSlot renders it when
9
+ // reading via runtime.getGlobal, but no visible output is wanted — the
10
+ // section exists purely to make the data editable through the admin UI.
11
+
12
+ import type { EditableSlot } from '@agntcms/next/client'
13
+ import type { ImageValue } from '@agntcms/next'
14
+
15
+ interface Props {
16
+ readonly siteName: EditableSlot<'text', string>
17
+ readonly baseUrl: EditableSlot<'text', string>
18
+ readonly defaultOgImage: EditableSlot<'image', ImageValue>
19
+ readonly defaultDescription: EditableSlot<'text', string>
20
+ }
21
+
22
+ export function SiteMetaComponent(_props: Props) {
23
+ // Intentional no-op — this global is consumed by server metadata
24
+ // helpers only. Rendering it in the page body would be incorrect.
25
+ return null
26
+ }
@@ -0,0 +1,13 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { SiteMetaComponent } from './component'
4
+
5
+ export const SiteMeta = defineSection({
6
+ name: 'SiteMeta',
7
+ // 'Global' category groups this section with SiteHeader/SiteFooter in the
8
+ // picker so authors understand it is a layout/infrastructure section rather
9
+ // than a page content block.
10
+ category: 'Global',
11
+ schema,
12
+ component: SiteMetaComponent,
13
+ })
@@ -0,0 +1,18 @@
1
+ import { TextField, ImageField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ // Site name used in the page title template: "<page title> | <siteName>"
5
+ siteName: TextField,
6
+ // Canonical base URL, e.g. "https://agntcms.dev". Used by sitemap.ts
7
+ // and generateMetadata to construct canonical URLs. Include protocol,
8
+ // no trailing slash.
9
+ baseUrl: TextField,
10
+ // Fallback OG image shown when a page has no seo.ogImage and no
11
+ // coverImage. Optional — pages that always set their own OG image
12
+ // do not need this.
13
+ defaultOgImage: ImageField,
14
+ // Global fallback description. Shown on the home page (before any
15
+ // page-level seo.description is available) and used as openGraph
16
+ // description in layout.tsx.
17
+ defaultDescription: TextField,
18
+ }