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
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
2
|
import { useStore } from '@nanostores/react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
epinetCustomFilters,
|
|
5
|
+
getEpinetCustomFilters,
|
|
6
|
+
setEpinetCustomFilters,
|
|
7
|
+
} from '@/stores/analytics';
|
|
4
8
|
import { TractStackAPI } from '@/utils/api';
|
|
5
9
|
|
|
6
10
|
const VERBOSE = false;
|
|
@@ -252,7 +256,7 @@ class AnalyticsService {
|
|
|
252
256
|
this.setCachedResponse(cacheKey, analyticsData);
|
|
253
257
|
onUpdate(analyticsData);
|
|
254
258
|
|
|
255
|
-
|
|
259
|
+
setEpinetCustomFilters(window.TRACTSTACK_CONFIG?.tenantId || 'default', {
|
|
256
260
|
...filters,
|
|
257
261
|
availableFilters: data.availableFilters || [],
|
|
258
262
|
});
|
|
@@ -298,9 +302,9 @@ class AnalyticsService {
|
|
|
298
302
|
if (VERBOSE) console.log('🏁 Initializing analytics filters');
|
|
299
303
|
const nowUTC = new Date();
|
|
300
304
|
const oneWeekAgoUTC = new Date(nowUTC.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
301
|
-
const current =
|
|
305
|
+
const current = getEpinetCustomFilters();
|
|
302
306
|
if (!current.enabled) {
|
|
303
|
-
|
|
307
|
+
setEpinetCustomFilters(tenantId, {
|
|
304
308
|
enabled: true,
|
|
305
309
|
visitorType: 'all',
|
|
306
310
|
selectedUserId: null,
|
|
@@ -139,7 +139,7 @@ export default function Wizard({
|
|
|
139
139
|
const buildWizardData = async () => {
|
|
140
140
|
try {
|
|
141
141
|
const homePage = activeContentMap.find(
|
|
142
|
-
(item) => item.slug === homeSlug
|
|
142
|
+
(item: FullContentMapItem) => item.slug === homeSlug
|
|
143
143
|
);
|
|
144
144
|
|
|
145
145
|
let homeData = null;
|
|
@@ -173,7 +173,9 @@ export default function Wizard({
|
|
|
173
173
|
hasPanes: !!homePage?.panes?.length,
|
|
174
174
|
hasSeo: !!homePage?.description,
|
|
175
175
|
hasMenu: !!homeData?.menuId,
|
|
176
|
-
hasAnyMenu: activeContentMap.some(
|
|
176
|
+
hasAnyMenu: activeContentMap.some(
|
|
177
|
+
(item: FullContentMapItem) => item.type === 'Menu'
|
|
178
|
+
),
|
|
177
179
|
};
|
|
178
180
|
|
|
179
181
|
setWizardData(data);
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { getCachedFullContentMap, getFullContentMap } from '@/stores/analytics';
|
|
2
|
+
import { getCodeHookResources } from '@/lib/resources';
|
|
3
|
+
import type { ResourceNode } from '@/types/compositorTypes';
|
|
4
|
+
|
|
5
|
+
export interface CodeHookBladeContext {
|
|
6
|
+
tenantId: string;
|
|
7
|
+
paneId: string;
|
|
8
|
+
optionsStr: string;
|
|
9
|
+
options?: { params: { options: string } };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CodeHookResourceFilters {
|
|
13
|
+
categories: string[];
|
|
14
|
+
slugs: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function parseCodeHookBladeContext(
|
|
18
|
+
searchParams: URLSearchParams
|
|
19
|
+
): CodeHookBladeContext {
|
|
20
|
+
const tenantId = searchParams.get('tenantId') || 'default';
|
|
21
|
+
const paneId = searchParams.get('paneId') || '';
|
|
22
|
+
const optionsStr = searchParams.get('options') || '';
|
|
23
|
+
const options = optionsStr ? { params: { options: optionsStr } } : undefined;
|
|
24
|
+
return { tenantId, paneId, optionsStr, options };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function resolveCodeHookFullContentMap(
|
|
28
|
+
tenantId: string
|
|
29
|
+
): Promise<any[]> {
|
|
30
|
+
let fullContentMap = getCachedFullContentMap(tenantId);
|
|
31
|
+
if (!fullContentMap.length) {
|
|
32
|
+
fullContentMap = await getFullContentMap(tenantId);
|
|
33
|
+
}
|
|
34
|
+
return fullContentMap;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function parseCodeHookResourceFilters(
|
|
38
|
+
optionsStr: string,
|
|
39
|
+
logLabel?: string
|
|
40
|
+
): CodeHookResourceFilters {
|
|
41
|
+
const categories: string[] = [];
|
|
42
|
+
const slugs: string[] = [];
|
|
43
|
+
if (!optionsStr) {
|
|
44
|
+
return { categories, slugs };
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const parsed = JSON.parse(optionsStr);
|
|
48
|
+
if (typeof parsed.category === 'string' && parsed.category) {
|
|
49
|
+
categories.push(...parsed.category.split('|'));
|
|
50
|
+
}
|
|
51
|
+
if (typeof parsed.slugs === 'string' && parsed.slugs) {
|
|
52
|
+
slugs.push(...parsed.slugs.split(','));
|
|
53
|
+
}
|
|
54
|
+
if (typeof parsed.slug === 'string' && parsed.slug) {
|
|
55
|
+
slugs.push(parsed.slug);
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error(`Invalid options for ${logLabel ?? 'codehook resources'}`, e);
|
|
59
|
+
}
|
|
60
|
+
return { categories, slugs };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function resolveCodeHookResources(
|
|
64
|
+
tenantId: string,
|
|
65
|
+
optionsStr: string,
|
|
66
|
+
logLabel?: string
|
|
67
|
+
): Promise<ResourceNode[]> {
|
|
68
|
+
const { categories, slugs } = parseCodeHookResourceFilters(
|
|
69
|
+
optionsStr,
|
|
70
|
+
logLabel
|
|
71
|
+
);
|
|
72
|
+
return getCodeHookResources(tenantId, categories, slugs);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function buildCodeHookBladePath(
|
|
76
|
+
hookId: string,
|
|
77
|
+
ctx: Pick<CodeHookBladeContext, 'paneId' | 'tenantId' | 'optionsStr'>
|
|
78
|
+
): string {
|
|
79
|
+
const params = new URLSearchParams({
|
|
80
|
+
paneId: ctx.paneId,
|
|
81
|
+
tenantId: ctx.tenantId,
|
|
82
|
+
});
|
|
83
|
+
if (ctx.optionsStr) {
|
|
84
|
+
params.set('options', ctx.optionsStr);
|
|
85
|
+
}
|
|
86
|
+
return `/codehooks/${hookId}?${params.toString()}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function resolveSSRFetchOrigin(pageUrl: URL, siteUrl?: string): string {
|
|
90
|
+
if (siteUrl) {
|
|
91
|
+
try {
|
|
92
|
+
return new URL(siteUrl).origin;
|
|
93
|
+
} catch {
|
|
94
|
+
// fall through to page origin
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return pageUrl.origin;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function fetchCodeHookBladeHtml(
|
|
101
|
+
bladePath: string,
|
|
102
|
+
request: Request,
|
|
103
|
+
origin: string
|
|
104
|
+
): Promise<string> {
|
|
105
|
+
try {
|
|
106
|
+
const url = new URL(bladePath, origin);
|
|
107
|
+
const res = await fetch(url, {
|
|
108
|
+
headers: {
|
|
109
|
+
cookie: request.headers.get('cookie') ?? '',
|
|
110
|
+
accept: 'text/html',
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
console.error(
|
|
115
|
+
`Failed to SSR-fetch codehook blade ${bladePath}. Status: ${res.status}`
|
|
116
|
+
);
|
|
117
|
+
return '';
|
|
118
|
+
}
|
|
119
|
+
return res.text();
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`Error SSR-fetching codehook blade ${bladePath}:`, error);
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function fetchCodeHookBladesForPanes(options: {
|
|
127
|
+
paneIds: string[];
|
|
128
|
+
codeHookTargets: Record<string, string>;
|
|
129
|
+
tenantId: string;
|
|
130
|
+
request: Request;
|
|
131
|
+
origin: string;
|
|
132
|
+
}): Promise<Record<string, string>> {
|
|
133
|
+
const { paneIds, codeHookTargets, tenantId, request, origin } = options;
|
|
134
|
+
const result: Record<string, string> = {};
|
|
135
|
+
|
|
136
|
+
await Promise.all(
|
|
137
|
+
paneIds
|
|
138
|
+
.filter((paneId) => codeHookTargets[paneId])
|
|
139
|
+
.map(async (paneId) => {
|
|
140
|
+
const hookId = codeHookTargets[paneId];
|
|
141
|
+
const optionsStr = codeHookTargets[`${paneId}-${hookId}`] || '';
|
|
142
|
+
const bladePath = buildCodeHookBladePath(hookId, {
|
|
143
|
+
paneId,
|
|
144
|
+
tenantId,
|
|
145
|
+
optionsStr,
|
|
146
|
+
});
|
|
147
|
+
result[paneId] = await fetchCodeHookBladeHtml(
|
|
148
|
+
bladePath,
|
|
149
|
+
request,
|
|
150
|
+
origin
|
|
151
|
+
);
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
import { headerResourcesStore, HEADER_RESOURCES_TTL } from '@/stores/resources';
|
|
2
2
|
import type { ResourceNode } from '@/types/compositorTypes';
|
|
3
3
|
|
|
4
|
+
// Stateless resource fetch for codehook blades. POSTs categories/slugs to the
|
|
5
|
+
// nodes/resources endpoint, unwraps the { resources, count } envelope, and
|
|
6
|
+
// returns the FLAT ResourceNode[] (the API shape) unchanged - no grouping.
|
|
7
|
+
// Components that need a keyed view reshape internally. No cache.
|
|
8
|
+
export async function getCodeHookResources(
|
|
9
|
+
tenantId: string,
|
|
10
|
+
categories: string[] = [],
|
|
11
|
+
slugs: string[] = []
|
|
12
|
+
): Promise<ResourceNode[]> {
|
|
13
|
+
if (categories.length === 0 && slugs.length === 0) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const goBackend =
|
|
18
|
+
import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(`${goBackend}/api/v1/nodes/resources`, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
'X-Tenant-ID': tenantId,
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({ categories, slugs }),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
console.error(
|
|
32
|
+
`Failed to fetch codehook resources. Status: ${response.status}`
|
|
33
|
+
);
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const payload = await response.json();
|
|
38
|
+
return (payload.resources as ResourceNode[]) || [];
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Error fetching codehook resources:', error);
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
4
45
|
export async function getHeaderResources(
|
|
5
46
|
tenantId: string,
|
|
6
47
|
categories: string[],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { handleFailedResponse } from '@/utils/backend';
|
|
2
|
-
import type { ImpressionNode
|
|
2
|
+
import type { ImpressionNode } from '@/types/compositorTypes';
|
|
3
3
|
|
|
4
4
|
export interface StoryData {
|
|
5
5
|
id: string;
|
|
@@ -8,7 +8,6 @@ export interface StoryData {
|
|
|
8
8
|
paneIds: string[];
|
|
9
9
|
codeHookTargets: Record<string, string>;
|
|
10
10
|
codeHookVisibility: Record<string, boolean | string[]>;
|
|
11
|
-
resourcesPayload: Record<string, ResourceNode[]>;
|
|
12
11
|
impressions: ImpressionNode[];
|
|
13
12
|
fragments: Record<string, string>;
|
|
14
13
|
menu: any;
|
|
@@ -6,7 +6,7 @@ import { getFullContentMap } from '@/stores/analytics';
|
|
|
6
6
|
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
7
7
|
import { joinUrlPaths } from '@/utils/helpers';
|
|
8
8
|
import { handleFailedResponse } from '@/utils/backend';
|
|
9
|
-
import {
|
|
9
|
+
import { availableCodeHookIds } from '@/custom/codehooks';
|
|
10
10
|
import StoryKeepHeader from '@/components/edit/Header';
|
|
11
11
|
import StoryKeepToolBar from '@/components/edit/ToolBar';
|
|
12
12
|
import StoryKeepToolMode from '@/components/edit/ToolMode';
|
|
@@ -188,7 +188,7 @@ for (const [key, value] of Astro.url.searchParams) {
|
|
|
188
188
|
fullContentMap={fullContentMap}
|
|
189
189
|
fullCanonicalURL={fullCanonicalURL}
|
|
190
190
|
urlParams={urlParams}
|
|
191
|
-
availableCodeHooks={
|
|
191
|
+
availableCodeHooks={availableCodeHookIds}
|
|
192
192
|
client:only="react"
|
|
193
193
|
/>
|
|
194
194
|
</div>
|
|
@@ -213,7 +213,7 @@ for (const [key, value] of Astro.url.searchParams) {
|
|
|
213
213
|
}
|
|
214
214
|
<div class="pointer-events-auto max-h-full">
|
|
215
215
|
<SettingsPanel
|
|
216
|
-
availableCodeHooks={
|
|
216
|
+
availableCodeHooks={availableCodeHookIds}
|
|
217
217
|
client:only="react"
|
|
218
218
|
/>
|
|
219
219
|
</div>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Layout from '@/layouts/Layout.astro';
|
|
3
|
-
import CodeHook from '@/custom/CodeHook.astro';
|
|
4
3
|
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
5
4
|
import { getFullContentMap } from '@/stores/analytics';
|
|
6
5
|
import { getOrSetSessionId } from '@/lib/session';
|
|
7
6
|
import { getStoryData } from '@/lib/storyData';
|
|
7
|
+
import {
|
|
8
|
+
fetchCodeHookBladesForPanes,
|
|
9
|
+
resolveSSRFetchOrigin,
|
|
10
|
+
} from '@/lib/codeHookHelper';
|
|
8
11
|
import { preHealthCheck } from '@/utils/backend';
|
|
9
12
|
|
|
10
13
|
const tenantId =
|
|
@@ -43,7 +46,6 @@ const storyfragmentId = storyData.id;
|
|
|
43
46
|
const storyfragmentTitle = storyData.title || 'Untitled Story';
|
|
44
47
|
const paneIds = storyData.paneIds || [];
|
|
45
48
|
const codeHookTargets = storyData.codeHookTargets || {};
|
|
46
|
-
const resourcesPayload = storyData.resourcesPayload || {};
|
|
47
49
|
|
|
48
50
|
if (paneIds.length === 0) {
|
|
49
51
|
console.log(`Empty Story Fragment. Redirecting to /storykeep`);
|
|
@@ -66,6 +68,14 @@ if (!brandConfig.SITE_INIT) {
|
|
|
66
68
|
return Astro.redirect('/storykeep');
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
const codeHookHtml = await fetchCodeHookBladesForPanes({
|
|
72
|
+
paneIds,
|
|
73
|
+
codeHookTargets,
|
|
74
|
+
tenantId,
|
|
75
|
+
request: Astro.request,
|
|
76
|
+
origin: resolveSSRFetchOrigin(Astro.url, brandConfig.SITE_URL),
|
|
77
|
+
});
|
|
78
|
+
|
|
69
79
|
const ogImage =
|
|
70
80
|
typeof storyData.socialImagePath === `string`
|
|
71
81
|
? storyData.socialImagePath
|
|
@@ -95,77 +105,73 @@ paneIds.forEach((paneId: string) => {
|
|
|
95
105
|
<main id="main-content" class="w-full">
|
|
96
106
|
<div class="panes-container">
|
|
97
107
|
{
|
|
98
|
-
paneIds.map((paneId: string) =>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
unsetBeliefIds:
|
|
141
|
-
storyData.codeHookVisibility[paneId].join(','),
|
|
142
|
-
paneId: paneId,
|
|
143
|
-
})}
|
|
144
|
-
hx-preserve="true"
|
|
145
|
-
>
|
|
146
|
-
<svg
|
|
147
|
-
class="h-6 w-6"
|
|
148
|
-
fill="none"
|
|
149
|
-
viewBox="0 0 24 24"
|
|
150
|
-
stroke-width="1.5"
|
|
151
|
-
stroke="currentColor"
|
|
108
|
+
paneIds.map((paneId: string) => {
|
|
109
|
+
const hookId = codeHookTargets[paneId];
|
|
110
|
+
const isCodeHook = !!hookId;
|
|
111
|
+
return (
|
|
112
|
+
<div id={paneSlugLookup[paneId]}>
|
|
113
|
+
<div
|
|
114
|
+
id={`pane-${paneId}`}
|
|
115
|
+
data-pane-id={paneId}
|
|
116
|
+
class="pane-fragment-container"
|
|
117
|
+
style={
|
|
118
|
+
!isCodeHook
|
|
119
|
+
? undefined
|
|
120
|
+
: !storyData.codeHookVisibility?.[paneId]
|
|
121
|
+
? 'display:none;'
|
|
122
|
+
: 'display:block;'
|
|
123
|
+
}
|
|
124
|
+
hx-get={
|
|
125
|
+
!isCodeHook ? `/api/v1/fragments/panes/${paneId}` : undefined
|
|
126
|
+
}
|
|
127
|
+
hx-trigger={!isCodeHook ? 'refresh' : undefined}
|
|
128
|
+
hx-swap={!isCodeHook ? 'innerHTML scroll:none' : undefined}
|
|
129
|
+
>
|
|
130
|
+
{isCodeHook ? (
|
|
131
|
+
<div class="relative overflow-hidden">
|
|
132
|
+
<Fragment set:html={codeHookHtml[paneId] || ''} />
|
|
133
|
+
<div id={`pane-${paneId}-unset`}>
|
|
134
|
+
{Array.isArray(
|
|
135
|
+
storyData.codeHookVisibility?.[paneId]
|
|
136
|
+
) && (
|
|
137
|
+
<button
|
|
138
|
+
type="button"
|
|
139
|
+
class="absolute right-2 top-2 z-10 rounded-full bg-white p-1.5 text-mydarkgrey hover:bg-black hover:text-white"
|
|
140
|
+
title="Go Back"
|
|
141
|
+
hx-post="/api/v1/state"
|
|
142
|
+
hx-trigger="click"
|
|
143
|
+
hx-swap="none"
|
|
144
|
+
hx-vals={JSON.stringify({
|
|
145
|
+
unsetBeliefIds:
|
|
146
|
+
storyData.codeHookVisibility[paneId].join(','),
|
|
147
|
+
paneId: paneId,
|
|
148
|
+
})}
|
|
149
|
+
hx-preserve="true"
|
|
152
150
|
>
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
<svg
|
|
152
|
+
class="h-6 w-6"
|
|
153
|
+
fill="none"
|
|
154
|
+
viewBox="0 0 24 24"
|
|
155
|
+
stroke-width="1.5"
|
|
156
|
+
stroke="currentColor"
|
|
157
|
+
>
|
|
158
|
+
<path
|
|
159
|
+
stroke-linecap="round"
|
|
160
|
+
stroke-linejoin="round"
|
|
161
|
+
d="M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3"
|
|
162
|
+
/>
|
|
163
|
+
</svg>
|
|
164
|
+
</button>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
161
167
|
</div>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
168
|
+
) : (
|
|
169
|
+
<Fragment set:html={storyData.fragments[paneId] || ''} />
|
|
170
|
+
)}
|
|
171
|
+
</div>
|
|
166
172
|
</div>
|
|
167
|
-
|
|
168
|
-
)
|
|
173
|
+
);
|
|
174
|
+
})
|
|
169
175
|
}
|
|
170
176
|
</div>
|
|
171
177
|
</main>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
const hookId = Astro.params.hookId || '';
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<div class="my-4 w-full bg-gray-50 p-6">
|
|
7
|
+
<div
|
|
8
|
+
class="mb-4 rounded-lg border-2 border-dashed border-gray-300 bg-slate-50 p-6"
|
|
9
|
+
>
|
|
10
|
+
<h3 class="text-lg text-gray-700">
|
|
11
|
+
Code Hook:{' '}
|
|
12
|
+
<span class="font-action font-bold">{hookId || 'unknown'}</span>
|
|
13
|
+
</h3>
|
|
14
|
+
<p class="mt-2 text-sm text-gray-500">
|
|
15
|
+
CodeHook not activated for this install.
|
|
16
|
+
</p>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import BunnyVideoWrapper from '@/components/codehooks/BunnyVideoWrapper.astro';
|
|
4
|
+
import { parseCodeHookBladeContext } from '@/lib/codeHookHelper';
|
|
5
|
+
|
|
6
|
+
const { options } = parseCodeHookBladeContext(Astro.url.searchParams);
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<BunnyVideoWrapper options={options} />
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import EpinetWrapper from '@/components/codehooks/EpinetWrapper';
|
|
4
|
+
import {
|
|
5
|
+
parseCodeHookBladeContext,
|
|
6
|
+
resolveCodeHookFullContentMap,
|
|
7
|
+
} from '@/lib/codeHookHelper';
|
|
8
|
+
|
|
9
|
+
const { tenantId } = parseCodeHookBladeContext(Astro.url.searchParams);
|
|
10
|
+
const fullContentMap = await resolveCodeHookFullContentMap(tenantId);
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<div style="min-height: 400px;">
|
|
14
|
+
<EpinetWrapper fullContentMap={fullContentMap} client:only="react" />
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import FeaturedArticle from '@/components/codehooks/FeaturedArticle.astro';
|
|
4
|
+
import {
|
|
5
|
+
parseCodeHookBladeContext,
|
|
6
|
+
resolveCodeHookFullContentMap,
|
|
7
|
+
} from '@/lib/codeHookHelper';
|
|
8
|
+
|
|
9
|
+
const { tenantId, options } = parseCodeHookBladeContext(Astro.url.searchParams);
|
|
10
|
+
const fullContentMap = await resolveCodeHookFullContentMap(tenantId);
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<FeaturedArticle options={options} fullContentMap={fullContentMap} />
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import ListContent from '@/components/codehooks/ListContent.astro';
|
|
4
|
+
import {
|
|
5
|
+
parseCodeHookBladeContext,
|
|
6
|
+
resolveCodeHookFullContentMap,
|
|
7
|
+
} from '@/lib/codeHookHelper';
|
|
8
|
+
|
|
9
|
+
const { tenantId, options } = parseCodeHookBladeContext(Astro.url.searchParams);
|
|
10
|
+
const fullContentMap = await resolveCodeHookFullContentMap(tenantId);
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<ListContent options={options} fullContentMap={fullContentMap} />
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import SearchWidget from '@/components/codehooks/SearchWidget.tsx';
|
|
4
|
+
import {
|
|
5
|
+
parseCodeHookBladeContext,
|
|
6
|
+
resolveCodeHookFullContentMap,
|
|
7
|
+
} from '@/lib/codeHookHelper';
|
|
8
|
+
|
|
9
|
+
const { tenantId } = parseCodeHookBladeContext(Astro.url.searchParams);
|
|
10
|
+
const fullContentMap = await resolveCodeHookFullContentMap(tenantId);
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<SearchWidget fullContentMap={fullContentMap} client:load />
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import ShopifyProductGrid from '@/custom/shopify/ShopifyProductGrid';
|
|
4
|
+
import {
|
|
5
|
+
parseCodeHookBladeContext,
|
|
6
|
+
resolveCodeHookResources,
|
|
7
|
+
} from '@/lib/codeHookHelper';
|
|
8
|
+
|
|
9
|
+
const { tenantId, optionsStr, options } = parseCodeHookBladeContext(
|
|
10
|
+
Astro.url.searchParams
|
|
11
|
+
);
|
|
12
|
+
const resources = await resolveCodeHookResources(
|
|
13
|
+
tenantId,
|
|
14
|
+
optionsStr,
|
|
15
|
+
'shopify-product-grid'
|
|
16
|
+
);
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<div style="min-height: 400px;">
|
|
20
|
+
<ShopifyProductGrid
|
|
21
|
+
options={options}
|
|
22
|
+
resources={resources}
|
|
23
|
+
client:only="react"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
export const partial = true;
|
|
3
|
+
import ShopifyServiceList from '@/custom/shopify/ShopifyServiceList';
|
|
4
|
+
import {
|
|
5
|
+
parseCodeHookBladeContext,
|
|
6
|
+
resolveCodeHookResources,
|
|
7
|
+
} from '@/lib/codeHookHelper';
|
|
8
|
+
|
|
9
|
+
const { tenantId, optionsStr, options } = parseCodeHookBladeContext(
|
|
10
|
+
Astro.url.searchParams
|
|
11
|
+
);
|
|
12
|
+
const resources = await resolveCodeHookResources(
|
|
13
|
+
tenantId,
|
|
14
|
+
optionsStr,
|
|
15
|
+
'shopify-service-list'
|
|
16
|
+
);
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<div style="min-height: 300px;">
|
|
20
|
+
<ShopifyServiceList
|
|
21
|
+
options={options}
|
|
22
|
+
resources={resources}
|
|
23
|
+
client:only="react"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
@@ -6,7 +6,7 @@ import { getFullContentMap } from '@/stores/analytics';
|
|
|
6
6
|
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
7
7
|
import { joinUrlPaths } from '@/utils/helpers';
|
|
8
8
|
import { handleFailedResponse } from '@/utils/backend';
|
|
9
|
-
import {
|
|
9
|
+
import { availableCodeHookIds } from '@/custom/codehooks';
|
|
10
10
|
import StoryKeepHeader from '@/components/edit/Header';
|
|
11
11
|
import StoryKeepToolBar from '@/components/edit/ToolBar';
|
|
12
12
|
import StoryKeepToolMode from '@/components/edit/ToolMode';
|
|
@@ -175,7 +175,7 @@ for (const [key, value] of Astro.url.searchParams) {
|
|
|
175
175
|
fullContentMap={fullContentMap}
|
|
176
176
|
fullCanonicalURL={canonicalURL}
|
|
177
177
|
urlParams={urlParams}
|
|
178
|
-
availableCodeHooks={
|
|
178
|
+
availableCodeHooks={availableCodeHookIds}
|
|
179
179
|
client:only="react"
|
|
180
180
|
/>
|
|
181
181
|
</div>
|
|
@@ -201,7 +201,7 @@ for (const [key, value] of Astro.url.searchParams) {
|
|
|
201
201
|
<div class="pointer-events-auto max-h-full">
|
|
202
202
|
<SettingsPanel
|
|
203
203
|
config={brandConfig}
|
|
204
|
-
availableCodeHooks={
|
|
204
|
+
availableCodeHooks={availableCodeHookIds}
|
|
205
205
|
client:only="react"
|
|
206
206
|
/>
|
|
207
207
|
</div>
|