create-ailk 0.7.0 → 0.8.0
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 +44 -10
- package/component-catalog.json +520 -5
- package/component-catalog.md +9 -6
- package/dist/cli.js +22 -24
- package/dist/lib/extract-module-bundle.js +5 -1
- package/dist/lib/module-license-gate.d.ts +79 -0
- package/dist/lib/module-license-gate.js +160 -12
- package/dist/lib/module-tier.d.ts +45 -16
- package/dist/lib/module-tier.js +76 -0
- package/dist/lib/pro-callout.js +10 -2
- package/dist/parse-args.d.ts +78 -10
- package/dist/parse-args.js +204 -14
- package/dist/programmatic.d.ts +39 -9
- package/dist/programmatic.js +163 -25
- package/dist/site-roster.js +11 -6
- package/dist/starter-grid.d.ts +216 -0
- package/dist/starter-grid.js +449 -0
- package/dist/surfaces.d.ts +4 -4
- package/dist/surfaces.js +102 -43
- package/dist/template-manifest.d.ts +36 -17
- package/dist/template-manifest.js +121 -367
- package/dist/template-names.d.ts +14 -12
- package/dist/template-names.js +13 -17
- package/package.json +3 -3
- package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -1
- package/site-templates/_base/content/en/Feature/feature-1.mdx +69 -0
- package/site-templates/_base/content/en/Feature/feature-2.mdx +69 -0
- package/site-templates/_base/content/en/Feature/feature-3.mdx +69 -0
- package/site-templates/_base/content/en/FeaturesList/features.mdx +91 -0
- package/site-templates/_base/content/en/GlossaryList/glossary.mdx +0 -1
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +0 -1
- package/site-templates/_base/content/en/PortfolioItem/sample-four.mdx +105 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-one.mdx +34 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-three.mdx +94 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-two.mdx +45 -0
- package/site-templates/_base/content/en/PortfolioList/portfolio.mdx +169 -0
- package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +15 -0
- package/site-templates/_base/content/en/UseCase/persona-1.mdx +69 -0
- package/site-templates/_base/content/en/UseCase/persona-2.mdx +69 -0
- package/site-templates/_base/content/en/UseCase/persona-3.mdx +69 -0
- package/site-templates/designs/standard/DESIGN.md +5 -0
- package/site-templates/marketing-site/DESIGN.md +5 -0
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +89 -25
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +35 -14
- package/site-templates/marketing-site-free/DESIGN.md +5 -0
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +95 -29
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +74 -44
- package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +199 -0
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +17 -29
- package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -1
- package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
- package/site-templates/saas-product/DESIGN.md +5 -0
- package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
- package/site-templates/{simple-service → shapes/local-business-service}/TEMPLATE-MANIFEST.json +96 -76
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +302 -0
- package/site-templates/shapes/local-business-service/ailk-template.json +10 -0
- package/site-templates/{simple-service → shapes/local-business-service}/content/en/AboutPage/about.mdx +4 -4
- package/site-templates/shapes/local-business-service/content/en/HomePage/home.mdx +70 -0
- package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/shapes/local-business-service/content/en/PortfolioList/portfolio.mdx +171 -0
- package/site-templates/{simple-service → shapes/local-business-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +7 -8
- package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +39 -0
- package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +39 -0
- package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +39 -0
- package/site-templates/shapes/local-business-service/content/en/ServicesList/services.mdx +61 -0
- package/site-templates/shapes/local-business-service/provenance.json +4 -0
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +362 -0
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +300 -0
- package/site-templates/shapes/organization-service/ailk-template.json +10 -0
- package/site-templates/shapes/organization-service/content/en/AboutPage/about.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/HomePage/home.mdx +85 -0
- package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/shapes/organization-service/content/en/PortfolioList/portfolio.mdx +171 -0
- package/site-templates/shapes/organization-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
- package/site-templates/shapes/organization-service/content/en/Service/first-engagement.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/Service/second-engagement.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/Service/third-engagement.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/ServicesList/services.mdx +72 -0
- package/site-templates/shapes/organization-service/provenance.json +4 -0
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +369 -0
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +299 -0
- package/site-templates/shapes/person-service/ailk-template.json +10 -0
- package/site-templates/shapes/person-service/content/_site.mdx +85 -0
- package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +39 -0
- package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +97 -0
- package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +169 -0
- package/site-templates/shapes/person-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
- package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +38 -0
- package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +38 -0
- package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +38 -0
- package/site-templates/{simple-service → shapes/person-service}/content/en/ServicesList/services.mdx +16 -16
- package/site-templates/shapes/person-service/provenance.json +4 -0
- package/templates/.claude/skills/README.md +3 -2
- package/templates/.claude/skills/add-page/references/page-types.md +4 -0
- package/templates/.claude/skills/setup-database/SKILL.md +156 -0
- package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +154 -0
- package/templates/.claude/skills/setup-deploy/SKILL.md +64 -32
- package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +19 -28
- package/templates/.claude/skills/setup-deploy/references/runbook-template.md +58 -102
- package/templates/DESIGN.md +5 -0
- package/templates/README.md +46 -38
- package/templates/apps/api/CLAUDE.md +3 -2
- package/templates/apps/api/src/config/__tests__/index.test.ts +115 -14
- package/templates/apps/api/src/config/index.ts +35 -16
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +30 -0
- package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +96 -0
- package/templates/apps/api/src/lib/lead-capture-store.ts +12 -0
- package/templates/apps/api/src/lib/lead-delivery.ts +52 -0
- package/templates/apps/api/src/openapi/spec.ts +63 -12
- package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +88 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +100 -0
- package/templates/apps/api/src/routes/leads/index.ts +46 -1
- package/templates/apps/api/src/server.ts +7 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +194 -0
- package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +124 -0
- package/templates/apps/api/src/services/lead-routing.ts +140 -30
- package/templates/apps/api/src/services/leads-inbox.ts +48 -11
- package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
- package/templates/apps/mcp/src/tools/create_project.ts +21 -6
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +14 -6
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +10 -9
- package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +32 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +129 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +227 -84
- package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +50 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +73 -20
- package/templates/apps/web/app/[locale]/contact/page.tsx +105 -15
- package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
- package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +64 -0
- package/templates/apps/web/app/[locale]/features/page.tsx +52 -0
- package/templates/apps/web/app/[locale]/layout.tsx +37 -5
- package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +75 -0
- package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +163 -0
- package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +66 -0
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +106 -14
- package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
- package/templates/apps/web/app/[locale]/portfolio/page.tsx +49 -0
- package/templates/apps/web/app/[locale]/use-cases/[slug]/page.tsx +18 -3
- package/templates/apps/web/lib/nav-config.ts +48 -36
- package/templates/apps/web/lib/site-identity.ts +14 -0
- package/templates/apps/web/messages/en.json +28 -2
- package/templates/content/_site.mdx +4 -2
- package/templates/content/en/BlogList/blog.mdx +37 -16
- package/templates/content/en/ContactPage/contact.mdx +14 -44
- package/templates/content/en/HomePage/home.mdx +8 -16
- package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
- package/templates/content/en/UseCasesList/use-cases.mdx +6 -6
- package/templates/database/CHANGELOG.md +7 -0
- package/templates/database/package.json +1 -1
- package/versions.json +33 -33
- package/site-templates/_base/content/en/UseCase/first-use-case.mdx +0 -23
- package/site-templates/_base/content/en/UseCase/second-use-case.mdx +0 -23
- package/site-templates/_base/content/en/UseCase/third-use-case.mdx +0 -23
- package/site-templates/simple-service/DESIGN.md +0 -162
- package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -333
- package/site-templates/simple-service/ailk-template.json +0 -11
- package/site-templates/simple-service/content/en/BookCall/book-call.mdx +0 -53
- package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -32
- package/site-templates/simple-service/content/en/FAQPage/faq.mdx +0 -56
- package/site-templates/simple-service/content/en/HomePage/home.mdx +0 -85
- package/site-templates/simple-service/content/en/Service/landscape-design.mdx +0 -40
- package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +0 -40
- package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +0 -40
- package/site-templates/simple-service/provenance.json +0 -4
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -211
- package/templates/apps/web/app/[locale]/contact/__tests__/ContactForm.test.tsx +0 -96
- package/templates/content/en/SoftwareProduct/product.mdx +0 -175
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Template manifest — `local-business-service`
|
|
2
|
+
|
|
3
|
+
> The Free `local-business-service` shape starter (#6757, roadmap § 6 Phase 2) — a local business selling a service in one service area, scaffolded keyless with no `--template` alias of its own. Generated file: the regions between `<!-- generated:begin <id> -->` and `<!-- generated:end -->` are produced by `scripts/build-template-manifest.mjs --template local-business-service --check` from the composed layer stack (this tree → `_base` → the always-copied overlay), each roster row's MDX `sections[]`, and `component-catalog.json`. Everything outside the markers is written by hand.
|
|
4
|
+
|
|
5
|
+
| Field | Value |
|
|
6
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
7
|
+
| Starter | `local-business-service` (a `SHAPE_STARTERS` entry, not a `--template` alias) |
|
|
8
|
+
| Level | Free (derived from `requires` — `marketing` only; never declared) |
|
|
9
|
+
| `requires` | `[marketing]` |
|
|
10
|
+
| `extends` | `_base` — lineage only, never level |
|
|
11
|
+
| Delivery | keyless — ships in the tarball at `site-templates/shapes/local-business-service/` |
|
|
12
|
+
| Sample content posture | every line of copy is a **placeholder**; no seed carries a price (D4) |
|
|
13
|
+
| `mainEntity` | `LocalBusiness` (this shape's own — the overlay `_site.mdx` keeps `siteIdentity.kind: Organization`; the owner sets `kind: LocalBusiness`) |
|
|
14
|
+
|
|
15
|
+
## 1. Chrome
|
|
16
|
+
|
|
17
|
+
This starter declares **no `layout` block** — the default marketing chrome.
|
|
18
|
+
|
|
19
|
+
### Layout knobs (#5612)
|
|
20
|
+
|
|
21
|
+
<!-- generated:begin layout -->
|
|
22
|
+
|
|
23
|
+
| Knob | Value |
|
|
24
|
+
| -------------------- | --------- |
|
|
25
|
+
| `nav` | `full` |
|
|
26
|
+
| `footer` | `columns` |
|
|
27
|
+
| `announcementBanner` | `false` |
|
|
28
|
+
| `home` | `default` |
|
|
29
|
+
|
|
30
|
+
<!-- generated:end -->
|
|
31
|
+
|
|
32
|
+
### Theme (locked)
|
|
33
|
+
|
|
34
|
+
<!-- generated:begin theme -->
|
|
35
|
+
|
|
36
|
+
| Setting | Value |
|
|
37
|
+
| ------------------------ | ---------- |
|
|
38
|
+
| `corners` | `square` |
|
|
39
|
+
| `eyebrowCase` | `sentence` |
|
|
40
|
+
| `placeholders` | `fill` |
|
|
41
|
+
| `checkmarks` | `plain` |
|
|
42
|
+
| `colors.light.bg` | `#ffffff` |
|
|
43
|
+
| `colors.light.bgMuted` | `#ffffff` |
|
|
44
|
+
| `colors.light.surface` | `#ffffff` |
|
|
45
|
+
| `colors.light.border` | `#000000` |
|
|
46
|
+
| `colors.light.text` | `#000000` |
|
|
47
|
+
| `colors.light.textMuted` | `#333333` |
|
|
48
|
+
| `colors.light.primary` | `#000000` |
|
|
49
|
+
| `colors.light.primaryFg` | `#ffffff` |
|
|
50
|
+
| `colors.light.accent` | `#000000` |
|
|
51
|
+
| `colors.dark.bg` | `#000000` |
|
|
52
|
+
| `colors.dark.bgMuted` | `#000000` |
|
|
53
|
+
| `colors.dark.surface` | `#000000` |
|
|
54
|
+
| `colors.dark.border` | `#ffffff` |
|
|
55
|
+
| `colors.dark.text` | `#ffffff` |
|
|
56
|
+
| `colors.dark.textMuted` | `#cccccc` |
|
|
57
|
+
| `colors.dark.primary` | `#ffffff` |
|
|
58
|
+
| `colors.dark.primaryFg` | `#000000` |
|
|
59
|
+
| `colors.dark.accent` | `#ffffff` |
|
|
60
|
+
|
|
61
|
+
<!-- generated:end -->
|
|
62
|
+
|
|
63
|
+
## 2. Pages
|
|
64
|
+
|
|
65
|
+
One `page=<route>` region per roster row, generated from the seed file the composed layer stack lands for that route.
|
|
66
|
+
|
|
67
|
+
`/`:
|
|
68
|
+
|
|
69
|
+
<!-- generated:begin page=/ -->
|
|
70
|
+
|
|
71
|
+
| # | Section | Component | Copy (first line) |
|
|
72
|
+
| --- | ---------------------------------------------------------- | --------- | --------------------------------------------------------------- |
|
|
73
|
+
| 1 | `hero` (centered · eyebrow "{Your service area}" · 2 CTAs) | `Hero` | {One line on the job you do and the trust it takes to hire you} |
|
|
74
|
+
| 2 | `items` (columns=3 · items ×3) | `Items` | What we do |
|
|
75
|
+
| 3 | `cta` (minimal · 2 CTAs) | `CTA` | Ready to get started? |
|
|
76
|
+
|
|
77
|
+
<!-- generated:end -->
|
|
78
|
+
|
|
79
|
+
`/services`:
|
|
80
|
+
|
|
81
|
+
<!-- generated:begin page=/services -->
|
|
82
|
+
|
|
83
|
+
| # | Section | Component | Copy (first line) |
|
|
84
|
+
| --- | -------------------------------------- | --------- | -------------------- |
|
|
85
|
+
| 1 | `hero` (centered · eyebrow "Services") | `Hero` | Three jobs, one crew |
|
|
86
|
+
| 2 | `items` (columns=3 · items ×3) | `Items` | What we do |
|
|
87
|
+
| 3 | `cta` (minimal · 1 CTA) | `CTA` | Not sure which one? |
|
|
88
|
+
|
|
89
|
+
<!-- generated:end -->
|
|
90
|
+
|
|
91
|
+
`/services/[slug]`:
|
|
92
|
+
|
|
93
|
+
<!-- generated:begin page=/services/[slug] -->
|
|
94
|
+
|
|
95
|
+
_Detail route over `content/en/Service/` — 3 seed pages: `first-job.mdx`, `second-job.mdx`, `third-job.mdx`._
|
|
96
|
+
<!-- generated:end -->
|
|
97
|
+
|
|
98
|
+
`/about`:
|
|
99
|
+
|
|
100
|
+
<!-- generated:begin page=/about -->
|
|
101
|
+
|
|
102
|
+
| # | Section | Component | Copy (first line) |
|
|
103
|
+
| --- | ------------------------------------------ | -------------- | -------------------------------------------------- |
|
|
104
|
+
| 1 | `content-block` (narrow · eyebrow "About") | `ContentBlock` | {A small crew, the same neighborhoods, every week} |
|
|
105
|
+
| 2 | `cta` (minimal · 2 CTAs) | `CTA` | Want us to take a look? |
|
|
106
|
+
|
|
107
|
+
<!-- generated:end -->
|
|
108
|
+
|
|
109
|
+
`/contact` (always-copied overlay seed):
|
|
110
|
+
|
|
111
|
+
<!-- generated:begin page=/contact -->
|
|
112
|
+
|
|
113
|
+
| # | Section | Component | Copy (first line) |
|
|
114
|
+
| --- | --------------------------------------------------------- | --------- | ------------------------------------- |
|
|
115
|
+
| 1 | `hero` (split · eyebrow "Contact" · checklist ×3 · 1 CTA) | `Hero` | Get every message in your email, free |
|
|
116
|
+
|
|
117
|
+
<!-- generated:end -->
|
|
118
|
+
|
|
119
|
+
`/faq` (always-copied overlay seed):
|
|
120
|
+
|
|
121
|
+
<!-- generated:begin page=/faq -->
|
|
122
|
+
|
|
123
|
+
| # | Section | Component | Copy (first line) |
|
|
124
|
+
| --- | ------------------------------------------------------- | --------- | ---------------------------------------- |
|
|
125
|
+
| 1 | `hero` (gapBelow=tight · eyebrow "FAQ") | `Hero` | FAQs |
|
|
126
|
+
| 2 | `faq` (accordion · items ×5 · 1 CTA · initialOpen none) | `FAQ` | {A question your customers actually ask} |
|
|
127
|
+
| 3 | `faq` (accordion · items ×5 · 1 CTA · initialOpen none) | `FAQ` | {A second group of questions} |
|
|
128
|
+
|
|
129
|
+
<!-- generated:end -->
|
|
130
|
+
|
|
131
|
+
`/glossary`, `/newsletter`, `/book-a-call` (base-layer seeds every starter carries, #6658 D5 — `/newsletter` is this tree's own byte copy of the Free newsletter, D4/D9):
|
|
132
|
+
|
|
133
|
+
<!-- generated:begin page=/glossary -->
|
|
134
|
+
|
|
135
|
+
| # | Section | Component | Copy (first line) |
|
|
136
|
+
| --- | ----------------------------------- | --------------- | -------------------------------------------- |
|
|
137
|
+
| 1 | `hero` (eyebrow "Glossary" · 1 CTA) | `Hero` | {Glossary: the terms your customers look up} |
|
|
138
|
+
| 2 | `glossary-index` (columns) | `GlossaryIndex` | {Terms, A to Z} |
|
|
139
|
+
|
|
140
|
+
<!-- generated:end -->
|
|
141
|
+
|
|
142
|
+
<!-- generated:begin page=/newsletter -->
|
|
143
|
+
|
|
144
|
+
| # | Section | Component | Copy (first line) |
|
|
145
|
+
| --- | -------------------------------------- | --------- | --------------------------------------- |
|
|
146
|
+
| 1 | `hero` (eyebrow "Newsletter" · 2 CTAs) | `Hero` | {Start a free newsletter with Substack} |
|
|
147
|
+
| 2 | `faq` (expanded · items ×3) | `FAQ` | FAQs |
|
|
148
|
+
|
|
149
|
+
<!-- generated:end -->
|
|
150
|
+
|
|
151
|
+
<!-- generated:begin page=/book-a-call -->
|
|
152
|
+
|
|
153
|
+
| # | Section | Component | Copy (first line) |
|
|
154
|
+
| --- | -------------------------------------- | --------- | ------------------------------------------ |
|
|
155
|
+
| 1 | `hero` (eyebrow "Book a call" · 1 CTA) | `Hero` | {Book a call: what a visitor gets from it} |
|
|
156
|
+
| 2 | `items` (columns=3 · items ×3) | `Items` | What happens on the call? |
|
|
157
|
+
|
|
158
|
+
<!-- generated:end -->
|
|
159
|
+
|
|
160
|
+
`/purchase-policy` (this tree's own service-shape override — cancellation and refunds, D4):
|
|
161
|
+
|
|
162
|
+
<!-- generated:begin page=/purchase-policy -->
|
|
163
|
+
|
|
164
|
+
| # | Section | Component | Copy (first line) |
|
|
165
|
+
| --- | ----------------------------------- | ----------------- | ----------------- |
|
|
166
|
+
| 1 | `document-chassis` (layout=article) | `DocumentChassis` | Purchase Policy |
|
|
167
|
+
|
|
168
|
+
<!-- generated:end -->
|
|
169
|
+
|
|
170
|
+
`/privacy`, `/terms` (base-layer seeds):
|
|
171
|
+
|
|
172
|
+
<!-- generated:begin page=/privacy -->
|
|
173
|
+
|
|
174
|
+
| # | Section | Component | Copy (first line) |
|
|
175
|
+
| --- | ----------------------------------- | ----------------- | ----------------- |
|
|
176
|
+
| 1 | `document-chassis` (layout=article) | `DocumentChassis` | Privacy Policy |
|
|
177
|
+
|
|
178
|
+
<!-- generated:end -->
|
|
179
|
+
|
|
180
|
+
<!-- generated:begin page=/terms -->
|
|
181
|
+
|
|
182
|
+
| # | Section | Component | Copy (first line) |
|
|
183
|
+
| --- | ----------------------------------- | ----------------- | ----------------- |
|
|
184
|
+
| 1 | `document-chassis` (layout=article) | `DocumentChassis` | Terms of Service |
|
|
185
|
+
|
|
186
|
+
<!-- generated:end -->
|
|
187
|
+
|
|
188
|
+
`/blog` (the Free teaser row, § 1.8 — served by the generic `[slug]` route over the always-copied overlay's `BlogList/blog.mdx`):
|
|
189
|
+
|
|
190
|
+
<!-- generated:begin page=/blog -->
|
|
191
|
+
|
|
192
|
+
| # | Section | Component | Copy (first line) |
|
|
193
|
+
| --- | ------------------------------------------------------------ | -------------- | ----------------------------------------------------------------- |
|
|
194
|
+
| 1 | `hero` (centered · gapBelow=tight · eyebrow "Blog" · 2 CTAs) | `Hero` | Get free blog/docs from Fumadocs |
|
|
195
|
+
| 2 | `blog-list` (grid) | `BlogList` | |
|
|
196
|
+
| 3 | `logoCloud` (layout=inline · logos ×6) | `LogoCloud` | Don’t just take our word for it |
|
|
197
|
+
| 4 | `testimonials` (quote · items ×1) | `Testimonials` | {A customer quote, in their own words, about the result they got} |
|
|
198
|
+
|
|
199
|
+
<!-- generated:end -->
|
|
200
|
+
|
|
201
|
+
`/portfolio` (this tree's own override of the `_base` seed — both primary CTAs point at `/contact`, D4):
|
|
202
|
+
|
|
203
|
+
<!-- generated:begin page=/portfolio -->
|
|
204
|
+
|
|
205
|
+
| # | Section | Component | Copy (first line) |
|
|
206
|
+
| --- | ---------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------- |
|
|
207
|
+
| 1 | `hero` (default · gapBelow=tight · size=display · surface=wash-secondary · eyebrow "{Portfolio}" · 2 CTAs) | `Hero` | {The work, before and after.} |
|
|
208
|
+
| 2 | `items` (tile · surface=none · columns=2 · items ×4) | `Items` | |
|
|
209
|
+
| 3 | `cta` (beam · chips ×3 · 2 CTAs) | `CTA` | {Is your property the before or the after?} |
|
|
210
|
+
| 4 | `faq` (centered · surface=gray-100 · accordion · items ×3 · initialOpen first) | `FAQ` | Frequently Asked Questions |
|
|
211
|
+
|
|
212
|
+
<!-- generated:end -->
|
|
213
|
+
|
|
214
|
+
`/portfolio/[slug]`:
|
|
215
|
+
|
|
216
|
+
<!-- generated:begin page=/portfolio/[slug] -->
|
|
217
|
+
|
|
218
|
+
_Detail route over `content/en/PortfolioItem/` — 4 seed pages: `sample-four.mdx`, `sample-one.mdx`, `sample-three.mdx`, `sample-two.mdx`._
|
|
219
|
+
<!-- generated:end -->
|
|
220
|
+
|
|
221
|
+
### 3a. Differences from the standard `local-business-service` derivation
|
|
222
|
+
|
|
223
|
+
The standard page set for this shape (`derive-roster.py --shape local-business-service --primary-goal generate-leads --registry packages/schema/src/registry/entries.ts`, harness commit `7bdaf148e1b0e639cd90a80008955e55cc4aa2b5`) is 36 rows, `mainEntity: LocalBusiness`. This starter's roster is that set minus the standard rows the table below drops, plus the rows the table after it adds, each with a reason.
|
|
224
|
+
|
|
225
|
+
**Standard rows dropped:**
|
|
226
|
+
|
|
227
|
+
| Standard row | Reason |
|
|
228
|
+
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
229
|
+
| `TeamList` · `TeamMember` | a placeholder starter has no team to list; `/about` carries the people |
|
|
230
|
+
| `CareersList` · `JobPosting` | a placeholder starter has no open roles |
|
|
231
|
+
| `PartnersList` · `Partner` | a placeholder starter has no partners to list |
|
|
232
|
+
| `ProjectsList` · `Project` | the portfolio pair (`/portfolio`) is the proof of past work; `/projects` is the signal-collectors sample listing |
|
|
233
|
+
| `Pricing` | a service is priced on its own `Service` page (or quoted), not on a pricing table |
|
|
234
|
+
| `CaseStudiesList` · `CaseStudy` · `TestimonialsList` · `ClientsList` | proof pages need real customers (the #6658 reason) |
|
|
235
|
+
| `UseCasesList` · `UseCase` | each `Service` page names who it is for; the `_base` persona seeds are product copy that links `/pricing` |
|
|
236
|
+
| `EventsList` · `Event` · `DownloadsList` | a placeholder starter has no events or downloads |
|
|
237
|
+
| `ResourcesHub` · `ResourceDetail` · `HowTo` · `Whitepaper` | the Resources content system is the goal-driven default a site grows into, not a starter page |
|
|
238
|
+
| `LocationsList` · `Location` · `ServiceAreaPage` | a placeholder starter is one location; `/contact` carries the address and the area served |
|
|
239
|
+
|
|
240
|
+
**Rows added:**
|
|
241
|
+
|
|
242
|
+
| Row added | Reason |
|
|
243
|
+
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
244
|
+
| `PurchasePolicyPage` | every shape carries one purchase policy with its shape's sections — service: cancellation and refunds (#6646 D3) |
|
|
245
|
+
| `PortfolioList` · `PortfolioItem` | the portfolio pair belongs to every shape's standard roster (operator, 2026-09-25; roadmap § 4) |
|
|
246
|
+
| `BlogList` | every Free scaffold's nav links `/blog` unconditionally (`renderNavConfig`, operator ruling 2026-09-23); the Free teaser serves it, as on organization-product (§ 1.8) |
|
|
247
|
+
|
|
248
|
+
`|S − D| = 11` and `|R| = 15`.
|
|
249
|
+
|
|
250
|
+
## 4. Roster, as the registry declares it
|
|
251
|
+
|
|
252
|
+
`local-business-service` is a `SHAPE_STARTERS` entry, not a declared `--template` alias: `TEMPLATE_MANIFESTS` and `RECOGNIZED_TEMPLATES` never carry its name (NFR-3). The merged roster, as the registry composes it:
|
|
253
|
+
|
|
254
|
+
<!-- generated:begin roster -->
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
local-business-service:
|
|
258
|
+
requires: [marketing]
|
|
259
|
+
categories: [hvac, roofing, plumbing, electrical, landscaping, auto-repair]
|
|
260
|
+
shape: local-business-service
|
|
261
|
+
design: standard
|
|
262
|
+
roster:
|
|
263
|
+
- { route: "/", kind: page, content: ["content/en/HomePage/home.mdx"] }
|
|
264
|
+
- { route: "/services", kind: page, content: ["content/en/ServicesList/services.mdx"] }
|
|
265
|
+
- { route: "/services/[slug]", kind: page, contentDir: "content/en/Service" }
|
|
266
|
+
- { route: "/about", kind: page, content: ["content/en/AboutPage/about.mdx"] }
|
|
267
|
+
- { route: "/contact", kind: page, content: ["content/en/ContactPage/contact.mdx"] }
|
|
268
|
+
- { route: "/faq", kind: page, content: ["content/en/FAQPage/faq.mdx"] }
|
|
269
|
+
- { route: "/glossary", kind: page, content: ["content/en/GlossaryList/glossary.mdx"] }
|
|
270
|
+
- { route: "/newsletter", kind: page, content: ["content/en/NewsletterSignup/newsletter.mdx"] }
|
|
271
|
+
- { route: "/book-a-call", kind: page, content: ["content/en/BookCall/book-call.mdx"] }
|
|
272
|
+
- { route: "/purchase-policy", kind: page, content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"] }
|
|
273
|
+
- { route: "/privacy", kind: page, content: ["content/en/PrivacyPage/privacy.mdx"] }
|
|
274
|
+
- { route: "/terms", kind: page, content: ["content/en/TermsPage/terms.mdx"] }
|
|
275
|
+
- { route: "/blog", kind: page, content: ["content/en/BlogList/blog.mdx"] }
|
|
276
|
+
- { route: "/portfolio", kind: page, content: ["content/en/PortfolioList/portfolio.mdx"] }
|
|
277
|
+
- { route: "/portfolio/[slug]", kind: page, contentDir: "content/en/PortfolioItem" }
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
<!-- generated:end -->
|
|
281
|
+
|
|
282
|
+
By source:
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
starter: / · /services · /services/<slug> · /about · /contact · /faq
|
|
286
|
+
/glossary · /newsletter · /book-a-call · /purchase-policy
|
|
287
|
+
/privacy · /terms · /blog · /portfolio · /portfolio/<slug>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Every row is module-less: `requires` is `[marketing]` alone, so `mergeRoster` contributes nothing beyond this tree's own fifteen rows.
|
|
291
|
+
|
|
292
|
+
## 5. Component inventory
|
|
293
|
+
|
|
294
|
+
<!-- generated:begin inventory -->
|
|
295
|
+
|
|
296
|
+
| Tier | Used by this template |
|
|
297
|
+
| -------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
298
|
+
| Shell | `MarketingShell` |
|
|
299
|
+
| Chrome | `Nav`, `Footer`, `Banner` (+ `BannerConsentIsland`, `BannerDismissIsland`) |
|
|
300
|
+
| Sections | `BlogList`, `ContentBlock`, `CTA`, `DocumentChassis`, `FAQ`, `GlossaryIndex`, `Hero`, `Items`, `LogoCloud`, `Testimonials` |
|
|
301
|
+
|
|
302
|
+
<!-- generated:end -->
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "local-business-service",
|
|
3
|
+
"requires": ["marketing"],
|
|
4
|
+
"extends": "_base",
|
|
5
|
+
"installMap": {
|
|
6
|
+
"provenance.json": ".ailk-template.json",
|
|
7
|
+
"TEMPLATE-MANIFEST.json": ".ailk-site-manifest.json"
|
|
8
|
+
},
|
|
9
|
+
"postInstall": "Starter local-business-service installed. Its /faq, /contact and /blog seed pages came with the always-copied overlay; /glossary, /newsletter, /book-a-call, /privacy and /terms with the base layer it extends (content/en/). This tree's own /, /about, /services (+ three jobs), /purchase-policy and /portfolio pages are its own compositions. Every line of copy is a placeholder — replace it before you launch."
|
|
10
|
+
}
|
|
@@ -12,7 +12,7 @@ sections:
|
|
|
12
12
|
{
|
|
13
13
|
"variant": "narrow",
|
|
14
14
|
"eyebrow": "About",
|
|
15
|
-
"headline": "{A small crew, the same
|
|
15
|
+
"headline": "{A small crew, the same neighborhoods, every week}",
|
|
16
16
|
"body": "{Two or three sentences on how the business started, how far you travel, and what you will not take on. Keep it short — this page is read on a phone in a driveway.}",
|
|
17
17
|
},
|
|
18
18
|
},
|
|
@@ -23,11 +23,11 @@ sections:
|
|
|
23
23
|
{
|
|
24
24
|
"variant": "minimal",
|
|
25
25
|
"headline": "Want us to take a look?",
|
|
26
|
-
"primaryCta": { "label": "
|
|
26
|
+
"primaryCta": { "label": "Get in touch", "href": "/contact" },
|
|
27
27
|
"secondaryCta":
|
|
28
28
|
{
|
|
29
|
-
"label": "
|
|
30
|
-
"href": "/
|
|
29
|
+
"label": "See services",
|
|
30
|
+
"href": "/services",
|
|
31
31
|
"variant": "outline",
|
|
32
32
|
},
|
|
33
33
|
},
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "HomePage"
|
|
3
|
+
slug: "home"
|
|
4
|
+
title: "Your Company"
|
|
5
|
+
description: "Placeholder home for the local-business-service starter — a local business selling a service in {Your service area}. Replace every line before you launch."
|
|
6
|
+
sections:
|
|
7
|
+
[
|
|
8
|
+
{
|
|
9
|
+
"id": "hero",
|
|
10
|
+
"type": "hero",
|
|
11
|
+
"data":
|
|
12
|
+
{
|
|
13
|
+
"variant": "centered",
|
|
14
|
+
"eyebrow": "{Your service area}",
|
|
15
|
+
"headline": "{One line on the job you do and the trust it takes to hire you}",
|
|
16
|
+
"subheadline": "{One line on who you serve and what they get. Name the street, the town or the county — a local reader is looking for their own.}",
|
|
17
|
+
"primaryCta": { "label": "Get in touch", "href": "/contact" },
|
|
18
|
+
"secondaryCta":
|
|
19
|
+
{
|
|
20
|
+
"label": "See services",
|
|
21
|
+
"href": "/services",
|
|
22
|
+
"variant": "outline",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "services",
|
|
28
|
+
"type": "items",
|
|
29
|
+
"data":
|
|
30
|
+
{
|
|
31
|
+
"headline": "What we do",
|
|
32
|
+
"columns": 3,
|
|
33
|
+
"items":
|
|
34
|
+
[
|
|
35
|
+
{
|
|
36
|
+
"title": "{First job}",
|
|
37
|
+
"description": "{One line on what this job is and who it suits.}",
|
|
38
|
+
"link": { "label": "Read more", "href": "/services/first-job" },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"title": "{Second job}",
|
|
42
|
+
"description": "{One line on what this job is and who it suits.}",
|
|
43
|
+
"link":
|
|
44
|
+
{ "label": "Read more", "href": "/services/second-job" },
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"title": "{Third job}",
|
|
48
|
+
"description": "{One line on what this job is and who it suits.}",
|
|
49
|
+
"link": { "label": "Read more", "href": "/services/third-job" },
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": "closing",
|
|
56
|
+
"type": "cta",
|
|
57
|
+
"data":
|
|
58
|
+
{
|
|
59
|
+
"variant": "minimal",
|
|
60
|
+
"headline": "Ready to get started?",
|
|
61
|
+
"description": "{One line inviting the reader to reach out.}",
|
|
62
|
+
"primaryCta": { "label": "Get in touch", "href": "/contact" },
|
|
63
|
+
"secondaryCta":
|
|
64
|
+
{ "label": "Ask a question", "href": "/faq", "variant": "outline" },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
Placeholder copy. Every headline, every line of body copy on this site is a placeholder — replace them before you launch.
|
package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "NewsletterSignup"
|
|
3
|
+
slug: "newsletter"
|
|
4
|
+
title: "{Start a free newsletter with Substack}"
|
|
5
|
+
description: "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}"
|
|
6
|
+
schema:
|
|
7
|
+
mainEntity:
|
|
8
|
+
"@type": "Offer"
|
|
9
|
+
name: "{Your newsletter name}"
|
|
10
|
+
price: 0
|
|
11
|
+
priceCurrency: "USD"
|
|
12
|
+
sections:
|
|
13
|
+
[
|
|
14
|
+
{
|
|
15
|
+
"id": "hero",
|
|
16
|
+
"type": "hero",
|
|
17
|
+
"data":
|
|
18
|
+
{
|
|
19
|
+
"eyebrow": "Newsletter",
|
|
20
|
+
"headline": "{Start a free newsletter with Substack}",
|
|
21
|
+
"subheadline": "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}",
|
|
22
|
+
"primaryCta":
|
|
23
|
+
{ "label": "{Connect Substack}", "href": "https://substack.com" },
|
|
24
|
+
"secondaryCta":
|
|
25
|
+
{
|
|
26
|
+
"label": "{Upgrade to Pro}",
|
|
27
|
+
"href": "https://ailaunchkit.ai/pricing",
|
|
28
|
+
"variant": "outline",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "faq",
|
|
34
|
+
"type": "faq",
|
|
35
|
+
"data":
|
|
36
|
+
{
|
|
37
|
+
"headline": "FAQs",
|
|
38
|
+
"presentation": "expanded",
|
|
39
|
+
"items":
|
|
40
|
+
[
|
|
41
|
+
{
|
|
42
|
+
"question": "{How often will I hear from you?}",
|
|
43
|
+
"answer": "{Answer in one or two plain sentences}",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"question": "{What will I get?}",
|
|
47
|
+
"answer": "{Answer in one or two plain sentences}",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"question": "{Can I unsubscribe?}",
|
|
51
|
+
"answer": "{Answer in one or two plain sentences}",
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
]
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
{/* Rendered from frontmatter `sections[]` by the /newsletter route. The Free template has no signup form: the hero points the owner to Substack, or to Pro for subscriber capture. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Placeholder copy — replace every {brace} with your own words before you launch. */}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "PortfolioList"
|
|
3
|
+
slug: "portfolio"
|
|
4
|
+
title: "{Before and after, compared} | {Company name}"
|
|
5
|
+
description: "{Every job shown as a comparison — what the property had, what it has now, and what changed in between.}"
|
|
6
|
+
sections:
|
|
7
|
+
[
|
|
8
|
+
{
|
|
9
|
+
"id": "cases-hero",
|
|
10
|
+
"type": "hero",
|
|
11
|
+
"data":
|
|
12
|
+
{
|
|
13
|
+
"variant": "default",
|
|
14
|
+
"size": "display",
|
|
15
|
+
"surface": "wash-secondary",
|
|
16
|
+
"gapBelow": "tight",
|
|
17
|
+
"eyebrow": "{Portfolio}",
|
|
18
|
+
"eyebrowTone": "brand",
|
|
19
|
+
"headline": "{The work, before and after.}",
|
|
20
|
+
"subheadline": "{Two or three sentences on why the comparison is the honest proof — what the before cost, what the after changed, and how a reader can check it.}",
|
|
21
|
+
"subtitleSize": "lead",
|
|
22
|
+
"ctaSize": "xl",
|
|
23
|
+
"primaryCta": { "label": "Get in touch", "href": "/contact" },
|
|
24
|
+
"secondaryCta": { "label": "{See services}", "href": "/services" },
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "cases-tiles",
|
|
29
|
+
"type": "items",
|
|
30
|
+
"data":
|
|
31
|
+
{
|
|
32
|
+
"variant": "tile",
|
|
33
|
+
"tileHover": "outline",
|
|
34
|
+
"columns": 2,
|
|
35
|
+
"surface": "none",
|
|
36
|
+
"items":
|
|
37
|
+
[
|
|
38
|
+
{
|
|
39
|
+
"title": "{Example one}: before and after",
|
|
40
|
+
"description": "{One sentence on what example one had, and what it has now}",
|
|
41
|
+
"rows":
|
|
42
|
+
[
|
|
43
|
+
{
|
|
44
|
+
"label": "THE PROPERTY",
|
|
45
|
+
"body": "{What kind of property it is and where}",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"label": "WHAT CHANGED",
|
|
49
|
+
"body": "{The one thing the after does that the before could not}",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
"link":
|
|
53
|
+
{
|
|
54
|
+
"label": "See the comparison →",
|
|
55
|
+
"href": "/portfolio/sample-one",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"title": "{Example two}: before and after",
|
|
60
|
+
"description": "{One sentence on what example two had, and what it has now}",
|
|
61
|
+
"rows":
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
"label": "THE PROPERTY",
|
|
65
|
+
"body": "{What kind of property it is and where}",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"label": "WHAT CHANGED",
|
|
69
|
+
"body": "{The one thing the after does that the before could not}",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
"link":
|
|
73
|
+
{
|
|
74
|
+
"label": "See the comparison →",
|
|
75
|
+
"href": "/portfolio/sample-two",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"title": "{Example three}: before and after",
|
|
80
|
+
"description": "{One sentence on what example three had, and what it has now}",
|
|
81
|
+
"rows":
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
"label": "THE PROPERTY",
|
|
85
|
+
"body": "{What kind of property it is and where}",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"label": "WHAT CHANGED",
|
|
89
|
+
"body": "{The one thing the after does that the before could not}",
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
"link":
|
|
93
|
+
{
|
|
94
|
+
"label": "See the comparison →",
|
|
95
|
+
"href": "/portfolio/sample-three",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"title": "{Example four}: before and after",
|
|
100
|
+
"description": "{One sentence on what example four had, and what it has now}",
|
|
101
|
+
"rows":
|
|
102
|
+
[
|
|
103
|
+
{
|
|
104
|
+
"label": "THE PROPERTY",
|
|
105
|
+
"body": "{What kind of property it is and where}",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"label": "WHAT CHANGED",
|
|
109
|
+
"body": "{The one thing the after does that the before could not}",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
"link":
|
|
113
|
+
{
|
|
114
|
+
"label": "See the comparison →",
|
|
115
|
+
"href": "/portfolio/sample-four",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "cases-close",
|
|
123
|
+
"type": "cta",
|
|
124
|
+
"data":
|
|
125
|
+
{
|
|
126
|
+
"variant": "beam",
|
|
127
|
+
"headline": "{Is your property the before or the after?}",
|
|
128
|
+
"description": "{One line offering the reader the same comparison for their own property.}",
|
|
129
|
+
"primaryCta": { "label": "Get in touch", "href": "/contact" },
|
|
130
|
+
"secondaryCta": { "label": "{See services}", "href": "/services" },
|
|
131
|
+
"chips":
|
|
132
|
+
[
|
|
133
|
+
"{Proof you can check}",
|
|
134
|
+
"{Every job shown both ways}",
|
|
135
|
+
"{Re-checked every quarter}",
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "cases-faq",
|
|
141
|
+
"type": "faq",
|
|
142
|
+
"data":
|
|
143
|
+
{
|
|
144
|
+
"headline": "Frequently Asked Questions",
|
|
145
|
+
"variant": "centered",
|
|
146
|
+
"presentation": "accordion",
|
|
147
|
+
"questionSize": "body-lg",
|
|
148
|
+
"initialOpen": "first",
|
|
149
|
+
"containerWidth": "default",
|
|
150
|
+
"surface": "gray-100",
|
|
151
|
+
"items":
|
|
152
|
+
[
|
|
153
|
+
{
|
|
154
|
+
"question": "{How do you pick which jobs to show?}",
|
|
155
|
+
"answer": "{Two or three sentences.}",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"question": "{Are the before photos real?}",
|
|
159
|
+
"answer": "{Two or three sentences.}",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"question": "{Can I see a job like mine?}",
|
|
163
|
+
"answer": "{Two or three sentences.}",
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
]
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
{/* This tree's override of the `_base` PortfolioList page (D4): the `_base` page's two primary CTAs link `/pricing`, a route this shape does not serve, so this override keeps the same section types and four sample comparisons and points both primary CTAs at `/contact` instead. */}
|