astro-tractstack 2.3.4 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/bin/create-tractstack.js +38 -59
  2. package/dist/index.js +74 -40
  3. package/package.json +46 -9
  4. package/templates/custom/customHelpers.ts +45 -0
  5. package/templates/custom/minimal/codehooks.ts +13 -0
  6. package/templates/custom/shopify/Cart.tsx +2 -2
  7. package/templates/custom/shopify/CartIcon.tsx +1 -1
  8. package/templates/custom/shopify/CheckoutModal.tsx +3 -3
  9. package/templates/custom/shopify/ShopifyCartManager.tsx +3 -3
  10. package/templates/custom/shopify/ShopifyCheckout.tsx +1 -1
  11. package/templates/custom/shopify/ShopifyProductGrid.tsx +5 -5
  12. package/templates/custom/shopify/ShopifyServiceList.tsx +5 -5
  13. package/templates/custom/shopify/shopifyCustomHelper.ts +10 -0
  14. package/templates/{src/utils/customHelpers.ts → custom/shopify/shopifyHelpers.ts} +0 -74
  15. package/templates/custom/with-examples/codehooks.ts +15 -0
  16. package/templates/src/components/Header.astro +1 -1
  17. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +38 -23
  18. package/templates/src/components/codehooks/EpinetTableView.tsx +5 -2
  19. package/templates/src/components/codehooks/EpinetWrapper.tsx +10 -5
  20. package/templates/src/components/codehooks/FeaturedArticle.astro +3 -3
  21. package/templates/src/components/codehooks/ListContent.astro +3 -3
  22. package/templates/src/components/codehooks/SearchWidget.tsx +1 -1
  23. package/templates/src/components/compositor/Node.tsx +13 -2
  24. package/templates/src/components/compositor/nodes/Pane.tsx +2 -14
  25. package/templates/src/components/edit/pane/AddPanePanel.tsx +3 -2
  26. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +35 -14
  27. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +1 -1
  28. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +2 -2
  29. package/templates/src/components/search/SearchResults.tsx +1 -1
  30. package/templates/src/components/search/SearchWrapper.tsx +1 -1
  31. package/templates/src/components/storykeep/Dashboard_Analytics.tsx +8 -4
  32. package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +5 -2
  33. package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +1 -1
  34. package/templates/src/components/storykeep/shopify/ShopifyDashboard_Sales.tsx +1 -1
  35. package/templates/src/components/storykeep/state/FetchAnalytics.tsx +8 -4
  36. package/templates/src/components/storykeep/widgets/Wizard.tsx +4 -2
  37. package/templates/src/lib/codeHookHelper.ts +156 -0
  38. package/templates/src/lib/resources.ts +41 -0
  39. package/templates/src/lib/storyData.ts +1 -2
  40. package/templates/src/pages/[...slug]/edit.astro +3 -3
  41. package/templates/src/pages/[...slug].astro +76 -70
  42. package/templates/src/pages/codehooks/[...hookId].astro +18 -0
  43. package/templates/src/pages/codehooks/bunny-video.astro +9 -0
  44. package/templates/src/pages/codehooks/custom-hero.astro +6 -0
  45. package/templates/src/pages/codehooks/epinet.astro +15 -0
  46. package/templates/src/pages/codehooks/featured-article.astro +13 -0
  47. package/templates/src/pages/codehooks/get-crafting.astro +8 -0
  48. package/templates/src/pages/codehooks/list-content.astro +13 -0
  49. package/templates/src/pages/codehooks/search-widget.astro +13 -0
  50. package/templates/src/pages/codehooks/shopify-product-grid.astro +25 -0
  51. package/templates/src/pages/codehooks/shopify-service-list.astro +25 -0
  52. package/templates/src/pages/context/[...contextSlug]/edit.astro +3 -3
  53. package/templates/src/pages/context/[...contextSlug].astro +47 -10
  54. package/templates/src/pages/sandbox.astro +3 -14
  55. package/templates/src/stores/analytics.ts +77 -107
  56. package/utils/inject-files.ts +76 -41
  57. package/templates/custom/minimal/CodeHook.astro +0 -72
  58. package/templates/custom/with-examples/CodeHook.astro +0 -81
  59. package/templates/custom/with-examples/ProductCard.astro +0 -29
  60. package/templates/custom/with-examples/ProductCardWrapper.astro +0 -43
  61. package/templates/custom/with-examples/ProductGrid.astro +0 -64
  62. package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -157
  63. package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -279
  64. /package/templates/{src/utils/booking → custom/shopify}/appointmentMode.ts +0 -0
@@ -7,14 +7,33 @@ import {
7
7
  writeFileSync,
8
8
  existsSync,
9
9
  } from 'fs';
10
- import { resolve } from 'path';
10
+ import { dirname, resolve } from 'path';
11
+ import { fileURLToPath } from 'url';
11
12
  import { homedir } from 'os';
12
13
  import { execSync } from 'child_process';
13
14
  import prompts from 'prompts';
14
15
  import kleur from 'kleur';
15
16
 
16
- // Keep in sync with package.json pnpm.overrides["@internationalized/date"]
17
- const INTL_DATE_VERSION = '3.10.1';
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+
19
+ function loadInstallManifest() {
20
+ const pkg = JSON.parse(
21
+ readFileSync(resolve(__dirname, '../package.json'), 'utf-8')
22
+ );
23
+ const manifest = pkg.tractstackInstall;
24
+ if (!manifest?.dependencies) {
25
+ throw new Error(
26
+ 'astro-tractstack package.json is missing tractstackInstall.dependencies'
27
+ );
28
+ }
29
+ return manifest;
30
+ }
31
+
32
+ function formatPackageSpecs(deps) {
33
+ return Object.entries(deps)
34
+ .map(([name, version]) => (version ? `${name}@${version}` : name))
35
+ .join(' ');
36
+ }
18
37
 
19
38
  // Detect package manager
20
39
  function detectPackageManager() {
@@ -332,67 +351,27 @@ PUBLIC_ENABLE_BUNNY="${finalResponses.enableBunny ? 'true' : 'false'}"
332
351
  packageManager === 'pnpm' ? 'pnpm add' : `${packageManager} add`;
333
352
 
334
353
  console.log(kleur.cyan('\nInstalling dependencies...'));
335
- try {
336
- // Install React and Node adapter
337
- execSync(
338
- `${addCommand} react@^19.0.0 react-dom@^19.0.0 astro@^5.16.6 @astrojs/react@^4.4.2 @astrojs/node@^9.4.3`,
339
- { stdio: 'inherit' }
340
- );
341
- console.log(kleur.green('✅ React and Node adapter installed'));
342
-
343
- // Install core dependencies
344
- execSync(
345
- `${addCommand} @nanostores/react@^1.0.0 nanostores@^1.0.1 @nanostores/persistent ulid@^3.0.1`,
346
- {
347
- stdio: 'inherit',
348
- }
349
- );
350
- console.log(kleur.green('✅ State management installed'));
351
-
352
- // Install UI components
353
- execSync(
354
- `${addCommand} @ark-ui/react@^5.30.0 @heroicons/react@^2.1.1 @internationalized/date@${INTL_DATE_VERSION}`,
355
- {
356
- stdio: 'inherit',
357
- }
358
- );
359
- console.log(kleur.green('✅ UI components installed'));
360
-
361
- // Install visualization dependencies
362
- execSync(
363
- `${addCommand} d3@^7.9.0 d3-sankey@^0.12.3 recharts@^3.1.2 player.js@^0.1.0 tinycolor2@^1.6.0 html-to-image@^1.11.13`,
364
- {
365
- stdio: 'inherit',
366
- }
367
- );
368
- console.log(kleur.green('✅ Visualization dependencies installed'));
354
+ const installManifest = loadInstallManifest();
355
+ const dependencySpecs = formatPackageSpecs(installManifest.dependencies);
356
+ const devDependencySpecs = formatPackageSpecs(
357
+ installManifest.devDependencies || {}
358
+ );
369
359
 
370
- // Install additional dependencies
371
- execSync(
372
- `${addCommand} path-to-regexp@^8.0.0 postcss postcss-selector-parser`,
373
- { stdio: 'inherit' }
374
- );
375
- console.log(kleur.green('✅ Additional dependencies installed'));
360
+ try {
361
+ execSync(`${addCommand} ${dependencySpecs}`, { stdio: 'inherit' });
362
+ console.log(kleur.green('✅ TractStack dependencies installed'));
376
363
 
377
- // Install dev dependencies
378
- execSync(
379
- `${addCommand} -D @types/node@^22.18.0 @types/react@^19.0.0 @types/react-dom@^19.0.0 @types/d3@^7.4.3 @types/d3-sankey@^0.12.3 prettier@^3.7.4 prettier-plugin-astro@^0.14.1 prettier-plugin-tailwindcss@^0.7.2 typescript@^5.9.3 @types/tinycolor2@^1.4.6 @mhsdesign/jit-browser-tailwindcss@^0.4.2`,
380
- { stdio: 'inherit' }
381
- );
382
- console.log(kleur.green('✅ Dev dependencies installed'));
364
+ if (devDependencySpecs) {
365
+ execSync(`${addCommand} -D ${devDependencySpecs}`, { stdio: 'inherit' });
366
+ console.log(kleur.green('✅ Dev dependencies installed'));
367
+ }
383
368
  } catch (error) {
384
369
  console.log(kleur.red('❌ Failed to install dependencies'));
385
370
  console.log('Please run manually:');
386
- console.log(
387
- kleur.cyan(
388
- `${addCommand} react@^19.0.0 react-dom@^19.0.0 astro@^5.16.6 @astrojs/react@^4.4.2 @astrojs/node@^9.4.3 @nanostores/react@^1.0.0 nanostores@^1.0.1 @nanostores/persistent ulid@^3.0.1 @ark-ui/react@^5.30.0 @heroicons/react@^2.1.1 @internationalized/date@${INTL_DATE_VERSION} d3@^7.9.0 d3-sankey@^0.12.3 recharts@^3.1.2 player.js@^0.1.0 tinycolor2@1.6.0 html-to-image@^1.11.13 path-to-regexp@^8.0.0 postcss postcss-selector-parser`
389
- )
390
- );
391
- console.log(
392
- kleur.cyan(
393
- `${addCommand} -D @types/node@^22.18.0 @types/react@^19.0.0 @types/react-dom@^19.0.0 @types/d3@^7.4.3 @types/d3-sankey@^0.12.3 prettier@^3.7.4 prettier-plugin-astro@^0.14.1 prettier-plugin-tailwindcss@^0.7.2 typescript@^5.9.3 @types/tinycolor2@^1.4.6 @mhsdesign/jit-browser-tailwindcss@^0.4.2`
394
- )
395
- );
371
+ console.log(kleur.cyan(`${addCommand} ${dependencySpecs}`));
372
+ if (devDependencySpecs) {
373
+ console.log(kleur.cyan(`${addCommand} -D ${devDependencySpecs}`));
374
+ }
396
375
  process.exit(1);
397
376
  }
398
377
 
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { fileURLToPath as d } from "node:url";
2
2
  import { dirname as i, resolve as l } from "node:path";
3
- import { existsSync as n, mkdirSync as x, copyFileSync as k, writeFileSync as u } from "node:fs";
3
+ import { existsSync as n, mkdirSync as k, copyFileSync as x, writeFileSync as u } from "node:fs";
4
4
  import { resolve as a } from "path";
5
5
  function g(t) {
6
6
  const e = i(d(t));
@@ -1497,18 +1497,6 @@ async function y(t, e, c) {
1497
1497
  ),
1498
1498
  dest: "src/components/codehooks/ListContentSetup.tsx"
1499
1499
  },
1500
- {
1501
- src: t(
1502
- "../templates/src/components/codehooks/ProductCardSetup.tsx"
1503
- ),
1504
- dest: "src/components/codehooks/ProductCardSetup.tsx"
1505
- },
1506
- {
1507
- src: t(
1508
- "../templates/src/components/codehooks/ProductGridSetup.tsx"
1509
- ),
1510
- dest: "src/components/codehooks/ProductGridSetup.tsx"
1511
- },
1512
1500
  {
1513
1501
  src: t(
1514
1502
  "../templates/src/components/codehooks/BunnyVideoWrapper.astro"
@@ -1519,6 +1507,31 @@ async function y(t, e, c) {
1519
1507
  src: t("../templates/src/components/codehooks/BunnyVideoSetup.tsx"),
1520
1508
  dest: "src/components/codehooks/BunnyVideoSetup.tsx"
1521
1509
  },
1510
+ // CodeHook Blades (partial routes; core hooks overwritable)
1511
+ {
1512
+ src: t("../templates/src/pages/codehooks/featured-article.astro"),
1513
+ dest: "src/pages/codehooks/featured-article.astro"
1514
+ },
1515
+ {
1516
+ src: t("../templates/src/pages/codehooks/list-content.astro"),
1517
+ dest: "src/pages/codehooks/list-content.astro"
1518
+ },
1519
+ {
1520
+ src: t("../templates/src/pages/codehooks/search-widget.astro"),
1521
+ dest: "src/pages/codehooks/search-widget.astro"
1522
+ },
1523
+ {
1524
+ src: t("../templates/src/pages/codehooks/bunny-video.astro"),
1525
+ dest: "src/pages/codehooks/bunny-video.astro"
1526
+ },
1527
+ {
1528
+ src: t("../templates/src/pages/codehooks/epinet.astro"),
1529
+ dest: "src/pages/codehooks/epinet.astro"
1530
+ },
1531
+ {
1532
+ src: t("../templates/src/pages/codehooks/[...hookId].astro"),
1533
+ dest: "src/pages/codehooks/[...hookId].astro"
1534
+ },
1522
1535
  // Widget Components
1523
1536
  {
1524
1537
  src: t("../templates/src/components/widgets/Impression.tsx"),
@@ -1545,6 +1558,10 @@ async function y(t, e, c) {
1545
1558
  src: t("../templates/src/lib/resources.ts"),
1546
1559
  dest: "src/lib/resources.ts"
1547
1560
  },
1561
+ {
1562
+ src: t("../templates/src/lib/codeHookHelper.ts"),
1563
+ dest: "src/lib/codeHookHelper.ts"
1564
+ },
1548
1565
  // Client Scripts
1549
1566
  {
1550
1567
  src: t("../templates/src/client/htmx.min.js"),
@@ -2319,13 +2336,6 @@ async function y(t, e, c) {
2319
2336
  dest: "src/pages/storykeep/init.astro"
2320
2337
  },
2321
2338
  // Custom Components (Conditional)
2322
- {
2323
- src: t(
2324
- c?.includeExamples ? "../templates/custom/with-examples/CodeHook.astro" : "../templates/custom/minimal/CodeHook.astro"
2325
- ),
2326
- dest: "src/custom/CodeHook.astro",
2327
- protected: !0
2328
- },
2329
2339
  {
2330
2340
  src: t(
2331
2341
  c?.includeExamples ? "../templates/custom/with-examples/CustomRoutes.astro" : "../templates/custom/minimal/CustomRoutes.astro"
@@ -2334,20 +2344,28 @@ async function y(t, e, c) {
2334
2344
  protected: !0
2335
2345
  },
2336
2346
  {
2337
- src: t(
2338
- c?.includeExamples ? "../templates/custom/with-examples/HeaderWidget.astro" : "../templates/custom/minimal/HeaderWidget.astro"
2339
- ),
2347
+ src: t("../templates/custom/minimal/HeaderWidget.astro"),
2340
2348
  dest: "src/custom/HeaderWidget.astro",
2341
2349
  protected: !0
2342
2350
  },
2343
2351
  {
2344
- src: t("../templates/src/utils/customHelpers.ts"),
2345
- dest: "src/utils/customHelpers.ts",
2352
+ src: t("../templates/custom/customHelpers.ts"),
2353
+ dest: "src/custom/customHelpers.ts",
2354
+ protected: !0
2355
+ },
2356
+ {
2357
+ src: t("../templates/custom/shopify/shopifyCustomHelper.ts"),
2358
+ dest: "src/custom/shopify/shopifyCustomHelper.ts",
2359
+ protected: !0
2360
+ },
2361
+ {
2362
+ src: t("../templates/custom/shopify/shopifyHelpers.ts"),
2363
+ dest: "src/custom/shopify/shopifyHelpers.ts",
2346
2364
  protected: !0
2347
2365
  },
2348
2366
  {
2349
- src: t("../templates/src/utils/booking/appointmentMode.ts"),
2350
- dest: "src/utils/booking/appointmentMode.ts",
2367
+ src: t("../templates/custom/shopify/appointmentMode.ts"),
2368
+ dest: "src/custom/shopify/appointmentMode.ts",
2351
2369
  protected: !0
2352
2370
  },
2353
2371
  {
@@ -2395,6 +2413,29 @@ async function y(t, e, c) {
2395
2413
  dest: "src/custom/shopify/NativeBookingCalendar.tsx",
2396
2414
  protected: !0
2397
2415
  },
2416
+ // CodeHook manifest (frontend capability list; hand-maintained, protected)
2417
+ {
2418
+ src: t(
2419
+ c?.includeExamples ? "../templates/custom/with-examples/codehooks.ts" : "../templates/custom/minimal/codehooks.ts"
2420
+ ),
2421
+ dest: "src/custom/codehooks.ts",
2422
+ protected: !0
2423
+ },
2424
+ // CodeHook Blades (userland hooks; protected once installed)
2425
+ {
2426
+ src: t(
2427
+ "../templates/src/pages/codehooks/shopify-product-grid.astro"
2428
+ ),
2429
+ dest: "src/pages/codehooks/shopify-product-grid.astro",
2430
+ protected: !0
2431
+ },
2432
+ {
2433
+ src: t(
2434
+ "../templates/src/pages/codehooks/shopify-service-list.astro"
2435
+ ),
2436
+ dest: "src/pages/codehooks/shopify-service-list.astro",
2437
+ protected: !0
2438
+ },
2398
2439
  // Example Components (Conditional)
2399
2440
  ...c?.includeExamples ? [
2400
2441
  {
@@ -2410,20 +2451,13 @@ async function y(t, e, c) {
2410
2451
  protected: !0
2411
2452
  },
2412
2453
  {
2413
- src: t("../templates/custom/with-examples/ProductGrid.astro"),
2414
- dest: "src/custom/ProductGrid.astro",
2415
- protected: !0
2416
- },
2417
- {
2418
- src: t(
2419
- "../templates/custom/with-examples/ProductCardWrapper.astro"
2420
- ),
2421
- dest: "src/custom/ProductCardWrapper.astro",
2454
+ src: t("../templates/src/pages/codehooks/custom-hero.astro"),
2455
+ dest: "src/pages/codehooks/custom-hero.astro",
2422
2456
  protected: !0
2423
2457
  },
2424
2458
  {
2425
- src: t("../templates/custom/with-examples/ProductCard.astro"),
2426
- dest: "src/custom/ProductCard.astro",
2459
+ src: t("../templates/src/pages/codehooks/get-crafting.astro"),
2460
+ dest: "src/pages/codehooks/get-crafting.astro",
2427
2461
  protected: !0
2428
2462
  },
2429
2463
  {
@@ -2443,11 +2477,11 @@ async function y(t, e, c) {
2443
2477
  for (const s of o)
2444
2478
  try {
2445
2479
  const p = i(s.dest);
2446
- n(p) || x(p, { recursive: !0 });
2480
+ n(p) || k(p, { recursive: !0 });
2447
2481
  const r = !s.protected && (s.dest === "tailwind.config.cjs" || s.dest.startsWith("src/components/codehooks/") || s.dest.startsWith("src/components/widgets/") || s.dest.startsWith("src/") || s.dest.startsWith("public/client/") || s.dest === ".gitignore");
2448
2482
  if (!n(s.dest) || r)
2449
2483
  if (n(s.src))
2450
- k(s.src, s.dest), e.info(`Updated ${s.dest}`);
2484
+ x(s.src, s.dest), e.info(`Updated ${s.dest}`);
2451
2485
  else {
2452
2486
  const m = f(s.dest);
2453
2487
  u(s.dest, m), e.info(`Created placeholder ${s.dest}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-tractstack",
3
- "version": "2.3.4",
3
+ "version": "2.4.0",
4
4
  "description": "Astro integration for TractStack - the free web press by At Risk Media",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -50,19 +50,57 @@
50
50
  "react": "^19.0.0",
51
51
  "react-dom": "^19.0.0"
52
52
  },
53
+ "tractstackInstall": {
54
+ "dependencies": {
55
+ "react": "^19.0.0",
56
+ "react-dom": "^19.0.0",
57
+ "astro": "^5.16.6",
58
+ "@astrojs/react": "^4.4.2",
59
+ "@astrojs/node": "^9.4.3",
60
+ "@nanostores/react": "^1.1.0",
61
+ "nanostores": "^1.3.0",
62
+ "@nanostores/persistent": "^1.3.4",
63
+ "ulid": "^3.0.2",
64
+ "@ark-ui/react": "^5.37.2",
65
+ "@internationalized/date": "^3.12.0",
66
+ "@heroicons/react": "^2.2.0",
67
+ "d3": "^7.9.0",
68
+ "d3-sankey": "^0.12.3",
69
+ "recharts": "^3.8.1",
70
+ "player.js": "^0.1.0",
71
+ "tinycolor2": "^1.6.0",
72
+ "html-to-image": "^1.11.13",
73
+ "path-to-regexp": "^8.4.2",
74
+ "postcss": "^8.5.15",
75
+ "postcss-selector-parser": "^7.1.4"
76
+ },
77
+ "devDependencies": {
78
+ "@types/node": "^22.20.0",
79
+ "@types/react": "^19.2.17",
80
+ "@types/react-dom": "^19.2.3",
81
+ "@types/d3": "^7.4.3",
82
+ "@types/d3-sankey": "^0.12.5",
83
+ "prettier": "^3.8.4",
84
+ "prettier-plugin-astro": "^0.14.1",
85
+ "prettier-plugin-tailwindcss": "^0.7.4",
86
+ "typescript": "^5.9.3",
87
+ "@types/tinycolor2": "^1.4.6",
88
+ "@mhsdesign/jit-browser-tailwindcss": "^0.4.2"
89
+ }
90
+ },
53
91
  "dependencies": {
54
92
  "@calcom/embed-react": "^1.5.3",
55
93
  "kleur": "^4.1.5",
56
94
  "prompts": "^2.4.2"
57
95
  },
58
96
  "devDependencies": {
59
- "@ark-ui/react": "^5.30.0",
97
+ "@ark-ui/react": "^5.37.2",
60
98
  "@astrojs/react": "^4.4.2",
61
- "@heroicons/react": "^2.1.1",
62
- "@internationalized/date": "^3.10.1",
99
+ "@heroicons/react": "^2.2.0",
100
+ "@internationalized/date": "^3.12.0",
63
101
  "@mhsdesign/jit-browser-tailwindcss": "^0.4.2",
64
- "@nanostores/persistent": "^1.3.3",
65
- "@nanostores/react": "^1.0.0",
102
+ "@nanostores/persistent": "^1.3.4",
103
+ "@nanostores/react": "^1.1.0",
66
104
  "@types/d3": "^7.4.3",
67
105
  "@types/d3-sankey": "^0.12.5",
68
106
  "@types/node": "^22.18.0",
@@ -74,7 +112,7 @@
74
112
  "d3": "^7.9.0",
75
113
  "d3-sankey": "^0.12.3",
76
114
  "html-to-image": "^1.11.13",
77
- "nanostores": "^1.1.0",
115
+ "nanostores": "^1.3.0",
78
116
  "player.js": "^0.1.0",
79
117
  "postcss": "^8.5.6",
80
118
  "postcss-selector-parser": "^7.1.1",
@@ -96,8 +134,7 @@
96
134
  "packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0",
97
135
  "pnpm": {
98
136
  "overrides": {
99
- "esbuild@<=0.24.2": ">=0.25.0",
100
- "@internationalized/date": "3.10.1"
137
+ "esbuild@<=0.24.2": ">=0.25.0"
101
138
  }
102
139
  }
103
140
  }
@@ -0,0 +1,45 @@
1
+ // URL Helper: Strip category prefix from slug
2
+ // e.g., "people-bleako" -> "bleako"
3
+ export function getCleanSlug(categorySlug: string, fullSlug: string): string {
4
+ const prefix = `${categorySlug}-`;
5
+ return fullSlug.startsWith(prefix) ? fullSlug.slice(prefix.length) : fullSlug;
6
+ }
7
+
8
+ // Build proper URL for resource
9
+ // e.g., category="people", slug="people-bleako" -> "/people/bleako"
10
+ export function getResourceUrl(categorySlug: string, fullSlug: string): string {
11
+ const cleanSlug = getCleanSlug(categorySlug, fullSlug);
12
+ return `/${categorySlug}/${cleanSlug}`;
13
+ }
14
+
15
+ // Image Helper: Placeholder implementation
16
+ export function getResourceImage(
17
+ id: string,
18
+ slug: string,
19
+ category: string
20
+ ): string {
21
+ console.log(`please define getResourceImage`, id, slug, category);
22
+ return '/static.jpg';
23
+ }
24
+
25
+ export function getResourceDescription(
26
+ id: string,
27
+ slug: string,
28
+ category: string
29
+ ): string | null {
30
+ console.log(`please define getResourceDescription`, id, slug, category);
31
+ return null;
32
+ }
33
+
34
+ // Initialize search data - override in custom implementation
35
+ export function initSearch(): void {
36
+ // Default implementation does nothing
37
+ // Override this function in your custom implementation to load search data
38
+ }
39
+
40
+ // Field Visibility Controls for ResourceForm
41
+ export const resourceFormHideFields = ['shopifyImage'];
42
+
43
+ // Field Formatting Controls for ResourceForm
44
+ // Fields listed here will be treated as JSON objects but rendered as stringified text areas
45
+ export const resourceJsonifyFields = ['shopifyData', 'shopifyImage'];
@@ -0,0 +1,13 @@
1
+ // Static, hand-maintained per-install manifest of available codehook ids.
2
+ // The backend never sees this; it is a frontend build capability list only.
3
+ // To add/remove a hook, edit this array AND add/remove the matching blade at
4
+ // src/pages/codehooks/{id}.astro. Not regenerated automatically.
5
+ export const availableCodeHookIds: string[] = [
6
+ 'featured-article',
7
+ 'list-content',
8
+ 'search-widget',
9
+ 'bunny-video',
10
+ 'epinet',
11
+ 'shopify-product-grid',
12
+ 'shopify-service-list',
13
+ ];
@@ -12,14 +12,14 @@ import {
12
12
  type CartItemState,
13
13
  } from '@/stores/shopify';
14
14
  import { getShopifyImage } from '@/utils/helpers';
15
- import { deriveAppointmentConstraints } from '@/utils/booking/appointmentMode';
15
+ import { deriveAppointmentConstraints } from '@/custom/shopify/appointmentMode';
16
16
  import {
17
17
  getServiceLinkedProduct,
18
18
  getServiceVariantIdFromCanonicalProduct,
19
19
  getSharedFeeChargeLineSummary,
20
20
  isSharedFeeService,
21
21
  parsePrimaryShopifyProductData,
22
- } from '@/utils/customHelpers';
22
+ } from '@/custom/shopify/shopifyHelpers';
23
23
  import type { ResourceNode } from '@/types/compositorTypes';
24
24
 
25
25
  interface CartProps {
@@ -1,6 +1,6 @@
1
1
  import { useStore } from '@nanostores/react';
2
2
  import { cartStore } from '@/stores/shopify';
3
- import { getCartIconCount } from '@/utils/customHelpers';
3
+ import { getCartIconCount } from '@/custom/shopify/shopifyHelpers';
4
4
  import type { ResourceNode } from '@/types/compositorTypes';
5
5
 
6
6
  interface CartIconProps {
@@ -24,7 +24,8 @@ import { bookingHelpers } from '@/utils/api/bookingHelpers';
24
24
  import {
25
25
  deriveAppointmentConstraints,
26
26
  pickInitialAppointmentMode,
27
- } from '@/utils/booking/appointmentMode';
27
+ type AppointmentMode,
28
+ } from '@/custom/shopify/appointmentMode';
28
29
  import { NativeBookingCalendar } from './NativeBookingCalendar';
29
30
  import { ProfileStorage } from '@/utils/profileStorage';
30
31
  import {
@@ -35,7 +36,7 @@ import {
35
36
  hasGidBackedCheckout,
36
37
  isSharedFeeService,
37
38
  parsePrimaryShopifyProductData,
38
- } from '@/utils/customHelpers';
39
+ } from '@/custom/shopify/shopifyHelpers';
39
40
  import type { ResourceNode } from '@/types/compositorTypes';
40
41
 
41
42
  type CheckoutState =
@@ -45,7 +46,6 @@ type CheckoutState =
45
46
  | 'SUMMARY'
46
47
  | 'PROCESSING'
47
48
  | 'SUCCESS';
48
- type AppointmentMode = 'IN_PERSON' | 'REMOTE';
49
49
 
50
50
  interface CheckoutModalProps {
51
51
  maxLength: number;
@@ -7,13 +7,13 @@ import {
7
7
  transactionTraceId,
8
8
  } from '@/stores/shopify';
9
9
  import { bookingHelpers } from '@/utils/api/bookingHelpers';
10
+ import { RESTRICTION_MESSAGES } from '@/custom/shopify/shopifyCustomHelper';
10
11
  import {
11
- RESTRICTION_MESSAGES,
12
12
  calculateCartDuration,
13
13
  getCartItemKey,
14
14
  isSharedFeeService,
15
- } from '@/utils/customHelpers';
16
- import { wouldCartHaveImpossibleRemoteMix } from '@/utils/booking/appointmentMode';
15
+ } from '@/custom/shopify/shopifyHelpers';
16
+ import { wouldCartHaveImpossibleRemoteMix } from '@/custom/shopify/appointmentMode';
17
17
  import type { ResourceNode } from '@/types/compositorTypes';
18
18
  import type { CartItemState } from '@/stores/shopify';
19
19
  import type { BrandConfigState } from '@/types/tractstack';
@@ -6,7 +6,7 @@ import {
6
6
  CART_STATES,
7
7
  isShopifyHandoff,
8
8
  } from '@/stores/shopify';
9
- import { buildShopifyCheckoutLines } from '@/utils/customHelpers';
9
+ import { buildShopifyCheckoutLines } from '@/custom/shopify/shopifyHelpers';
10
10
  import type { ResourceNode } from '@/types/compositorTypes';
11
11
 
12
12
  interface ShopifyCheckoutProps {
@@ -1,12 +1,12 @@
1
1
  import { useState } from 'react';
2
2
  import { useStore } from '@nanostores/react';
3
3
  import { cartStore, addQueue, type CartAction } from '@/stores/shopify';
4
- import { collectServiceGids } from '@/utils/customHelpers';
4
+ import { collectServiceGids } from '@/custom/shopify/shopifyHelpers';
5
5
  import { getShopifyImage } from '@/utils/helpers';
6
6
  import type { ResourceNode } from '@/types/compositorTypes';
7
7
 
8
8
  interface Props {
9
- resources: Record<string, ResourceNode[]>;
9
+ resources: ResourceNode[];
10
10
  options?: {
11
11
  params?: {
12
12
  options?: string;
@@ -218,9 +218,9 @@ function ProductCard({ resource, allServices }: ProductCardProps) {
218
218
 
219
219
  const HEX_BG_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
220
220
 
221
- export default function ShopifyProductGrid({ resources = {}, options }: Props) {
222
- let products = resources['product'] || [];
223
- const services = resources['service'] || [];
221
+ export default function ShopifyProductGrid({ resources = [], options }: Props) {
222
+ let products = resources.filter((r) => r.categorySlug === 'product');
223
+ const services = resources.filter((r) => r.categorySlug === 'service');
224
224
 
225
225
  let group = '';
226
226
  let title = '';
@@ -4,11 +4,11 @@ import {
4
4
  getCartItemKey,
5
5
  getServiceVariantIdFromCanonicalProduct,
6
6
  isSharedFeeService,
7
- } from '@/utils/customHelpers';
7
+ } from '@/custom/shopify/shopifyHelpers';
8
8
  import type { ResourceNode } from '@/types/compositorTypes';
9
9
 
10
10
  interface Props {
11
- resources: Record<string, ResourceNode[]>;
11
+ resources: ResourceNode[];
12
12
  options?: {
13
13
  params?: {
14
14
  options?: string;
@@ -18,11 +18,11 @@ interface Props {
18
18
 
19
19
  const HEX_BG_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
20
20
 
21
- export default function ShopifyServiceList({ resources = {}, options }: Props) {
21
+ export default function ShopifyServiceList({ resources = [], options }: Props) {
22
22
  const cart = useStore(cartStore);
23
23
 
24
- const products = resources['product'] || [];
25
- let services = resources['service'] || [];
24
+ const products = resources.filter((r) => r.categorySlug === 'product');
25
+ let services = resources.filter((r) => r.categorySlug === 'service');
26
26
 
27
27
  let group = '';
28
28
  let title = '';
@@ -0,0 +1,10 @@
1
+ export const RESTRICTION_MESSAGES = {
2
+ BOOKING: (duration: number) =>
3
+ `This is a ${duration} minute service. On checkout we'll help you book at your convenience.`,
4
+ TERMS: 'Please review the terms for this item before adding it to your cart.',
5
+ MAX_DURATION: (max: number) =>
6
+ `You cannot book more than ${max} minutes of services in one session.`,
7
+ INCOMPATIBLE_REMOTE:
8
+ 'This service cannot be combined with the services already in your cart. Some require remote-only delivery while others can only be delivered in person.',
9
+ DEFAULT_ADD: (title: string) => `${title} has been added to your cart.`,
10
+ };