create-ailk 0.7.0 → 0.9.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.
Files changed (310) hide show
  1. package/README.md +112 -10
  2. package/component-catalog.json +798 -49
  3. package/component-catalog.md +9 -6
  4. package/dist/add-module.d.ts +20 -0
  5. package/dist/add-module.js +43 -7
  6. package/dist/add-route.d.ts +56 -0
  7. package/dist/add-route.js +286 -0
  8. package/dist/apply-design-md.d.ts +7 -0
  9. package/dist/apply-design-md.js +50 -0
  10. package/dist/apply-design.d.ts +64 -0
  11. package/dist/apply-design.js +273 -0
  12. package/dist/claude-md.d.ts +111 -0
  13. package/dist/claude-md.js +334 -0
  14. package/dist/cli.js +114 -28
  15. package/dist/derive-architecture.js +41 -36
  16. package/dist/design-compile.d.ts +71 -0
  17. package/dist/design-compile.js +98 -0
  18. package/dist/design-package.d.ts +83 -0
  19. package/dist/design-package.js +468 -0
  20. package/dist/design-presets.d.ts +86 -0
  21. package/dist/design-presets.js +642 -0
  22. package/dist/design-scaffold.d.ts +76 -0
  23. package/dist/design-scaffold.js +220 -0
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +4 -1
  26. package/dist/legacy-nav-renderers.d.ts +45 -0
  27. package/dist/legacy-nav-renderers.js +545 -0
  28. package/dist/lib/auth-secret-file.d.ts +19 -0
  29. package/dist/lib/auth-secret-file.js +112 -0
  30. package/dist/lib/design-checks.d.ts +78 -0
  31. package/dist/lib/design-checks.js +174 -0
  32. package/dist/lib/extract-module-bundle.js +5 -1
  33. package/dist/lib/license-key-files.d.ts +9 -0
  34. package/dist/lib/license-key-files.js +2 -2
  35. package/dist/lib/module-license-gate.d.ts +89 -0
  36. package/dist/lib/module-license-gate.js +171 -12
  37. package/dist/lib/module-tier.d.ts +45 -16
  38. package/dist/lib/module-tier.js +76 -0
  39. package/dist/lib/pro-callout.js +10 -2
  40. package/dist/lib/render-verdict.d.ts +52 -0
  41. package/dist/lib/render-verdict.js +77 -0
  42. package/dist/lib/scaffold-render-sweep.d.ts +105 -0
  43. package/dist/lib/scaffold-render-sweep.js +236 -0
  44. package/dist/module-architecture.d.ts +19 -16
  45. package/dist/module-architecture.js +64 -21
  46. package/dist/parse-args.d.ts +88 -10
  47. package/dist/parse-args.js +272 -21
  48. package/dist/programmatic.d.ts +66 -12
  49. package/dist/programmatic.js +361 -34
  50. package/dist/site-chrome.d.ts +19 -9
  51. package/dist/site-chrome.js +23 -13
  52. package/dist/site-manifest.d.ts +25 -0
  53. package/dist/site-manifest.js +254 -0
  54. package/dist/site-roster.d.ts +41 -0
  55. package/dist/site-roster.js +149 -11
  56. package/dist/starter-grid.d.ts +232 -0
  57. package/dist/starter-grid.js +545 -0
  58. package/dist/surfaces.d.ts +41 -9
  59. package/dist/surfaces.js +268 -92
  60. package/dist/template-manifest.d.ts +65 -29
  61. package/dist/template-manifest.js +161 -382
  62. package/dist/template-names.d.ts +14 -12
  63. package/dist/template-names.js +13 -17
  64. package/package.json +5 -4
  65. package/site-templates/_base/content/en/Feature/feature-1.mdx +69 -0
  66. package/site-templates/_base/content/en/Feature/feature-2.mdx +69 -0
  67. package/site-templates/_base/content/en/Feature/feature-3.mdx +69 -0
  68. package/site-templates/_base/content/en/FeaturesList/features.mdx +91 -0
  69. package/site-templates/_base/content/en/GlossaryList/glossary.mdx +0 -1
  70. package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +0 -1
  71. package/site-templates/_base/content/en/PortfolioItem/sample-four.mdx +105 -0
  72. package/site-templates/_base/content/en/PortfolioItem/sample-one.mdx +34 -0
  73. package/site-templates/_base/content/en/PortfolioItem/sample-three.mdx +94 -0
  74. package/site-templates/_base/content/en/PortfolioItem/sample-two.mdx +45 -0
  75. package/site-templates/_base/content/en/PortfolioList/portfolio.mdx +169 -0
  76. package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +15 -0
  77. package/site-templates/_base/content/en/UseCase/persona-1.mdx +70 -0
  78. package/site-templates/_base/content/en/UseCase/persona-2.mdx +70 -0
  79. package/site-templates/_base/content/en/UseCase/persona-3.mdx +70 -0
  80. package/site-templates/{minimalism-site/TEMPLATE-MANIFEST.json → aliases/minimalism-site.TEMPLATE-MANIFEST.json} +72 -40
  81. package/site-templates/designs/minimalism/DESIGN.md +98 -6
  82. package/site-templates/designs/minimalism/sample/README.md +48 -0
  83. package/site-templates/designs/standard/DESIGN.md +103 -6
  84. package/site-templates/marketing-site/DESIGN.md +103 -6
  85. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +144 -47
  86. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +82 -41
  87. package/site-templates/marketing-site-free/DESIGN.md +103 -6
  88. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +150 -48
  89. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +114 -67
  90. package/site-templates/marketing-site-free/ailk-template.json +1 -1
  91. package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +59 -0
  92. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +199 -0
  93. package/site-templates/saas-product/DESIGN.md +103 -6
  94. package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
  95. package/site-templates/{simple-service → shapes/local-business-service}/TEMPLATE-MANIFEST.json +210 -81
  96. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +356 -0
  97. package/site-templates/shapes/local-business-service/ailk-template.json +10 -0
  98. package/site-templates/{simple-service → shapes/local-business-service}/content/en/AboutPage/about.mdx +4 -4
  99. package/site-templates/shapes/local-business-service/content/en/HomePage/home.mdx +70 -0
  100. package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  101. package/site-templates/shapes/local-business-service/content/en/PortfolioList/portfolio.mdx +171 -0
  102. package/site-templates/{minimalism-site → shapes/local-business-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +7 -8
  103. package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +39 -0
  104. package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +39 -0
  105. package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +39 -0
  106. package/site-templates/shapes/local-business-service/content/en/ServicesList/services.mdx +61 -0
  107. package/site-templates/shapes/local-business-service/provenance.json +4 -0
  108. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +471 -0
  109. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +354 -0
  110. package/site-templates/shapes/organization-service/ailk-template.json +10 -0
  111. package/site-templates/shapes/organization-service/content/en/AboutPage/about.mdx +38 -0
  112. package/site-templates/shapes/organization-service/content/en/HomePage/home.mdx +85 -0
  113. package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  114. package/site-templates/shapes/organization-service/content/en/PortfolioList/portfolio.mdx +171 -0
  115. package/site-templates/shapes/organization-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  116. package/site-templates/{minimalism-site → shapes/organization-service}/content/en/ServicesList/services.mdx +3 -4
  117. package/site-templates/shapes/organization-service/provenance.json +4 -0
  118. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +478 -0
  119. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +353 -0
  120. package/site-templates/shapes/person-service/ailk-template.json +10 -0
  121. package/site-templates/shapes/person-service/content/_site.mdx +85 -0
  122. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +39 -0
  123. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +97 -0
  124. package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  125. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +171 -0
  126. package/site-templates/{simple-service → shapes/person-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +10 -11
  127. package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +38 -0
  128. package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +38 -0
  129. package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +38 -0
  130. package/site-templates/{simple-service → shapes/person-service}/content/en/ServicesList/services.mdx +16 -16
  131. package/site-templates/shapes/person-service/provenance.json +4 -0
  132. package/templates/.claude/rules/architecture.md +7 -0
  133. package/templates/.claude/skills/README.md +5 -3
  134. package/templates/.claude/skills/add-auth/references/env-vars.md +22 -15
  135. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +3 -2
  136. package/templates/.claude/skills/add-page/SKILL.md +241 -238
  137. package/templates/.claude/skills/add-page/references/page-types.md +85 -72
  138. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
  139. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
  140. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
  141. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
  142. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
  143. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
  144. package/templates/.claude/skills/check-site/SKILL.md +23 -0
  145. package/templates/.claude/skills/fill-page/SKILL.md +26 -7
  146. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
  147. package/templates/.claude/skills/setup-database/SKILL.md +156 -0
  148. package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +154 -0
  149. package/templates/.claude/skills/setup-deploy/SKILL.md +64 -32
  150. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +44 -36
  151. package/templates/.claude/skills/setup-deploy/references/runbook-template.md +58 -102
  152. package/templates/.claude/skills/update-page/SKILL.md +117 -0
  153. package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
  154. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
  155. package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
  156. package/templates/.github/workflows/ci.yml +4 -0
  157. package/templates/.prettierignore +1 -0
  158. package/templates/CLAUDE.md +146 -103
  159. package/templates/DESIGN.md +103 -6
  160. package/templates/README.md +63 -43
  161. package/templates/apps/api/.env.example +2 -1
  162. package/templates/apps/api/CLAUDE.md +3 -2
  163. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
  164. package/templates/apps/api/src/__tests__/server.test.ts +116 -0
  165. package/templates/apps/api/src/config/__tests__/index.test.ts +115 -14
  166. package/templates/apps/api/src/config/index.ts +35 -16
  167. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +30 -0
  168. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +96 -0
  169. package/templates/apps/api/src/lib/lead-capture-store.ts +12 -0
  170. package/templates/apps/api/src/lib/lead-delivery.ts +52 -0
  171. package/templates/apps/api/src/lib/stripe.ts +9 -0
  172. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
  173. package/templates/apps/api/src/middleware/auth.ts +54 -0
  174. package/templates/apps/api/src/openapi/spec.ts +63 -12
  175. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
  176. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
  177. package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
  178. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +88 -0
  179. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +100 -0
  180. package/templates/apps/api/src/routes/leads/index.ts +46 -1
  181. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
  182. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
  183. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
  184. package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
  185. package/templates/apps/api/src/server.ts +35 -0
  186. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +194 -0
  187. package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +124 -0
  188. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
  189. package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
  190. package/templates/apps/api/src/services/lead-routing.ts +140 -30
  191. package/templates/apps/api/src/services/leads-inbox.ts +48 -11
  192. package/templates/apps/api/src/services/revalidation.ts +60 -15
  193. package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
  194. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
  195. package/templates/apps/mcp/src/tools/create_project.ts +21 -6
  196. package/templates/apps/mcp/src/tools/purchase.ts +4 -2
  197. package/templates/apps/web/.env.example +13 -0
  198. package/templates/apps/web/CLAUDE.md +22 -28
  199. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
  200. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
  201. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
  202. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
  203. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
  204. package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
  205. package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
  206. package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
  207. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +14 -6
  208. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +10 -9
  209. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +32 -0
  210. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +129 -0
  211. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +227 -84
  212. package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +50 -0
  213. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +73 -20
  214. package/templates/apps/web/app/[locale]/contact/page.tsx +105 -15
  215. package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
  216. package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +64 -0
  217. package/templates/apps/web/app/[locale]/features/page.tsx +52 -0
  218. package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +21 -5
  219. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
  220. package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
  221. package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
  222. package/templates/apps/web/app/[locale]/layout.tsx +65 -17
  223. package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +75 -0
  224. package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +163 -0
  225. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +66 -0
  226. package/templates/apps/web/app/[locale]/newsletter/page.tsx +106 -14
  227. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
  228. package/templates/apps/web/app/[locale]/{book-a-call → portfolio}/page.tsx +12 -13
  229. package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
  230. package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
  231. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
  232. package/templates/apps/web/app/api/revalidate/route.ts +78 -36
  233. package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
  234. package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
  235. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
  236. package/templates/apps/web/lib/locale-guard.ts +18 -0
  237. package/templates/apps/web/lib/meet-placeholder.ts +5 -0
  238. package/templates/apps/web/lib/nav-config.ts +50 -37
  239. package/templates/apps/web/lib/site-brand.tsx +13 -9
  240. package/templates/apps/web/lib/site-identity.ts +14 -0
  241. package/templates/apps/web/lib/site-logo.tsx +36 -0
  242. package/templates/apps/web/lib/site-theme.ts +46 -26
  243. package/templates/apps/web/messages/en.json +45 -5
  244. package/templates/apps/web/middleware.ts +28 -4
  245. package/templates/content/_site.mdx +4 -2
  246. package/templates/content/en/BlogList/blog.mdx +37 -16
  247. package/templates/content/en/BookCall/book-a-call.mdx +80 -0
  248. package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
  249. package/templates/content/en/BookCall/onsite-service.mdx +56 -0
  250. package/templates/content/en/BookCall/start-project.mdx +56 -0
  251. package/templates/content/en/ContactPage/contact.mdx +43 -34
  252. package/templates/content/en/HomePage/home.mdx +10 -22
  253. package/templates/content/en/LandingPage/meet.mdx +59 -0
  254. package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
  255. package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
  256. package/templates/database/CHANGELOG.md +14 -0
  257. package/templates/database/package.json +1 -1
  258. package/templates/package.json +2 -1
  259. package/templates/tools/check-claude-md.ts +128 -0
  260. package/versions.json +33 -33
  261. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -53
  262. package/site-templates/_base/content/en/UseCase/first-use-case.mdx +0 -23
  263. package/site-templates/_base/content/en/UseCase/second-use-case.mdx +0 -23
  264. package/site-templates/_base/content/en/UseCase/third-use-case.mdx +0 -23
  265. package/site-templates/minimalism-site/DESIGN.md +0 -162
  266. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -470
  267. package/site-templates/minimalism-site/ailk-template.json +0 -23
  268. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
  269. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -53
  270. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
  271. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
  272. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
  273. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
  274. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
  275. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
  276. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
  277. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
  278. package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
  279. package/site-templates/minimalism-site/provenance.json +0 -4
  280. package/site-templates/simple-service/DESIGN.md +0 -162
  281. package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -333
  282. package/site-templates/simple-service/ailk-template.json +0 -11
  283. package/site-templates/simple-service/content/en/BookCall/book-call.mdx +0 -53
  284. package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -32
  285. package/site-templates/simple-service/content/en/FAQPage/faq.mdx +0 -56
  286. package/site-templates/simple-service/content/en/HomePage/home.mdx +0 -85
  287. package/site-templates/simple-service/content/en/Service/landscape-design.mdx +0 -40
  288. package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +0 -40
  289. package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +0 -40
  290. package/site-templates/simple-service/provenance.json +0 -4
  291. package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
  292. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -211
  293. package/templates/apps/web/app/[locale]/contact/__tests__/ContactForm.test.tsx +0 -96
  294. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
  295. package/templates/content/en/SoftwareProduct/product.mdx +0 -175
  296. /package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +0 -0
  297. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
  298. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
  299. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
  300. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
  301. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
  302. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
  303. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
  304. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
  305. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
  306. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
  307. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
  308. /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/first-engagement.mdx +0 -0
  309. /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/second-engagement.mdx +0 -0
  310. /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/third-engagement.mdx +0 -0
@@ -1,32 +0,0 @@
1
- ---
2
- type: "ContactPage"
3
- slug: "contact"
4
- title: "Contact"
5
- description: "One form, three fields, an inline confirmation. Placeholder copy — replace before you launch."
6
- sections:
7
- [
8
- {
9
- "id": "hero",
10
- "type": "hero",
11
- "data":
12
- {
13
- "variant": "centered",
14
- "eyebrow": "Contact",
15
- "headline": "Tell us about the yard",
16
- "subheadline": "{One line on what happens after you send this, and how long it takes. If a call is faster, say so.}",
17
- },
18
- },
19
- {
20
- "id": "closing",
21
- "type": "cta",
22
- "data":
23
- {
24
- "variant": "minimal",
25
- "headline": "Would a visit be faster?",
26
- "primaryCta": { "label": "Book a visit →", "href": "/meet" },
27
- },
28
- },
29
- ]
30
- ---
31
-
32
- The /contact route mounts the page's one contact surface — the guided intake, with its fallback form — which posts to the site's own API (`/v1/leads/submit`) and confirms inline. Placeholder copy.
@@ -1,56 +0,0 @@
1
- ---
2
- type: "FAQPage"
3
- slug: "faq"
4
- title: "FAQ"
5
- description: "The questions people ask before they book. Placeholder copy — replace every answer before you launch."
6
- sections:
7
- [
8
- {
9
- "id": "faq",
10
- "type": "faq",
11
- "data":
12
- {
13
- "headline": "Questions",
14
- "variant": "centered",
15
- "initialOpen": "first",
16
- "items":
17
- [
18
- {
19
- "question": "{Which areas do you cover?}",
20
- "answer": "{Name the towns, the radius or the postcodes. A reader outside them should know it here.}",
21
- },
22
- {
23
- "question": "{How often do you visit?}",
24
- "answer": "{Give the real cadence for the recurring job, and say what happens in winter.}",
25
- },
26
- {
27
- "question": "{What does it cost?}",
28
- "answer": "{The three service pages carry the prices. Say here what moves them — yard size, access, waste removal.}",
29
- },
30
- {
31
- "question": "{How do I pay?}",
32
- "answer": "{Say when payment is taken and how. Checkout runs on your own Stripe account; the card details never touch this site.}",
33
- },
34
- {
35
- "question": "{What if I need to cancel?}",
36
- "answer": "{Point at the cancellation policy and give the notice period in one line.}",
37
- },
38
- ],
39
- "supportLink":
40
- { "label": "Still stuck? Get in touch", "href": "/contact" },
41
- },
42
- },
43
- {
44
- "id": "closing",
45
- "type": "cta",
46
- "data":
47
- {
48
- "variant": "minimal",
49
- "headline": "Still have a question?",
50
- "primaryCta": { "label": "Contact us →", "href": "/contact" },
51
- },
52
- },
53
- ]
54
- ---
55
-
56
- Placeholder copy. Replace every answer before you launch.
@@ -1,85 +0,0 @@
1
- ---
2
- type: "HomePage"
3
- slug: "home"
4
- title: "Your Company"
5
- description: "Placeholder home for the simple-service template — a lawn-care site that books a visit and takes the payment. 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": "{Lawn care that turns up when it says it will}",
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": "Book a visit →", "href": "/meet" },
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": "{Lawn maintenance}",
37
- "description": "{One line on the recurring visit — what it includes and how often it runs.}",
38
- "link":
39
- {
40
- "label": "Read more",
41
- "href": "/services/lawn-maintenance",
42
- },
43
- },
44
- {
45
- "title": "{Seasonal cleanup}",
46
- "description": "{One line on the spring and autumn clear-down.}",
47
- "link":
48
- {
49
- "label": "Read more",
50
- "href": "/services/seasonal-cleanup",
51
- },
52
- },
53
- {
54
- "title": "{Landscape design}",
55
- "description": "{One line on the design-and-plant job, and what a customer ends up with.}",
56
- "link":
57
- {
58
- "label": "Read more",
59
- "href": "/services/landscape-design",
60
- },
61
- },
62
- ],
63
- },
64
- },
65
- {
66
- "id": "closing",
67
- "type": "cta",
68
- "data":
69
- {
70
- "variant": "minimal",
71
- "headline": "Ready for a tidier yard?",
72
- "description": "{One line inviting the reader to pick a time rather than fill in a form.}",
73
- "primaryCta": { "label": "Book a visit →", "href": "/meet" },
74
- "secondaryCta":
75
- {
76
- "label": "Ask a question",
77
- "href": "/contact",
78
- "variant": "outline",
79
- },
80
- },
81
- },
82
- ]
83
- ---
84
-
85
- Placeholder copy. Every headline, every line of body copy and every price on this site is a placeholder — replace them before you launch.
@@ -1,40 +0,0 @@
1
- ---
2
- type: "Service"
3
- slug: "landscape-design"
4
- title: "{Landscape design}"
5
- description: "{One line on what this job is and who it suits. Replace before you launch.}"
6
- price: 1250
7
- priceCurrency: "USD"
8
- provider:
9
- name: "{Your Company}"
10
- schema:
11
- serviceType: "{Landscape design}"
12
- areaServed: "{Your service area}"
13
- ---
14
-
15
- # \{Landscape design\}
16
-
17
- \{Open with the situation a reader is in when they come looking for this. Two or
18
- three sentences, no more — the detail belongs under the headings below.\}
19
-
20
- ## What it covers
21
-
22
- - \{The first thing you actually do\}
23
- - \{The second thing you actually do\}
24
- - \{The third thing you actually do\}
25
-
26
- ## How it runs
27
-
28
- \{One paragraph on the shape of the visit: how it is scheduled, how long it
29
- takes, who turns up, and what you need from the customer beforehand.\}
30
-
31
- ## What you end up with
32
-
33
- \{One paragraph on the result. Be concrete — describe the yard when the crew
34
- drives away.\}
35
-
36
- ## What it costs
37
-
38
- \{The price in this page's frontmatter is a PLACEHOLDER. It is what the site
39
- publishes as a schema.org `Offer`, so an agent reading this page quotes it —
40
- replace it with your real number before you launch.\}
@@ -1,40 +0,0 @@
1
- ---
2
- type: "Service"
3
- slug: "lawn-maintenance"
4
- title: "{Lawn maintenance}"
5
- description: "{One line on what this job is and who it suits. Replace before you launch.}"
6
- price: 149
7
- priceCurrency: "USD"
8
- provider:
9
- name: "{Your Company}"
10
- schema:
11
- serviceType: "{Lawn maintenance}"
12
- areaServed: "{Your service area}"
13
- ---
14
-
15
- # \{Lawn maintenance\}
16
-
17
- \{Open with the situation a reader is in when they come looking for this. Two or
18
- three sentences, no more — the detail belongs under the headings below.\}
19
-
20
- ## What it covers
21
-
22
- - \{The first thing you actually do\}
23
- - \{The second thing you actually do\}
24
- - \{The third thing you actually do\}
25
-
26
- ## How it runs
27
-
28
- \{One paragraph on the shape of the visit: how it is scheduled, how long it
29
- takes, who turns up, and what you need from the customer beforehand.\}
30
-
31
- ## What you end up with
32
-
33
- \{One paragraph on the result. Be concrete — describe the yard when the crew
34
- drives away.\}
35
-
36
- ## What it costs
37
-
38
- \{The price in this page's frontmatter is a PLACEHOLDER. It is what the site
39
- publishes as a schema.org `Offer`, so an agent reading this page quotes it —
40
- replace it with your real number before you launch.\}
@@ -1,40 +0,0 @@
1
- ---
2
- type: "Service"
3
- slug: "seasonal-cleanup"
4
- title: "{Seasonal cleanup}"
5
- description: "{One line on what this job is and who it suits. Replace before you launch.}"
6
- price: 289
7
- priceCurrency: "USD"
8
- provider:
9
- name: "{Your Company}"
10
- schema:
11
- serviceType: "{Seasonal cleanup}"
12
- areaServed: "{Your service area}"
13
- ---
14
-
15
- # \{Seasonal cleanup\}
16
-
17
- \{Open with the situation a reader is in when they come looking for this. Two or
18
- three sentences, no more — the detail belongs under the headings below.\}
19
-
20
- ## What it covers
21
-
22
- - \{The first thing you actually do\}
23
- - \{The second thing you actually do\}
24
- - \{The third thing you actually do\}
25
-
26
- ## How it runs
27
-
28
- \{One paragraph on the shape of the visit: how it is scheduled, how long it
29
- takes, who turns up, and what you need from the customer beforehand.\}
30
-
31
- ## What you end up with
32
-
33
- \{One paragraph on the result. Be concrete — describe the yard when the crew
34
- drives away.\}
35
-
36
- ## What it costs
37
-
38
- \{The price in this page's frontmatter is a PLACEHOLDER. It is what the site
39
- publishes as a schema.org `Offer`, so an agent reading this page quotes it —
40
- replace it with your real number before you launch.\}
@@ -1,4 +0,0 @@
1
- {
2
- "template": "simple-service",
3
- "requires": ["marketing", "scheduling", "commerce"]
4
- }
@@ -1,28 +0,0 @@
1
- // Emitted by `add-page` at `app/{{SLUG}}/page.tsx`. Substitutions:
2
- // {{SLUG}} — page slug (e.g., "pricing")
3
- // {{TYPE}} — schema.org @type (e.g., "Service")
4
- // {{BUILDER}} — typed builder name (e.g., "buildService")
5
- // {{TITLE}} — page title (e.g., "Pricing")
6
- import { notFound } from "next/navigation";
7
-
8
- import { JsonLd } from "@working-theory/jsonld";
9
- import { {{BUILDER}} } from "@working-theory/schema";
10
- import { mdxAdapter } from "@/lib/content";
11
-
12
- export default async function {{TYPE}}Page() {
13
- const page = await mdxAdapter.getPage("{{SLUG}}");
14
- if (!page) return notFound();
15
-
16
- const schema = {{BUILDER}}(page);
17
-
18
- return (
19
- <main className="mx-auto max-w-3xl px-6 py-12">
20
- <JsonLd schema={schema} />
21
- <article className="prose dark:prose-invert">
22
- <h1>{page.title}</h1>
23
- {page.description ? <p className="lead">{page.description}</p> : null}
24
- {/* Render MDX body via your project's MDX renderer of choice. */}
25
- </article>
26
- </main>
27
- );
28
- }
@@ -1,211 +0,0 @@
1
- "use client";
2
-
3
- /**
4
- * ContactForm — client component that wires the contact form to
5
- * captureLeadAction via useFormState.
6
- *
7
- * Validation errors render inline next to each field.
8
- * Success shows a confirmation message.
9
- * Server errors show a generic fallback message.
10
- *
11
- * Honeypot + rate-limit enforcement lives in apps/api; no duplication here.
12
- *
13
- * `initialValues` (#4534, epic #4521's integration leg): optional prefill
14
- * for name/email/message, set via `defaultValue` (the fields stay
15
- * uncontrolled — unchanged for the no-prop call site). Lets
16
- * `ConversationalIntakeWrapper` carry over whatever the visitor already
17
- * typed into the conversation before Skip (or a failed auto-submit)
18
- * dropped them here, instead of asking them to retype it.
19
- *
20
- * Consent (#6466): a real checkbox named by a `ConsentStatement` whose
21
- * "Terms" links to the locale-aware `/terms` route. It starts unticked and
22
- * the submit button stays disabled until it is ticked — the form is
23
- * `noValidate`, so `required` alone would gate nothing. The statement is
24
- * wired by `aria-labelledby`, never a wrapping `<label>`, so clicking the
25
- * link follows it instead of toggling the box (the ConsentGroup rule).
26
- *
27
- * Composition (#6514): every control and message is a `@working-theory/ui`
28
- * primitive — `Label`/`Input`/`Textarea` for the fields, `Alert` for the
29
- * success and form-level error, `InlineMessage` for the per-field messages
30
- * (its `error` variant carries `role="alert"`), `Button` for submit. The honeypot hides behind
31
- * the `hidden` attribute on its wrapper rather than an inline style object.
32
- */
33
-
34
- import {
35
- Alert,
36
- AlertDescription,
37
- Button,
38
- Checkbox,
39
- type CheckboxProps,
40
- ConsentStatement,
41
- InlineMessage,
42
- Input,
43
- Label,
44
- localeHref,
45
- Textarea,
46
- } from "@working-theory/ui";
47
- import { useLocale, useTranslations } from "next-intl";
48
- import { useCallback, useState } from "react";
49
- import { useFormState, useFormStatus } from "react-dom";
50
-
51
- import { captureLeadAction } from "./contact.actions";
52
-
53
- export interface ContactFormInitialValues {
54
- name?: string;
55
- email?: string;
56
- message?: string;
57
- }
58
-
59
- type CheckedState = Parameters<NonNullable<CheckboxProps["onCheckedChange"]>>[0];
60
-
61
- interface ContactFormProps {
62
- initialValues?: ContactFormInitialValues;
63
- }
64
-
65
- function SubmitButton({ disabled }: { disabled: boolean }) {
66
- const t = useTranslations("contact");
67
- const { pending } = useFormStatus();
68
- return (
69
- <Button
70
- type="submit"
71
- disabled={pending || disabled}
72
- data-testid="contact-submit"
73
- >
74
- {pending ? t("sending") : t("sendMessage")}
75
- </Button>
76
- );
77
- }
78
-
79
- export function ContactForm({ initialValues }: ContactFormProps = {}) {
80
- const t = useTranslations("contact");
81
- const locale = useLocale();
82
- const [state, formAction] = useFormState(captureLeadAction, null);
83
- const [consented, setConsented] = useState(false);
84
- const handleConsentChange = useCallback((checked: CheckedState) => {
85
- setConsented(checked === true);
86
- }, []);
87
-
88
- if (state?.kind === "success") {
89
- return (
90
- <Alert variant="success" data-testid="contact-success">
91
- <AlertDescription>{t("successMessage")}</AlertDescription>
92
- </Alert>
93
- );
94
- }
95
-
96
- const fieldErrors = state?.kind === "error" ? (state.fieldErrors ?? {}) : {};
97
- const formError =
98
- state?.kind === "error" && !state.fieldErrors ? state.message : undefined;
99
-
100
- return (
101
- <form action={formAction} noValidate>
102
- {formError && (
103
- <Alert variant="error" data-testid="contact-form-error">
104
- <AlertDescription>{formError}</AlertDescription>
105
- </Alert>
106
- )}
107
-
108
- {/* Honeypot — hidden from users; bots fill it; API rejects non-empty */}
109
- <div hidden>
110
- <Input
111
- type="text"
112
- name="website"
113
- tabIndex={-1}
114
- aria-hidden="true"
115
- data-testid="contact-honeypot"
116
- />
117
- </div>
118
-
119
- <div>
120
- <Label htmlFor="contact-name">{t("nameLabel")}</Label>
121
- <Input
122
- id="contact-name"
123
- name="name"
124
- type="text"
125
- autoComplete="name"
126
- data-testid="contact-name-input"
127
- required
128
- defaultValue={initialValues?.name}
129
- aria-describedby={fieldErrors.name ? "contact-name-error" : undefined}
130
- />
131
- {fieldErrors.name && (
132
- <InlineMessage
133
- variant="error"
134
- id="contact-name-error"
135
- data-testid="contact-name-error"
136
- >
137
- {fieldErrors.name}
138
- </InlineMessage>
139
- )}
140
- </div>
141
-
142
- <div>
143
- <Label htmlFor="contact-email">{t("emailLabel")}</Label>
144
- <Input
145
- id="contact-email"
146
- name="email"
147
- type="email"
148
- autoComplete="email"
149
- data-testid="contact-email-input"
150
- required
151
- defaultValue={initialValues?.email}
152
- aria-describedby={
153
- fieldErrors.email ? "contact-email-error" : undefined
154
- }
155
- />
156
- {fieldErrors.email && (
157
- <InlineMessage
158
- variant="error"
159
- id="contact-email-error"
160
- data-testid="contact-email-error"
161
- >
162
- {fieldErrors.email}
163
- </InlineMessage>
164
- )}
165
- </div>
166
-
167
- <div>
168
- <Label htmlFor="contact-message">{t("messageLabel")}</Label>
169
- <Textarea
170
- id="contact-message"
171
- name="message"
172
- rows={5}
173
- data-testid="contact-message-input"
174
- defaultValue={initialValues?.message}
175
- aria-describedby={
176
- fieldErrors.message ? "contact-message-error" : undefined
177
- }
178
- />
179
- {fieldErrors.message && (
180
- <InlineMessage
181
- variant="error"
182
- id="contact-message-error"
183
- data-testid="contact-message-error"
184
- >
185
- {fieldErrors.message}
186
- </InlineMessage>
187
- )}
188
- </div>
189
-
190
- <div className="flex items-start gap-3">
191
- <Checkbox
192
- id="contact-consent"
193
- name="consent"
194
- value="true"
195
- checked={consented}
196
- onCheckedChange={handleConsentChange}
197
- aria-labelledby="contact-consent-statement"
198
- className="mt-0.5"
199
- data-testid="contact-consent"
200
- />
201
- <ConsentStatement
202
- id="contact-consent-statement"
203
- statement={t("consentStatement")}
204
- policies={{ terms: localeHref(locale, "/terms") }}
205
- />
206
- </div>
207
-
208
- <SubmitButton disabled={!consented} />
209
- </form>
210
- );
211
- }
@@ -1,96 +0,0 @@
1
- /**
2
- * Tests for ContactForm's consent row (#6466, spec AC-2 / AC-3).
3
- *
4
- * ContactForm is the only form a /contact visitor can submit — the fallback
5
- * `ConversationalIntakeWrapper` swaps in on Skip or a failed auto-submit. Its
6
- * consent line must be a real control: a visible, unticked checkbox named by
7
- * a statement whose "Terms" is a link, and a submit button that stays
8
- * disabled until the box is ticked (the form is `noValidate`, so `required`
9
- * alone would gate nothing).
10
- *
11
- * jsdom lacks `useFormState`/`useFormStatus` (see
12
- * page-renderer-migration.test.tsx), so `react-dom` is extended with inert
13
- * stand-ins; the outermost network boundary (`@working-theory/api-client`)
14
- * is mocked so the real server action module loads without a network.
15
- */
16
- import { fireEvent, render, screen } from "@testing-library/react";
17
- import { localeHref } from "@working-theory/ui";
18
-
19
- const MESSAGES: Record<string, string> = {
20
- consentStatement: "I accept the [Terms](terms).",
21
- };
22
-
23
- jest.mock("next-intl", () => ({
24
- useTranslations: () => (key: string) => MESSAGES[key] ?? key,
25
- useLocale: () => "en",
26
- }));
27
-
28
- jest.mock("react-dom", () => ({
29
- ...jest.requireActual("react-dom"),
30
- useFormState: (_action: unknown, initial: unknown) => [initial, jest.fn()],
31
- useFormStatus: () => ({ pending: false }),
32
- }));
33
-
34
- jest.mock("@working-theory/api-client", () => ({
35
- leads: { submit: jest.fn() },
36
- }));
37
-
38
- import { ContactForm } from "../ContactForm.js";
39
-
40
- // jsdom does not implement ResizeObserver — the Radix Checkbox renders a
41
- // hidden form-bubble input that observes size. Polyfill with a no-op.
42
- beforeAll(() => {
43
- global.ResizeObserver = class ResizeObserver {
44
- observe() {}
45
- unobserve() {}
46
- disconnect() {}
47
- };
48
- });
49
-
50
- describe("ContactForm consent row (#6466)", () => {
51
- it("renders a visible, unticked checkbox (AC-2 i)", () => {
52
- render(<ContactForm />);
53
- const checkbox = screen.getByRole("checkbox");
54
- expect(checkbox).toBeVisible();
55
- expect(checkbox).toHaveAttribute("aria-checked", "false");
56
- });
57
-
58
- it("links 'Terms' to the locale-aware /terms route (AC-2 ii)", () => {
59
- render(<ContactForm />);
60
- const link = screen.getByRole("link", { name: "Terms" });
61
- expect(link).toHaveAttribute("href", localeHref("en", "/terms"));
62
- });
63
-
64
- it("names the checkbox by the consent statement (AC-2 iii)", () => {
65
- render(<ContactForm />);
66
- // jsdom's accname pads the inline link with a space ("Terms .").
67
- expect(screen.getByRole("checkbox")).toHaveAccessibleName(
68
- /^I accept the Terms ?\.$/,
69
- );
70
- });
71
-
72
- it("clicking the Terms link does not tick the box (AC-2 iv)", () => {
73
- render(<ContactForm />);
74
- const link = screen.getByRole("link", { name: "Terms" });
75
- // A wrapping <label> is what would forward the click to the box.
76
- expect(link.closest("label")).toBeNull();
77
- link.addEventListener("click", (event) => event.preventDefault());
78
- fireEvent.click(link);
79
- expect(screen.getByRole("checkbox")).toHaveAttribute(
80
- "aria-checked",
81
- "false",
82
- );
83
- });
84
-
85
- it("keeps submit disabled until the box is ticked (AC-3)", () => {
86
- render(<ContactForm />);
87
- const submit = screen.getByTestId("contact-submit");
88
- expect(submit).toBeDisabled();
89
- fireEvent.click(screen.getByRole("checkbox"));
90
- expect(screen.getByRole("checkbox")).toHaveAttribute(
91
- "aria-checked",
92
- "true",
93
- );
94
- expect(submit).toBeEnabled();
95
- });
96
- });