@aglyn/plugins-ai 1.0.0-beta.291 → 1.0.0-beta.293

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 (149) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-site-import-job.component.js +5 -4
  3. package/src/lib/components/ai-site-import-job.component.js.map +1 -1
  4. package/src/lib/components/ai-site-import-start.component.js +3 -3
  5. package/src/lib/components/ai-site-import-start.component.js.map +1 -1
  6. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  7. package/src/lib/components/ai-site-start-card.component.js +129 -29
  8. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  9. package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
  10. package/src/lib/components/ai-site-start-steps.component.js +42 -25
  11. package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
  12. package/src/lib/components/ai-site-style-previews.d.ts +17 -0
  13. package/src/lib/components/ai-site-style-previews.js +26 -95
  14. package/src/lib/components/ai-site-style-previews.js.map +1 -1
  15. package/src/lib/declarations.server.js +22 -0
  16. package/src/lib/declarations.server.js.map +1 -1
  17. package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
  18. package/src/lib/jobs/ai-job-import-step.js +179 -49
  19. package/src/lib/jobs/ai-job-import-step.js.map +1 -1
  20. package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
  21. package/src/lib/jobs/ai-job-layout-language.js +156 -113
  22. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  23. package/src/lib/jobs/ai-job-layout-step.js +56 -17
  24. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  25. package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
  26. package/src/lib/jobs/ai-job-page-language.js +120 -66
  27. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  28. package/src/lib/jobs/ai-job-page-step.js +27 -7
  29. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  30. package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
  31. package/src/lib/jobs/ai-job-site-datasets.js +36 -16
  32. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  33. package/src/lib/jobs/ai-jobs.js +6 -2
  34. package/src/lib/jobs/ai-jobs.js.map +1 -1
  35. package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
  36. package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
  37. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  38. package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
  39. package/src/lib/jobs/ai-site-import-compile.js +1143 -0
  40. package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
  41. package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
  42. package/src/lib/jobs/ai-site-import-document.js +23 -489
  43. package/src/lib/jobs/ai-site-import-document.js.map +1 -1
  44. package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
  45. package/src/lib/jobs/ai-site-import-look.js +163 -52
  46. package/src/lib/jobs/ai-site-import-look.js.map +1 -1
  47. package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
  48. package/src/lib/jobs/ai-site-import-publish.js +19 -5
  49. package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
  50. package/src/lib/jobs/ai-site-late-photos.js +4 -2
  51. package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
  52. package/src/lib/jobs/ai-site-publish.d.ts +10 -1
  53. package/src/lib/jobs/ai-site-publish.js +8 -3
  54. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  55. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
  56. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
  57. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
  58. package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
  59. package/src/lib/layout-language/ai-layout-compiler.js +677 -33
  60. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  61. package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
  62. package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
  63. package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
  64. package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
  65. package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
  66. package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
  67. package/src/lib/layout-language/ai-layout-frame.js +121 -29
  68. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  69. package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
  70. package/src/lib/layout-language/ai-layout-language.js +85 -120
  71. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  72. package/src/lib/model/ai-credit-estimate.d.ts +11 -7
  73. package/src/lib/model/ai-credit-estimate.js +11 -7
  74. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  75. package/src/lib/model/ai-site-import.d.ts +307 -13
  76. package/src/lib/model/ai-site-import.js +227 -19
  77. package/src/lib/model/ai-site-import.js.map +1 -1
  78. package/src/lib/model/ai-site-look.d.ts +65 -1
  79. package/src/lib/model/ai-site-look.js +141 -23
  80. package/src/lib/model/ai-site-look.js.map +1 -1
  81. package/src/lib/model/ai-site-photos.d.ts +2 -0
  82. package/src/lib/model/ai-site-photos.js.map +1 -1
  83. package/src/lib/model/ai-site-start-steps.d.ts +4 -3
  84. package/src/lib/model/ai-site-start-steps.js +11 -3
  85. package/src/lib/model/ai-site-start-steps.js.map +1 -1
  86. package/src/lib/model/ai-site-start.d.ts +23 -2
  87. package/src/lib/model/ai-site-start.js +25 -3
  88. package/src/lib/model/ai-site-start.js.map +1 -1
  89. package/src/lib/providers/routing.d.ts +11 -0
  90. package/src/lib/providers/routing.js +23 -0
  91. package/src/lib/providers/routing.js.map +1 -1
  92. package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
  93. package/src/lib/runtime/ai-doctrine-validators.js +7 -2
  94. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  95. package/src/lib/runtime/ai-icon-library.d.ts +4 -0
  96. package/src/lib/runtime/ai-icon-library.js +4 -0
  97. package/src/lib/runtime/ai-icon-library.js.map +1 -1
  98. package/src/lib/runtime/ai-node-tree.js +5 -1
  99. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  100. package/src/lib/runtime/ai-palette.d.ts +2 -0
  101. package/src/lib/runtime/ai-palette.generated.js +19 -3
  102. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  103. package/src/lib/runtime/ai-palette.js +2 -1
  104. package/src/lib/runtime/ai-palette.js.map +1 -1
  105. package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
  106. package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
  107. package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
  108. package/src/lib/site-import/site-import-crawl.d.ts +18 -1
  109. package/src/lib/site-import/site-import-crawl.js +70 -10
  110. package/src/lib/site-import/site-import-crawl.js.map +1 -1
  111. package/src/lib/site-import/site-import-css.d.ts +110 -0
  112. package/src/lib/site-import/site-import-css.js +826 -0
  113. package/src/lib/site-import/site-import-css.js.map +1 -0
  114. package/src/lib/site-import/site-import-html.d.ts +116 -1
  115. package/src/lib/site-import/site-import-html.js +538 -46
  116. package/src/lib/site-import/site-import-html.js.map +1 -1
  117. package/src/lib/site-import/site-import-layout.d.ts +79 -0
  118. package/src/lib/site-import/site-import-layout.js +1608 -0
  119. package/src/lib/site-import/site-import-layout.js.map +1 -0
  120. package/src/lib/site-import/site-import-nav.d.ts +40 -0
  121. package/src/lib/site-import/site-import-nav.js +437 -0
  122. package/src/lib/site-import/site-import-nav.js.map +1 -0
  123. package/src/lib/site-import/site-import-page.d.ts +8 -1
  124. package/src/lib/site-import/site-import-page.js +24 -2
  125. package/src/lib/site-import/site-import-page.js.map +1 -1
  126. package/src/lib/assets/site-styles/beauty.webp +0 -0
  127. package/src/lib/assets/site-styles/blog.webp +0 -0
  128. package/src/lib/assets/site-styles/business.webp +0 -0
  129. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  130. package/src/lib/assets/site-styles/education.webp +0 -0
  131. package/src/lib/assets/site-styles/events.webp +0 -0
  132. package/src/lib/assets/site-styles/fitness.webp +0 -0
  133. package/src/lib/assets/site-styles/landing.webp +0 -0
  134. package/src/lib/assets/site-styles/music.webp +0 -0
  135. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  136. package/src/lib/assets/site-styles/personal.webp +0 -0
  137. package/src/lib/assets/site-styles/photography.webp +0 -0
  138. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  139. package/src/lib/assets/site-styles/professional.webp +0 -0
  140. package/src/lib/assets/site-styles/realestate.webp +0 -0
  141. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  142. package/src/lib/assets/site-styles/store.webp +0 -0
  143. package/src/lib/assets/site-styles/studio.webp +0 -0
  144. package/src/lib/assets/site-styles/trades.webp +0 -0
  145. package/src/lib/assets/site-styles/wellness.webp +0 -0
  146. package/src/lib/assets/site-styles/yoga.webp +0 -0
  147. package/src/lib/site-import/site-import-review.d.ts +0 -40
  148. package/src/lib/site-import/site-import-review.js +0 -149
  149. package/src/lib/site-import/site-import-review.js.map +0 -1
@@ -23,6 +23,7 @@ import { mdiCreation, mdiPageLayoutHeaderFooter, mdiWebSync } from "@aglyn/share
23
23
  import { pluginDocsHelp } from "@aglyn/aglyn/app-utils/docs-help";
24
24
  import { HelpTip, MdiIcon } from "@aglyn/shared-ui-jsx";
25
25
  import BlockedControl from "@aglyn/shared-ui-jsx/components/blocked-control.component";
26
+ import { OptionCardGrid } from "@aglyn/shared-ui-jsx/components/option-card-grid.component";
26
27
  import { PrerequisiteNotice } from "@aglyn/shared-ui-jsx/components/prerequisite-notice.component";
27
28
  import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
28
29
  import { useUser } from "@aglyn/tenant-feature-instance";
@@ -34,12 +35,12 @@ import { AI_JOB_AUTO_CONFIRM_INPUT, AI_SITE_FREE_PAGES, aiFreeCreditsNoneLeftTex
34
35
  import { FREE_AI_TASTE_CREDITS_PER_MONTH } from "../plan-entitlements.js";
35
36
  import { AI_CREDITS_CONFIRM_CODE, aiCreditRangeText } from "../model/ai-credit-estimate.js";
36
37
  import { AiCreditsPromptNotice } from "./ai-credits-prompt.component.js";
37
- import { AI_SITE_START_ANSWERS, aiSiteStartAnswersFromClientBuild, aiSiteStartBrief, aiSiteStartClientBrief, aiSiteStartClientInputs, aiSiteStartClientNote, aiSiteStartExtrasGiven, aiSiteStartInputs, aiSiteStartRefusal } from "../model/ai-site-start.js";
38
+ import { AI_SITE_START_ANSWERS, AI_SITE_START_STYLE_REQUIRED, aiSiteStartAnswersFromClientBuild, aiSiteStartBrief, aiSiteStartClientBrief, aiSiteStartClientInputs, aiSiteStartClientNote, aiSiteStartExtrasGiven, aiSiteStartInputs, aiSiteStartKind, aiSiteStartRefusal } from "../model/ai-site-start.js";
38
39
  import { aiSiteInspirationLimit } from "../model/ai-site-inspiration.js";
39
40
  import { aiSiteStartFieldErrors, aiSiteStartFirstInvalidStep, aiSiteStartNextStep, aiSiteStartPreviousStep, aiSiteStartStepErrors, aiSiteStartStepIndex, AI_SITE_START_STEPS, AI_SITE_START_STEP_FIELDS } from "../model/ai-site-start-steps.js";
40
41
  import { aiSiteKindOfInputs } from "../model/ai-site-kinds.js";
41
42
  import { aiSiteStartClickOf, useAiSiteStartTracking } from "./ai-site-start-tracking.js";
42
- import { AudienceStep, DetailsStep, KindStep, MoreDetails, ReviewStep, StartProgress, StepHelp, StyleStep } from "./ai-site-start-steps.component.js";
43
+ import { aiSiteStyleCards, AudienceStep, DetailsStep, KindStep, MoreDetails, ReviewStep, StartProgress, StepHelp, StyleStep } from "./ai-site-start-steps.component.js";
43
44
  import { AiJobFollow } from "./ai-job-follow.component.js";
44
45
  import { AiModelSelector } from "./ai-model-selector.component.js";
45
46
  import { useAiModelChoice } from "./use-ai-model-choice.js";
@@ -163,7 +164,7 @@ import { aiSiteImportOfferOf } from "../model/ai-site-import-view.js";
163
164
  */ const START_HELP = {
164
165
  choose: pluginDocsHelp('aiStart', {
165
166
  anchor: '#how-do-you-want-to-start',
166
- excerpt: 'The starter site gives you a ready-made home page to edit. Start with AI asks a few questions, then plans, writes and publishes your pages.'
167
+ excerpt: 'The starter site gives you a ready-made home page to edit, in a style you choose. Start with AI asks a few questions, then plans, writes and publishes your pages.'
167
168
  }),
168
169
  estimate: pluginDocsHelp('aiCredits', {
169
170
  anchor: '#before-a-job-starts',
@@ -202,9 +203,9 @@ function SectionLabel({ children, help }) {
202
203
  * held, and only the review turns them into the job, through the same
203
204
  * `aiSiteStartBrief` and `aiSiteStartInputs`. Each step is reported as a
204
205
  * funnel, with where people struggle (`ai-site-start-tracking.ts`).
205
- */ export function AiSiteStartCard({ hostId, orgId, orgSlug, host, startBlank, leave, pendingSite, clientBuild, initialAnswers = null }) {
206
- var _ref, _ref1, _ref2, _ref3, _aiFreeSitePrompt;
207
- var _aiSiteKindOfInputs, _modelChoice_options_options_find, _modelChoice_options;
206
+ */ export function AiSiteStartCard({ hostId, orgId, orgSlug, host, startBlank, leave, pendingSite, chooseStarter: chooseStarterInShell, clientBuild, initialAnswers = null }) {
207
+ var _ref, _ref1, _ref2, _ref3, _aiFreeSitePrompt, _aiSiteStartRefusal;
208
+ var _aiSiteKindOfInputs, _modelChoice_options_options_find, _modelChoice_options, _pendingSite_previewControl;
208
209
  const { data: user } = useUser();
209
210
  const router = useRouter();
210
211
  // Held in a ref so a request reads WHO is signed in, never the identity of
@@ -248,6 +249,10 @@ function SectionLabel({ children, help }) {
248
249
  const [busy, setBusy] = useState(false);
249
250
  // The starter card's own busy state while `startBlank` runs (AGL-3594).
250
251
  const [startingStarter, setStartingStarter] = useState(false);
252
+ // The starter card's style choice (AGL-4049): drawn after the starter card
253
+ // is clicked, with nothing chosen until a card is.
254
+ const [pickingStyle, setPickingStyle] = useState(false);
255
+ const [starterStyle, setStarterStyle] = useState(null);
251
256
  const [notice, setNotice] = useState(null);
252
257
  /** The site job "Plan my site" started, as the create door answered with it. */ const [started, setStarted] = useState(null);
253
258
  // The Free taste's page band (AGL-3594), read off the verdict request.
@@ -340,9 +345,10 @@ function SectionLabel({ children, help }) {
340
345
  siteKind
341
346
  })) != null ? _aiFreeSitePrompt : serverPrompt : null;
342
347
  const noneLeft = freeTaste && freeCredits !== null && freeCredits.left <= 0;
343
- const refusal = aiSiteStartRefusal(answers, {
348
+ // The door's refusal, else the questions' own: a style not yet chosen (AGL-4049).
349
+ const refusal = (_aiSiteStartRefusal = aiSiteStartRefusal(answers, {
344
350
  freeTaste
345
- });
351
+ })) != null ? _aiSiteStartRefusal : answers.style === null ? AI_SITE_START_STYLE_REQUIRED : null;
346
352
  const band = aiSitePagesBand(freeTaste);
347
353
  // On a paid plan the person picks the model that builds the site (AGL-3660),
348
354
  // Auto by default, from the models their plan allows; every step of the job
@@ -371,7 +377,7 @@ function SectionLabel({ children, help }) {
371
377
  }) : answers;
372
378
  if (!orgId || aiSiteStartRefusal(asked, {
373
379
  freeTaste
374
- }) || noneLeft) return;
380
+ }) || asked.style === null || noneLeft) return;
375
381
  // Past what is left, only an explicit go-ahead starts it.
376
382
  if (freeTaste && !options.creditsConfirmed && aiFreeSitePrompt(freeCredits, asked.pages, {
377
383
  siteKind
@@ -442,7 +448,10 @@ function SectionLabel({ children, help }) {
442
448
  };
443
449
  if (!hostId && pendingSite) {
444
450
  if (!pendingSite.created && !await refused(await requestJob(null, true))) return;
445
- const made = await pendingSite.create();
451
+ // The style the questions took (AGL-4049), recorded on the site.
452
+ const made = await pendingSite.create(asked.style ? {
453
+ style: asked.style
454
+ } : undefined);
446
455
  if ('error' in made) {
447
456
  setNotice(made.error);
448
457
  if (made.address) setStep('choose');
@@ -522,33 +531,54 @@ function SectionLabel({ children, help }) {
522
531
  clientIntake,
523
532
  siteInspiration
524
533
  ]);
525
- // The zone's `startBlank`. Before the site exists it creates it with the
526
- // starter, and answers `false` when it could not — most often a name or
527
- // address to fix, which step 1 shows.
528
- const runStartBlank = useCallback(()=>{
529
- const result = startBlank();
534
+ // The zone's `startBlank`, with the style chosen for the starter (AGL-4049).
535
+ // Before the site exists it creates it with the starter, and answers
536
+ // `false` when it could not — most often a name or address to fix, which
537
+ // step 1 shows.
538
+ const runStartBlank = useCallback((options)=>{
539
+ const result = startBlank((options == null ? void 0 : options.style) ? {
540
+ style: options.style
541
+ } : undefined);
530
542
  if (result && typeof result.then === 'function') {
531
543
  void result.then((done)=>{
532
544
  if (done) return;
533
545
  setStartingStarter(false);
546
+ setPickingStyle(false);
534
547
  setStep('choose');
535
548
  });
536
549
  }
537
550
  }, [
538
551
  startBlank
539
552
  ]);
553
+ // The starter card asks a style first (AGL-4049): nothing is created, and
554
+ // nothing chosen, until a style card is clicked and Create site with it.
555
+ // Where the shell offers "Choose your starter" — the platform's styles and
556
+ // the marketplace's starters together — the card hands the choice to it
557
+ // instead, and asks no style itself.
540
558
  const chooseStarter = useCallback(()=>{
541
559
  if (pendingSite && !pendingSite.created && !pendingSite.check()) return;
542
- setStartingStarter(true);
543
560
  trackEvent('site_start_choice', {
544
561
  choice: 'starter'
545
562
  });
563
+ if (chooseStarterInShell && pendingSite && !pendingSite.created) return chooseStarterInShell();
564
+ setPickingStyle(true);
565
+ }, [
566
+ chooseStarterInShell,
567
+ pendingSite
568
+ ]);
569
+ const starterInShell = Boolean(chooseStarterInShell && pendingSite && !pendingSite.created);
570
+ const createStarter = useCallback(()=>{
571
+ if (!starterStyle || startingStarter) return;
572
+ setStartingStarter(true);
546
573
  // The starter is a way to start, not a way to leave: no abandonment after it.
547
574
  tracker.finish();
548
- runStartBlank();
575
+ runStartBlank({
576
+ style: starterStyle
577
+ });
549
578
  }, [
550
- pendingSite,
551
579
  runStartBlank,
580
+ starterStyle,
581
+ startingStarter,
552
582
  tracker
553
583
  ]);
554
584
  const chooseImport = useCallback(()=>{
@@ -648,9 +678,15 @@ function SectionLabel({ children, help }) {
648
678
  setStep(target);
649
679
  };
650
680
  if (verdict !== 'ready') return null;
681
+ // The style a way out gives the starter on a site that exists (AGL-4049):
682
+ // the one the starter's style view or the questions took, if any.
683
+ const exitStyle = starterStyle != null ? starterStyle : answers.style !== null ? aiSiteStartKind(answers).id : null;
684
+ const giveStarter = ()=>runStartBlank(exitStyle ? {
685
+ style: exitStyle
686
+ } : undefined);
651
687
  // Before a job is started Skip is the blank site, which writes the starter
652
688
  // (AGL-3594); after, it only closes — the job builds the site.
653
- const exit = started ? leave != null ? leave : runStartBlank : runStartBlank;
689
+ const exit = started ? leave != null ? leave : giveStarter : giveStarter;
654
690
  // Skip, as the header draws it: before a site is started it is leaving the questions.
655
691
  const skip = ()=>{
656
692
  if (!started) tracker.abandon('skip');
@@ -659,10 +695,10 @@ function SectionLabel({ children, help }) {
659
695
  // Escape and the close control. Before "Create site" has made the site
660
696
  // (AGL-3761) there is nothing to give a starter to, so they only close,
661
697
  // and nothing is created; otherwise they are the same way out as Skip.
662
- const dismissTo = creating && !started ? leave != null ? leave : runStartBlank : exit;
698
+ const dismissTo = creating && !started ? leave != null ? leave : giveStarter : exit;
663
699
  // Anything the person typed or picked, which a dismissal must not discard
664
700
  // silently (AGL-3660). After a job starts there is nothing left to lose.
665
- const drafted = !started && Boolean(answers.siteType.trim() || answers.audience.trim() || answers.kind !== null || aiSiteStartExtrasGiven(answers).length > 0 || creating && (pendingSite == null ? void 0 : pendingSite.dirty));
701
+ const drafted = !started && Boolean(answers.siteType.trim() || answers.audience.trim() || answers.style !== null || starterStyle !== null || aiSiteStartExtrasGiven(answers).length > 0 || creating && (pendingSite == null ? void 0 : pendingSite.dirty));
666
702
  // Escape and the close control: a dismissal, never a choice. Escape that
667
703
  // bubbled here through React from a portal outside this dialog's own DOM is
668
704
  // a nested menu's, already handled there, and is not this dialog's to act on.
@@ -704,7 +740,9 @@ function SectionLabel({ children, help }) {
704
740
  const estimateText = freeTaste ? freeCredits ? `${aiCreditRangeText(estimate)}. You have ${freeCredits.left.toLocaleString('en-US')} of your ${freeCredits.total.toLocaleString('en-US')} free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}` : `${aiCreditRangeText(estimate)}, of the ${FREE_AI_TASTE_CREDITS_PER_MONTH} AI credits you get free each month` : `${aiCreditRangeText(estimate)}, estimated`;
705
741
  // The card is drawn wherever the workspace could use it, disabled where it cannot yet.
706
742
  const showsImport = importAvailability.state === 'ready' || importAvailability.state === 'blocked';
707
- const choosing = step === 'choose' && !started && !importing;
743
+ // The starter's style view (AGL-4049), on step 1.
744
+ const stylingStarter = step === 'choose' && pickingStyle && !started && !importing;
745
+ const choosing = step === 'choose' && !pickingStyle && !started && !importing;
708
746
  const reviewing = step === 'review' && !started && !importing;
709
747
  const asking = step !== 'choose' && !started && !importing;
710
748
  // Each answer's reason not to go forward, shown on a step once Next was refused there.
@@ -753,6 +791,9 @@ function SectionLabel({ children, help }) {
753
791
  const heading = importing ? {
754
792
  title: 'Bring my site',
755
793
  lede: `Bring the website you have now into ${PLATFORM_BRAND_NAME}: its pages, words and photos. First, prove it is yours.`
794
+ } : stylingStarter ? {
795
+ title: 'Choose a style',
796
+ lede: 'Your site starts with a home page, a header and a footer in the style you choose. You can change everything later.'
756
797
  } : HEADINGS[step];
757
798
  // Enter in a text answer is Next. A select, a card or a button keeps its own Enter.
758
799
  const onStepKeyDown = (event)=>{
@@ -821,7 +862,7 @@ function SectionLabel({ children, help }) {
821
862
  },
822
863
  children: 'Start your site'
823
864
  }),
824
- /*#__PURE__*/ _jsx(Button, {
865
+ creating && !started ? null : /*#__PURE__*/ _jsx(Button, {
825
866
  color: "inherit",
826
867
  onClick: skip,
827
868
  "aria-label": started ? 'Close' : 'Skip and start blank',
@@ -839,7 +880,7 @@ function SectionLabel({ children, help }) {
839
880
  },
840
881
  onKeyDown: onStepKeyDown,
841
882
  children: [
842
- importing ? null : /*#__PURE__*/ _jsx(Box, {
883
+ importing || stylingStarter ? null : /*#__PURE__*/ _jsx(Box, {
843
884
  sx: {
844
885
  pt: {
845
886
  xs: 3,
@@ -853,7 +894,7 @@ function SectionLabel({ children, help }) {
853
894
  })
854
895
  }),
855
896
  /*#__PURE__*/ _jsx(Container, {
856
- maxWidth: choosing || step === 'kind' || step === 'style' ? 'md' : 'sm',
897
+ maxWidth: choosing || stylingStarter || step === 'kind' || step === 'style' ? 'md' : 'sm',
857
898
  disableGutters: true,
858
899
  sx: {
859
900
  py: {
@@ -890,7 +931,7 @@ function SectionLabel({ children, help }) {
890
931
  variant: "body1",
891
932
  color: "text.secondary",
892
933
  children: [
893
- choosing ? /*#__PURE__*/ _jsx(HelpTip, _extends({
934
+ choosing || stylingStarter ? /*#__PURE__*/ _jsx(HelpTip, _extends({
894
935
  sx: {
895
936
  float: 'right'
896
937
  }
@@ -939,6 +980,28 @@ function SectionLabel({ children, help }) {
939
980
  pendingSite: pendingSite,
940
981
  onBack: ()=>setImporting(false),
941
982
  leave: leave
983
+ }) : stylingStarter ? /*#__PURE__*/ _jsxs(Stack, {
984
+ spacing: 3,
985
+ component: "section",
986
+ "aria-label": "Style of your starter site",
987
+ children: [
988
+ /*#__PURE__*/ _jsx(OptionCardGrid, {
989
+ label: "Style of site",
990
+ "data-start-area": "starter-style-cards",
991
+ columns: {
992
+ xs: 2,
993
+ sm: 2,
994
+ md: 3
995
+ },
996
+ options: aiSiteStyleCards(),
997
+ value: starterStyle,
998
+ onChange: (id)=>{
999
+ setStarterStyle(id);
1000
+ tracker.fieldPicked('style');
1001
+ }
1002
+ }),
1003
+ creating ? pendingSite == null ? void 0 : (_pendingSite_previewControl = pendingSite.previewControl) == null ? void 0 : _pendingSite_previewControl.call(pendingSite, 'starter') : null
1004
+ ]
942
1005
  }) : choosing ? /*#__PURE__*/ _jsxs(Stack, {
943
1006
  spacing: 2,
944
1007
  children: [
@@ -961,8 +1024,8 @@ function SectionLabel({ children, help }) {
961
1024
  accent: "secondary",
962
1025
  icon: mdiPageLayoutHeaderFooter.path,
963
1026
  iconId: "page-layout-header-footer",
964
- title: "Start from the starter site",
965
- description: "A ready-made home page with a header, footer and contact form you can edit.",
1027
+ title: starterInShell ? 'Start from a starter site' : 'Start from the starter site',
1028
+ description: starterInShell ? 'A ready-made website from the marketplace, in a style you choose.' : 'A ready-made home page with a header, footer and contact form, in a style you choose.',
966
1029
  busy: startingStarter,
967
1030
  onChoose: chooseStarter
968
1031
  }),
@@ -991,7 +1054,7 @@ function SectionLabel({ children, help }) {
991
1054
  icon: mdiWebSync.path,
992
1055
  iconId: "web-sync",
993
1056
  title: "Bring my site",
994
- description: `Bring the website you have now into ${PLATFORM_BRAND_NAME}: its pages, words and photos, rewritten in your new design.`,
1057
+ description: `Bring the website you have now into ${PLATFORM_BRAND_NAME}: every word as you wrote it, laid out as your pages are, in your new site’s preview.`,
995
1058
  blocked: importAvailability.state === 'blocked' ? importAvailability.message : null,
996
1059
  onChoose: chooseImport,
997
1060
  children: importAvailability.state === 'blocked' && importAvailability.reason === 'plan' ? /*#__PURE__*/ _jsx(Chip, {
@@ -1084,6 +1147,43 @@ function SectionLabel({ children, help }) {
1084
1147
  })
1085
1148
  ]
1086
1149
  }),
1150
+ stylingStarter && /* The starter's style view (AGL-4049): Create site waits for a style. */ /*#__PURE__*/ _jsxs(DialogActions, {
1151
+ "data-start-area": "footer",
1152
+ sx: _extends({
1153
+ px: {
1154
+ xs: 2,
1155
+ sm: 3
1156
+ },
1157
+ py: 2,
1158
+ flexWrap: 'wrap',
1159
+ rowGap: 1,
1160
+ columnGap: 2,
1161
+ borderTop: 1,
1162
+ borderColor: 'divider'
1163
+ }, AI_SITE_START_SURFACE_SX),
1164
+ children: [
1165
+ /*#__PURE__*/ _jsx(Button, {
1166
+ onClick: ()=>setPickingStyle(false),
1167
+ disabled: startingStarter,
1168
+ sx: {
1169
+ mr: 'auto'
1170
+ },
1171
+ children: 'Back'
1172
+ }),
1173
+ starterStyle ? null : /*#__PURE__*/ _jsx(Typography, {
1174
+ variant: "body2",
1175
+ color: "text.secondary",
1176
+ children: 'Choose a style to continue.'
1177
+ }),
1178
+ /*#__PURE__*/ _jsx(Button, {
1179
+ variant: "contained",
1180
+ size: "large",
1181
+ disabled: !starterStyle || startingStarter,
1182
+ onClick: createStarter,
1183
+ children: startingStarter ? creating ? 'Creating…' : 'Starting…' : creating ? 'Create site' : 'Use this style'
1184
+ })
1185
+ ]
1186
+ }),
1087
1187
  asking && /* The footer stays put while the questions scroll. It wraps, because
1088
1188
  the estimate, the reason and the buttons are wider than a phone. */ /*#__PURE__*/ _jsxs(DialogActions, {
1089
1189
  "data-start-area": "footer",