astro-tractstack 2.2.10 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +1 -1
  2. package/bin/create-tractstack.js +2 -2
  3. package/dist/index.js +177 -18
  4. package/package.json +4 -2
  5. package/templates/custom/minimal/CodeHook.astro +22 -5
  6. package/templates/custom/shopify/Cart.tsx +372 -0
  7. package/templates/custom/shopify/CartIcon.tsx +47 -0
  8. package/templates/custom/shopify/CartModal.tsx +63 -0
  9. package/templates/custom/shopify/CheckoutModal.tsx +576 -0
  10. package/templates/custom/shopify/NativeBookingCalendar.tsx +375 -0
  11. package/templates/custom/shopify/ShopifyCartManager.tsx +200 -0
  12. package/templates/custom/shopify/ShopifyCheckout.tsx +167 -0
  13. package/templates/custom/shopify/ShopifyProductGrid.tsx +247 -0
  14. package/templates/custom/shopify/ShopifyServiceList.tsx +135 -0
  15. package/templates/custom/shopify/cart.astro +23 -0
  16. package/templates/custom/with-examples/CodeHook.astro +17 -1
  17. package/templates/custom/with-examples/ProductGrid.astro +1 -1
  18. package/templates/src/client/app.js +4 -2
  19. package/templates/src/components/Footer.astro +4 -4
  20. package/templates/src/components/Header.astro +44 -12
  21. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +3 -3
  22. package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +2 -2
  23. package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +2 -2
  24. package/templates/src/components/edit/pane/steps/AiLibraryCopyStep.tsx +3 -3
  25. package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +2 -2
  26. package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +7 -7
  27. package/templates/src/components/form/advanced/APIConfigSection.tsx +407 -38
  28. package/templates/src/components/form/shopify/SchedulingSection.tsx +354 -0
  29. package/templates/src/components/storykeep/Dashboard.tsx +18 -4
  30. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +1 -0
  31. package/templates/src/components/storykeep/Dashboard_Content.tsx +5 -96
  32. package/templates/src/components/storykeep/Dashboard_Shopify.tsx +668 -0
  33. package/templates/src/components/storykeep/StoryKeepBackdrop.astro +43 -23
  34. package/templates/src/components/storykeep/controls/content/BeliefTable.tsx +14 -5
  35. package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +0 -14
  36. package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +36 -13
  37. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +5 -2
  38. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +4 -11
  39. package/templates/src/components/storykeep/controls/content/MenuTable.tsx +14 -5
  40. package/templates/src/components/storykeep/controls/content/ProductTable.tsx +333 -0
  41. package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +9 -5
  42. package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +108 -8
  43. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +13 -4
  44. package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +14 -5
  45. package/templates/src/components/storykeep/shopify/ShopifyDashboard.tsx +111 -0
  46. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Bookings.tsx +393 -0
  47. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Products.tsx +46 -0
  48. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Schedule.tsx +78 -0
  49. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Search.tsx +55 -0
  50. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Services.tsx +47 -0
  51. package/templates/src/lib/resources.ts +11 -21
  52. package/templates/src/pages/api/auth/lookup-lead.ts +72 -0
  53. package/templates/src/pages/api/booking/availability.ts +72 -0
  54. package/templates/src/pages/api/booking/cancel.ts +73 -0
  55. package/templates/src/pages/api/booking/confirm.ts +82 -0
  56. package/templates/src/pages/api/booking/hold.ts +75 -0
  57. package/templates/src/pages/api/booking/list.ts +66 -0
  58. package/templates/src/pages/api/booking/metrics.ts +60 -0
  59. package/templates/src/pages/api/booking/release.ts +76 -0
  60. package/templates/src/pages/api/sandbox.ts +2 -2
  61. package/templates/src/pages/api/shopify/createCart.ts +69 -0
  62. package/templates/src/pages/api/shopify/getProducts.ts +64 -0
  63. package/templates/src/pages/storykeep/login.astro +26 -24
  64. package/templates/src/pages/storykeep/logout.astro +1 -10
  65. package/templates/src/pages/storykeep/manage.astro +69 -0
  66. package/templates/src/pages/storykeep/{content.astro → pages.astro} +4 -8
  67. package/templates/src/pages/storykeep/shopify.astro +101 -0
  68. package/templates/src/stores/navigation.ts +3 -42
  69. package/templates/src/stores/nodes.ts +3 -1
  70. package/templates/src/stores/resources.ts +7 -10
  71. package/templates/src/stores/shopify.ts +266 -0
  72. package/templates/src/types/tractstack.ts +75 -0
  73. package/templates/src/utils/api/advancedConfig.ts +7 -1
  74. package/templates/src/utils/api/advancedHelpers.ts +87 -7
  75. package/templates/src/utils/api/bookingHelpers.ts +125 -0
  76. package/templates/src/utils/api/brandHelpers.ts +14 -0
  77. package/templates/src/utils/api/resourceConfig.ts +13 -5
  78. package/templates/src/utils/auth.ts +29 -9
  79. package/templates/src/utils/compositor/aiGeneration.ts +3 -3
  80. package/templates/src/utils/compositor/aiPaneParser.ts +2 -2
  81. package/templates/src/utils/customHelpers.ts +49 -0
  82. package/templates/src/utils/helpers.ts +59 -0
  83. package/templates/src/utils/profileStorage.ts +5 -0
  84. package/templates/src/utils/tenantResolver.ts +2 -1
  85. package/utils/inject-files.ts +161 -2
@@ -4,13 +4,19 @@ import SearchWrapper from '@/components/search/SearchWrapper';
4
4
  import { getFullContentMap } from '@/stores/analytics';
5
5
  import { isAuthenticated, isAdmin, getUserRole } from '@/utils/auth';
6
6
  import ImpressionWrapper from '@/components/widgets/ImpressionWrapper';
7
- import type { MenuNode } from '@/types/tractstack';
8
7
  import type { ImpressionNode } from '@/types/compositorTypes';
8
+ import { getHeaderResources } from '@/lib/resources';
9
+ import ShopifyCartManager from '@/custom/shopify/ShopifyCartManager';
10
+ import CartIcon from '@/custom/shopify/CartIcon';
11
+ import CartModal from '@/custom/shopify/CartModal';
12
+ import CheckoutModal from '@/custom/shopify/CheckoutModal';
13
+ import type { MenuNode, BrandConfig } from '@/types/tractstack';
14
+ import type { ResourceNode } from '@/types/compositorTypes';
9
15
 
10
16
  export interface Props {
11
17
  title: string;
12
18
  slug: string;
13
- brandConfig: any;
19
+ brandConfig: BrandConfig;
14
20
  isContext?: boolean;
15
21
  isStoryKeep?: boolean;
16
22
  isEditable?: boolean;
@@ -32,13 +38,11 @@ const {
32
38
  storyfragmentId = undefined,
33
39
  impressions = [],
34
40
  } = Astro.props;
35
-
36
41
  const isHome = slug === brandConfig?.HOME_SLUG;
37
42
 
38
43
  const tenantId =
39
44
  Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
40
45
  const fullContentMap = await getFullContentMap(tenantId);
41
-
42
46
  const getAssetPath = (configPath: string, fallback: string) => {
43
47
  // Always prioritize brandConfig values when they exist
44
48
  if (configPath && configPath !== '') {
@@ -52,17 +56,39 @@ const wordmarkMode =
52
56
  brandConfig?.WORDMARK_MODE && brandConfig.WORDMARK_MODE !== ''
53
57
  ? brandConfig.WORDMARK_MODE
54
58
  : 'default';
55
-
56
59
  // Auth status
57
60
  const authStatus = {
58
61
  isAuthenticated: isAuthenticated(Astro),
59
62
  isAdmin: isAdmin(Astro),
60
63
  userRole: getUserRole(Astro),
61
64
  };
65
+
66
+ const hasShopify = brandConfig?.HAS_SHOPIFY;
67
+ let shopifyResources: ResourceNode[] = [];
68
+ if (hasShopify) {
69
+ shopifyResources = await getHeaderResources(tenantId, ['product', 'service']);
70
+ }
62
71
  ---
63
72
 
64
73
  <header class="relative shadow-inner">
65
- <!-- TOP ROW: Logo/Wordmark + Menu + Auth Controls -->
74
+ {
75
+ hasShopify ? (
76
+ <>
77
+ {slug !== `cart` ? (
78
+ <div class="flex w-full justify-end px-4 py-2 md:px-8">
79
+ <CartIcon client:only="react" />
80
+ </div>
81
+ ) : (
82
+ <CheckoutModal
83
+ client:only="react"
84
+ resources={shopifyResources}
85
+ maxLength={brandConfig?.scheduling?.maxLengthMinutes || 180}
86
+ />
87
+ )}
88
+ </>
89
+ ) : null
90
+ }
91
+
66
92
  <div
67
93
  class="flex flex-row flex-nowrap items-center justify-between px-4 py-3 md:px-8"
68
94
  >
@@ -72,10 +98,12 @@ const authStatus = {
72
98
  [`default`, `logo`].includes(wordmarkMode) ? (
73
99
  <>
74
100
  <img
101
+ id="t8k-logo"
75
102
  src={logo}
76
103
  alt="Logo"
77
104
  class="pointer-events-none h-8 w-auto"
78
105
  />
106
+
79
107
  <span class="w-2" />
80
108
  </>
81
109
  ) : null
@@ -83,6 +111,7 @@ const authStatus = {
83
111
  {
84
112
  [`default`, `wordmark`].includes(wordmarkMode) ? (
85
113
  <img
114
+ id="t8k-wordmark"
86
115
  src={wordmark}
87
116
  alt="Wordmark"
88
117
  class="pointer-events-none h-14 w-auto max-w-48 md:max-w-72"
@@ -105,7 +134,6 @@ const authStatus = {
105
134
  }
106
135
  </div>
107
136
 
108
- <!-- BOTTOM ROW: Title + Action Icons -->
109
137
  <div
110
138
  class="flex flex-row flex-nowrap justify-between bg-mywhite px-4 pb-3 pt-4 shadow-inner md:px-8"
111
139
  >
@@ -198,7 +226,6 @@ const authStatus = {
198
226
  localStorage.getItem('tractstack_has_profile') === '1';
199
227
 
200
228
  if (!sessionId) return;
201
-
202
229
  const rememberMeContainer = document.getElementById(
203
230
  'remember-me-container'
204
231
  );
@@ -211,7 +238,6 @@ const authStatus = {
211
238
  consent || hasProfile
212
239
  ? '<svg class="h-6 w-6 text-myblue/80" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m3.75 13.5 10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75Z" /></svg>'
213
240
  : '<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 3l18 18M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75Z" /></svg>';
214
-
215
241
  rememberMeContainer.innerHTML = `
216
242
  <a href="/storykeep/profile"
217
243
  class="hover:text-myblue hover:rotate-6"
@@ -339,6 +365,15 @@ const authStatus = {
339
365
  )
340
366
  }
341
367
 
368
+ {
369
+ !isStoryKeep && hasShopify && (
370
+ <>
371
+ <ShopifyCartManager resources={shopifyResources} client:only="react" />
372
+ <CartModal client:only="react" />
373
+ </>
374
+ )
375
+ }
376
+
342
377
  <script>
343
378
  if (document.readyState === 'loading') {
344
379
  document.addEventListener('DOMContentLoaded', setupAdminModal);
@@ -383,7 +418,6 @@ const authStatus = {
383
418
  tractStackKeys.forEach((key) => localStorage.removeItem(key));
384
419
 
385
420
  console.log('TractStack: Complete logout finished');
386
-
387
421
  // Redirect to home page
388
422
  window.location.href = '/';
389
423
  } else {
@@ -432,7 +466,6 @@ const authStatus = {
432
466
  return;
433
467
  }
434
468
  });
435
-
436
469
  document.addEventListener('keydown', function (e) {
437
470
  if (e.key === 'Escape') {
438
471
  const modal = document.getElementById('admin-modal');
@@ -441,7 +474,6 @@ const authStatus = {
441
474
  }
442
475
  }
443
476
  });
444
-
445
477
  function closeModal() {
446
478
  const modal = document.getElementById('admin-modal');
447
479
  const heartBtn = document.getElementById('admin-heart-btn');
@@ -276,9 +276,9 @@ const AddPaneNewPanel = ({
276
276
  {!hasAssemblyAI && (
277
277
  <div className="rounded-lg border-l-4 border-blue-400 bg-blue-50 p-4 shadow-sm">
278
278
  <p className="text-sm text-blue-800">
279
- Tract Stack uses AssemblyAI AskLemur service to generate designs,
280
- describe content, and streamline the management of your site. We
281
- strongly recommend enabling these features. See{' '}
279
+ Tract Stack uses AssemblyAI to generate designs, describe content,
280
+ and streamline the management of your site. We strongly recommend
281
+ enabling these features. See{' '}
282
282
  <a
283
283
  href="https://freewebpress.org"
284
284
  target="_blank"
@@ -11,7 +11,7 @@ import { AiDesignStep, type AiDesignConfig } from './steps/AiDesignStep';
11
11
  import { AiRefineDesignStep } from './steps/AiRefineDesignStep';
12
12
  import prompts from '@/constants/prompts.json';
13
13
  import { parseAiPane } from '@/utils/compositor/aiPaneParser';
14
- import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
14
+ import { callAaiAPI } from '@/utils/compositor/aiGeneration';
15
15
  import type { PaneNode, TemplatePane } from '@/types/compositorTypes';
16
16
 
17
17
  interface AiRestylePaneModalProps {
@@ -87,7 +87,7 @@ export const AiRestylePaneModal = ({
87
87
  .replace('{{COPY_INPUT}}', 'A generic content section')
88
88
  .replace('{{LAYOUT_TYPE}}', 'Text Only');
89
89
 
90
- const resultStr = await callAskLemurAPI({
90
+ const resultStr = await callAaiAPI({
91
91
  prompt: formattedPrompt,
92
92
  context: shellPromptDetails.system || '',
93
93
  expectJson: true,
@@ -6,7 +6,7 @@ import ArrowPathRoundedSquareIcon from '@heroicons/react/24/outline/ArrowPathRou
6
6
  import prompts from '@/constants/prompts.json';
7
7
  import { htmlToHtmlAst } from '@/utils/compositor/htmlAst';
8
8
  import type { TemplatePane } from '@/types/compositorTypes';
9
- import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
9
+ import { callAaiAPI } from '@/utils/compositor/aiGeneration';
10
10
  import BooleanToggle from '@/components/form/BooleanToggle';
11
11
  import { AiDesignStep, type AiDesignConfig } from './AiDesignStep';
12
12
 
@@ -86,7 +86,7 @@ export const AiCreativeDesignStep = ({
86
86
  userPrompt = userPrompt.replace('{{DESIGN_NOTES}}', combinedNotes);
87
87
 
88
88
  // Use shared infrastructure utility
89
- const rawHtml = await callAskLemurAPI({
89
+ const rawHtml = await callAaiAPI({
90
90
  prompt: userPrompt,
91
91
  context: systemPrompt,
92
92
  expectJson: false,
@@ -6,7 +6,7 @@ import {
6
6
  convertTemplateToAIShell,
7
7
  } from '@/utils/compositor/designLibraryHelper';
8
8
  import { parseAiPane, parseAiCopyHtml } from '@/utils/compositor/aiPaneParser';
9
- import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
9
+ import { callAaiAPI } from '@/utils/compositor/aiGeneration';
10
10
  import { CopyInputStep, type CopyMode } from './CopyInputStep';
11
11
  import type { DesignLibraryEntry } from '@/types/tractstack';
12
12
  import type { TemplatePane } from '@/types/compositorTypes';
@@ -159,7 +159,7 @@ export const AiLibraryCopyStep = ({
159
159
  .replace('{{LAYOUT_TYPE}}', layoutType)
160
160
  .replace('{{COLUMN_EXAMPLE}}', columnPreset.example);
161
161
 
162
- const copyResult = await callAskLemurAPI({
162
+ const copyResult = await callAaiAPI({
163
163
  prompt: formattedCopyPrompt,
164
164
  context: copyPromptDetails.system || '',
165
165
  expectJson: false,
@@ -201,7 +201,7 @@ export const AiLibraryCopyStep = ({
201
201
  .replace('{{LAYOUT_TYPE}}', layoutType)
202
202
  .replace('{{SHELL_JSON}}', shellResult);
203
203
 
204
- const copyResult = await callAskLemurAPI({
204
+ const copyResult = await callAaiAPI({
205
205
  prompt: formattedCopyPrompt,
206
206
  context: copyPromptDetails.system || '',
207
207
  expectJson: false,
@@ -5,7 +5,7 @@ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
5
5
  import ArrowPathRoundedSquareIcon from '@heroicons/react/24/outline/ArrowPathRoundedSquareIcon';
6
6
  import prompts from '@/constants/prompts.json';
7
7
  import { htmlToHtmlAst, cleanHtml } from '@/utils/compositor/htmlAst';
8
- import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
8
+ import { callAaiAPI } from '@/utils/compositor/aiGeneration';
9
9
  import type { TemplatePane } from '@/types/compositorTypes';
10
10
 
11
11
  interface AiRefineDesignStepProps {
@@ -54,7 +54,7 @@ export const AiRefineDesignStep = ({
54
54
  userPrompt = userPrompt.replace('{{HTML_INPUT}}', cleanHtml(initialHtml));
55
55
 
56
56
  // 1. Get RAW output from AI
57
- const resultHtml = await callAskLemurAPI({
57
+ const resultHtml = await callAaiAPI({
58
58
  prompt: userPrompt,
59
59
  context: systemPrompt,
60
60
  expectJson: false,
@@ -4,7 +4,7 @@ import {
4
4
  parseAiPane,
5
5
  createDefaultShell,
6
6
  } from '@/utils/compositor/aiPaneParser';
7
- import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
7
+ import { callAaiAPI } from '@/utils/compositor/aiGeneration';
8
8
  import { markdownToHtml } from '@/utils/compositor/htmlAst';
9
9
  import { CopyInputStep, type CopyMode } from './CopyInputStep';
10
10
  import { AiDesignStep, type AiDesignConfig } from './AiDesignStep';
@@ -148,7 +148,7 @@ export const AiStandardDesignStep = ({
148
148
  let shellResult = '';
149
149
 
150
150
  if (isAiStyling) {
151
- // AI Path: Generate Shell via AskLemur
151
+ // AI Path: Generate Shell via Aai
152
152
  let designInput = `Generate a design using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme with a **${aiDesignConfig.theme.toLowerCase()}** theme.`;
153
153
  if (aiDesignConfig.baseColor)
154
154
  designInput += ` Base the colors around **${aiDesignConfig.baseColor}**.`;
@@ -173,7 +173,7 @@ export const AiStandardDesignStep = ({
173
173
  );
174
174
  }
175
175
 
176
- shellResult = await callAskLemurAPI({
176
+ shellResult = await callAaiAPI({
177
177
  prompt: formattedShellPrompt,
178
178
  context: masterShellSystem,
179
179
  expectJson: true,
@@ -204,7 +204,7 @@ export const AiStandardDesignStep = ({
204
204
  .replace('{{LAYOUT_TYPE}}', layoutType)
205
205
  .replace('{{SHELL_JSON}}', shellResult);
206
206
 
207
- finalHtml = await callAskLemurAPI({
207
+ finalHtml = await callAaiAPI({
208
208
  prompt: formattedCopyPrompt,
209
209
  context: masterCopySystem,
210
210
  expectJson: false,
@@ -218,7 +218,7 @@ export const AiStandardDesignStep = ({
218
218
  .replace('{{SHELL_JSON}}', shellResult)
219
219
  .replace('{{COPY_INPUT}}', copyValue);
220
220
 
221
- finalHtml = await callAskLemurAPI({
221
+ finalHtml = await callAaiAPI({
222
222
  prompt: formattedStylePrompt,
223
223
  context: masterStyleSystem,
224
224
  expectJson: false,
@@ -246,7 +246,7 @@ export const AiStandardDesignStep = ({
246
246
  .replace('{{SHELL_JSON}}', shellResult)
247
247
  .replace('{{COPY_INPUT}}', content);
248
248
 
249
- const styledHtml = await callAskLemurAPI({
249
+ const styledHtml = await callAaiAPI({
250
250
  prompt: formattedStylePrompt,
251
251
  context: masterStyleSystem,
252
252
  expectJson: false,
@@ -289,7 +289,7 @@ export const AiStandardDesignStep = ({
289
289
  .replace('{{LAYOUT_TYPE}}', layoutType)
290
290
  .replace('{{COLUMN_EXAMPLE}}', columnPreset.example);
291
291
 
292
- const copyResult = await callAskLemurAPI({
292
+ const copyResult = await callAaiAPI({
293
293
  prompt: formattedCopyPrompt,
294
294
  context: masterCopySystem,
295
295
  expectJson: false,