astro-tractstack 2.3.5 → 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 (49) hide show
  1. package/bin/create-tractstack.js +38 -59
  2. package/dist/index.js +60 -36
  3. package/package.json +46 -9
  4. package/templates/custom/minimal/codehooks.ts +13 -0
  5. package/templates/custom/shopify/ShopifyProductGrid.tsx +4 -4
  6. package/templates/custom/shopify/ShopifyServiceList.tsx +4 -4
  7. package/templates/custom/with-examples/codehooks.ts +15 -0
  8. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +38 -23
  9. package/templates/src/components/codehooks/EpinetTableView.tsx +5 -2
  10. package/templates/src/components/codehooks/EpinetWrapper.tsx +10 -5
  11. package/templates/src/components/codehooks/FeaturedArticle.astro +3 -3
  12. package/templates/src/components/codehooks/ListContent.astro +3 -3
  13. package/templates/src/components/compositor/Node.tsx +13 -2
  14. package/templates/src/components/compositor/nodes/Pane.tsx +2 -14
  15. package/templates/src/components/edit/pane/AddPanePanel.tsx +3 -2
  16. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +35 -14
  17. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +1 -1
  18. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +2 -2
  19. package/templates/src/components/storykeep/Dashboard_Analytics.tsx +8 -4
  20. package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +5 -2
  21. package/templates/src/components/storykeep/state/FetchAnalytics.tsx +8 -4
  22. package/templates/src/components/storykeep/widgets/Wizard.tsx +4 -2
  23. package/templates/src/lib/codeHookHelper.ts +156 -0
  24. package/templates/src/lib/resources.ts +41 -0
  25. package/templates/src/lib/storyData.ts +1 -2
  26. package/templates/src/pages/[...slug]/edit.astro +3 -3
  27. package/templates/src/pages/[...slug].astro +76 -70
  28. package/templates/src/pages/codehooks/[...hookId].astro +18 -0
  29. package/templates/src/pages/codehooks/bunny-video.astro +9 -0
  30. package/templates/src/pages/codehooks/custom-hero.astro +6 -0
  31. package/templates/src/pages/codehooks/epinet.astro +15 -0
  32. package/templates/src/pages/codehooks/featured-article.astro +13 -0
  33. package/templates/src/pages/codehooks/get-crafting.astro +8 -0
  34. package/templates/src/pages/codehooks/list-content.astro +13 -0
  35. package/templates/src/pages/codehooks/search-widget.astro +13 -0
  36. package/templates/src/pages/codehooks/shopify-product-grid.astro +25 -0
  37. package/templates/src/pages/codehooks/shopify-service-list.astro +25 -0
  38. package/templates/src/pages/context/[...contextSlug]/edit.astro +3 -3
  39. package/templates/src/pages/context/[...contextSlug].astro +47 -10
  40. package/templates/src/pages/sandbox.astro +3 -14
  41. package/templates/src/stores/analytics.ts +77 -107
  42. package/utils/inject-files.ts +62 -37
  43. package/templates/custom/minimal/CodeHook.astro +0 -72
  44. package/templates/custom/with-examples/CodeHook.astro +0 -81
  45. package/templates/custom/with-examples/ProductCard.astro +0 -29
  46. package/templates/custom/with-examples/ProductCardWrapper.astro +0 -43
  47. package/templates/custom/with-examples/ProductGrid.astro +0 -64
  48. package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -157
  49. package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -279
@@ -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,9 +2344,7 @@ 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
  },
@@ -2405,6 +2413,29 @@ async function y(t, e, c) {
2405
2413
  dest: "src/custom/shopify/NativeBookingCalendar.tsx",
2406
2414
  protected: !0
2407
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
+ },
2408
2439
  // Example Components (Conditional)
2409
2440
  ...c?.includeExamples ? [
2410
2441
  {
@@ -2420,20 +2451,13 @@ async function y(t, e, c) {
2420
2451
  protected: !0
2421
2452
  },
2422
2453
  {
2423
- src: t("../templates/custom/with-examples/ProductGrid.astro"),
2424
- dest: "src/custom/ProductGrid.astro",
2425
- protected: !0
2426
- },
2427
- {
2428
- src: t(
2429
- "../templates/custom/with-examples/ProductCardWrapper.astro"
2430
- ),
2431
- dest: "src/custom/ProductCardWrapper.astro",
2454
+ src: t("../templates/src/pages/codehooks/custom-hero.astro"),
2455
+ dest: "src/pages/codehooks/custom-hero.astro",
2432
2456
  protected: !0
2433
2457
  },
2434
2458
  {
2435
- src: t("../templates/custom/with-examples/ProductCard.astro"),
2436
- dest: "src/custom/ProductCard.astro",
2459
+ src: t("../templates/src/pages/codehooks/get-crafting.astro"),
2460
+ dest: "src/pages/codehooks/get-crafting.astro",
2437
2461
  protected: !0
2438
2462
  },
2439
2463
  {
@@ -2453,11 +2477,11 @@ async function y(t, e, c) {
2453
2477
  for (const s of o)
2454
2478
  try {
2455
2479
  const p = i(s.dest);
2456
- n(p) || x(p, { recursive: !0 });
2480
+ n(p) || k(p, { recursive: !0 });
2457
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");
2458
2482
  if (!n(s.dest) || r)
2459
2483
  if (n(s.src))
2460
- k(s.src, s.dest), e.info(`Updated ${s.dest}`);
2484
+ x(s.src, s.dest), e.info(`Updated ${s.dest}`);
2461
2485
  else {
2462
2486
  const m = f(s.dest);
2463
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.5",
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,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
+ ];
@@ -6,7 +6,7 @@ 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 = '';
@@ -8,7 +8,7 @@ import {
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,15 @@
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
+ 'custom-hero',
14
+ 'get-crafting',
15
+ ];
@@ -11,7 +11,10 @@ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
11
11
  import CheckCircleIcon from '@heroicons/react/24/outline/CheckCircleIcon';
12
12
  import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
13
13
  import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
14
- import { epinetCustomFilters } from '@/stores/analytics';
14
+ import {
15
+ epinetCustomFilters,
16
+ setEpinetCustomFilters,
17
+ } from '@/stores/analytics';
15
18
  import EpinetTableView from './EpinetTableView';
16
19
  import { MAX_ANALYTICS_HOURS } from '@/constants';
17
20
  import type { AppliedFilter } from '@/stores/analytics';
@@ -220,7 +223,7 @@ const EpinetDurationSelector = ({
220
223
  }
221
224
  setIsApplying(true);
222
225
  try {
223
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
226
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
224
227
  ...$epinetCustomFilters,
225
228
  visitorType: localFilters.visitorType,
226
229
  selectedUserId: localFilters.selectedUserId,
@@ -794,10 +797,16 @@ const EpinetDurationSelector = ({
794
797
  collection={createListCollection({
795
798
  items: [
796
799
  { value: '', label: 'Select user' },
797
- ...paginatedUserCounts.map((user) => ({
798
- value: user.id,
799
- label: `${user.id} (${user.count} events)`,
800
- })),
800
+ ...paginatedUserCounts.map(
801
+ (user: {
802
+ id: string;
803
+ count: number;
804
+ isKnown: boolean;
805
+ }) => ({
806
+ value: user.id,
807
+ label: `${user.id} (${user.count} events)`,
808
+ })
809
+ ),
801
810
  ],
802
811
  })}
803
812
  value={
@@ -844,23 +853,29 @@ const EpinetDurationSelector = ({
844
853
  Select user
845
854
  </Select.ItemText>
846
855
  </Select.Item>,
847
- ...paginatedUserCounts.map((user) => (
848
- <Select.Item
849
- key={user.id}
850
- item={{
851
- value: user.id,
852
- label: `${user.id} (${user.count} events)`,
853
- }}
854
- className="epinet-user-select-item cursor-pointer select-none p-2 text-sm text-gray-700 hover:bg-slate-100"
855
- >
856
- <Select.ItemText>
857
- {user.id}{' '}
858
- <span className="text-xs text-gray-500">
859
- ({user.count} events)
860
- </span>
861
- </Select.ItemText>
862
- </Select.Item>
863
- )),
856
+ ...paginatedUserCounts.map(
857
+ (user: {
858
+ id: string;
859
+ count: number;
860
+ isKnown: boolean;
861
+ }) => (
862
+ <Select.Item
863
+ key={user.id}
864
+ item={{
865
+ value: user.id,
866
+ label: `${user.id} (${user.count} events)`,
867
+ }}
868
+ className="epinet-user-select-item cursor-pointer select-none p-2 text-sm text-gray-700 hover:bg-slate-100"
869
+ >
870
+ <Select.ItemText>
871
+ {user.id}{' '}
872
+ <span className="text-xs text-gray-500">
873
+ ({user.count} events)
874
+ </span>
875
+ </Select.ItemText>
876
+ </Select.Item>
877
+ )
878
+ ),
864
879
  ]
865
880
  ) : (
866
881
  <div className="p-2 text-sm text-gray-500">
@@ -1,7 +1,10 @@
1
1
  import { useState, useEffect } from 'react';
2
2
  import { useStore } from '@nanostores/react';
3
3
  import { classNames } from '@/utils/helpers';
4
- import { epinetCustomFilters } from '@/stores/analytics';
4
+ import {
5
+ epinetCustomFilters,
6
+ setEpinetCustomFilters,
7
+ } from '@/stores/analytics';
5
8
  import { Accordion } from '@ark-ui/react';
6
9
  import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
7
10
  import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
@@ -176,7 +179,7 @@ const EpinetTableView = ({
176
179
  const endTimeUTC = new Date(
177
180
  Date.UTC(year, month - 1, day, hour, 59, 59, 999)
178
181
  );
179
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
182
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
180
183
  ...$epinetCustomFilters,
181
184
  startTimeUTC: startTimeUTC.toISOString(),
182
185
  endTimeUTC: endTimeUTC.toISOString(),
@@ -6,7 +6,12 @@ import {
6
6
  type ReactNode,
7
7
  } from 'react';
8
8
  import { useStore } from '@nanostores/react';
9
- import { epinetCustomFilters, type AppliedFilter } from '@/stores/analytics';
9
+ import {
10
+ epinetCustomFilters,
11
+ getEpinetCustomFilters,
12
+ setEpinetCustomFilters,
13
+ type AppliedFilter,
14
+ } from '@/stores/analytics';
10
15
  import { TractStackAPI } from '@/utils/api';
11
16
  import SankeyDiagram from './SankeyDiagram';
12
17
  import EpinetDurationSelector from './EpinetDurationSelector';
@@ -97,7 +102,7 @@ const EpinetWrapper = ({
97
102
  useEffect(() => {
98
103
  const nowUTC = new Date();
99
104
  const oneWeekAgoUTC = new Date(nowUTC.getTime() - 7 * 24 * 60 * 60 * 1000);
100
- epinetCustomFilters.set(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
105
+ setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
101
106
  enabled: true,
102
107
  visitorType: 'all',
103
108
  selectedUserId: null,
@@ -133,7 +138,7 @@ const EpinetWrapper = ({
133
138
 
134
139
  const handleBeliefFilterChange = (beliefSlug: string, value: string) => {
135
140
  const tenantId = window.TRACTSTACK_CONFIG?.tenantId || 'default';
136
- const currentFilters = epinetCustomFilters.get();
141
+ const currentFilters = getEpinetCustomFilters();
137
142
  let newFilters: AppliedFilter[] = [
138
143
  ...(currentFilters.appliedFilters || []),
139
144
  ];
@@ -151,7 +156,7 @@ const EpinetWrapper = ({
151
156
  }
152
157
  }
153
158
 
154
- epinetCustomFilters.set(tenantId, {
159
+ setEpinetCustomFilters(tenantId, {
155
160
  ...currentFilters,
156
161
  appliedFilters: newFilters,
157
162
  });
@@ -229,7 +234,7 @@ const EpinetWrapper = ({
229
234
  error: null,
230
235
  isLoading: false,
231
236
  });
232
- epinetCustomFilters.set(
237
+ setEpinetCustomFilters(
233
238
  window.TRACTSTACK_CONFIG?.tenantId || 'default',
234
239
  {
235
240
  ...$epinetCustomFilters,
@@ -7,10 +7,10 @@ export interface Props {
7
7
  options?: string;
8
8
  };
9
9
  };
10
- contentMap: FullContentMapItem[];
10
+ fullContentMap: FullContentMapItem[];
11
11
  }
12
12
 
13
- const { options, contentMap } = Astro.props;
13
+ const { options, fullContentMap } = Astro.props;
14
14
 
15
15
  let parsedOptions;
16
16
  try {
@@ -22,7 +22,7 @@ try {
22
22
 
23
23
  const slug = parsedOptions.slug || '';
24
24
 
25
- const featuredStory = contentMap.find(
25
+ const featuredStory = fullContentMap.find(
26
26
  (item: FullContentMapItem) =>
27
27
  item.slug === slug &&
28
28
  item.type === 'StoryFragment' &&
@@ -7,10 +7,10 @@ export interface Props {
7
7
  options?: string;
8
8
  };
9
9
  };
10
- contentMap: FullContentMapItem[];
10
+ fullContentMap: FullContentMapItem[];
11
11
  }
12
12
 
13
- const { options, contentMap } = Astro.props;
13
+ const { options, fullContentMap } = Astro.props;
14
14
 
15
15
  // Parse component options
16
16
  let parsedOptions;
@@ -36,7 +36,7 @@ const title = parsedOptions.title;
36
36
  const bgColor = parsedOptions.bgColor || '';
37
37
 
38
38
  // Filter for valid stories to display
39
- const validPages = contentMap.filter(
39
+ const validPages = fullContentMap.filter(
40
40
  (item: FullContentMapItem): boolean =>
41
41
  item.type === 'StoryFragment' &&
42
42
  typeof item.description === 'string' &&