astro-tractstack 2.0.0-rc.9 → 2.0.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/LICENSE +8 -97
- package/README.md +7 -5
- package/bin/create-tractstack.js +31 -8
- package/dist/index.js +106 -29
- package/package.json +10 -5
- package/templates/css/frontend.css +1 -1
- package/templates/custom/minimal/CodeHook.astro +13 -12
- package/templates/custom/minimal/CustomRoutes.astro +25 -31
- package/templates/custom/with-examples/CodeHook.astro +22 -11
- package/templates/custom/with-examples/CustomRoutes.astro +4 -8
- package/templates/custom/with-examples/ProductCard.astro +29 -0
- package/templates/custom/with-examples/ProductCardWrapper.astro +43 -0
- package/templates/custom/with-examples/ProductGrid.astro +64 -0
- package/templates/custom/with-examples/pages/Collections.astro +58 -98
- package/templates/gitignore +42 -0
- package/templates/prettierignore +5 -0
- package/templates/prettierrc +19 -0
- package/templates/src/client/app.js +127 -0
- package/templates/src/client/htmx.min.js +3519 -0
- package/templates/src/client/view.js +429 -0
- package/templates/src/components/Footer.astro +4 -9
- package/templates/src/components/Header.astro +67 -60
- package/templates/src/components/Menu.tsx +188 -52
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +2 -2
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +9 -13
- package/templates/src/components/codehooks/EpinetTableView.tsx +11 -7
- package/templates/src/components/codehooks/EpinetWrapper.tsx +10 -9
- package/templates/src/components/codehooks/FeaturedArticle.astro +105 -0
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +318 -0
- package/templates/src/components/codehooks/ListContent.astro +32 -162
- package/templates/src/components/codehooks/ListContentSetup.tsx +43 -138
- package/templates/src/components/codehooks/ProductCardSetup.tsx +152 -0
- package/templates/src/components/codehooks/ProductGridSetup.tsx +274 -0
- package/templates/src/components/codehooks/SearchWidget.tsx +453 -0
- package/templates/src/components/compositor/Node.tsx +3 -6
- package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +21 -11
- package/templates/src/components/compositor/elements/BunnyVideo.tsx +21 -20
- package/templates/src/components/compositor/nodes/Pane.tsx +51 -21
- package/templates/src/components/compositor/nodes/RenderChildren.tsx +6 -1
- package/templates/src/components/compositor/nodes/Widget.tsx +16 -2
- package/templates/src/components/compositor/preview/FeaturedArticlePreview.tsx +155 -0
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +20 -1
- package/templates/src/components/edit/Header.tsx +10 -4
- package/templates/src/components/edit/PanelSwitch.tsx +11 -7
- package/templates/src/components/edit/SettingsPanel.tsx +29 -18
- package/templates/src/components/edit/ToolBar.tsx +1 -28
- package/templates/src/components/edit/ToolMode.tsx +45 -32
- package/templates/src/components/edit/pane/AddPanePanel_break.tsx +12 -2
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +8 -2
- package/templates/src/components/edit/pane/AddPanePanel_newAICopy_modal.tsx +1 -1
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +17 -27
- package/templates/src/components/edit/pane/PageGenSelector.tsx +16 -16
- package/templates/src/components/edit/pane/PageGenSpecial.tsx +26 -49
- package/templates/src/components/edit/pane/PageGen_preview.tsx +17 -2
- package/templates/src/components/edit/pane/PanePanel_path.tsx +2 -4
- package/templates/src/components/edit/pane/PanePanel_title.tsx +243 -76
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +17 -19
- package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +48 -37
- package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +60 -55
- package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +56 -50
- package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +54 -47
- package/templates/src/components/edit/panels/StyleLinkPanel_add.tsx +54 -44
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +113 -138
- package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +54 -40
- package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +3 -3
- package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +56 -49
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +14 -5
- package/templates/src/components/edit/state/SaveModal.tsx +316 -169
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +1 -1
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +56 -55
- package/templates/src/components/edit/widgets/BunnyWidget.tsx +538 -59
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +656 -0
- package/templates/src/components/edit/widgets/ToggleWidget.tsx +9 -16
- package/templates/src/components/fields/ArtpackImage.tsx +4 -1
- package/templates/src/components/fields/BackgroundImage.tsx +1 -1
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +127 -35
- package/templates/src/components/fields/ColorPickerCombo.tsx +66 -62
- package/templates/src/components/fields/ImageUpload.tsx +1 -1
- package/templates/src/components/fields/ViewportComboBox.tsx +59 -42
- package/templates/src/components/form/ActionBuilderBeliefSelector.tsx +117 -0
- package/templates/src/components/form/ActionBuilderField.tsx +306 -87
- package/templates/src/components/search/SearchModal.tsx +420 -0
- package/templates/src/components/search/SearchResults.tsx +367 -0
- package/templates/src/components/search/SearchWrapper.tsx +46 -0
- package/templates/src/components/storykeep/Dashboard_Advanced.tsx +1 -1
- package/templates/src/components/storykeep/Dashboard_Analytics.tsx +34 -8
- package/templates/src/components/storykeep/Dashboard_Branding.tsx +1 -1
- package/templates/src/components/storykeep/Dashboard_Content.tsx +6 -0
- package/templates/src/components/storykeep/StoryKeepBackdrop.astro +87 -0
- package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +38 -34
- package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +1 -1
- package/templates/src/components/storykeep/controls/content/MenuForm.tsx +56 -8
- package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +18 -3
- package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +5 -8
- package/templates/src/components/storykeep/state/FetchAnalytics.tsx +274 -228
- package/templates/src/components/storykeep/widgets/Wizard.tsx +14 -7
- package/templates/src/components/widgets/ImpressionWrapper.tsx +0 -1
- package/templates/src/constants/shapes.ts +9 -0
- package/templates/src/constants.ts +2121 -16
- package/templates/src/hooks/useSearch.ts +228 -0
- package/templates/src/layouts/Layout.astro +213 -104
- package/templates/src/lib/storyData.ts +4 -1
- package/templates/src/pages/[...slug]/edit.astro +14 -14
- package/templates/src/pages/[...slug].astro +82 -21
- package/templates/src/pages/api/orphan-analysis.ts +0 -1
- package/templates/src/pages/api/tailwind.ts +23 -21
- package/templates/src/pages/context/[...contextSlug]/edit.astro +14 -14
- package/templates/src/pages/context/[...contextSlug].astro +7 -2
- package/templates/src/pages/storykeep/advanced.astro +5 -4
- package/templates/src/pages/storykeep/branding.astro +5 -4
- package/templates/src/pages/storykeep/content.astro +5 -4
- package/templates/src/pages/storykeep/init.astro +40 -1
- package/templates/src/pages/storykeep/login.astro +1 -1
- package/templates/src/pages/storykeep.astro +5 -4
- package/templates/src/stores/nodes.ts +59 -88
- package/templates/src/stores/orphanAnalysis.ts +19 -21
- package/templates/src/stores/storykeep.ts +7 -0
- package/templates/src/types/compositorTypes.ts +6 -0
- package/templates/src/types/tractstack.ts +17 -0
- package/templates/src/utils/actions/lispLexer.ts +2 -2
- package/templates/src/utils/actions/preParse_Action.ts +3 -0
- package/templates/src/utils/api/beliefHelpers.ts +12 -36
- package/templates/src/utils/api/menuHelpers.ts +2 -2
- package/templates/src/utils/api.ts +26 -0
- package/templates/src/utils/compositor/TemplateNodes.ts +7 -0
- package/templates/src/utils/compositor/allowInsert.ts +5 -3
- package/templates/src/utils/compositor/nodesHelper.ts +4 -0
- package/templates/src/utils/compositor/processMarkdown.ts +16 -2
- package/templates/src/utils/compositor/reduceNodesClassNames.ts +4 -0
- package/templates/src/utils/compositor/templateMarkdownStyles.ts +13 -13
- package/templates/src/utils/compositor/typeGuards.ts +1 -0
- package/templates/src/utils/customHelpers.ts +38 -0
- package/templates/src/utils/helpers.ts +2 -2
- package/templates/src/utils/layout.ts +65 -144
- package/utils/inject-files.ts +95 -18
- package/templates/src/client/analytics-events.js +0 -207
- package/templates/src/client/belief-events.js +0 -191
- package/templates/src/client/sse.js +0 -613
- package/templates/src/components/codehooks/FeaturedContent.astro +0 -273
- package/templates/src/components/codehooks/FeaturedContentSetup.tsx +0 -738
- package/templates/src/components/compositor/preview/FeaturedContentPreview.tsx +0 -128
- package/templates/src/components/edit/pane/PanePanel_slug.tsx +0 -219
package/utils/inject-files.ts
CHANGED
|
@@ -29,7 +29,15 @@ export async function injectTemplateFiles(
|
|
|
29
29
|
dest: 'env.example',
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
|
-
src: resolve('../templates
|
|
32
|
+
src: resolve('../templates/prettierrc'),
|
|
33
|
+
dest: '.prettierrc',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
src: resolve('../templates/prettierignore'),
|
|
37
|
+
dest: '.prettierignore',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
src: resolve('../templates/gitignore'),
|
|
33
41
|
dest: '.gitignore',
|
|
34
42
|
},
|
|
35
43
|
{
|
|
@@ -222,6 +230,12 @@ export async function injectTemplateFiles(
|
|
|
222
230
|
src: resolve('../templates/src/components/edit/widgets/BeliefWidget.tsx'),
|
|
223
231
|
dest: 'src/components/edit/widgets/BeliefWidget.tsx',
|
|
224
232
|
},
|
|
233
|
+
{
|
|
234
|
+
src: resolve(
|
|
235
|
+
'../templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx'
|
|
236
|
+
),
|
|
237
|
+
dest: 'src/components/edit/widgets/InteractiveDisclosureWidget.tsx',
|
|
238
|
+
},
|
|
225
239
|
{
|
|
226
240
|
src: resolve(
|
|
227
241
|
'../templates/src/components/edit/widgets/IdentifyAsWidget.tsx'
|
|
@@ -471,10 +485,6 @@ export async function injectTemplateFiles(
|
|
|
471
485
|
src: resolve('../templates/src/components/edit/pane/PanePanel_path.tsx'),
|
|
472
486
|
dest: 'src/components/edit/pane/PanePanel_path.tsx',
|
|
473
487
|
},
|
|
474
|
-
{
|
|
475
|
-
src: resolve('../templates/src/components/edit/pane/PanePanel_slug.tsx'),
|
|
476
|
-
dest: 'src/components/edit/pane/PanePanel_slug.tsx',
|
|
477
|
-
},
|
|
478
488
|
{
|
|
479
489
|
src: resolve('../templates/src/components/edit/pane/PanePanel_title.tsx'),
|
|
480
490
|
dest: 'src/components/edit/pane/PanePanel_title.tsx',
|
|
@@ -546,9 +556,9 @@ export async function injectTemplateFiles(
|
|
|
546
556
|
},
|
|
547
557
|
{
|
|
548
558
|
src: resolve(
|
|
549
|
-
'../templates/src/components/compositor/preview/
|
|
559
|
+
'../templates/src/components/compositor/preview/FeaturedArticlePreview.tsx'
|
|
550
560
|
),
|
|
551
|
-
dest: 'src/components/compositor/preview/
|
|
561
|
+
dest: 'src/components/compositor/preview/FeaturedArticlePreview.tsx',
|
|
552
562
|
},
|
|
553
563
|
|
|
554
564
|
// Server side stores
|
|
@@ -902,7 +912,23 @@ export async function injectTemplateFiles(
|
|
|
902
912
|
src: resolve('../templates/src/components/Fragment.astro'),
|
|
903
913
|
dest: 'src/components/Fragment.astro',
|
|
904
914
|
},
|
|
905
|
-
|
|
915
|
+
// Search Components
|
|
916
|
+
{
|
|
917
|
+
src: resolve('../templates/src/components/search/SearchWrapper.tsx'),
|
|
918
|
+
dest: 'src/components/search/SearchWrapper.tsx',
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
src: resolve('../templates/src/components/search/SearchModal.tsx'),
|
|
922
|
+
dest: 'src/components/search/SearchModal.tsx',
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
src: resolve('../templates/src/components/search/SearchResults.tsx'),
|
|
926
|
+
dest: 'src/components/search/SearchResults.tsx',
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
src: resolve('../templates/src/hooks/useSearch.ts'),
|
|
930
|
+
dest: 'src/hooks/useSearch.ts',
|
|
931
|
+
},
|
|
906
932
|
// Profile Components
|
|
907
933
|
{
|
|
908
934
|
src: resolve('../templates/src/components/profile/ProfileConsent.tsx'),
|
|
@@ -982,6 +1008,12 @@ export async function injectTemplateFiles(
|
|
|
982
1008
|
src: resolve('../templates/src/components/form/ActionBuilderField.tsx'),
|
|
983
1009
|
dest: 'src/components/form/ActionBuilderField.tsx',
|
|
984
1010
|
},
|
|
1011
|
+
{
|
|
1012
|
+
src: resolve(
|
|
1013
|
+
'../templates/src/components/form/ActionBuilderBeliefSelector.tsx'
|
|
1014
|
+
),
|
|
1015
|
+
dest: 'src/components/form/ActionBuilderBeliefSelector.tsx',
|
|
1016
|
+
},
|
|
985
1017
|
{
|
|
986
1018
|
src: resolve('../templates/src/components/form/MagicPathBuilder.tsx'),
|
|
987
1019
|
dest: 'src/components/form/MagicPathBuilder.tsx',
|
|
@@ -1038,6 +1070,12 @@ export async function injectTemplateFiles(
|
|
|
1038
1070
|
},
|
|
1039
1071
|
|
|
1040
1072
|
// StoryKeep Dashboard Components
|
|
1073
|
+
{
|
|
1074
|
+
src: resolve(
|
|
1075
|
+
'../templates/src/components/storykeep/StoryKeepBackdrop.astro'
|
|
1076
|
+
),
|
|
1077
|
+
dest: 'src/components/storykeep/StoryKeepBackdrop.astro',
|
|
1078
|
+
},
|
|
1041
1079
|
{
|
|
1042
1080
|
src: resolve('../templates/src/components/storykeep/Dashboard.tsx'),
|
|
1043
1081
|
dest: 'src/components/storykeep/Dashboard.tsx',
|
|
@@ -1212,17 +1250,21 @@ export async function injectTemplateFiles(
|
|
|
1212
1250
|
src: resolve('../templates/src/components/codehooks/SankeyDiagram.tsx'),
|
|
1213
1251
|
dest: 'src/components/codehooks/SankeyDiagram.tsx',
|
|
1214
1252
|
},
|
|
1253
|
+
{
|
|
1254
|
+
src: resolve('../templates/src/components/codehooks/SearchWidget.tsx'),
|
|
1255
|
+
dest: 'src/components/codehooks/SearchWidget.tsx',
|
|
1256
|
+
},
|
|
1215
1257
|
{
|
|
1216
1258
|
src: resolve(
|
|
1217
|
-
'../templates/src/components/codehooks/
|
|
1259
|
+
'../templates/src/components/codehooks/FeaturedArticle.astro'
|
|
1218
1260
|
),
|
|
1219
|
-
dest: 'src/components/codehooks/
|
|
1261
|
+
dest: 'src/components/codehooks/FeaturedArticle.astro',
|
|
1220
1262
|
},
|
|
1221
1263
|
{
|
|
1222
1264
|
src: resolve(
|
|
1223
|
-
'../templates/src/components/codehooks/
|
|
1265
|
+
'../templates/src/components/codehooks/FeaturedArticleSetup.tsx'
|
|
1224
1266
|
),
|
|
1225
|
-
dest: 'src/components/codehooks/
|
|
1267
|
+
dest: 'src/components/codehooks/FeaturedArticleSetup.tsx',
|
|
1226
1268
|
},
|
|
1227
1269
|
{
|
|
1228
1270
|
src: resolve('../templates/src/components/codehooks/ListContent.astro'),
|
|
@@ -1234,6 +1276,18 @@ export async function injectTemplateFiles(
|
|
|
1234
1276
|
),
|
|
1235
1277
|
dest: 'src/components/codehooks/ListContentSetup.tsx',
|
|
1236
1278
|
},
|
|
1279
|
+
{
|
|
1280
|
+
src: resolve(
|
|
1281
|
+
'../templates/src/components/codehooks/ProductCardSetup.tsx'
|
|
1282
|
+
),
|
|
1283
|
+
dest: 'src/components/codehooks/ProductCardSetup.tsx',
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
src: resolve(
|
|
1287
|
+
'../templates/src/components/codehooks/ProductGridSetup.tsx'
|
|
1288
|
+
),
|
|
1289
|
+
dest: 'src/components/codehooks/ProductGridSetup.tsx',
|
|
1290
|
+
},
|
|
1237
1291
|
{
|
|
1238
1292
|
src: resolve(
|
|
1239
1293
|
'../templates/src/components/codehooks/BunnyVideoWrapper.astro'
|
|
@@ -1271,16 +1325,16 @@ export async function injectTemplateFiles(
|
|
|
1271
1325
|
|
|
1272
1326
|
// Client Scripts
|
|
1273
1327
|
{
|
|
1274
|
-
src: resolve('../templates/src/client/
|
|
1275
|
-
dest: 'public/client/
|
|
1328
|
+
src: resolve('../templates/src/client/htmx.min.js'),
|
|
1329
|
+
dest: 'public/client/htmx.min.js',
|
|
1276
1330
|
},
|
|
1277
1331
|
{
|
|
1278
|
-
src: resolve('../templates/src/client/
|
|
1279
|
-
dest: 'public/client/
|
|
1332
|
+
src: resolve('../templates/src/client/view.js'),
|
|
1333
|
+
dest: 'public/client/view.js',
|
|
1280
1334
|
},
|
|
1281
1335
|
{
|
|
1282
|
-
src: resolve('../templates/src/client/
|
|
1283
|
-
dest: 'public/client/
|
|
1336
|
+
src: resolve('../templates/src/client/app.js'),
|
|
1337
|
+
dest: 'public/client/app.js',
|
|
1284
1338
|
},
|
|
1285
1339
|
|
|
1286
1340
|
// StoryKeep Editor (add new section)
|
|
@@ -2044,6 +2098,11 @@ export async function injectTemplateFiles(
|
|
|
2044
2098
|
dest: 'src/custom/CustomRoutes.astro',
|
|
2045
2099
|
protected: true,
|
|
2046
2100
|
},
|
|
2101
|
+
{
|
|
2102
|
+
src: resolve('../templates/src/utils/customHelpers.ts'),
|
|
2103
|
+
dest: 'src/utils/customHelpers.ts',
|
|
2104
|
+
protected: true,
|
|
2105
|
+
},
|
|
2047
2106
|
|
|
2048
2107
|
// Example Components (Conditional)
|
|
2049
2108
|
...(config?.includeExamples
|
|
@@ -2053,6 +2112,23 @@ export async function injectTemplateFiles(
|
|
|
2053
2112
|
dest: 'src/custom/CustomHero.astro',
|
|
2054
2113
|
protected: true,
|
|
2055
2114
|
},
|
|
2115
|
+
{
|
|
2116
|
+
src: resolve('../templates/custom/with-examples/ProductGrid.astro'),
|
|
2117
|
+
dest: 'src/custom/ProductGrid.astro',
|
|
2118
|
+
protected: true,
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
src: resolve(
|
|
2122
|
+
'../templates/custom/with-examples/ProductCardWrapper.astro'
|
|
2123
|
+
),
|
|
2124
|
+
dest: 'src/custom/ProductCardWrapper.astro',
|
|
2125
|
+
protected: true,
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
src: resolve('../templates/custom/with-examples/ProductCard.astro'),
|
|
2129
|
+
dest: 'src/custom/ProductCard.astro',
|
|
2130
|
+
protected: true,
|
|
2131
|
+
},
|
|
2056
2132
|
{
|
|
2057
2133
|
src: resolve(
|
|
2058
2134
|
'../templates/custom/with-examples/pages/Collections.astro'
|
|
@@ -2084,6 +2160,7 @@ export async function injectTemplateFiles(
|
|
|
2084
2160
|
file.dest.startsWith('src/components/codehooks/') ||
|
|
2085
2161
|
file.dest.startsWith('src/components/widgets/') ||
|
|
2086
2162
|
file.dest.startsWith('src/') ||
|
|
2163
|
+
file.dest.startsWith('public/client/') ||
|
|
2087
2164
|
file.dest === '.gitignore');
|
|
2088
2165
|
|
|
2089
2166
|
if (!existsSync(file.dest) || shouldOverwrite) {
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
const THRESHOLD_GLOSSED = 7000; // 7 seconds in ms
|
|
2
|
-
const THRESHOLD_READ = 42000; // 42 seconds in ms
|
|
3
|
-
const VERBOSE = false;
|
|
4
|
-
|
|
5
|
-
const paneViewTimes = new Map();
|
|
6
|
-
let hasTrackedEntered =
|
|
7
|
-
localStorage.getItem('tractstack_entered_tracked') === 'true';
|
|
8
|
-
let currentStoryfragmentId = null;
|
|
9
|
-
let isPageInitialized = false;
|
|
10
|
-
let globalObserver = null;
|
|
11
|
-
|
|
12
|
-
function waitForSessionReady() {
|
|
13
|
-
return new Promise((resolve) => {
|
|
14
|
-
if (window.TRACTSTACK_CONFIG?.session?.isReady) {
|
|
15
|
-
resolve();
|
|
16
|
-
} else {
|
|
17
|
-
window.addEventListener('tractstack:session-ready', () => resolve(), {
|
|
18
|
-
once: true,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function initAnalyticsTracking(storyfragmentId) {
|
|
25
|
-
if (isPageInitialized) return;
|
|
26
|
-
isPageInitialized = true;
|
|
27
|
-
|
|
28
|
-
if (VERBOSE)
|
|
29
|
-
console.log('📊 ANALYTICS: Initializing tracking for page view.');
|
|
30
|
-
currentStoryfragmentId = storyfragmentId || null;
|
|
31
|
-
initPaneVisibilityTracking();
|
|
32
|
-
await waitForSessionReady();
|
|
33
|
-
trackEnteredEvent();
|
|
34
|
-
trackPageViewedEvent();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function trackEnteredEvent() {
|
|
38
|
-
if (!hasTrackedEntered && currentStoryfragmentId) {
|
|
39
|
-
sendAnalyticsEvent({
|
|
40
|
-
contentId: currentStoryfragmentId,
|
|
41
|
-
contentType: 'StoryFragment',
|
|
42
|
-
eventVerb: 'ENTERED',
|
|
43
|
-
});
|
|
44
|
-
hasTrackedEntered = true;
|
|
45
|
-
localStorage.setItem('tractstack_entered_tracked', 'true');
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function trackPageViewedEvent() {
|
|
50
|
-
if (currentStoryfragmentId) {
|
|
51
|
-
// This event is now PURELY for analytics. It no longer triggers
|
|
52
|
-
// a synchronization workaround on the backend.
|
|
53
|
-
sendAnalyticsEvent({
|
|
54
|
-
contentId: currentStoryfragmentId,
|
|
55
|
-
contentType: 'StoryFragment',
|
|
56
|
-
eventVerb: 'PAGEVIEWED',
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function initPaneVisibilityTracking() {
|
|
62
|
-
if (globalObserver) {
|
|
63
|
-
globalObserver.disconnect();
|
|
64
|
-
}
|
|
65
|
-
globalObserver = new IntersectionObserver(
|
|
66
|
-
(entries) => {
|
|
67
|
-
entries.forEach((entry) => {
|
|
68
|
-
const paneId = getPaneIdFromElement(entry.target);
|
|
69
|
-
if (!paneId) return;
|
|
70
|
-
if (entry.isIntersecting) {
|
|
71
|
-
if (!paneViewTimes.has(paneId)) {
|
|
72
|
-
paneViewTimes.set(paneId, Date.now());
|
|
73
|
-
}
|
|
74
|
-
} else {
|
|
75
|
-
const startTime = paneViewTimes.get(paneId);
|
|
76
|
-
if (startTime) {
|
|
77
|
-
const duration = Date.now() - startTime;
|
|
78
|
-
paneViewTimes.delete(paneId);
|
|
79
|
-
let eventVerb = null;
|
|
80
|
-
if (duration >= THRESHOLD_READ) eventVerb = 'READ';
|
|
81
|
-
else if (duration >= THRESHOLD_GLOSSED) eventVerb = 'GLOSSED';
|
|
82
|
-
if (eventVerb) {
|
|
83
|
-
sendAnalyticsEvent({
|
|
84
|
-
contentId: paneId,
|
|
85
|
-
contentType: 'Pane',
|
|
86
|
-
eventVerb,
|
|
87
|
-
duration,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
},
|
|
94
|
-
{ threshold: 0.1, rootMargin: '0px' }
|
|
95
|
-
);
|
|
96
|
-
observeAllPanes();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function observeAllPanes() {
|
|
100
|
-
if (!globalObserver) return;
|
|
101
|
-
const panes = document.querySelectorAll('[data-pane-id]');
|
|
102
|
-
panes.forEach((pane) => globalObserver.observe(pane));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function setupLifecycleListeners() {
|
|
106
|
-
if (window.ANALYTICS_INITIALIZED) return;
|
|
107
|
-
window.ANALYTICS_INITIALIZED = true;
|
|
108
|
-
|
|
109
|
-
if (VERBOSE)
|
|
110
|
-
console.log(
|
|
111
|
-
'📊 ANALYTICS: Setting up lifecycle listeners for the first time.'
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
window.addEventListener('beforeunload', () => {
|
|
115
|
-
flushPendingPaneEvents();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
document.addEventListener('astro:page-load', () => {
|
|
119
|
-
isPageInitialized = false;
|
|
120
|
-
flushPendingPaneEvents();
|
|
121
|
-
if (window.TRACTSTACK_CONFIG?.storyfragmentId) {
|
|
122
|
-
initAnalyticsTracking(window.TRACTSTACK_CONFIG.storyfragmentId);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
if (document.readyState === 'complete') {
|
|
127
|
-
if (window.TRACTSTACK_CONFIG?.storyfragmentId) {
|
|
128
|
-
initAnalyticsTracking(window.TRACTSTACK_CONFIG.storyfragmentId);
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
document.addEventListener(
|
|
132
|
-
'DOMContentLoaded',
|
|
133
|
-
() => {
|
|
134
|
-
if (window.TRACTSTACK_CONFIG?.storyfragmentId) {
|
|
135
|
-
initAnalyticsTracking(window.TRACTSTACK_CONFIG.storyfragmentId);
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
{ once: true }
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function flushPendingPaneEvents() {
|
|
144
|
-
if (paneViewTimes.size === 0) return;
|
|
145
|
-
const flushTime = Date.now();
|
|
146
|
-
paneViewTimes.forEach((startTime, paneId) => {
|
|
147
|
-
const duration = flushTime - startTime;
|
|
148
|
-
let eventVerb = null;
|
|
149
|
-
if (duration >= THRESHOLD_READ) eventVerb = 'READ';
|
|
150
|
-
else if (duration >= THRESHOLD_GLOSSED) eventVerb = 'GLOSSED';
|
|
151
|
-
if (eventVerb) {
|
|
152
|
-
sendAnalyticsEvent({
|
|
153
|
-
contentId: paneId,
|
|
154
|
-
contentType: 'Pane',
|
|
155
|
-
eventVerb,
|
|
156
|
-
duration,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
paneViewTimes.clear();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async function sendAnalyticsEvent(event) {
|
|
164
|
-
try {
|
|
165
|
-
const config = window.TRACTSTACK_CONFIG;
|
|
166
|
-
if (!config || !config.sessionId) return; // Use server-provided session ID
|
|
167
|
-
|
|
168
|
-
const sessionId = config.sessionId;
|
|
169
|
-
const formData = {
|
|
170
|
-
beliefId: event.contentId,
|
|
171
|
-
beliefType: event.contentType,
|
|
172
|
-
beliefValue: event.eventVerb,
|
|
173
|
-
paneId: '',
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
if (event.duration !== undefined) {
|
|
177
|
-
formData.duration = event.duration.toString();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
await fetch(`${config.backendUrl}/api/v1/state`, {
|
|
181
|
-
method: 'POST',
|
|
182
|
-
headers: {
|
|
183
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
184
|
-
'X-Tenant-ID': config.tenantId,
|
|
185
|
-
'X-TractStack-Session-ID': sessionId,
|
|
186
|
-
'X-StoryFragment-ID': config.storyfragmentId,
|
|
187
|
-
},
|
|
188
|
-
body: new URLSearchParams(formData),
|
|
189
|
-
});
|
|
190
|
-
} catch (error) {
|
|
191
|
-
console.error('❌ API ERROR: Analytics event failed', error, event);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function getPaneIdFromElement(element) {
|
|
196
|
-
return element.getAttribute('data-pane-id');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
window.initAnalyticsTracking = initAnalyticsTracking;
|
|
200
|
-
|
|
201
|
-
setupLifecycleListeners();
|
|
202
|
-
|
|
203
|
-
if (VERBOSE) {
|
|
204
|
-
console.log(
|
|
205
|
-
'📊 ANALYTICS: Analytics events module loaded and is persistent.'
|
|
206
|
-
);
|
|
207
|
-
}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
const VERBOSE = false;
|
|
2
|
-
|
|
3
|
-
// This function now contains all essential one-time and recurring HTMX setup.
|
|
4
|
-
function configureHtmx() {
|
|
5
|
-
if (!window.htmx) return;
|
|
6
|
-
|
|
7
|
-
if (!window.HTMX_CONFIGURED) {
|
|
8
|
-
window.htmx.config.selfRequestsOnly = false;
|
|
9
|
-
window.HTMX_CONFIGURED = true;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
window.htmx.on(document.body, 'htmx:configRequest', function (evt) {
|
|
13
|
-
const config = window.TRACTSTACK_CONFIG;
|
|
14
|
-
if (!config || !config.sessionId) return; // Check for config and session ID
|
|
15
|
-
|
|
16
|
-
if (evt.detail.path && evt.detail.path.startsWith('/api/v1/')) {
|
|
17
|
-
evt.detail.path = config.backendUrl + evt.detail.path;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// MODIFIED: Use session ID from the global config object
|
|
21
|
-
const sessionId = config.sessionId;
|
|
22
|
-
evt.detail.headers['X-Tenant-ID'] = config.tenantId;
|
|
23
|
-
evt.detail.headers['X-StoryFragment-ID'] = config.storyfragmentId;
|
|
24
|
-
if (sessionId) {
|
|
25
|
-
evt.detail.headers['X-TractStack-Session-ID'] = sessionId;
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const pageBeliefs = {};
|
|
31
|
-
let activeStoryfragmentId = null;
|
|
32
|
-
|
|
33
|
-
function waitForSessionReady() {
|
|
34
|
-
return new Promise((resolve) => {
|
|
35
|
-
// This event is fired by sse.ts after the handshake is complete.
|
|
36
|
-
if (window.TRACTSTACK_CONFIG?.session?.isReady) {
|
|
37
|
-
resolve();
|
|
38
|
-
} else {
|
|
39
|
-
window.addEventListener('tractstack:session-ready', () => resolve(), {
|
|
40
|
-
once: true,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function initializeBeliefs() {
|
|
47
|
-
if (window.BELIEF_INITIALIZED) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
window.BELIEF_INITIALIZED = true;
|
|
51
|
-
|
|
52
|
-
if (VERBOSE)
|
|
53
|
-
console.log(
|
|
54
|
-
'🔧 BELIEF: First-time initialization of belief handlers and HTMX config.'
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
configureHtmx(); // Run config on initial load.
|
|
58
|
-
|
|
59
|
-
document.addEventListener('change', function (event) {
|
|
60
|
-
const target = event.target;
|
|
61
|
-
if (
|
|
62
|
-
target.matches &&
|
|
63
|
-
(target.matches('select[data-belief-id]') ||
|
|
64
|
-
target.matches('input[type="checkbox"][data-belief-id]'))
|
|
65
|
-
) {
|
|
66
|
-
handleBeliefChange(target);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function handleBeliefChange(element) {
|
|
72
|
-
const beliefId = element.getAttribute('data-belief-id');
|
|
73
|
-
const beliefType = element.getAttribute('data-belief-type');
|
|
74
|
-
const paneId = element.getAttribute('data-pane-id');
|
|
75
|
-
|
|
76
|
-
if (!beliefId || !beliefType) {
|
|
77
|
-
if (VERBOSE)
|
|
78
|
-
console.error('🔴 BELIEF: Missing required attributes on', element.id);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let beliefValue;
|
|
83
|
-
if (element.type === 'checkbox') {
|
|
84
|
-
beliefValue = element.checked ? 'BELIEVES_YES' : 'BELIEVES_NO';
|
|
85
|
-
} else {
|
|
86
|
-
beliefValue = element.value;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (VERBOSE)
|
|
90
|
-
console.log('🔄 BELIEF: Widget changed', {
|
|
91
|
-
beliefId,
|
|
92
|
-
beliefType,
|
|
93
|
-
beliefValue,
|
|
94
|
-
paneId,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
trackBeliefState(beliefId, beliefValue);
|
|
98
|
-
|
|
99
|
-
// Pass the current page's beliefs to the backend
|
|
100
|
-
await sendBeliefUpdate({
|
|
101
|
-
beliefId,
|
|
102
|
-
beliefType,
|
|
103
|
-
beliefValue,
|
|
104
|
-
paneId: paneId || '',
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async function sendBeliefUpdate(data) {
|
|
109
|
-
await waitForSessionReady();
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
const config = window.TRACTSTACK_CONFIG;
|
|
113
|
-
if (!config || !config.sessionId) return; // Check for config and session ID
|
|
114
|
-
|
|
115
|
-
if (VERBOSE)
|
|
116
|
-
console.log('🚨 FRONTEND DEBUG: Sending belief update with headers:', {
|
|
117
|
-
'X-StoryFragment-ID': config.storyfragmentId,
|
|
118
|
-
beliefData: data,
|
|
119
|
-
currentSSEContext: 'check sse.ts logs',
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const sessionId = config.sessionId;
|
|
123
|
-
const headers = {
|
|
124
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
125
|
-
'X-Tenant-ID': config.tenantId,
|
|
126
|
-
'X-StoryFragment-ID': config.storyfragmentId,
|
|
127
|
-
'X-TractStack-Session-ID': sessionId,
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
if (VERBOSE)
|
|
131
|
-
console.log('📡 BELIEF: Session ready, sending update.', { data });
|
|
132
|
-
|
|
133
|
-
const response = await fetch(`${config.backendUrl}/api/v1/state`, {
|
|
134
|
-
method: 'POST',
|
|
135
|
-
headers: headers,
|
|
136
|
-
body: new URLSearchParams(data),
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
if (!response.ok) {
|
|
140
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
141
|
-
}
|
|
142
|
-
} catch (error) {
|
|
143
|
-
const errorMessage =
|
|
144
|
-
error instanceof Error ? error.message : 'Unknown error';
|
|
145
|
-
if (VERBOSE)
|
|
146
|
-
console.error('🔴 BELIEF: Update failed', {
|
|
147
|
-
error: errorMessage,
|
|
148
|
-
beliefId: data.beliefId,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function trackBeliefState(beliefId, beliefValue) {
|
|
154
|
-
if (!activeStoryfragmentId) return;
|
|
155
|
-
|
|
156
|
-
if (!pageBeliefs[activeStoryfragmentId]) {
|
|
157
|
-
pageBeliefs[activeStoryfragmentId] = {};
|
|
158
|
-
}
|
|
159
|
-
pageBeliefs[activeStoryfragmentId][beliefId] = beliefValue;
|
|
160
|
-
if (VERBOSE)
|
|
161
|
-
console.log(`📝 BELIEF: Tracked state for page ${activeStoryfragmentId}`, {
|
|
162
|
-
...pageBeliefs[activeStoryfragmentId],
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function setActiveStoryFragment() {
|
|
167
|
-
if (window.TRACTSTACK_CONFIG?.storyfragmentId) {
|
|
168
|
-
activeStoryfragmentId = window.TRACTSTACK_CONFIG.storyfragmentId;
|
|
169
|
-
if (VERBOSE)
|
|
170
|
-
console.log(
|
|
171
|
-
`📖 BELIEF: Active story fragment set to ${activeStoryfragmentId}`
|
|
172
|
-
);
|
|
173
|
-
// Ensure a state object exists for the newly active page
|
|
174
|
-
if (!pageBeliefs[activeStoryfragmentId]) {
|
|
175
|
-
pageBeliefs[activeStoryfragmentId] = {};
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
initializeBeliefs();
|
|
181
|
-
|
|
182
|
-
document.addEventListener('astro:page-load', () => {
|
|
183
|
-
configureHtmx();
|
|
184
|
-
setActiveStoryFragment();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Also set the active story on the very first page load.
|
|
188
|
-
document.addEventListener('DOMContentLoaded', setActiveStoryFragment);
|
|
189
|
-
|
|
190
|
-
if (VERBOSE)
|
|
191
|
-
console.log('🔧 BELIEF: Belief events module loaded and is persistent.');
|