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.
- package/README.md +39 -0
- package/dist/index.mjs +297 -0
- package/dist/template/.claude/settings.json +6 -0
- package/dist/template/.claude/skills/.gitkeep +0 -0
- package/dist/template/.claude-plugin/channel/server.mjs +254 -0
- package/dist/template/.claude-plugin/channel/server.ts +369 -0
- package/dist/template/.claude-plugin/plugin.json +17 -0
- package/dist/template/.mcp.json +8 -0
- package/dist/template/BRAND.md +49 -0
- package/dist/template/CLAUDE.md +157 -0
- package/dist/template/agntcms/config.ts +49 -0
- package/dist/template/agntcms/sections/ArticleBody/component.tsx +32 -0
- package/dist/template/agntcms/sections/ArticleBody/index.ts +10 -0
- package/dist/template/agntcms/sections/ArticleBody/schema.ts +5 -0
- package/dist/template/agntcms/sections/ArticleHero/component.tsx +87 -0
- package/dist/template/agntcms/sections/ArticleHero/index.ts +10 -0
- package/dist/template/agntcms/sections/ArticleHero/schema.ts +12 -0
- package/dist/template/agntcms/sections/Banner/component.tsx +83 -0
- package/dist/template/agntcms/sections/Banner/index.ts +10 -0
- package/dist/template/agntcms/sections/Banner/schema.ts +9 -0
- package/dist/template/agntcms/sections/BlogIndex/component.tsx +173 -0
- package/dist/template/agntcms/sections/BlogIndex/index.ts +10 -0
- package/dist/template/agntcms/sections/BlogIndex/schema.ts +33 -0
- package/dist/template/agntcms/sections/BlogIndexHeader/component.tsx +44 -0
- package/dist/template/agntcms/sections/BlogIndexHeader/index.ts +10 -0
- package/dist/template/agntcms/sections/BlogIndexHeader/schema.ts +8 -0
- package/dist/template/agntcms/sections/BlogPostBody/component.tsx +50 -0
- package/dist/template/agntcms/sections/BlogPostBody/index.ts +10 -0
- package/dist/template/agntcms/sections/BlogPostBody/schema.ts +10 -0
- package/dist/template/agntcms/sections/BlogPostHero/component.tsx +88 -0
- package/dist/template/agntcms/sections/BlogPostHero/index.ts +10 -0
- package/dist/template/agntcms/sections/BlogPostHero/schema.ts +35 -0
- package/dist/template/agntcms/sections/CaseStudies/component.tsx +92 -0
- package/dist/template/agntcms/sections/CaseStudies/index.ts +10 -0
- package/dist/template/agntcms/sections/CaseStudies/schema.ts +17 -0
- package/dist/template/agntcms/sections/ContactForm/component.tsx +119 -0
- package/dist/template/agntcms/sections/ContactForm/index.ts +10 -0
- package/dist/template/agntcms/sections/ContactForm/schema.ts +15 -0
- package/dist/template/agntcms/sections/DocsArticle/component.tsx +266 -0
- package/dist/template/agntcms/sections/DocsArticle/index.ts +10 -0
- package/dist/template/agntcms/sections/DocsArticle/schema.ts +33 -0
- package/dist/template/agntcms/sections/FAQ/component.tsx +57 -0
- package/dist/template/agntcms/sections/FAQ/index.ts +10 -0
- package/dist/template/agntcms/sections/FAQ/schema.ts +11 -0
- package/dist/template/agntcms/sections/FeatureGrid/component.tsx +117 -0
- package/dist/template/agntcms/sections/FeatureGrid/index.ts +10 -0
- package/dist/template/agntcms/sections/FeatureGrid/schema.ts +21 -0
- package/dist/template/agntcms/sections/FeaturedArticles/component.tsx +99 -0
- package/dist/template/agntcms/sections/FeaturedArticles/index.ts +10 -0
- package/dist/template/agntcms/sections/FeaturedArticles/schema.ts +17 -0
- package/dist/template/agntcms/sections/GettingStarted/component.tsx +116 -0
- package/dist/template/agntcms/sections/GettingStarted/index.ts +10 -0
- package/dist/template/agntcms/sections/GettingStarted/schema.ts +11 -0
- package/dist/template/agntcms/sections/Hero/component.tsx +148 -0
- package/dist/template/agntcms/sections/Hero/index.ts +10 -0
- package/dist/template/agntcms/sections/Hero/schema.ts +16 -0
- package/dist/template/agntcms/sections/HowItWorks/component.tsx +57 -0
- package/dist/template/agntcms/sections/HowItWorks/index.ts +10 -0
- package/dist/template/agntcms/sections/HowItWorks/schema.ts +11 -0
- package/dist/template/agntcms/sections/ImageText/component.tsx +110 -0
- package/dist/template/agntcms/sections/ImageText/index.ts +10 -0
- package/dist/template/agntcms/sections/ImageText/schema.ts +14 -0
- package/dist/template/agntcms/sections/LogoStrip/component.tsx +37 -0
- package/dist/template/agntcms/sections/LogoStrip/index.ts +10 -0
- package/dist/template/agntcms/sections/LogoStrip/schema.ts +6 -0
- package/dist/template/agntcms/sections/Newsletter/component.tsx +48 -0
- package/dist/template/agntcms/sections/Newsletter/index.ts +10 -0
- package/dist/template/agntcms/sections/Newsletter/schema.ts +8 -0
- package/dist/template/agntcms/sections/OpenSource/component.tsx +99 -0
- package/dist/template/agntcms/sections/OpenSource/index.ts +10 -0
- package/dist/template/agntcms/sections/OpenSource/schema.ts +13 -0
- package/dist/template/agntcms/sections/PainAnswer/component.tsx +81 -0
- package/dist/template/agntcms/sections/PainAnswer/index.ts +10 -0
- package/dist/template/agntcms/sections/PainAnswer/schema.ts +15 -0
- package/dist/template/agntcms/sections/PricingPlans/component.tsx +100 -0
- package/dist/template/agntcms/sections/PricingPlans/index.ts +10 -0
- package/dist/template/agntcms/sections/PricingPlans/schema.ts +13 -0
- package/dist/template/agntcms/sections/Problem/component.tsx +49 -0
- package/dist/template/agntcms/sections/Problem/index.ts +10 -0
- package/dist/template/agntcms/sections/Problem/schema.ts +12 -0
- package/dist/template/agntcms/sections/SiteFooter/component.tsx +88 -0
- package/dist/template/agntcms/sections/SiteFooter/index.ts +10 -0
- package/dist/template/agntcms/sections/SiteFooter/schema.ts +13 -0
- package/dist/template/agntcms/sections/SiteHeader/component.tsx +99 -0
- package/dist/template/agntcms/sections/SiteHeader/index.ts +10 -0
- package/dist/template/agntcms/sections/SiteHeader/schema.ts +14 -0
- package/dist/template/agntcms/sections/SiteMeta/component.tsx +26 -0
- package/dist/template/agntcms/sections/SiteMeta/index.ts +13 -0
- package/dist/template/agntcms/sections/SiteMeta/schema.ts +18 -0
- package/dist/template/agntcms/sections/TabbedFeatures/component.tsx +120 -0
- package/dist/template/agntcms/sections/TabbedFeatures/index.ts +10 -0
- package/dist/template/agntcms/sections/TabbedFeatures/schema.ts +13 -0
- package/dist/template/agntcms/sections/TeamGrid/component.tsx +77 -0
- package/dist/template/agntcms/sections/TeamGrid/index.ts +10 -0
- package/dist/template/agntcms/sections/TeamGrid/schema.ts +14 -0
- package/dist/template/agntcms/sections/Testimonials/component.tsx +76 -0
- package/dist/template/agntcms/sections/Testimonials/index.ts +10 -0
- package/dist/template/agntcms/sections/Testimonials/schema.ts +12 -0
- package/dist/template/agntcms/sections/WhatIsBuilt/component.tsx +86 -0
- package/dist/template/agntcms/sections/WhatIsBuilt/index.ts +10 -0
- package/dist/template/agntcms/sections/WhatIsBuilt/schema.ts +20 -0
- package/dist/template/agntcms/site-meta.ts +81 -0
- package/dist/template/app/[[...slug]]/page.tsx +123 -0
- package/dist/template/app/admin/AdminPageClient.tsx +77 -0
- package/dist/template/app/admin/AdminPageDynamic.tsx +24 -0
- package/dist/template/app/admin/page.tsx +14 -0
- package/dist/template/app/api/agntcms/_shared.ts +80 -0
- package/dist/template/app/api/agntcms/assets/route.ts +11 -0
- package/dist/template/app/api/agntcms/assets/upload/route.ts +11 -0
- package/dist/template/app/api/agntcms/draft/discard/route.ts +12 -0
- package/dist/template/app/api/agntcms/draft/list/route.ts +11 -0
- package/dist/template/app/api/agntcms/draft/publish/route.ts +11 -0
- package/dist/template/app/api/agntcms/draft/reorder/route.ts +10 -0
- package/dist/template/app/api/agntcms/draft/save/route.ts +11 -0
- package/dist/template/app/api/agntcms/events/route.ts +12 -0
- package/dist/template/app/api/agntcms/forms/delete/route.ts +17 -0
- package/dist/template/app/api/agntcms/forms/list/route.ts +24 -0
- package/dist/template/app/api/agntcms/forms/read/route.ts +23 -0
- package/dist/template/app/api/agntcms/forms/submit/route.ts +17 -0
- package/dist/template/app/api/agntcms/global/delete/route.ts +13 -0
- package/dist/template/app/api/agntcms/global/history/route.ts +10 -0
- package/dist/template/app/api/agntcms/global/list/route.ts +14 -0
- package/dist/template/app/api/agntcms/global/read/route.ts +11 -0
- package/dist/template/app/api/agntcms/global/rollback/route.ts +10 -0
- package/dist/template/app/api/agntcms/global/save/route.ts +14 -0
- package/dist/template/app/api/agntcms/mcp/route.ts +12 -0
- package/dist/template/app/api/agntcms/page/delete/route.ts +10 -0
- package/dist/template/app/api/agntcms/page/duplicate/route.ts +11 -0
- package/dist/template/app/api/agntcms/page/history/route.ts +10 -0
- package/dist/template/app/api/agntcms/page/list/route.ts +10 -0
- package/dist/template/app/api/agntcms/page/read/route.ts +11 -0
- package/dist/template/app/api/agntcms/page/rename/route.ts +10 -0
- package/dist/template/app/api/agntcms/page/rollback/route.ts +10 -0
- package/dist/template/app/api/agntcms/page/unpublish/route.ts +11 -0
- package/dist/template/app/api/agntcms/preview/enter/route.ts +13 -0
- package/dist/template/app/api/agntcms/preview/exit/route.ts +10 -0
- package/dist/template/app/api/agntcms/preview/issue/route.ts +12 -0
- package/dist/template/app/api/agntcms/template/list/route.ts +15 -0
- package/dist/template/app/apple-icon.svg +9 -0
- package/dist/template/app/icon.svg +9 -0
- package/dist/template/app/layout.tsx +107 -0
- package/dist/template/app/not-found.tsx +75 -0
- package/dist/template/app/robots.ts +33 -0
- package/dist/template/app/sitemap.ts +49 -0
- package/dist/template/content/globals/site-footer.json +53 -0
- package/dist/template/content/globals/site-header.json +18 -0
- package/dist/template/content/globals/site-meta.json +13 -0
- package/dist/template/content/pages/404.json +34 -0
- package/dist/template/content/pages/about.json +307 -0
- package/dist/template/content/pages/article-editor.json +61 -0
- package/dist/template/content/pages/article-schemas.json +61 -0
- package/dist/template/content/pages/blog.json +162 -0
- package/dist/template/content/pages/contact.json +29 -0
- package/dist/template/content/pages/home.json +243 -0
- package/dist/template/content/pages/pricing.json +219 -0
- package/dist/template/content/pages/services.json +177 -0
- package/dist/template/fonts/Satoshi-Medium.woff2 +0 -0
- package/dist/template/fonts/Satoshi-Regular.woff2 +0 -0
- package/dist/template/next.config.ts +6 -0
- package/dist/template/package.json +36 -0
- package/dist/template/postcss.config.mjs +5 -0
- package/dist/template/public/assets/.gitkeep +0 -0
- package/dist/template/public/assets/0418d7ed21f57e7b9e0546725c92b8419daeaa355675d9070fab0c2013cf1524.jpg +0 -0
- package/dist/template/public/assets/0d0475f21aa96435a8ed3cdb2fddcc6278492e76ae842f569432454f4d33631a.jpg +0 -0
- package/dist/template/public/assets/27457a1adee2372030d9876b0d52c44d46be98843999935eaef2526b9b961f12.jpg +0 -0
- package/dist/template/public/assets/3855d91192f0c6120b01427b78ef84e52baa9f4b5a17d4271e41c1bfd95a5b0c.jpg +0 -0
- package/dist/template/public/assets/3b3b90c5084635b746be673ede92a328f002f5621a42c9a5cb89c5e2435652cb.jpg +0 -0
- package/dist/template/public/assets/3e76165a78fd3e7b8ed1e93dee50803ae11110c756c8c1c89229a2dec2bc0abf.jpg +0 -0
- package/dist/template/public/assets/4a3e28f85dc850c347ea0fd931696aa936a6bd45f193e7f1c9328b5896fb272c.jpg +0 -0
- package/dist/template/public/assets/579f67d5fd4c9106c6cdf2ef29f50df934ad0fc2b7849bac1e1cfb1e3f92303b.jpg +0 -0
- package/dist/template/public/assets/5b95209269661bb60fb250f1da682e05b9efa64dd42f350608b299e6bf1f2f35.jpg +0 -0
- package/dist/template/public/assets/5e04b46f8317ef95a7ddf85aedfe5c098a755f05056325d0251eccf95ce51172.jpg +0 -0
- package/dist/template/public/assets/6167a9164be2cf1183bdfdd4946bf9b908570e79e92a2380c25f0bb702422bbd.jpg +0 -0
- package/dist/template/public/assets/75e723ec316de28247924e5dfb73a4b266e10de605e749f150883d280ed8ed16.jpg +0 -0
- package/dist/template/public/assets/816a11e6a7245feaf51bbebf09d1bda3f125b334bc24fc3b8f47b5380a7b4294.jpg +0 -0
- package/dist/template/public/assets/81eba6f5654b8746a9b0cba1a9521a67f2b4afaaefc7c88d66dfab1461270d8f.jpg +0 -0
- package/dist/template/public/assets/82a2ce9e49361098f77a28755779dc5a7c026831cbd135175749c1304e21dacc.jpg +0 -0
- package/dist/template/public/assets/8d7b02ba277ba56bdafdbd47b01f7df6d993c714b4dc2305eb65a1307c09647d.jpg +0 -0
- package/dist/template/public/assets/b303185b471678e4d62f678a1549ee26022f4745407d08cae44ecb1c25352293.jpg +0 -0
- package/dist/template/public/assets/b69b49169c11546100d6dd5280073bc0d84cbbcc6d33fa01ecf6a5866fa42237.jpg +0 -0
- package/dist/template/public/assets/c4d2f0d1a310e457ac722a399693652e3c86c55b294243d5ffc679394e12f9d1.jpg +0 -0
- package/dist/template/public/assets/cae09f4729f8a348b67267c2f2a550be0f3bfa420689afe1a5cf8b7e2b146238.png +0 -0
- package/dist/template/public/assets/cb3acf58b57417a4b26474ba04c096af7103c4320ed2f4f3683f79d7670a055c.jpg +0 -0
- package/dist/template/public/assets/d5a0701b2d156284e0ce851cd2534ec632db34f91fbcbee3b8a7784d45ce78d2.jpg +0 -0
- package/dist/template/public/assets/d6ef1c3f48b0e488521794fb60701da1fd2c3a1621d6ac5f17ccfd4909d3be60.jpg +0 -0
- package/dist/template/public/assets/de249ff9be2539cf0d1ce092de3c57001839b6c3e14fcee3fc31a7b7673ae007.jpg +0 -0
- package/dist/template/public/assets/eac45438956be187b010e24b3289757aa00f227c190d49ee99fea510552dd2ba.jpg +0 -0
- package/dist/template/public/assets/f8b9200065b5436c6a88361839edc2b89be88d3037c84a80d3ee95c32891510b.jpg +0 -0
- package/dist/template/public/assets/placeholder.png +0 -0
- package/dist/template/public/brand/mark.svg +6 -0
- package/dist/template/public/brand/wordmark-light.svg +6 -0
- package/dist/template/public/brand/wordmark.svg +6 -0
- package/dist/template/styles/globals.css +69 -0
- package/dist/template/styles/theme.css +492 -0
- package/dist/template/styles/typography.css +469 -0
- package/dist/template/tsconfig.json +30 -0
- 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,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,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,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,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
|
+
}
|