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.
- package/bin/create-tractstack.js +38 -59
- package/dist/index.js +74 -40
- package/package.json +46 -9
- package/templates/custom/customHelpers.ts +45 -0
- package/templates/custom/minimal/codehooks.ts +13 -0
- package/templates/custom/shopify/Cart.tsx +2 -2
- package/templates/custom/shopify/CartIcon.tsx +1 -1
- package/templates/custom/shopify/CheckoutModal.tsx +3 -3
- package/templates/custom/shopify/ShopifyCartManager.tsx +3 -3
- package/templates/custom/shopify/ShopifyCheckout.tsx +1 -1
- package/templates/custom/shopify/ShopifyProductGrid.tsx +5 -5
- package/templates/custom/shopify/ShopifyServiceList.tsx +5 -5
- package/templates/custom/shopify/shopifyCustomHelper.ts +10 -0
- package/templates/{src/utils/customHelpers.ts → custom/shopify/shopifyHelpers.ts} +0 -74
- package/templates/custom/with-examples/codehooks.ts +15 -0
- package/templates/src/components/Header.astro +1 -1
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +38 -23
- package/templates/src/components/codehooks/EpinetTableView.tsx +5 -2
- package/templates/src/components/codehooks/EpinetWrapper.tsx +10 -5
- package/templates/src/components/codehooks/FeaturedArticle.astro +3 -3
- package/templates/src/components/codehooks/ListContent.astro +3 -3
- package/templates/src/components/codehooks/SearchWidget.tsx +1 -1
- package/templates/src/components/compositor/Node.tsx +13 -2
- package/templates/src/components/compositor/nodes/Pane.tsx +2 -14
- package/templates/src/components/edit/pane/AddPanePanel.tsx +3 -2
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +35 -14
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +1 -1
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +2 -2
- package/templates/src/components/search/SearchResults.tsx +1 -1
- package/templates/src/components/search/SearchWrapper.tsx +1 -1
- package/templates/src/components/storykeep/Dashboard_Analytics.tsx +8 -4
- package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +5 -2
- package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +1 -1
- package/templates/src/components/storykeep/shopify/ShopifyDashboard_Sales.tsx +1 -1
- package/templates/src/components/storykeep/state/FetchAnalytics.tsx +8 -4
- package/templates/src/components/storykeep/widgets/Wizard.tsx +4 -2
- package/templates/src/lib/codeHookHelper.ts +156 -0
- package/templates/src/lib/resources.ts +41 -0
- package/templates/src/lib/storyData.ts +1 -2
- package/templates/src/pages/[...slug]/edit.astro +3 -3
- package/templates/src/pages/[...slug].astro +76 -70
- package/templates/src/pages/codehooks/[...hookId].astro +18 -0
- package/templates/src/pages/codehooks/bunny-video.astro +9 -0
- package/templates/src/pages/codehooks/custom-hero.astro +6 -0
- package/templates/src/pages/codehooks/epinet.astro +15 -0
- package/templates/src/pages/codehooks/featured-article.astro +13 -0
- package/templates/src/pages/codehooks/get-crafting.astro +8 -0
- package/templates/src/pages/codehooks/list-content.astro +13 -0
- package/templates/src/pages/codehooks/search-widget.astro +13 -0
- package/templates/src/pages/codehooks/shopify-product-grid.astro +25 -0
- package/templates/src/pages/codehooks/shopify-service-list.astro +25 -0
- package/templates/src/pages/context/[...contextSlug]/edit.astro +3 -3
- package/templates/src/pages/context/[...contextSlug].astro +47 -10
- package/templates/src/pages/sandbox.astro +3 -14
- package/templates/src/stores/analytics.ts +77 -107
- package/utils/inject-files.ts +76 -41
- package/templates/custom/minimal/CodeHook.astro +0 -72
- package/templates/custom/with-examples/CodeHook.astro +0 -81
- package/templates/custom/with-examples/ProductCard.astro +0 -29
- package/templates/custom/with-examples/ProductCardWrapper.astro +0 -43
- package/templates/custom/with-examples/ProductGrid.astro +0 -64
- package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -157
- package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -279
- /package/templates/{src/utils/booking → custom/shopify}/appointmentMode.ts +0 -0
package/bin/create-tractstack.js
CHANGED
|
@@ -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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
371
|
-
execSync(
|
|
372
|
-
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
-
|
|
388
|
-
|
|
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
|
|
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/
|
|
2345
|
-
dest: "src/
|
|
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/
|
|
2350
|
-
dest: "src/
|
|
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
|
|
2414
|
-
dest: "src/custom
|
|
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/
|
|
2426
|
-
dest: "src/
|
|
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) ||
|
|
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
|
-
|
|
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
|
+
"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.
|
|
97
|
+
"@ark-ui/react": "^5.37.2",
|
|
60
98
|
"@astrojs/react": "^4.4.2",
|
|
61
|
-
"@heroicons/react": "^2.
|
|
62
|
-
"@internationalized/date": "^3.
|
|
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.
|
|
65
|
-
"@nanostores/react": "^1.
|
|
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.
|
|
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 '@/
|
|
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 '@/
|
|
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 '@/
|
|
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
|
-
|
|
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 '@/
|
|
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 '@/
|
|
16
|
-
import { wouldCartHaveImpossibleRemoteMix } from '@/
|
|
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 '@/
|
|
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 '@/
|
|
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:
|
|
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 =
|
|
222
|
-
let products = resources
|
|
223
|
-
const services = resources
|
|
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 '@/
|
|
7
|
+
} from '@/custom/shopify/shopifyHelpers';
|
|
8
8
|
import type { ResourceNode } from '@/types/compositorTypes';
|
|
9
9
|
|
|
10
10
|
interface Props {
|
|
11
|
-
resources:
|
|
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 =
|
|
21
|
+
export default function ShopifyServiceList({ resources = [], options }: Props) {
|
|
22
22
|
const cart = useStore(cartStore);
|
|
23
23
|
|
|
24
|
-
const products = resources
|
|
25
|
-
let services = resources
|
|
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
|
+
};
|