create-ailk 0.21.0 → 0.23.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/component-catalog.json +186 -8
- package/component-catalog.md +9 -7
- package/dist/add-module.js +20 -14
- package/dist/add-route.d.ts +55 -1
- package/dist/add-route.js +294 -12
- package/dist/cli.js +27 -10
- package/dist/derive-architecture.d.ts +12 -3
- package/dist/derive-architecture.js +20 -8
- package/dist/design-package.js +7 -2
- package/dist/lib/design-checks.js +4 -2
- package/dist/lib/env-catalog.js +5 -5
- package/dist/lib/npm-auth.d.ts +9 -0
- package/dist/lib/npm-auth.js +48 -0
- package/dist/lib/scaffold-render-sweep.d.ts +3 -2
- package/dist/lib/scaffold-render-sweep.js +5 -8
- package/dist/module-architecture.js +99 -9
- package/dist/paid-sections.d.ts +21 -2
- package/dist/paid-sections.js +69 -7
- package/dist/programmatic.js +19 -5
- package/dist/seed-flows.d.ts +4 -1
- package/dist/seed-flows.js +50 -4
- package/dist/site-chrome.d.ts +8 -0
- package/dist/site-chrome.js +17 -1
- package/dist/spoke-checkout.d.ts +65 -41
- package/dist/spoke-checkout.js +208 -430
- package/dist/starter-grid.d.ts +0 -3
- package/dist/starter-grid.js +24 -14
- package/dist/surfaces.js +52 -26
- package/dist/sync-routes.d.ts +38 -1
- package/dist/sync-routes.js +187 -13
- package/dist/template-record.d.ts +4 -3
- package/dist/template-record.js +8 -4
- package/dist/topology.js +25 -1
- package/dist/update.js +15 -0
- package/package.json +3 -3
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +4 -49
- package/site-templates/_base/content/en/Pricing/pricing.mdx +3 -21
- package/site-templates/designs/minimalism/DESIGN.md +1 -1
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +23 -20
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +28 -14
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +15 -39
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +38 -34
- package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/templates/.env.example +9 -7
- package/templates/.github/workflows/ci.yml +13 -0
- package/templates/README.md +1 -0
- package/templates/_gitignore +4 -0
- package/templates/apps/api/.env.example +27 -0
- package/templates/apps/api/CLAUDE.md +87 -17
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +2 -0
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +45 -0
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +185 -0
- package/templates/apps/api/src/config/index.ts +109 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
- package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +19 -0
- package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +149 -0
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +116 -0
- package/templates/apps/api/src/lib/consent-store.ts +28 -0
- package/templates/apps/api/src/lib/error-serializer.ts +74 -7
- package/templates/apps/api/src/lib/flow-completion-store.ts +136 -0
- package/templates/apps/api/src/lib/hub-sign-in-store.ts +38 -2
- package/templates/apps/api/src/lib/proposal-paid-store.ts +21 -4
- package/templates/apps/api/src/lib/stripe.ts +74 -4
- package/templates/apps/api/src/lib/webhook-idempotency.ts +66 -2
- package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +14 -3
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +218 -0
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +174 -0
- package/templates/apps/api/src/middleware/auth.ts +13 -6
- package/templates/apps/api/src/middleware/rate-limit.ts +226 -4
- package/templates/apps/api/src/openapi/spec.ts +33 -3
- package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +49 -0
- package/templates/apps/api/src/routes/auth/hub-sign-in.ts +41 -0
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +325 -0
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +1300 -0
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +49 -0
- package/templates/apps/api/src/routes/checkout/session.ts +57 -25
- package/templates/apps/api/src/routes/checkout/sessions.ts +232 -82
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +386 -0
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +160 -0
- package/templates/apps/api/src/routes/consent/account.ts +268 -0
- package/templates/apps/api/src/routes/consent/index.ts +15 -7
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +36 -0
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +731 -0
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +753 -0
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +762 -0
- package/templates/apps/api/src/routes/content/get-page.ts +4 -0
- package/templates/apps/api/src/routes/content/index.ts +16 -2
- package/templates/apps/api/src/routes/content/offerings.ts +184 -0
- package/templates/apps/api/src/routes/content/pricing.ts +176 -0
- package/templates/apps/api/src/routes/content/shown-offerings.ts +229 -0
- package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +515 -0
- package/templates/apps/api/src/routes/leads/index.ts +164 -7
- package/templates/apps/api/src/routes/webhooks/README.md +66 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +649 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +814 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +80 -68
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +5 -5
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +8 -2
- package/templates/apps/api/src/routes/webhooks/index.ts +23 -0
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +384 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +245 -36
- package/templates/apps/api/src/server.ts +163 -46
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +313 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +51 -2
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +234 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +1383 -133
- package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +389 -0
- package/templates/apps/api/src/services/__tests__/person.test.ts +232 -1
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +444 -0
- package/templates/apps/api/src/services/checkout-buyer.ts +100 -4
- package/templates/apps/api/src/services/consent.ts +95 -0
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +13 -5
- package/templates/apps/api/src/services/entitlements.ts +157 -1
- package/templates/apps/api/src/services/lead-routing.ts +431 -47
- package/templates/apps/api/src/services/magnet-completion.ts +242 -0
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +295 -0
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +268 -0
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +868 -0
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +416 -0
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +396 -0
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +681 -0
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +231 -0
- package/templates/apps/api/src/services/offerings/catalog.ts +308 -0
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +385 -0
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +192 -0
- package/templates/apps/api/src/services/offerings/connection.ts +1003 -0
- package/templates/apps/api/src/services/offerings/index.ts +614 -0
- package/templates/apps/api/src/services/offerings/source.ts +140 -0
- package/templates/apps/api/src/services/offerings/store.ts +150 -0
- package/templates/apps/api/src/services/person.ts +164 -17
- package/templates/apps/api/src/services/plan-offerings.ts +125 -0
- package/templates/apps/api/src/services/public-site-resolver.ts +27 -15
- package/templates/apps/mcp/CLAUDE.md +22 -14
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +9 -4
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +358 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +364 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +4 -4
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +2 -2
- package/templates/apps/mcp/__tests__/server.test.ts +13 -11
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +208 -12
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +11 -11
- package/templates/apps/mcp/src/lib/shown-offerings.ts +105 -0
- package/templates/apps/mcp/src/server.ts +5 -0
- package/templates/apps/mcp/src/tools/get_offerings.ts +47 -30
- package/templates/apps/mcp/src/tools/get_pricing.ts +40 -40
- package/templates/apps/mcp/src/tools/purchase.ts +30 -2
- package/templates/apps/mcp/src/workspace-server.ts +15 -0
- package/templates/apps/web/.env.example +24 -31
- package/templates/apps/web/CLAUDE.md +393 -9
- package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +6 -2
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +5 -4
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +5 -1
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +2 -0
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +3 -14
- package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +2 -0
- package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +5 -1
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +160 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/sign-in-card.test.tsx +12 -9
- package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +105 -2
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +36 -3
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +47 -1
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +60 -22
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +16 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +85 -31
- package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +18 -4
- package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +3 -1
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +7 -4
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +227 -207
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout-sign-out.test.tsx +17 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +143 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-menu.test.tsx +4 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +385 -89
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/popups.test.tsx +5 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +44 -5
- package/templates/apps/web/app/[locale]/(authed)/account/account-frame.tsx +68 -34
- package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +0 -8
- package/templates/apps/web/app/[locale]/(authed)/account/agreements-actions.ts +39 -151
- package/templates/apps/web/app/[locale]/(authed)/account/agreements-gate.ts +61 -0
- package/templates/apps/web/app/[locale]/(authed)/account/agreements-prompt.tsx +143 -140
- package/templates/apps/web/app/[locale]/(authed)/account/layout.tsx +40 -6
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +68 -54
- package/templates/apps/web/app/[locale]/(authed)/account/privacy/page.tsx +5 -1
- package/templates/apps/web/app/[locale]/careers/[slug]/[action]/page.tsx +189 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +295 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +120 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +23 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +319 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-hub.test.tsx +172 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-set.test.tsx +149 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +141 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +424 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +72 -11
- package/templates/apps/web/app/[locale]/careers/page.tsx +129 -5
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/checkout/__tests__/pages.test.tsx +139 -0
- package/templates/apps/web/app/[locale]/checkout/__tests__/thank-you-account.test.tsx +136 -0
- package/templates/apps/web/app/[locale]/checkout/thank-you/page.tsx +114 -0
- package/templates/apps/web/app/[locale]/checkout/unavailable/page.tsx +51 -0
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +17 -1
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +79 -4
- package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +160 -13
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +466 -36
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +7 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +172 -57
- package/templates/apps/web/app/[locale]/contact/intake-script.ts +26 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +99 -60
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +341 -4
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.count.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.deliverable.test.tsx +200 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.ending.test.tsx +197 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.invite.test.tsx +257 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/account-invite.actions.test.ts +69 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +430 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +21 -9
- package/templates/apps/web/app/[locale]/flows/[slug]/account-invite.actions.ts +35 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +352 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +12 -73
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +10 -31
- package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/layout.tsx +55 -4
- package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +174 -104
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +95 -58
- package/templates/apps/web/app/[locale]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap +7 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/offerings.test.tsx +599 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/page.test.tsx +216 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +236 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +367 -6
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +4 -1
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/thanks/[slug]/AccountInviteLink.tsx +89 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/AccountInviteLink.test.tsx +104 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +38 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +17 -0
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +62 -3
- package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +70 -18
- package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +30 -9
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/api/auth/hub/authorize/__tests__/route.test.ts +114 -0
- package/templates/apps/web/app/api/auth/hub/authorize/route.ts +20 -3
- package/templates/apps/web/app/api/hub-session/__tests__/routes.test.ts +44 -1
- package/templates/apps/web/app/api/hub-session/sign-in/route.ts +22 -3
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +316 -0
- package/templates/apps/web/app/api/offerings/checkout/__tests__/route.test.ts +810 -0
- package/templates/apps/web/auth.ts +28 -2
- package/templates/apps/web/lib/__tests__/account-invite.test.ts +63 -0
- package/templates/apps/web/lib/__tests__/auth-routes.test.ts +27 -1
- package/templates/apps/web/lib/__tests__/consent-policies.test.ts +23 -0
- package/templates/apps/web/lib/__tests__/deck-page.test.ts +7 -1
- package/templates/apps/web/lib/__tests__/in-page-magnet.test.ts +265 -0
- package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +57 -0
- package/templates/apps/web/lib/__tests__/newsletter.actions.test.ts +293 -0
- package/templates/apps/web/lib/__tests__/offerings-pricing.test.ts +601 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +101 -25
- package/templates/apps/web/lib/account-invite.ts +37 -0
- package/templates/apps/web/lib/auth-routes.ts +36 -2
- package/templates/apps/web/lib/checkout-config.ts +16 -0
- package/templates/apps/web/lib/consent-policies.ts +22 -0
- package/templates/apps/web/lib/deck-page.ts +7 -0
- package/templates/apps/web/lib/deliverable-grant.ts +18 -0
- package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +111 -0
- package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +88 -32
- package/templates/apps/web/lib/in-page-magnet.ts +416 -0
- package/templates/apps/web/lib/magnet-routes.ts +42 -0
- package/templates/apps/web/lib/modules.generated.ts +9 -0
- package/templates/apps/web/lib/newsletter.actions.ts +202 -0
- package/templates/apps/web/lib/offerings-pricing.ts +326 -0
- package/templates/apps/web/lib/posting-title.ts +17 -0
- package/templates/apps/web/lib/prisma-for-auth.ts +8 -0
- package/templates/apps/web/lib/sign-up-agreements.ts +449 -0
- package/templates/apps/web/lib/site-chrome.ts +2 -0
- package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
- package/templates/apps/web/messages/en.json +71 -20
- package/templates/apps/web/middleware.ts +12 -2
- package/templates/apps/web/package.json +1 -0
- package/templates/apps/web/security-headers.config.ts +17 -0
- package/templates/apps/web/src/lib/__tests__/lead-write.test.ts +187 -0
- package/templates/apps/web/src/lib/__tests__/rate-limit.test.ts +67 -0
- package/templates/apps/web/src/lib/lead-write.ts +90 -0
- package/templates/apps/web/src/lib/rate-limit.ts +79 -0
- package/templates/content/en/BlogList/blog.mdx +4 -71
- package/templates/content/en/BookCall/book-a-call.mdx +1 -41
- package/templates/content/en/BookCall/onsite-estimate.mdx +1 -17
- package/templates/content/en/BookCall/onsite-service.mdx +1 -17
- package/templates/content/en/BookCall/start-project.mdx +1 -17
- package/templates/content/en/ContactPage/contact.mdx +6 -63
- package/templates/content/en/HomePage/home.mdx +3 -21
- package/templates/database/CHANGELOG.md +69 -0
- package/templates/database/__tests__/consent-source-checkout-migration.test.ts +79 -0
- package/templates/database/__tests__/flow-completion-migration.test.ts +115 -0
- package/templates/database/__tests__/flow-completion.db.test.ts +136 -0
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +161 -0
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +270 -0
- package/templates/database/__tests__/offerings-migration.test.ts +197 -0
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +86 -0
- package/templates/database/__tests__/offerings.db.test.ts +303 -0
- package/templates/database/__tests__/seed.test.ts +64 -1
- package/templates/database/auth/schema.prisma +4 -0
- package/templates/database/config/schema.prisma +91 -0
- package/templates/database/inbox/schema.prisma +17 -2
- package/templates/database/migrations/20261018120000_flow_completion/migration.sql +52 -0
- package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +27 -0
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +146 -0
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +77 -0
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +45 -0
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +47 -0
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +16 -0
- package/templates/database/package.json +1 -1
- package/templates/database/seed.ts +62 -3
- package/versions.json +35 -35
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -199
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up.actions.ts +0 -125
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +0 -93
- package/templates/apps/web/app/[locale]/downloads/page.tsx +0 -37
- package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +0 -139
- package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +0 -93
- package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +0 -120
- package/templates/apps/web/lib/meeting-slugs.ts +0 -63
|
@@ -3,21 +3,26 @@
|
|
|
3
3
|
// content the route 404s. Mirrors for/page.tsx: a sections-composed
|
|
4
4
|
// page renders its sections, a prose-only page its MDX body.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// The newsletter magnet is the only source (#8847 D11): the page reads the
|
|
7
|
+
// workspace's `newsletter` magnet (`flows.get("newsletter")`, shared for 15
|
|
8
|
+
// seconds per instance like /contact's read), else the seeded
|
|
9
|
+
// `newsletterFlowConfig` when the hub cannot be read. Its step title is the
|
|
10
|
+
// page's H1 and `<title>`, its body the line under it (`framedSources`), and
|
|
11
|
+
// the standard `NewsletterFormInline` — label, consent, help line, button and
|
|
12
|
+
// ending all the magnet's — goes into the page's first `contact-form`
|
|
13
|
+
// section, bound to `subscribeNewsletterAction`. Rendered on every request.
|
|
9
14
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
15
|
+
// A signup only when there is somewhere to keep it (#6730 D9): when the API
|
|
16
|
+
// does not accept a subscription (`GET /v1/leads/capture` — a database is set
|
|
17
|
+
// up), the slot holds `ContactFallback` with the site's contact email.
|
|
18
|
+
//
|
|
19
|
+
// An authored `newsletter` section never renders beside the slot. A page with
|
|
20
|
+
// no `contact-form` section keeps the composition it had before
|
|
21
|
+
// #8847: a content `newsletter` section renders as authored when accepting
|
|
22
|
+
// (its own form posts to `/v1/leads/subscribe`), a page with no such section
|
|
23
|
+
// gets the signup appended, and when not accepting every `newsletter` section
|
|
24
|
+
// is dropped before render, with any leading-hero CTA that pointed at a
|
|
25
|
+
// dropped section's anchor.
|
|
21
26
|
import type {
|
|
22
27
|
getMdxSource as defaultGetMdxSource,
|
|
23
28
|
getPageSections as defaultGetPageSections,
|
|
@@ -28,14 +33,25 @@ import {
|
|
|
28
33
|
renderPage,
|
|
29
34
|
renderPageMetadata,
|
|
30
35
|
} from "@working-theory/page-renderer";
|
|
31
|
-
import {
|
|
36
|
+
import { ContactFallback } from "@working-theory/ui";
|
|
37
|
+
import { NEWSLETTER_FLOW_SLUG, newsletterFlowConfig } from "@working-theory/validation";
|
|
32
38
|
import type { Metadata } from "next";
|
|
33
39
|
import { getTranslations } from "next-intl/server";
|
|
34
40
|
import type { ReactElement } from "react";
|
|
35
41
|
|
|
36
|
-
import {
|
|
42
|
+
import {
|
|
43
|
+
framedSources,
|
|
44
|
+
inPageView,
|
|
45
|
+
type InPageView,
|
|
46
|
+
newsletterSignup,
|
|
47
|
+
type NewsletterFormView,
|
|
48
|
+
readCaptureStatus,
|
|
49
|
+
readServedMagnet,
|
|
50
|
+
} from "../../../lib/in-page-magnet";
|
|
51
|
+
import { readSiteContactEmail } from "../contact/site-contact-email";
|
|
37
52
|
|
|
38
|
-
|
|
53
|
+
// #8847 D11 — rendered on every request; the magnet read behind it is shared for 15 seconds.
|
|
54
|
+
export const dynamic = "force-dynamic";
|
|
39
55
|
|
|
40
56
|
interface Props {
|
|
41
57
|
params: Promise<{ locale: string }>;
|
|
@@ -44,15 +60,16 @@ interface Props {
|
|
|
44
60
|
}
|
|
45
61
|
|
|
46
62
|
type Section = Awaited<ReturnType<typeof defaultGetPageSections>>[number];
|
|
63
|
+
type NewsletterView = InPageView & { form: NewsletterFormView };
|
|
47
64
|
|
|
48
|
-
/**
|
|
49
|
-
async function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
/** The served newsletter magnet's view when it maps, else the seeded config's. */
|
|
66
|
+
async function newsletterView(locale: string): Promise<NewsletterView> {
|
|
67
|
+
const magnet = await readServedMagnet(NEWSLETTER_FLOW_SLUG);
|
|
68
|
+
const view =
|
|
69
|
+
(magnet ? inPageView(magnet, locale, "newsletter") : null) ??
|
|
70
|
+
// The seeded config always maps: one step, its email and consent fields.
|
|
71
|
+
inPageView(newsletterFlowConfig, locale, "newsletter")!;
|
|
72
|
+
return view as NewsletterView;
|
|
56
73
|
}
|
|
57
74
|
|
|
58
75
|
/**
|
|
@@ -77,12 +94,22 @@ function withoutSignup(sections: Section[]): Section[] {
|
|
|
77
94
|
|
|
78
95
|
export async function generateMetadata({
|
|
79
96
|
params,
|
|
80
|
-
|
|
97
|
+
getMdxSource,
|
|
98
|
+
getPageSections,
|
|
99
|
+
}: Props): Promise<Metadata> {
|
|
81
100
|
const { locale } = await params;
|
|
101
|
+
const view = await newsletterView(locale);
|
|
102
|
+
// #8847 D11 — the `<title>` is the magnet's step title, like the H1.
|
|
103
|
+
const framed = framedSources({
|
|
104
|
+
getMdxSource: getMdxSource ?? loadMdxSource,
|
|
105
|
+
getPageSections: getPageSections ?? loadPageSections,
|
|
106
|
+
view,
|
|
107
|
+
});
|
|
82
108
|
return renderPageMetadata({
|
|
83
109
|
type: "NewsletterSignup",
|
|
84
110
|
slug: "newsletter",
|
|
85
111
|
locale,
|
|
112
|
+
getMdxSource: framed.getMdxSource,
|
|
86
113
|
});
|
|
87
114
|
}
|
|
88
115
|
|
|
@@ -92,51 +119,61 @@ export default async function Page({
|
|
|
92
119
|
getPageSections,
|
|
93
120
|
}: Props): Promise<ReactElement> {
|
|
94
121
|
const { locale } = await params;
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
122
|
+
const [status, view] = await Promise.all([readCaptureStatus(), newsletterView(locale)]);
|
|
123
|
+
const accepting = status?.newsletter === true;
|
|
124
|
+
const framed = framedSources({
|
|
125
|
+
getMdxSource: getMdxSource ?? loadMdxSource,
|
|
126
|
+
getPageSections: getPageSections ?? loadPageSections,
|
|
127
|
+
view,
|
|
128
|
+
});
|
|
129
|
+
const source = await framed.getMdxSource("NewsletterSignup", "newsletter", locale);
|
|
130
|
+
const declared = source ? await framed.getPageSections(source.frontmatter) : [];
|
|
102
131
|
const composed = declared.length > 0;
|
|
132
|
+
const slot = declared.find((s) => s.type === "contact-form")?.id;
|
|
103
133
|
const hasSignupSection = declared.some((s) => s.type === "newsletter");
|
|
134
|
+
const contactEmail = readSiteContactEmail();
|
|
135
|
+
|
|
136
|
+
let surface: ReactElement;
|
|
137
|
+
if (accepting) {
|
|
138
|
+
surface = newsletterSignup(view, {
|
|
139
|
+
locale,
|
|
140
|
+
className: "mx-auto",
|
|
141
|
+
...(contactEmail !== undefined && { fallbackEmail: contactEmail }),
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
const tc = await getTranslations({ locale, namespace: "contact" });
|
|
145
|
+
surface = (
|
|
146
|
+
<ContactFallback
|
|
147
|
+
email={contactEmail}
|
|
148
|
+
text={{
|
|
149
|
+
heading: tc("unavailableHeading"),
|
|
150
|
+
body: tc("unavailableBody", { email: "{email}" }),
|
|
151
|
+
noEmail: tc("unavailableNoEmail"),
|
|
152
|
+
}}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
104
156
|
|
|
105
157
|
const rendered = await renderPage({
|
|
106
158
|
type: "NewsletterSignup",
|
|
107
159
|
slug: "newsletter",
|
|
108
160
|
locale,
|
|
109
161
|
...(composed ? {} : { bodyMode: "mdx-body" as const }),
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
162
|
+
getMdxSource: framed.getMdxSource,
|
|
163
|
+
// With a slot the magnet's form is the page's one signup, so an authored
|
|
164
|
+
// `newsletter` section (posting around the magnet) never renders beside it.
|
|
165
|
+
getPageSections:
|
|
166
|
+
accepting && slot === undefined
|
|
167
|
+
? framed.getPageSections
|
|
168
|
+
: async (frontmatter: unknown) => withoutSignup(await framed.getPageSections(frontmatter)),
|
|
169
|
+
...(slot !== undefined && { sectionSlots: { [slot]: surface } }),
|
|
114
170
|
});
|
|
115
171
|
|
|
116
|
-
if (!accepting || hasSignupSection || source === null) return rendered;
|
|
117
|
-
|
|
118
|
-
const [t, tc] = await Promise.all([
|
|
119
|
-
getTranslations({ locale, namespace: "newsletter" }),
|
|
120
|
-
getTranslations({ locale, namespace: "contact" }),
|
|
121
|
-
]);
|
|
172
|
+
if (slot !== undefined || !accepting || hasSignupSection || source === null) return rendered;
|
|
122
173
|
return (
|
|
123
174
|
<>
|
|
124
175
|
{rendered}
|
|
125
|
-
|
|
126
|
-
action={subscribeNewsletterAction}
|
|
127
|
-
fields={[{ name: "email", label: t("emailLabel"), type: "email", required: true }]}
|
|
128
|
-
termsHref={localeHref(locale, "/terms")}
|
|
129
|
-
text={{
|
|
130
|
-
submit: t("submit"),
|
|
131
|
-
sending: t("sending"),
|
|
132
|
-
success: t("success"),
|
|
133
|
-
consentStatement: t("consentStatement"),
|
|
134
|
-
genericError: tc("genericError"),
|
|
135
|
-
unavailableHeading: tc("unavailableHeading"),
|
|
136
|
-
unavailableBody: tc("unavailableBody", { email: "{email}" }),
|
|
137
|
-
unavailableNoEmail: tc("unavailableNoEmail"),
|
|
138
|
-
}}
|
|
139
|
-
/>
|
|
176
|
+
{surface}
|
|
140
177
|
</>
|
|
141
178
|
);
|
|
142
179
|
}
|
|
@@ -25,7 +25,11 @@ type DeckGrounds = NonNullable<Parameters<typeof renderPage>[0]["deckGrounds"]>;
|
|
|
25
25
|
* carries `deckGrounds` only when the site's design sets one (#7719 D3), so
|
|
26
26
|
* this compiles against both shapes of the generated file.
|
|
27
27
|
*/
|
|
28
|
-
const chrome: SiteChrome & {
|
|
28
|
+
const chrome: SiteChrome & {
|
|
29
|
+
deckGrounds?: DeckGrounds;
|
|
30
|
+
deckPresentation?: true;
|
|
31
|
+
deckAnchors?: "bare";
|
|
32
|
+
} = siteChrome;
|
|
29
33
|
|
|
30
34
|
interface Props {
|
|
31
35
|
params: Promise<{ locale: string }>;
|
|
@@ -41,6 +45,8 @@ interface Props {
|
|
|
41
45
|
deckGrounds?: DeckGrounds;
|
|
42
46
|
/** The design's `layout.deckPresentation` (#7740); defaults to the generated `siteChrome`'s. */
|
|
43
47
|
deckPresentation?: boolean;
|
|
48
|
+
/** The design's `layout.deckAnchors` (#8773): `bare` names the slides `#<id>`; defaults to the generated `siteChrome`'s. */
|
|
49
|
+
deckAnchors?: "bare";
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
export async function generateMetadata({
|
|
@@ -57,6 +63,7 @@ export default async function Page({
|
|
|
57
63
|
home = chrome.home,
|
|
58
64
|
deckGrounds = chrome.deckGrounds,
|
|
59
65
|
deckPresentation = chrome.deckPresentation,
|
|
66
|
+
deckAnchors = chrome.deckAnchors,
|
|
60
67
|
}: Props): Promise<ReactElement> {
|
|
61
68
|
const { locale } = await params;
|
|
62
69
|
return renderPage({
|
|
@@ -83,5 +90,10 @@ export default async function Page({
|
|
|
83
90
|
// alignment field centred, card grids one column on phones, and slide
|
|
84
91
|
// anchors clear of the page's JSON-LD @id fragments.
|
|
85
92
|
...(home === "deck" && deckPresentation === true && { deckPresentation: true }),
|
|
93
|
+
// #8773 — and, when the design chooses it, names those slides `#<id>`
|
|
94
|
+
// (the `slide-` name kept only where the bare id would collide).
|
|
95
|
+
...(home === "deck" &&
|
|
96
|
+
deckPresentation === true &&
|
|
97
|
+
deckAnchors === "bare" && { deckAnchorStyle: "bare" as const }),
|
|
86
98
|
});
|
|
87
99
|
}
|
|
@@ -68,7 +68,7 @@ describe("partners/page — snapshot regression", () => {
|
|
|
68
68
|
});
|
|
69
69
|
const { container } = render(element);
|
|
70
70
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
|
71
|
-
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Partners","description":"Organisations partnering with AI Launch Kit.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"Organization"}]}}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Partners</h1><p data-testid="partners-description" class="mt-block-tight text-lead">Organisations partnering with AI Launch Kit.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-
|
|
71
|
+
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Partners","description":"Organisations partnering with AI Launch Kit.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"Organization"}]}}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Partners</h1><p data-testid="partners-description" class="mt-block-tight text-lead">Organisations partnering with AI Launch Kit.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div class="ailk-prose max-w-none text-(--color-text-muted) text-body-sm leading-relaxed [&>*:first-child]:mt-0 [&_h2]:mt-block-loose [&_h2]:scroll-mt-24 [&_h2]:text-heading-3 [&_h2]:font-display [&_h2]:text-(--color-fg) [&_h3]:mt-block-loose [&_h3]:scroll-mt-24 [&_h3]:text-heading-4 [&_h3]:font-display [&_h3]:text-(--color-fg) [&_h4]:mt-block-tight [&_h4]:scroll-mt-24 [&_h4]:text-heading-4 [&_h4]:font-display [&_h4]:text-(--color-fg) [&_h5]:mt-block-tight [&_h5]:scroll-mt-24 [&_h5]:text-heading-4 [&_h5]:font-display [&_h5]:text-(--color-fg) [&_h6]:mt-block-tight [&_h6]:scroll-mt-24 [&_h6]:text-heading-4 [&_h6]:font-display [&_h6]:text-(--color-fg) [&_p]:mt-paragraph [&_strong]:font-semibold [&_strong]:text-(--color-fg) [&_em]:italic [&_ul]:mt-paragraph [&_ul]:list-disc [&_ul]:ps-6 [&_ol]:mt-paragraph [&_ol]:list-decimal [&_ol]:ps-6 [&_li]:mt-1 [&_li]:ps-1 [&_li]:marker:text-(--color-text-muted) [&_li>ul]:mt-1 [&_li>ol]:mt-1 [&_blockquote]:mt-paragraph [&_blockquote]:border-s-4 [&_blockquote]:border-(--color-border-strong) [&_blockquote]:ps-4 [&_blockquote]:italic [&_blockquote]:text-(--color-text-muted) [&_hr]:my-block-loose [&_hr]:border-(--color-border) [&_a]:text-(--color-accent) [&_a]:underline [&_a]:underline-offset-4 [&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-(--color-surface-secondary) [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-code [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-(--color-fg) [&_pre]:mt-paragraph [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border-hairline [&_pre]:border-(--color-border) [&_pre]:bg-(--color-bg) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-body-sm [&_img]:mt-paragraph [&_img]:h-auto [&_img]:max-w-full [&_img]:rounded-lg [&_table]:mt-paragraph [&_table]:w-full [&_table]:border-collapse [&_table]:text-body-sm [&_th]:border-b [&_th]:border-(--color-border) [&_th]:bg-(--color-surface-secondary) [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-semibold [&_th]:text-(--color-fg) [&_td]:border-b [&_td]:border-(--color-border) [&_td]:px-3 [&_td]:py-2 [&_kbd]:rounded [&_kbd]:border-hairline [&_kbd]:border-(--color-border) [&_kbd]:bg-(--color-surface-secondary) [&_kbd]:px-1.5 [&_kbd]:py-0.5 [&_kbd]:text-caption [&_kbd]:font-mono" data-testid="mdx-content"><div data-testid="mdx-rendered">mdx-body-content</div></div></article></div></div></div></main>"`,
|
|
72
72
|
);
|
|
73
73
|
});
|
|
74
74
|
});
|
|
@@ -93,7 +93,7 @@ describe("partners/[slug]/page — snapshot regression", () => {
|
|
|
93
93
|
});
|
|
94
94
|
const { container } = render(element);
|
|
95
95
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
|
96
|
-
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Acme Corp","description":"Acme Corp is a strategic partner.","mainEntity":{"@context":"https://schema.org","@type":"Organization","name":"Acme Corp","description":"Acme Corp is a strategic partner."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Partners","item":"http://localhost:3000/en/partners"},{"@type":"ListItem","position":3,"name":"Acme Corp","item":"http://localhost:3000/en/partners/acme-corp"}]}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Acme Corp</h1><p data-testid="acme-corp-description" class="mt-block-tight text-lead">Acme Corp is a strategic partner.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-
|
|
96
|
+
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Acme Corp","description":"Acme Corp is a strategic partner.","mainEntity":{"@context":"https://schema.org","@type":"Organization","name":"Acme Corp","description":"Acme Corp is a strategic partner."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Partners","item":"http://localhost:3000/en/partners"},{"@type":"ListItem","position":3,"name":"Acme Corp","item":"http://localhost:3000/en/partners/acme-corp"}]}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Acme Corp</h1><p data-testid="acme-corp-description" class="mt-block-tight text-lead">Acme Corp is a strategic partner.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div class="ailk-prose max-w-none text-(--color-text-muted) text-body-sm leading-relaxed [&>*:first-child]:mt-0 [&_h2]:mt-block-loose [&_h2]:scroll-mt-24 [&_h2]:text-heading-3 [&_h2]:font-display [&_h2]:text-(--color-fg) [&_h3]:mt-block-loose [&_h3]:scroll-mt-24 [&_h3]:text-heading-4 [&_h3]:font-display [&_h3]:text-(--color-fg) [&_h4]:mt-block-tight [&_h4]:scroll-mt-24 [&_h4]:text-heading-4 [&_h4]:font-display [&_h4]:text-(--color-fg) [&_h5]:mt-block-tight [&_h5]:scroll-mt-24 [&_h5]:text-heading-4 [&_h5]:font-display [&_h5]:text-(--color-fg) [&_h6]:mt-block-tight [&_h6]:scroll-mt-24 [&_h6]:text-heading-4 [&_h6]:font-display [&_h6]:text-(--color-fg) [&_p]:mt-paragraph [&_strong]:font-semibold [&_strong]:text-(--color-fg) [&_em]:italic [&_ul]:mt-paragraph [&_ul]:list-disc [&_ul]:ps-6 [&_ol]:mt-paragraph [&_ol]:list-decimal [&_ol]:ps-6 [&_li]:mt-1 [&_li]:ps-1 [&_li]:marker:text-(--color-text-muted) [&_li>ul]:mt-1 [&_li>ol]:mt-1 [&_blockquote]:mt-paragraph [&_blockquote]:border-s-4 [&_blockquote]:border-(--color-border-strong) [&_blockquote]:ps-4 [&_blockquote]:italic [&_blockquote]:text-(--color-text-muted) [&_hr]:my-block-loose [&_hr]:border-(--color-border) [&_a]:text-(--color-accent) [&_a]:underline [&_a]:underline-offset-4 [&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-(--color-surface-secondary) [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-code [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-(--color-fg) [&_pre]:mt-paragraph [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border-hairline [&_pre]:border-(--color-border) [&_pre]:bg-(--color-bg) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-body-sm [&_img]:mt-paragraph [&_img]:h-auto [&_img]:max-w-full [&_img]:rounded-lg [&_table]:mt-paragraph [&_table]:w-full [&_table]:border-collapse [&_table]:text-body-sm [&_th]:border-b [&_th]:border-(--color-border) [&_th]:bg-(--color-surface-secondary) [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-semibold [&_th]:text-(--color-fg) [&_td]:border-b [&_td]:border-(--color-border) [&_td]:px-3 [&_td]:py-2 [&_kbd]:rounded [&_kbd]:border-hairline [&_kbd]:border-(--color-border) [&_kbd]:bg-(--color-surface-secondary) [&_kbd]:px-1.5 [&_kbd]:py-0.5 [&_kbd]:text-caption [&_kbd]:font-mono" data-testid="mdx-content"><div data-testid="mdx-rendered">mdx-body-content</div></div></article></div></div></div></main>"`,
|
|
97
97
|
);
|
|
98
98
|
});
|
|
99
99
|
|
package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`/pricing on an unconnected site is today's page (#8927 AC-4) renders today's DI page for ?plan=BASIC 1`] = `"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Pricing","description":"Plans for every stage."},{"@context":"https://schema.org","@type":"Offer","name":"Basic","price":"29","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"Offer","name":"Business","price":"79","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"Offer","name":"Agency","price":"199","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"AggregateOffer","priceCurrency":"USD","lowPrice":"29","highPrice":"199","offerCount":3}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Pricing</h1><p data-testid="pricing-description" class="mt-block-tight text-lead">Plans for every stage.</p></div><div class="ailk-section-renderer" data-testid="section-renderer"><span id="section-plans" class="ailk-section-anchor" aria-hidden="true" data-testid="section-anchor"></span><section class="py-section bg-(--color-bg)" data-testid="pricing" data-section="pricing"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8"><span hidden="" data-testid="pricing-recommended-anchor"></span><div class="grid gap-grid md:grid-cols-2 lg:grid-cols-3 mt-10 items-stretch pricing-card-row-grid" data-testid="pricing-grid" data-separation="gapped"><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card" aria-current="true"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-thin border-(--color-brand) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Basic</h3><div class="group inline-flex items-center border-hairline rounded-full transition-colors focus-visible:outline-none bg-(--color-brand) border-transparent text-(--color-fg-on-brand) hover:bg-(--color-brand)/90 focus-visible:bg-(--color-brand)/90 ps-2 pe-2 py-0.5 text-body-sm" data-testid="tier-badge">Recommended for you</div></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$29</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 bg-(--color-brand) text-(--color-fg-on-brand) not-disabled:hover:bg-(--button-hover-bg) not-disabled:hover:text-(--button-hover-fg) not-disabled:hover:outline not-disabled:hover:outline-1 not-disabled:hover:-outline-offset-1 not-disabled:hover:outline-(--button-hover-border) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:opacity-80 rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/basic" data-testid="tier-cta">Choose Basic</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">One site</span></li></ul></div></div></div><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-hairline border-(--color-border) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Business</h3></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$79</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 border-hairline border-(--color-border) text-(--color-fg) bg-transparent not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/business" data-testid="tier-cta">Choose Business</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">Three sites</span></li></ul></div></div></div><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-hairline border-(--color-border) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Agency</h3></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$199</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 border-hairline border-(--color-border) text-(--color-fg) bg-transparent not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/agency" data-testid="tier-cta">Choose Agency</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">Unlimited sites</span></li></ul></div></div></div></div></div></section></div></main>"`;
|
|
4
|
+
|
|
5
|
+
exports[`/pricing on an unconnected site is today's page (#8927 AC-4) renders today's DI page for ?plan=agency 1`] = `"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Pricing","description":"Plans for every stage."},{"@context":"https://schema.org","@type":"Offer","name":"Basic","price":"29","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"Offer","name":"Business","price":"79","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"Offer","name":"Agency","price":"199","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"AggregateOffer","priceCurrency":"USD","lowPrice":"29","highPrice":"199","offerCount":3}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Pricing</h1><p data-testid="pricing-description" class="mt-block-tight text-lead">Plans for every stage.</p></div><div class="ailk-section-renderer" data-testid="section-renderer"><span id="section-plans" class="ailk-section-anchor" aria-hidden="true" data-testid="section-anchor"></span><section class="py-section bg-(--color-bg)" data-testid="pricing" data-section="pricing"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8"><span hidden="" data-testid="pricing-recommended-anchor"></span><div class="grid gap-grid md:grid-cols-2 lg:grid-cols-3 mt-10 items-stretch pricing-card-row-grid" data-testid="pricing-grid" data-separation="gapped"><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-hairline border-(--color-border) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Basic</h3></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$29</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 border-hairline border-(--color-border) text-(--color-fg) bg-transparent not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/basic" data-testid="tier-cta">Choose Basic</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">One site</span></li></ul></div></div></div><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-hairline border-(--color-border) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Business</h3></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$79</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 border-hairline border-(--color-border) text-(--color-fg) bg-transparent not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/business" data-testid="tier-cta">Choose Business</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">Three sites</span></li></ul></div></div></div><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card" aria-current="true"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-thin border-(--color-brand) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Agency</h3><div class="group inline-flex items-center border-hairline rounded-full transition-colors focus-visible:outline-none bg-(--color-brand) border-transparent text-(--color-fg-on-brand) hover:bg-(--color-brand)/90 focus-visible:bg-(--color-brand)/90 ps-2 pe-2 py-0.5 text-body-sm" data-testid="tier-badge">Recommended for you</div></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$199</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 bg-(--color-brand) text-(--color-fg-on-brand) not-disabled:hover:bg-(--button-hover-bg) not-disabled:hover:text-(--button-hover-fg) not-disabled:hover:outline not-disabled:hover:outline-1 not-disabled:hover:-outline-offset-1 not-disabled:hover:outline-(--button-hover-border) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:opacity-80 rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/agency" data-testid="tier-cta">Choose Agency</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">Unlimited sites</span></li></ul></div></div></div></div></div></section></div></main>"`;
|
|
6
|
+
|
|
7
|
+
exports[`/pricing on an unconnected site is today's page (#8927 AC-4) renders today's DI page for no plan 1`] = `"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Pricing","description":"Plans for every stage."},{"@context":"https://schema.org","@type":"Offer","name":"Basic","price":"29","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"Offer","name":"Business","price":"79","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"Offer","name":"Agency","price":"199","priceCurrency":"USD"},{"@context":"https://schema.org","@type":"AggregateOffer","priceCurrency":"USD","lowPrice":"29","highPrice":"199","offerCount":3}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Pricing</h1><p data-testid="pricing-description" class="mt-block-tight text-lead">Plans for every stage.</p></div><div class="ailk-section-renderer" data-testid="section-renderer"><span id="section-plans" class="ailk-section-anchor" aria-hidden="true" data-testid="section-anchor"></span><section class="py-section bg-(--color-bg)" data-testid="pricing" data-section="pricing"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8"><div class="grid gap-grid md:grid-cols-2 lg:grid-cols-3 mt-10 items-stretch pricing-card-row-grid" data-testid="pricing-grid" data-separation="gapped"><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-hairline border-(--color-border) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Basic</h3></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$29</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 border-hairline border-(--color-border) text-(--color-fg) bg-transparent not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/basic" data-testid="tier-cta">Choose Basic</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">One site</span></li></ul></div></div></div><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card" aria-current="true"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-thin border-(--color-brand) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Business</h3><div class="group inline-flex items-center border-hairline rounded-full transition-colors focus-visible:outline-none bg-(--color-brand) border-transparent text-(--color-fg-on-brand) hover:bg-(--color-brand)/90 focus-visible:bg-(--color-brand)/90 ps-2 pe-2 py-0.5 text-body-sm" data-testid="tier-badge">Recommended</div></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$79</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 bg-(--color-brand) text-(--color-fg-on-brand) not-disabled:hover:bg-(--button-hover-bg) not-disabled:hover:text-(--button-hover-fg) not-disabled:hover:outline not-disabled:hover:outline-1 not-disabled:hover:-outline-offset-1 not-disabled:hover:outline-(--button-hover-border) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:opacity-80 rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/business" data-testid="tier-cta">Choose Business</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">Three sites</span></li></ul></div></div></div><div class="ailk-pricing-tier-card pricing-card-subgrid" data-testid="pricing-tier-card"><div class="pricing-card-subgrid-body"><div class="h-full rounded-card p-card pricing-card-subgrid border-hairline border-(--color-border) bg-(--color-surface-raised)" data-testid="card"><div class="row-start-1 flex flex-wrap items-center gap-2 justify-between"><h3 class="text-heading-3 font-display text-fg text-2xl font-normal">Agency</h3></div><div class="row-start-3 mt-6"><h4 class="text-heading-4 font-display text-fg text-4xl font-medium tracking-tight">$199</h4><span class="text-body font-body leading-normal text-fg mt-1 text-body-sm text-(--color-text-muted)">/month</span></div><div class="row-start-5 mt-6"><a class="inline-flex items-center justify-center gap-2 font-medium motion-safe:transition motion-safe:duration-(--button-hover-duration) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 border-hairline border-(--color-border) text-(--color-fg) bg-transparent not-disabled:hover:bg-(--button-hover-quiet-bg) not-disabled:hover:text-(--button-hover-quiet-fg) not-disabled:hover:opacity-(--button-hover-opacity) not-disabled:hover:transform-(--button-hover-transform) not-disabled:hover:shadow-(--button-hover-shadow) not-disabled:active:bg-gray-200 not-disabled:active:text-(--color-fg) rounded-control px-control-x min-h-(--control-height-big) w-full" href="/checkout/agency" data-testid="tier-cta">Choose Agency</a></div><ul class="row-start-6 mt-block-loose space-y-3" role="list"><li class="flex items-start gap-2"><span data-testid="feature-check-circle" class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full check-badge"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check size-[var(--icon-size-xs)] check-glyph" aria-label="Included" role="img"><path d="M20 6 9 17l-5-5"></path></svg></span><span class="text-body font-body leading-normal text-fg text-body-sm text-(--color-fg)">Unlimited sites</span></li></ul></div></div></div></div></div></section></div></main>"`;
|