astro-tractstack 2.3.5 → 2.4.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.
- package/bin/create-tractstack.js +38 -59
- package/dist/index.js +68 -36
- package/package.json +46 -9
- package/templates/custom/minimal/codehooks.ts +13 -0
- package/templates/custom/shopify/CartModal.tsx +11 -1
- package/templates/custom/shopify/CartReset.tsx +38 -0
- package/templates/custom/shopify/ShopifyCartManager.tsx +2 -0
- package/templates/custom/shopify/ShopifyProductGrid.tsx +4 -4
- package/templates/custom/shopify/ShopifyServiceList.tsx +56 -43
- package/templates/custom/shopify/cart-reset.astro +19 -0
- 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/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/storykeep/Dashboard_Analytics.tsx +8 -4
- package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +5 -2
- 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 +23 -0
- package/templates/src/pages/codehooks/shopify-service-list.astro +23 -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/templates/src/stores/shopify.ts +34 -4
- package/utils/inject-files.ts +70 -37
- 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
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Layout from '@/layouts/Layout.astro';
|
|
3
3
|
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
4
|
+
import { getFullContentMap } from '@/stores/analytics';
|
|
5
|
+
import {
|
|
6
|
+
buildCodeHookBladePath,
|
|
7
|
+
fetchCodeHookBladeHtml,
|
|
8
|
+
resolveSSRFetchOrigin,
|
|
9
|
+
} from '@/lib/codeHookHelper';
|
|
4
10
|
import { handleFailedResponse } from '@/utils/backend';
|
|
5
11
|
import { preHealthCheck } from '@/utils/backend';
|
|
6
12
|
|
|
@@ -56,6 +62,8 @@ try {
|
|
|
56
62
|
|
|
57
63
|
const paneId = contextPaneData.id;
|
|
58
64
|
const paneTitle = contextPaneData.title || 'Context';
|
|
65
|
+
const codeHookTarget = contextPaneData.codeHookTarget;
|
|
66
|
+
const codeHookOptions = contextPaneData.codeHookPayload?.options;
|
|
59
67
|
|
|
60
68
|
// Get rendered fragment for the context pane
|
|
61
69
|
let fragmentData = '';
|
|
@@ -94,6 +102,23 @@ const brandConfig = await getBrandConfig(tenantId);
|
|
|
94
102
|
if (!brandConfig.SITE_INIT) {
|
|
95
103
|
return Astro.redirect('/storykeep');
|
|
96
104
|
}
|
|
105
|
+
|
|
106
|
+
// Warm the in-process content-map store before SSR-fetching the codehook blade.
|
|
107
|
+
await getFullContentMap(tenantId);
|
|
108
|
+
|
|
109
|
+
let codeHookBladeHtml = '';
|
|
110
|
+
if (codeHookTarget) {
|
|
111
|
+
const bladePath = buildCodeHookBladePath(codeHookTarget, {
|
|
112
|
+
paneId,
|
|
113
|
+
tenantId,
|
|
114
|
+
optionsStr: codeHookOptions || '',
|
|
115
|
+
});
|
|
116
|
+
codeHookBladeHtml = await fetchCodeHookBladeHtml(
|
|
117
|
+
bladePath,
|
|
118
|
+
Astro.request,
|
|
119
|
+
resolveSSRFetchOrigin(Astro.url, brandConfig.SITE_URL)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
97
122
|
---
|
|
98
123
|
|
|
99
124
|
<Layout
|
|
@@ -108,16 +133,28 @@ if (!brandConfig.SITE_INIT) {
|
|
|
108
133
|
storyfragmentId={paneId}
|
|
109
134
|
>
|
|
110
135
|
<main id="main-content" class="w-full">
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
136
|
+
{
|
|
137
|
+
codeHookTarget ? (
|
|
138
|
+
<div
|
|
139
|
+
id={`pane-${paneId}`}
|
|
140
|
+
data-pane-id={paneId}
|
|
141
|
+
class="context-pane-container"
|
|
142
|
+
>
|
|
143
|
+
<Fragment set:html={codeHookBladeHtml} />
|
|
144
|
+
</div>
|
|
145
|
+
) : (
|
|
146
|
+
<div
|
|
147
|
+
id={`pane-${paneId}`}
|
|
148
|
+
data-pane-id={paneId}
|
|
149
|
+
class="context-pane-container"
|
|
150
|
+
hx-get={`/api/v1/fragments/panes/${paneId}`}
|
|
151
|
+
hx-trigger="refresh"
|
|
152
|
+
hx-swap="innerHTML scroll:none"
|
|
153
|
+
>
|
|
154
|
+
<Fragment set:html={fragmentData} />
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
121
158
|
|
|
122
159
|
<div class="py-12 text-center text-2xl md:text-3xl">
|
|
123
160
|
<button
|
|
@@ -5,9 +5,7 @@ import Layout from '@/layouts/Layout.astro';
|
|
|
5
5
|
import Header from '@/components/Header.astro';
|
|
6
6
|
import { getFullContentMap } from '@/stores/analytics';
|
|
7
7
|
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
8
|
-
import
|
|
9
|
-
components as codeHookComponents,
|
|
10
|
-
} from '@/custom/CodeHook.astro';
|
|
8
|
+
import { availableCodeHookIds } from '@/custom/codehooks';
|
|
11
9
|
import StoryKeepHeader from '@/components/edit/Header';
|
|
12
10
|
import StoryKeepToolBar from '@/components/edit/ToolBar';
|
|
13
11
|
import StoryKeepToolMode from '@/components/edit/ToolMode';
|
|
@@ -64,15 +62,6 @@ const sandboxToken = `${timestamp}.${signature}`;
|
|
|
64
62
|
isStoryKeep={true}
|
|
65
63
|
isEditor={true}
|
|
66
64
|
>
|
|
67
|
-
<CodeHook
|
|
68
|
-
target="get-tractstack"
|
|
69
|
-
options={{
|
|
70
|
-
params: {
|
|
71
|
-
options: JSON.stringify({ isEmbedded: false }),
|
|
72
|
-
},
|
|
73
|
-
}}
|
|
74
|
-
/>
|
|
75
|
-
|
|
76
65
|
<Header
|
|
77
66
|
title={title}
|
|
78
67
|
slug="sandbox"
|
|
@@ -115,7 +104,7 @@ const sandboxToken = `${timestamp}.${signature}`;
|
|
|
115
104
|
fullContentMap={fullContentMap}
|
|
116
105
|
fullCanonicalURL="/sandbox"
|
|
117
106
|
urlParams={urlParams}
|
|
118
|
-
availableCodeHooks={
|
|
107
|
+
availableCodeHooks={availableCodeHookIds}
|
|
119
108
|
isSandboxMode={true}
|
|
120
109
|
sandboxToken={sandboxToken}
|
|
121
110
|
client:only="react"
|
|
@@ -137,7 +126,7 @@ const sandboxToken = `${timestamp}.${signature}`;
|
|
|
137
126
|
|
|
138
127
|
<div class="pointer-events-auto max-h-full">
|
|
139
128
|
<SettingsPanel
|
|
140
|
-
availableCodeHooks={
|
|
129
|
+
availableCodeHooks={availableCodeHookIds}
|
|
141
130
|
client:only="react"
|
|
142
131
|
/>
|
|
143
132
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { atom } from 'nanostores';
|
|
1
|
+
import { atom, computed } from 'nanostores';
|
|
2
2
|
import { TractStackAPI } from '@/utils/api';
|
|
3
3
|
|
|
4
4
|
interface AvailableFilter {
|
|
@@ -11,43 +11,38 @@ export interface AppliedFilter {
|
|
|
11
11
|
value: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
export interface EpinetFiltersState {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
visitorType: 'all' | 'anonymous' | 'known';
|
|
17
|
+
selectedUserId: string | null;
|
|
18
|
+
startTimeUTC: string | null;
|
|
19
|
+
endTimeUTC: string | null;
|
|
20
|
+
userCounts: Array<{ id: string; count: number; isKnown: boolean }>;
|
|
21
|
+
hourlyNodeActivity: Record<
|
|
16
22
|
string,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
events: Record<string, number>;
|
|
30
|
-
visitorIds: string[];
|
|
31
|
-
}
|
|
32
|
-
>
|
|
33
|
-
>;
|
|
34
|
-
availableFilters: AvailableFilter[];
|
|
35
|
-
appliedFilters: AppliedFilter[];
|
|
36
|
-
}
|
|
37
|
-
>
|
|
38
|
-
>({});
|
|
23
|
+
Record<
|
|
24
|
+
string,
|
|
25
|
+
{
|
|
26
|
+
events: Record<string, number>;
|
|
27
|
+
visitorIds: string[];
|
|
28
|
+
}
|
|
29
|
+
>
|
|
30
|
+
>;
|
|
31
|
+
availableFilters: AvailableFilter[];
|
|
32
|
+
appliedFilters: AppliedFilter[];
|
|
33
|
+
}
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
export interface TenantFullContentMapState {
|
|
36
|
+
data: any[];
|
|
37
|
+
lastUpdated: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const tenantEpinetCustomFilters = atom<Record<string, EpinetFiltersState>>({});
|
|
41
|
+
|
|
42
|
+
const tenantFullContentMaps = atom<Record<string, TenantFullContentMapState>>(
|
|
43
|
+
{}
|
|
44
|
+
);
|
|
49
45
|
|
|
50
|
-
// Helper to get current tenant ID
|
|
51
46
|
function getCurrentTenantId(): string {
|
|
52
47
|
const resolvedTenantId =
|
|
53
48
|
(typeof window !== 'undefined' && window.TRACTSTACK_CONFIG?.tenantId) ||
|
|
@@ -56,9 +51,9 @@ function getCurrentTenantId(): string {
|
|
|
56
51
|
return resolvedTenantId;
|
|
57
52
|
}
|
|
58
53
|
|
|
59
|
-
const defaultEpinetFilters = {
|
|
54
|
+
const defaultEpinetFilters: EpinetFiltersState = {
|
|
60
55
|
enabled: false,
|
|
61
|
-
visitorType: 'all'
|
|
56
|
+
visitorType: 'all',
|
|
62
57
|
selectedUserId: null,
|
|
63
58
|
startTimeUTC: null,
|
|
64
59
|
endTimeUTC: null,
|
|
@@ -68,81 +63,56 @@ const defaultEpinetFilters = {
|
|
|
68
63
|
appliedFilters: [],
|
|
69
64
|
};
|
|
70
65
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
set: (tenantId: string, updates: any) => {
|
|
79
|
-
const currentFilters =
|
|
80
|
-
tenantEpinetCustomFilters.get()[tenantId] || defaultEpinetFilters;
|
|
81
|
-
tenantEpinetCustomFilters.set({
|
|
82
|
-
...tenantEpinetCustomFilters.get(),
|
|
83
|
-
[tenantId]: {
|
|
84
|
-
...currentFilters,
|
|
85
|
-
...updates,
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
subscribe: (callback: (value: any) => void) => {
|
|
91
|
-
const tenantId = getCurrentTenantId();
|
|
92
|
-
return tenantEpinetCustomFilters.subscribe((filters) => {
|
|
93
|
-
callback(filters[tenantId] || defaultEpinetFilters);
|
|
94
|
-
});
|
|
95
|
-
},
|
|
96
|
-
lc: 0,
|
|
97
|
-
listen: function (callback: any) {
|
|
98
|
-
return this.subscribe(callback);
|
|
99
|
-
},
|
|
100
|
-
notify: function () {},
|
|
101
|
-
off: function () {},
|
|
102
|
-
get value() {
|
|
103
|
-
return this.get();
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
return store;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const createFullContentMapStore = () => {
|
|
111
|
-
const store = {
|
|
112
|
-
get: () => {
|
|
113
|
-
const tenantId = getCurrentTenantId();
|
|
114
|
-
return tenantFullContentMaps.get()[tenantId] || null;
|
|
115
|
-
},
|
|
66
|
+
export const epinetCustomFilters = computed(
|
|
67
|
+
tenantEpinetCustomFilters,
|
|
68
|
+
(filters) => {
|
|
69
|
+
const tenantId = getCurrentTenantId();
|
|
70
|
+
return filters[tenantId] || defaultEpinetFilters;
|
|
71
|
+
}
|
|
72
|
+
);
|
|
116
73
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
[tenantId]: data,
|
|
121
|
-
});
|
|
122
|
-
},
|
|
74
|
+
export function getEpinetCustomFilters(): EpinetFiltersState {
|
|
75
|
+
return epinetCustomFilters.get();
|
|
76
|
+
}
|
|
123
77
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
off: function () {},
|
|
136
|
-
get value() {
|
|
137
|
-
return this.get();
|
|
78
|
+
export function setEpinetCustomFilters(
|
|
79
|
+
tenantId: string,
|
|
80
|
+
updates: Partial<EpinetFiltersState>
|
|
81
|
+
): void {
|
|
82
|
+
const currentFilters =
|
|
83
|
+
tenantEpinetCustomFilters.get()[tenantId] || defaultEpinetFilters;
|
|
84
|
+
tenantEpinetCustomFilters.set({
|
|
85
|
+
...tenantEpinetCustomFilters.get(),
|
|
86
|
+
[tenantId]: {
|
|
87
|
+
...currentFilters,
|
|
88
|
+
...updates,
|
|
138
89
|
},
|
|
139
|
-
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
140
92
|
|
|
141
|
-
|
|
142
|
-
|
|
93
|
+
export const fullContentMapStore = computed(tenantFullContentMaps, (maps) => {
|
|
94
|
+
const tenantId = getCurrentTenantId();
|
|
95
|
+
return maps[tenantId] || null;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export function setTenantFullContentMap(
|
|
99
|
+
tenantId: string,
|
|
100
|
+
data: TenantFullContentMapState
|
|
101
|
+
): void {
|
|
102
|
+
tenantFullContentMaps.set({
|
|
103
|
+
...tenantFullContentMaps.get(),
|
|
104
|
+
[tenantId]: data,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
143
107
|
|
|
144
|
-
|
|
145
|
-
|
|
108
|
+
// Synchronous in-process accessor for the warm content-map atom, keyed on an
|
|
109
|
+
// explicit tenantId (unlike fullContentMapStore.get(), which keys on
|
|
110
|
+
// getCurrentTenantId() and resolves the wrong tenant during SSR sub-requests).
|
|
111
|
+
// Returns [] on a cold miss; codehook blades fall back to the async
|
|
112
|
+
// getFullContentMap(tenantId) when this is empty.
|
|
113
|
+
export function getCachedFullContentMap(tenantId: string): any[] {
|
|
114
|
+
return tenantFullContentMaps.get()[tenantId]?.data ?? [];
|
|
115
|
+
}
|
|
146
116
|
|
|
147
117
|
export async function getFullContentMap(tenantId: string): Promise<any[]> {
|
|
148
118
|
const api = new TractStackAPI(tenantId);
|
|
@@ -26,6 +26,7 @@ export const modalState = atom<{
|
|
|
26
26
|
type: 'success' | 'restriction';
|
|
27
27
|
title: string;
|
|
28
28
|
message: string;
|
|
29
|
+
restrictionReason?: 'maxDuration' | 'incompatibleRemote';
|
|
29
30
|
}>({
|
|
30
31
|
isOpen: false,
|
|
31
32
|
type: 'success',
|
|
@@ -258,16 +259,45 @@ export function setCustomerDetails(details: Partial<CustomerDetails>) {
|
|
|
258
259
|
});
|
|
259
260
|
}
|
|
260
261
|
|
|
261
|
-
|
|
262
|
+
const SHOPIFY_PERSISTENCE_KEYS = [
|
|
263
|
+
'tractstack_shopify_queue',
|
|
264
|
+
'tractstack_shopify_cart',
|
|
265
|
+
'tractstack_shopify_queue_state',
|
|
266
|
+
'tractstack_shopify_cart_state',
|
|
267
|
+
'tractstack_shopify_trace_id',
|
|
268
|
+
'tractstack_shopify_appointment_mode',
|
|
269
|
+
'tractstack_shopify_customer',
|
|
270
|
+
] as const;
|
|
271
|
+
|
|
272
|
+
export function resetShopifyCommerceState() {
|
|
273
|
+
addQueue.set([]);
|
|
262
274
|
cartStore.set({});
|
|
275
|
+
cartState.set(CART_STATES.READY);
|
|
276
|
+
queueState.set(QUEUE_STATES.READY);
|
|
277
|
+
transactionTraceId.set('');
|
|
278
|
+
preferredAppointmentMode.set('IN_PERSON');
|
|
263
279
|
customerDetails.set({
|
|
264
280
|
name: '',
|
|
265
281
|
email: '',
|
|
266
282
|
leadId: '',
|
|
267
283
|
});
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
284
|
+
modalState.set({
|
|
285
|
+
isOpen: false,
|
|
286
|
+
type: 'success',
|
|
287
|
+
title: '',
|
|
288
|
+
message: '',
|
|
289
|
+
restrictionReason: undefined,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
if (typeof localStorage !== 'undefined') {
|
|
293
|
+
SHOPIFY_PERSISTENCE_KEYS.forEach((key) => {
|
|
294
|
+
localStorage.removeItem(key);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export function clearCommerceState() {
|
|
300
|
+
resetShopifyCommerceState();
|
|
271
301
|
}
|
|
272
302
|
|
|
273
303
|
export interface CartKeyParams {
|
package/utils/inject-files.ts
CHANGED
|
@@ -900,6 +900,14 @@ export async function injectTemplateFiles(
|
|
|
900
900
|
src: resolve('../templates/custom/shopify/cart.astro'),
|
|
901
901
|
dest: 'src/pages/cart.astro',
|
|
902
902
|
},
|
|
903
|
+
{
|
|
904
|
+
src: resolve('../templates/custom/shopify/cart-reset.astro'),
|
|
905
|
+
dest: 'src/pages/cart/reset.astro',
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
src: resolve('../templates/custom/shopify/CartReset.tsx'),
|
|
909
|
+
dest: 'src/custom/shopify/CartReset.tsx',
|
|
910
|
+
},
|
|
903
911
|
{
|
|
904
912
|
src: resolve('../templates/src/pages/privacy.astro'),
|
|
905
913
|
dest: 'src/pages/privacy.astro',
|
|
@@ -1518,18 +1526,6 @@ export async function injectTemplateFiles(
|
|
|
1518
1526
|
),
|
|
1519
1527
|
dest: 'src/components/codehooks/ListContentSetup.tsx',
|
|
1520
1528
|
},
|
|
1521
|
-
{
|
|
1522
|
-
src: resolve(
|
|
1523
|
-
'../templates/src/components/codehooks/ProductCardSetup.tsx'
|
|
1524
|
-
),
|
|
1525
|
-
dest: 'src/components/codehooks/ProductCardSetup.tsx',
|
|
1526
|
-
},
|
|
1527
|
-
{
|
|
1528
|
-
src: resolve(
|
|
1529
|
-
'../templates/src/components/codehooks/ProductGridSetup.tsx'
|
|
1530
|
-
),
|
|
1531
|
-
dest: 'src/components/codehooks/ProductGridSetup.tsx',
|
|
1532
|
-
},
|
|
1533
1529
|
{
|
|
1534
1530
|
src: resolve(
|
|
1535
1531
|
'../templates/src/components/codehooks/BunnyVideoWrapper.astro'
|
|
@@ -1541,6 +1537,32 @@ export async function injectTemplateFiles(
|
|
|
1541
1537
|
dest: 'src/components/codehooks/BunnyVideoSetup.tsx',
|
|
1542
1538
|
},
|
|
1543
1539
|
|
|
1540
|
+
// CodeHook Blades (partial routes; core hooks overwritable)
|
|
1541
|
+
{
|
|
1542
|
+
src: resolve('../templates/src/pages/codehooks/featured-article.astro'),
|
|
1543
|
+
dest: 'src/pages/codehooks/featured-article.astro',
|
|
1544
|
+
},
|
|
1545
|
+
{
|
|
1546
|
+
src: resolve('../templates/src/pages/codehooks/list-content.astro'),
|
|
1547
|
+
dest: 'src/pages/codehooks/list-content.astro',
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
src: resolve('../templates/src/pages/codehooks/search-widget.astro'),
|
|
1551
|
+
dest: 'src/pages/codehooks/search-widget.astro',
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
src: resolve('../templates/src/pages/codehooks/bunny-video.astro'),
|
|
1555
|
+
dest: 'src/pages/codehooks/bunny-video.astro',
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
src: resolve('../templates/src/pages/codehooks/epinet.astro'),
|
|
1559
|
+
dest: 'src/pages/codehooks/epinet.astro',
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
src: resolve('../templates/src/pages/codehooks/[...hookId].astro'),
|
|
1563
|
+
dest: 'src/pages/codehooks/[...hookId].astro',
|
|
1564
|
+
},
|
|
1565
|
+
|
|
1544
1566
|
// Widget Components
|
|
1545
1567
|
{
|
|
1546
1568
|
src: resolve('../templates/src/components/widgets/Impression.tsx'),
|
|
@@ -1568,6 +1590,10 @@ export async function injectTemplateFiles(
|
|
|
1568
1590
|
src: resolve('../templates/src/lib/resources.ts'),
|
|
1569
1591
|
dest: 'src/lib/resources.ts',
|
|
1570
1592
|
},
|
|
1593
|
+
{
|
|
1594
|
+
src: resolve('../templates/src/lib/codeHookHelper.ts'),
|
|
1595
|
+
dest: 'src/lib/codeHookHelper.ts',
|
|
1596
|
+
},
|
|
1571
1597
|
|
|
1572
1598
|
// Client Scripts
|
|
1573
1599
|
{
|
|
@@ -2357,15 +2383,6 @@ export async function injectTemplateFiles(
|
|
|
2357
2383
|
},
|
|
2358
2384
|
|
|
2359
2385
|
// Custom Components (Conditional)
|
|
2360
|
-
{
|
|
2361
|
-
src: resolve(
|
|
2362
|
-
config?.includeExamples
|
|
2363
|
-
? '../templates/custom/with-examples/CodeHook.astro'
|
|
2364
|
-
: '../templates/custom/minimal/CodeHook.astro'
|
|
2365
|
-
),
|
|
2366
|
-
dest: 'src/custom/CodeHook.astro',
|
|
2367
|
-
protected: true,
|
|
2368
|
-
},
|
|
2369
2386
|
{
|
|
2370
2387
|
src: resolve(
|
|
2371
2388
|
config?.includeExamples
|
|
@@ -2376,11 +2393,7 @@ export async function injectTemplateFiles(
|
|
|
2376
2393
|
protected: true,
|
|
2377
2394
|
},
|
|
2378
2395
|
{
|
|
2379
|
-
src: resolve(
|
|
2380
|
-
config?.includeExamples
|
|
2381
|
-
? '../templates/custom/with-examples/HeaderWidget.astro'
|
|
2382
|
-
: '../templates/custom/minimal/HeaderWidget.astro'
|
|
2383
|
-
),
|
|
2396
|
+
src: resolve('../templates/custom/minimal/HeaderWidget.astro'),
|
|
2384
2397
|
dest: 'src/custom/HeaderWidget.astro',
|
|
2385
2398
|
protected: true,
|
|
2386
2399
|
},
|
|
@@ -2450,6 +2463,33 @@ export async function injectTemplateFiles(
|
|
|
2450
2463
|
protected: true,
|
|
2451
2464
|
},
|
|
2452
2465
|
|
|
2466
|
+
// CodeHook manifest (frontend capability list; hand-maintained, protected)
|
|
2467
|
+
{
|
|
2468
|
+
src: resolve(
|
|
2469
|
+
config?.includeExamples
|
|
2470
|
+
? '../templates/custom/with-examples/codehooks.ts'
|
|
2471
|
+
: '../templates/custom/minimal/codehooks.ts'
|
|
2472
|
+
),
|
|
2473
|
+
dest: 'src/custom/codehooks.ts',
|
|
2474
|
+
protected: true,
|
|
2475
|
+
},
|
|
2476
|
+
|
|
2477
|
+
// CodeHook Blades (userland hooks; protected once installed)
|
|
2478
|
+
{
|
|
2479
|
+
src: resolve(
|
|
2480
|
+
'../templates/src/pages/codehooks/shopify-product-grid.astro'
|
|
2481
|
+
),
|
|
2482
|
+
dest: 'src/pages/codehooks/shopify-product-grid.astro',
|
|
2483
|
+
protected: true,
|
|
2484
|
+
},
|
|
2485
|
+
{
|
|
2486
|
+
src: resolve(
|
|
2487
|
+
'../templates/src/pages/codehooks/shopify-service-list.astro'
|
|
2488
|
+
),
|
|
2489
|
+
dest: 'src/pages/codehooks/shopify-service-list.astro',
|
|
2490
|
+
protected: true,
|
|
2491
|
+
},
|
|
2492
|
+
|
|
2453
2493
|
// Example Components (Conditional)
|
|
2454
2494
|
...(config?.includeExamples
|
|
2455
2495
|
? [
|
|
@@ -2466,20 +2506,13 @@ export async function injectTemplateFiles(
|
|
|
2466
2506
|
protected: true,
|
|
2467
2507
|
},
|
|
2468
2508
|
{
|
|
2469
|
-
src: resolve('../templates/custom
|
|
2470
|
-
dest: 'src/custom
|
|
2471
|
-
protected: true,
|
|
2472
|
-
},
|
|
2473
|
-
{
|
|
2474
|
-
src: resolve(
|
|
2475
|
-
'../templates/custom/with-examples/ProductCardWrapper.astro'
|
|
2476
|
-
),
|
|
2477
|
-
dest: 'src/custom/ProductCardWrapper.astro',
|
|
2509
|
+
src: resolve('../templates/src/pages/codehooks/custom-hero.astro'),
|
|
2510
|
+
dest: 'src/pages/codehooks/custom-hero.astro',
|
|
2478
2511
|
protected: true,
|
|
2479
2512
|
},
|
|
2480
2513
|
{
|
|
2481
|
-
src: resolve('../templates/
|
|
2482
|
-
dest: 'src/
|
|
2514
|
+
src: resolve('../templates/src/pages/codehooks/get-crafting.astro'),
|
|
2515
|
+
dest: 'src/pages/codehooks/get-crafting.astro',
|
|
2483
2516
|
protected: true,
|
|
2484
2517
|
},
|
|
2485
2518
|
{
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import FeaturedArticle from '@/components/codehooks/FeaturedArticle.astro';
|
|
3
|
-
import ListContent from '@/components/codehooks/ListContent.astro';
|
|
4
|
-
import SearchWidget from '@/components/codehooks/SearchWidget.tsx';
|
|
5
|
-
import BunnyVideoWrapper from '@/components/codehooks/BunnyVideoWrapper.astro';
|
|
6
|
-
import EpinetWrapper from '@/components/codehooks/EpinetWrapper';
|
|
7
|
-
import ShopifyProductGrid from '@/custom/shopify/ShopifyProductGrid';
|
|
8
|
-
import ShopifyServiceList from '@/custom/shopify/ShopifyServiceList';
|
|
9
|
-
import type { FullContentMapItem } from '@/types/tractstack';
|
|
10
|
-
import type { ResourceNode } from '@/types/compositorTypes';
|
|
11
|
-
// import CustomHero from './CustomHero.astro';
|
|
12
|
-
// Uncomment to add custom components
|
|
13
|
-
|
|
14
|
-
export interface Props {
|
|
15
|
-
target: string;
|
|
16
|
-
paneId: string;
|
|
17
|
-
fullContentMap: FullContentMapItem[];
|
|
18
|
-
resourcesPayload?: Record<string, ResourceNode[]>;
|
|
19
|
-
options?: {
|
|
20
|
-
params?: {
|
|
21
|
-
options?: string;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const { target, options, fullContentMap, resourcesPayload = {} } = Astro.props;
|
|
27
|
-
|
|
28
|
-
export const components = {
|
|
29
|
-
'featured-article': true,
|
|
30
|
-
'featured-content': true,
|
|
31
|
-
'list-content': true,
|
|
32
|
-
'search-widget': true,
|
|
33
|
-
'bunny-video': import.meta.env.PUBLIC_ENABLE_BUNNY === 'true',
|
|
34
|
-
epinet: true,
|
|
35
|
-
'shopify-product-grid': true,
|
|
36
|
-
'shopify-service-list': true,
|
|
37
|
-
// "custom-hero": true, // Uncomment when you create CustomHero.astro
|
|
38
|
-
};
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
target === 'list-content' ? (
|
|
43
|
-
<ListContent options={options} contentMap={fullContentMap} />
|
|
44
|
-
) : target === 'featured-article' ? (
|
|
45
|
-
<FeaturedArticle options={options} contentMap={fullContentMap} />
|
|
46
|
-
) : target === 'search-widget' ? (
|
|
47
|
-
<SearchWidget fullContentMap={fullContentMap} client:load />
|
|
48
|
-
) : target === 'bunny-video' && import.meta.env.PUBLIC_ENABLE_BUNNY ? (
|
|
49
|
-
<BunnyVideoWrapper options={options} />
|
|
50
|
-
) : target === 'epinet' ? (
|
|
51
|
-
<EpinetWrapper fullContentMap={fullContentMap} client:only="react" />
|
|
52
|
-
) : target === 'shopify-product-grid' ? (
|
|
53
|
-
<ShopifyProductGrid
|
|
54
|
-
options={options}
|
|
55
|
-
resources={resourcesPayload}
|
|
56
|
-
client:only="react"
|
|
57
|
-
/>
|
|
58
|
-
) : target === 'shopify-service-list' ? (
|
|
59
|
-
<ShopifyServiceList
|
|
60
|
-
options={options}
|
|
61
|
-
resources={resourcesPayload}
|
|
62
|
-
client:only="react"
|
|
63
|
-
/>
|
|
64
|
-
) : (
|
|
65
|
-
/* : target === "custom-hero" ? (
|
|
66
|
-
<CustomHero />
|
|
67
|
-
) */
|
|
68
|
-
<div class="rounded-lg bg-gray-50 p-8 text-center">
|
|
69
|
-
<p class="text-gray-600">CodeHook target "{target}" not found</p>
|
|
70
|
-
</div>
|
|
71
|
-
)
|
|
72
|
-
}
|