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,148 @@
1
+ 'use client'
2
+
3
+ import { EditableRichText, EditableImage, EditableLink, read, isSlotInPreview } from '@agntcms/next/client'
4
+ import type { EditableSlot } from '@agntcms/next/client'
5
+ import { hrefOf, isExternalLink } from '@agntcms/next'
6
+ import type { ImageValue, LinkValue } from '@agntcms/next'
7
+
8
+ interface Props {
9
+ readonly eyebrow: EditableSlot<'richText', string>
10
+ readonly headline: EditableSlot<'richText', string>
11
+ readonly lead: EditableSlot<'richText', string>
12
+ readonly image: EditableSlot<'image', ImageValue>
13
+ readonly primaryCta: EditableSlot<'link', LinkValue>
14
+ readonly secondaryCta: EditableSlot<'link', LinkValue>
15
+ readonly layout: EditableSlot<'text', string>
16
+ readonly background: EditableSlot<'text', string>
17
+ }
18
+
19
+ const HEADLINE_CLASSES =
20
+ "[&_h1]:font-display [&_h1]:font-semibold [&_h1]:text-ink [&_h1]:m-0 " +
21
+ "[&_h1]:!leading-[1.05] [&_h1]:!tracking-[-0.03em] " +
22
+ "[&_h2]:font-display [&_h2]:font-semibold [&_h2]:text-ink [&_h2]:m-0 " +
23
+ "[&_h2]:!leading-[1.05] [&_h2]:!tracking-[-0.03em] " +
24
+ "[&_p]:font-display [&_p]:font-semibold [&_p]:text-ink [&_p]:m-0 " +
25
+ "[&_p]:!leading-[1.05] [&_p]:!tracking-[-0.03em] " +
26
+ "[&_em]:not-italic [&_em]:text-ink-3 [&_em]:font-semibold"
27
+
28
+ function CtaButton({
29
+ field,
30
+ variant,
31
+ size = 'lg',
32
+ }: {
33
+ field: EditableSlot<'link', LinkValue>
34
+ variant: 'primary' | 'secondary'
35
+ size?: 'md' | 'lg'
36
+ }) {
37
+ const link = read(field)
38
+ const href = hrefOf(link)
39
+ const show = Boolean(href) || isSlotInPreview(field)
40
+ if (!show) return null
41
+ const base =
42
+ 'inline-flex items-center gap-2 whitespace-nowrap rounded-sm border transition-colors duration-200 ease-out font-medium no-underline'
43
+ const sizes = size === 'lg' ? 'text-[15px] px-[22px] py-[13px]' : 'text-sm px-[18px] py-[10px]'
44
+ const styles =
45
+ variant === 'primary'
46
+ ? 'bg-ink text-paper border-ink hover:bg-ink-2 hover:border-ink-2'
47
+ : 'bg-transparent text-ink border-hairline-2 hover:border-ink'
48
+ return (
49
+ <a
50
+ href={href || '#'}
51
+ target={isExternalLink(link) ? '_blank' : undefined}
52
+ rel={isExternalLink(link) ? 'noreferrer' : undefined}
53
+ >
54
+ <EditableLink field={field} className={`${base} ${sizes} ${styles}`} />
55
+ </a>
56
+ )
57
+ }
58
+
59
+ export function HeroComponent({
60
+ eyebrow,
61
+ headline,
62
+ lead,
63
+ image,
64
+ primaryCta,
65
+ secondaryCta,
66
+ layout,
67
+ background,
68
+ }: Props) {
69
+ const layoutMode = (read(layout) || 'split').trim()
70
+ const bg = (read(background) || 'paper').trim()
71
+ const img = read(image)
72
+ const hasImage = Boolean(img?.filename) || isSlotInPreview(image)
73
+ const bgClass = bg === 'paper-2' ? 'bg-paper-2' : 'bg-paper'
74
+
75
+ if (layoutMode === 'split') {
76
+ return (
77
+ <section className={`${bgClass}`}>
78
+ <div className="mx-auto w-full max-w-[1280px] px-8 py-[88px]">
79
+ <div className="grid grid-cols-1 gap-14 lg:grid-cols-[1.05fr_1fr] lg:items-center">
80
+ <div>
81
+ <EditableRichText
82
+ field={eyebrow}
83
+ className="[&_p]:font-mono [&_p]:font-medium [&_p]:text-[12px] [&_p]:tracking-[0.07em] [&_p]:uppercase [&_p]:text-ink-3 [&_p]:m-0"
84
+ />
85
+ <div className={`mt-4 ${HEADLINE_CLASSES} [&_h1]:!text-[clamp(40px,6vw,72px)] [&_h2]:!text-[clamp(40px,6vw,72px)] [&_p]:!text-[clamp(40px,6vw,72px)]`}>
86
+ <EditableRichText field={headline} />
87
+ </div>
88
+ <EditableRichText
89
+ field={lead}
90
+ className="mt-5 max-w-[540px] [&_p]:text-[19px] [&_p]:leading-[1.55] [&_p]:text-ink-2 [&_p]:m-0 [&_p+p]:mt-3"
91
+ />
92
+ <div className="mt-7 flex flex-wrap items-center gap-3">
93
+ <CtaButton field={primaryCta} variant="primary" />
94
+ <CtaButton field={secondaryCta} variant="secondary" />
95
+ </div>
96
+ </div>
97
+ {hasImage ? (
98
+ <div className="aspect-[5/4] overflow-hidden border border-hairline bg-paper-2">
99
+ <EditableImage
100
+ field={image}
101
+ className="!block h-full w-full object-cover [&_img]:h-full [&_img]:w-full [&_img]:object-cover"
102
+ />
103
+ </div>
104
+ ) : null}
105
+ </div>
106
+ </div>
107
+ </section>
108
+ )
109
+ }
110
+
111
+ // Stacked variants — centered or left-aligned, with optional image below.
112
+ const isCentered = layoutMode === 'stacked-center'
113
+ const alignWrapper = isCentered ? 'mx-auto text-center' : ''
114
+ const alignButtons = isCentered ? 'justify-center' : 'justify-start'
115
+ const leadAlign = isCentered ? 'mx-auto' : ''
116
+
117
+ return (
118
+ <section className={`${bgClass}`}>
119
+ <div className="mx-auto w-full max-w-[1280px] px-8 py-[88px]">
120
+ <div className={`max-w-[880px] ${alignWrapper}`}>
121
+ <EditableRichText
122
+ field={eyebrow}
123
+ className="[&_p]:font-mono [&_p]:font-medium [&_p]:text-[12px] [&_p]:tracking-[0.07em] [&_p]:uppercase [&_p]:text-ink-3 [&_p]:m-0"
124
+ />
125
+ <div className={`mt-4 ${HEADLINE_CLASSES} [&_h1]:!text-[clamp(48px,7vw,88px)] [&_h2]:!text-[clamp(48px,7vw,88px)] [&_p]:!text-[clamp(48px,7vw,88px)]`}>
126
+ <EditableRichText field={headline} />
127
+ </div>
128
+ <EditableRichText
129
+ field={lead}
130
+ className={`mt-5 max-w-[640px] ${leadAlign} [&_p]:text-[20px] [&_p]:leading-[1.55] [&_p]:text-ink-2 [&_p]:m-0 [&_p+p]:mt-3`}
131
+ />
132
+ <div className={`mt-8 flex flex-wrap items-center gap-3 ${alignButtons}`}>
133
+ <CtaButton field={primaryCta} variant="primary" />
134
+ <CtaButton field={secondaryCta} variant="secondary" />
135
+ </div>
136
+ {hasImage ? (
137
+ <div className="mt-12 aspect-[16/8] overflow-hidden border border-hairline bg-paper-2">
138
+ <EditableImage
139
+ field={image}
140
+ className="!block h-full w-full object-cover [&_img]:h-full [&_img]:w-full [&_img]:object-cover"
141
+ />
142
+ </div>
143
+ ) : null}
144
+ </div>
145
+ </div>
146
+ </section>
147
+ )
148
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { HeroComponent } from './component'
4
+
5
+ export const Hero = defineSection({
6
+ name: 'Hero',
7
+ category: 'Hero',
8
+ schema,
9
+ component: HeroComponent,
10
+ })
@@ -0,0 +1,16 @@
1
+ import { RichTextField, TextField, LinkField, ImageField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ eyebrow: RichTextField,
5
+ // Headline. Use *italic* for muted segments rendered in ink-3.
6
+ headline: RichTextField,
7
+ lead: RichTextField,
8
+ // Optional hero image — when filename is empty the hero renders text only.
9
+ image: ImageField,
10
+ primaryCta: LinkField,
11
+ secondaryCta: LinkField,
12
+ // "split" | "stacked-center" | "stacked-left". Default "split".
13
+ layout: TextField,
14
+ // "paper" | "paper-2". Default "paper".
15
+ background: TextField,
16
+ }
@@ -0,0 +1,57 @@
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 Step = SlotItem<typeof schema.steps.itemSchema>
8
+
9
+ interface Props {
10
+ readonly eyebrow: EditableSlot<'richText', string>
11
+ readonly headline: EditableSlot<'richText', string>
12
+ readonly steps: EditableSlot<'list', ReadonlyArray<Step>>
13
+ }
14
+
15
+ export function HowItWorksComponent({ eyebrow, headline, steps }: Props) {
16
+ return (
17
+ <section id="how" className="bg-bg-primary">
18
+ <div className="mx-auto max-w-[1080px] px-8 py-16 border-t-[0.5px] border-border-secondary">
19
+ <EditableRichText
20
+ field={eyebrow}
21
+ 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"
22
+ />
23
+ <EditableRichText
24
+ field={headline}
25
+ className="mb-6
26
+ [&_h2]:font-display [&_h2]:font-medium [&_h2]:text-text-primary [&_h2]:m-0
27
+ [&_h2]:max-w-[22ch]
28
+ [&_h2]:!text-[clamp(28px,3.6vw,40px)] [&_h2]:!leading-[1.1] [&_h2]:!tracking-[-0.02em]"
29
+ />
30
+ <EditableList
31
+ field={steps}
32
+ itemSchema={schema.steps.itemSchema}
33
+ className="grid grid-cols-1 md:grid-cols-3 gap-3 mt-8"
34
+ renderItem={(step) => (
35
+ <div className="h-full bg-bg-secondary border-[0.5px] border-border-primary rounded-lg px-[26px] py-6">
36
+ <EditableRichText
37
+ field={step.number}
38
+ as="div"
39
+ className="font-mono text-[11px] tracking-[0.10em] text-text-brand-primary uppercase"
40
+ />
41
+ <EditableRichText
42
+ field={step.title}
43
+ className="mt-3.5 mb-2.5
44
+ [&_h3]:font-display [&_h3]:font-medium [&_h3]:!text-[20px] [&_h3]:!leading-tight [&_h3]:tracking-[-0.02em] [&_h3]:text-text-primary [&_h3]:m-0
45
+ [&_p]:font-display [&_p]:font-medium [&_p]:!text-[20px] [&_p]:!leading-tight [&_p]:tracking-[-0.02em] [&_p]:text-text-primary [&_p]:m-0"
46
+ />
47
+ <EditableRichText
48
+ field={step.description}
49
+ className="prose [&_p]:text-sm [&_p]:leading-[1.65] [&_p]:text-text-secondary [&_p]:m-0"
50
+ />
51
+ </div>
52
+ )}
53
+ />
54
+ </div>
55
+ </section>
56
+ )
57
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { HowItWorksComponent } from './component'
4
+
5
+ export const HowItWorks = defineSection({
6
+ name: 'HowItWorks',
7
+ category: 'Content',
8
+ schema,
9
+ component: HowItWorksComponent,
10
+ })
@@ -0,0 +1,11 @@
1
+ import { RichTextField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ eyebrow: RichTextField,
5
+ headline: RichTextField,
6
+ steps: ListField({
7
+ number: RichTextField,
8
+ title: RichTextField,
9
+ description: RichTextField,
10
+ }),
11
+ }
@@ -0,0 +1,110 @@
1
+ 'use client'
2
+
3
+ import { EditableRichText, EditableImage, EditableLink, read, isSlotInPreview } from '@agntcms/next/client'
4
+ import type { EditableSlot } from '@agntcms/next/client'
5
+ import { hrefOf, isExternalLink } from '@agntcms/next'
6
+ import type { ImageValue, LinkValue } from '@agntcms/next'
7
+
8
+ interface Props {
9
+ readonly eyebrow: EditableSlot<'richText', string>
10
+ readonly headline: EditableSlot<'richText', string>
11
+ readonly body: EditableSlot<'richText', string>
12
+ readonly image: EditableSlot<'image', ImageValue>
13
+ readonly imagePosition: EditableSlot<'text', string>
14
+ readonly background: EditableSlot<'text', string>
15
+ readonly primaryCta: EditableSlot<'link', LinkValue>
16
+ readonly secondaryCta: EditableSlot<'link', LinkValue>
17
+ }
18
+
19
+ function CtaButton({
20
+ field,
21
+ variant,
22
+ }: {
23
+ field: EditableSlot<'link', LinkValue>
24
+ variant: 'primary' | 'secondary'
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-hairline-2 hover:border-ink'
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-2 whitespace-nowrap rounded-sm border px-[18px] py-[10px] text-sm font-medium no-underline transition-colors duration-200 ease-out ${styles}`}
43
+ />
44
+ </a>
45
+ )
46
+ }
47
+
48
+ export function ImageTextComponent({
49
+ eyebrow,
50
+ headline,
51
+ body,
52
+ image,
53
+ imagePosition,
54
+ background,
55
+ primaryCta,
56
+ secondaryCta,
57
+ }: Props) {
58
+ const position = (read(imagePosition) || 'left').trim()
59
+ const bg = (read(background) || 'paper').trim()
60
+ const bgClass = bg === 'paper-2' ? 'bg-paper-2' : 'bg-paper'
61
+
62
+ const imageBlock = (
63
+ <div className="aspect-[4/3] overflow-hidden border border-hairline bg-paper-2">
64
+ <EditableImage
65
+ field={image}
66
+ className="!block h-full w-full object-cover [&_img]:h-full [&_img]:w-full [&_img]:object-cover"
67
+ />
68
+ </div>
69
+ )
70
+
71
+ const textBlock = (
72
+ <div>
73
+ <EditableRichText
74
+ field={eyebrow}
75
+ className="[&_p]:font-mono [&_p]:font-medium [&_p]:text-[12px] [&_p]:tracking-[0.07em] [&_p]:uppercase [&_p]:text-ink-3 [&_p]:m-0"
76
+ />
77
+ <div className="mt-3 [&_h2]:m-0 [&_h2]:font-display [&_h2]:font-semibold [&_h2]:text-ink [&_h2]:text-[40px] [&_h2]:leading-[1.1] [&_h2]:tracking-[-0.025em] [&_p]:m-0 [&_p]:font-display [&_p]:font-semibold [&_p]:text-ink [&_p]:text-[40px] [&_p]:leading-[1.1] [&_p]:tracking-[-0.025em] [&_em]:not-italic [&_em]:text-ink-3 [&_em]:font-semibold">
78
+ <EditableRichText field={headline} />
79
+ </div>
80
+ <EditableRichText
81
+ field={body}
82
+ className="mt-4 [&_p]:m-0 [&_p]:text-[16.5px] [&_p]:leading-[1.65] [&_p]:text-ink-2 [&_p+p]:mt-3"
83
+ />
84
+ <div className="mt-6 flex flex-wrap gap-3">
85
+ <CtaButton field={primaryCta} variant="primary" />
86
+ <CtaButton field={secondaryCta} variant="secondary" />
87
+ </div>
88
+ </div>
89
+ )
90
+
91
+ return (
92
+ <section className={bgClass}>
93
+ <div className="mx-auto w-full max-w-[1280px] px-8 py-20">
94
+ <div className="grid grid-cols-1 gap-16 lg:grid-cols-2 lg:items-center">
95
+ {position === 'right' ? (
96
+ <>
97
+ {textBlock}
98
+ {imageBlock}
99
+ </>
100
+ ) : (
101
+ <>
102
+ {imageBlock}
103
+ {textBlock}
104
+ </>
105
+ )}
106
+ </div>
107
+ </div>
108
+ </section>
109
+ )
110
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { ImageTextComponent } from './component'
4
+
5
+ export const ImageText = defineSection({
6
+ name: 'ImageText',
7
+ category: 'Content',
8
+ schema,
9
+ component: ImageTextComponent,
10
+ })
@@ -0,0 +1,14 @@
1
+ import { RichTextField, TextField, LinkField, ImageField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ eyebrow: RichTextField,
5
+ headline: RichTextField,
6
+ body: RichTextField,
7
+ image: ImageField,
8
+ // "left" | "right". Default "left".
9
+ imagePosition: TextField,
10
+ // "paper" | "paper-2". Default "paper".
11
+ background: TextField,
12
+ primaryCta: LinkField,
13
+ secondaryCta: LinkField,
14
+ }
@@ -0,0 +1,37 @@
1
+ 'use client'
2
+
3
+ import { EditableRichText, EditableList, EditableText } from '@agntcms/next/client'
4
+ import type { EditableSlot, SlotItem } from '@agntcms/next/client'
5
+ import { schema } from './schema'
6
+
7
+ type Logo = SlotItem<typeof schema.logos.itemSchema>
8
+
9
+ interface Props {
10
+ readonly lead: EditableSlot<'richText', string>
11
+ readonly logos: EditableSlot<'list', ReadonlyArray<Logo>>
12
+ }
13
+
14
+ export function LogoStripComponent({ lead, logos }: Props) {
15
+ return (
16
+ <section className="bg-paper">
17
+ <div className="mx-auto w-full max-w-[1280px] px-8 py-8">
18
+ <EditableRichText
19
+ field={lead}
20
+ className="text-center [&_p]:font-mono [&_p]:font-medium [&_p]:text-[11px] [&_p]:tracking-[0.07em] [&_p]:uppercase [&_p]:text-ink-3 [&_p]:m-0 [&_p]:mb-5"
21
+ />
22
+ <EditableList
23
+ field={logos}
24
+ itemSchema={schema.logos.itemSchema}
25
+ className="flex flex-wrap items-center justify-between gap-8"
26
+ renderItem={(logo) => (
27
+ <EditableText
28
+ field={logo.name}
29
+ as="span"
30
+ className="font-mono font-medium text-sm tracking-[0.07em] uppercase text-ink-3"
31
+ />
32
+ )}
33
+ />
34
+ </div>
35
+ </section>
36
+ )
37
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { LogoStripComponent } from './component'
4
+
5
+ export const LogoStrip = defineSection({
6
+ name: 'LogoStrip',
7
+ category: 'Logos',
8
+ schema,
9
+ component: LogoStripComponent,
10
+ })
@@ -0,0 +1,6 @@
1
+ import { RichTextField, TextField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ lead: RichTextField,
5
+ logos: ListField({ name: TextField }),
6
+ }
@@ -0,0 +1,48 @@
1
+ 'use client'
2
+
3
+ import { EditableRichText, EditableText, read } from '@agntcms/next/client'
4
+ import type { EditableSlot } from '@agntcms/next/client'
5
+
6
+ interface Props {
7
+ readonly headline: EditableSlot<'richText', string>
8
+ readonly emailPlaceholder: EditableSlot<'text', string>
9
+ readonly buttonLabel: EditableSlot<'text', string>
10
+ readonly helperText: EditableSlot<'richText', string>
11
+ }
12
+
13
+ export function NewsletterComponent({
14
+ headline,
15
+ emailPlaceholder,
16
+ buttonLabel,
17
+ helperText,
18
+ }: Props) {
19
+ return (
20
+ <section className="bg-paper-2">
21
+ <div className="mx-auto w-full max-w-[720px] px-8 py-20 text-center">
22
+ <div className="[&_h2]:m-0 [&_h2]:font-display [&_h2]:font-semibold [&_h2]:text-ink [&_h2]:text-[36px] [&_h2]:leading-[1.1] [&_h2]:tracking-[-0.025em] [&_p]:m-0 [&_p]:font-display [&_p]:font-semibold [&_p]:text-ink [&_p]:text-[36px] [&_p]:leading-[1.1] [&_p]:tracking-[-0.025em] [&_em]:not-italic [&_em]:text-ink-3 [&_em]:font-semibold">
23
+ <EditableRichText field={headline} />
24
+ </div>
25
+ <form
26
+ onSubmit={(e) => e.preventDefault()}
27
+ className="mx-auto mt-7 flex max-w-[480px] items-end gap-0 border-b border-ink-2"
28
+ >
29
+ <input
30
+ type="email"
31
+ placeholder={read(emailPlaceholder) || 'you@company.com'}
32
+ className="flex-1 bg-transparent px-0 py-2.5 text-[15px] text-ink outline-none placeholder:text-ink-4"
33
+ />
34
+ <button
35
+ type="submit"
36
+ className="inline-flex items-center gap-2 whitespace-nowrap rounded-sm border border-ink bg-ink px-[18px] py-2.5 text-sm font-medium text-paper transition-colors duration-200 ease-out hover:bg-ink-2 hover:border-ink-2"
37
+ >
38
+ <EditableText field={buttonLabel} as="span" />
39
+ </button>
40
+ </form>
41
+ <EditableRichText
42
+ field={helperText}
43
+ className="mt-3.5 [&_p]:font-mono [&_p]:text-[12px] [&_p]:tracking-[0.07em] [&_p]:uppercase [&_p]:text-ink-3 [&_p]:m-0"
44
+ />
45
+ </div>
46
+ </section>
47
+ )
48
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { NewsletterComponent } from './component'
4
+
5
+ export const Newsletter = defineSection({
6
+ name: 'Newsletter',
7
+ category: 'Content',
8
+ schema,
9
+ component: NewsletterComponent,
10
+ })
@@ -0,0 +1,8 @@
1
+ import { RichTextField, TextField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ headline: RichTextField,
5
+ emailPlaceholder: TextField,
6
+ buttonLabel: TextField,
7
+ helperText: RichTextField,
8
+ }
@@ -0,0 +1,99 @@
1
+ 'use client'
2
+
3
+ import { EditableLink, EditableRichText, EditableList, read } 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 Stat = SlotItem<typeof schema.stats.itemSchema>
10
+
11
+ interface Props {
12
+ readonly eyebrow: EditableSlot<'richText', string>
13
+ readonly headline: EditableSlot<'richText', string>
14
+ readonly body: EditableSlot<'richText', string>
15
+ readonly stats: EditableSlot<'list', ReadonlyArray<Stat>>
16
+ readonly primaryCta: EditableSlot<'link', LinkValue>
17
+ readonly secondaryCta: EditableSlot<'link', LinkValue>
18
+ }
19
+
20
+ export function OpenSourceComponent({ eyebrow, headline, body, stats, primaryCta: rawPrimary, secondaryCta: rawSecondary }: Props) {
21
+ const primaryCta = read(rawPrimary)
22
+ const secondaryCta = read(rawSecondary)
23
+ return (
24
+ <section id="open-source" className="bg-bg-primary">
25
+ <div className="mx-auto max-w-[1080px] px-8 py-16 border-t-[0.5px] border-border-secondary">
26
+ <EditableRichText
27
+ field={eyebrow}
28
+ 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"
29
+ />
30
+ <EditableRichText
31
+ field={headline}
32
+ className="mb-6
33
+ [&_h2]:font-display [&_h2]:font-medium [&_h2]:text-text-primary [&_h2]:m-0
34
+ [&_h2]:max-w-[22ch]
35
+ [&_h2]:!text-[clamp(28px,3.6vw,40px)] [&_h2]:!leading-[1.1] [&_h2]:!tracking-[-0.02em]"
36
+ />
37
+ <EditableRichText
38
+ field={body}
39
+ className="prose max-w-[60ch]
40
+ [&_p]:text-text-primary [&_p]:m-0 [&_p]:mb-4 [&_p:last-child]:mb-0"
41
+ />
42
+
43
+ <EditableList
44
+ field={stats}
45
+ itemSchema={schema.stats.itemSchema}
46
+ className="grid grid-cols-2 md:grid-cols-4 border-[0.5px] border-border-primary rounded-lg my-8 mb-7 bg-bg-secondary overflow-hidden"
47
+ renderItem={(stat, index) => (
48
+ <div
49
+ className={[
50
+ 'px-6 py-6',
51
+ 'border-r-[0.5px] border-border-primary last:border-r-0',
52
+ index < 2 ? 'border-b-[0.5px] md:border-b-0' : '',
53
+ ].join(' ')}
54
+ >
55
+ <EditableRichText
56
+ field={stat.number}
57
+ as="div"
58
+ className="font-display font-medium text-[32px] tracking-[-0.04em] text-text-brand-primary"
59
+ />
60
+ <EditableRichText
61
+ field={stat.label}
62
+ as="div"
63
+ className="text-xs text-text-secondary mt-1 tracking-[0.04em]"
64
+ />
65
+ </div>
66
+ )}
67
+ />
68
+
69
+ <div className="flex gap-2.5 flex-wrap">
70
+ {hrefOf(primaryCta) && (
71
+ <a
72
+ href={hrefOf(primaryCta)}
73
+ target={isExternalLink(primaryCta) ? '_blank' : undefined}
74
+ rel={isExternalLink(primaryCta) ? 'noreferrer' : undefined}
75
+ className="inline-flex items-center gap-2 bg-transparent text-text-primary border-[0.5px] border-border-primary rounded-sm text-[13px] font-medium px-4 py-2 no-underline hover:bg-bg-secondary transition-colors"
76
+ >
77
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
78
+ <path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.56v-2c-3.2.7-3.87-1.36-3.87-1.36-.52-1.32-1.27-1.67-1.27-1.67-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.76 2.69 1.25 3.34.96.1-.74.4-1.25.72-1.54-2.55-.29-5.24-1.27-5.24-5.66 0-1.25.45-2.27 1.18-3.07-.12-.29-.51-1.46.11-3.04 0 0 .96-.31 3.15 1.17.91-.25 1.89-.38 2.86-.39.97 0 1.95.13 2.86.39 2.18-1.48 3.14-1.17 3.14-1.17.62 1.58.23 2.75.11 3.04.74.8 1.18 1.82 1.18 3.07 0 4.4-2.69 5.36-5.26 5.65.41.36.78 1.06.78 2.13v3.16c0 .31.21.67.8.56C20.21 21.39 23.5 17.08 23.5 12 23.5 5.65 18.35.5 12 .5z" />
79
+ </svg>
80
+ <EditableLink field={rawPrimary} className="no-underline" />
81
+ <span aria-hidden="true">↗</span>
82
+ </a>
83
+ )}
84
+ {hrefOf(secondaryCta) && (
85
+ <a
86
+ href={hrefOf(secondaryCta)}
87
+ target={isExternalLink(secondaryCta) ? '_blank' : undefined}
88
+ rel={isExternalLink(secondaryCta) ? 'noreferrer' : undefined}
89
+ className="inline-flex items-center gap-2 bg-transparent text-text-primary border-[0.5px] border-border-primary rounded-sm text-[13px] font-medium px-4 py-2 no-underline hover:bg-bg-secondary transition-colors"
90
+ >
91
+ <EditableLink field={rawSecondary} className="no-underline" />
92
+ <span aria-hidden="true">→</span>
93
+ </a>
94
+ )}
95
+ </div>
96
+ </div>
97
+ </section>
98
+ )
99
+ }
@@ -0,0 +1,10 @@
1
+ import { defineSection } from '@agntcms/next'
2
+ import { schema } from './schema'
3
+ import { OpenSourceComponent } from './component'
4
+
5
+ export const OpenSource = defineSection({
6
+ name: 'OpenSource',
7
+ category: 'Content',
8
+ schema,
9
+ component: OpenSourceComponent,
10
+ })
@@ -0,0 +1,13 @@
1
+ import { RichTextField, LinkField, ListField } from '@agntcms/next'
2
+
3
+ export const schema = {
4
+ eyebrow: RichTextField,
5
+ headline: RichTextField,
6
+ body: RichTextField,
7
+ stats: ListField({
8
+ number: RichTextField,
9
+ label: RichTextField,
10
+ }),
11
+ primaryCta: LinkField,
12
+ secondaryCta: LinkField,
13
+ }