astro-tractstack 2.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +56 -0
  3. package/astro.d.ts +64 -0
  4. package/bin/create-tractstack.js +483 -0
  5. package/dist/config.js +80 -0
  6. package/dist/index.js +2129 -0
  7. package/package.json +89 -0
  8. package/templates/artpacks/kCz/captainBreakfast_1080px.webp +0 -0
  9. package/templates/artpacks/kCz/captainBreakfast_1920px.webp +0 -0
  10. package/templates/artpacks/kCz/captainBreakfast_600px.webp +0 -0
  11. package/templates/artpacks/kCz/cleanDrips_1080px.webp +0 -0
  12. package/templates/artpacks/kCz/cleanDrips_1920px.webp +0 -0
  13. package/templates/artpacks/kCz/cleanDrips_600px.webp +0 -0
  14. package/templates/artpacks/kCz/crispwaves_1080px.webp +0 -0
  15. package/templates/artpacks/kCz/crispwaves_1920px.webp +0 -0
  16. package/templates/artpacks/kCz/crispwaves_600px.webp +0 -0
  17. package/templates/artpacks/kCz/dragonSkin_1080px.webp +0 -0
  18. package/templates/artpacks/kCz/dragonSkin_1920px.webp +0 -0
  19. package/templates/artpacks/kCz/dragonSkin_600px.webp +0 -0
  20. package/templates/artpacks/kCz/dragon_1080px.webp +0 -0
  21. package/templates/artpacks/kCz/dragon_1920px.webp +0 -0
  22. package/templates/artpacks/kCz/dragon_600px.webp +0 -0
  23. package/templates/artpacks/kCz/nightcity_1080px.webp +0 -0
  24. package/templates/artpacks/kCz/nightcity_1920px.webp +0 -0
  25. package/templates/artpacks/kCz/nightcity_600px.webp +0 -0
  26. package/templates/artpacks/kCz/pattern1_1080px.webp +0 -0
  27. package/templates/artpacks/kCz/pattern1_1920px.webp +0 -0
  28. package/templates/artpacks/kCz/pattern1_600px.webp +0 -0
  29. package/templates/artpacks/kCz/pattern2_1080px.webp +0 -0
  30. package/templates/artpacks/kCz/pattern2_1920px.webp +0 -0
  31. package/templates/artpacks/kCz/pattern2_600px.webp +0 -0
  32. package/templates/artpacks/kCz/skindrips_1080px.webp +0 -0
  33. package/templates/artpacks/kCz/skindrips_1920px.webp +0 -0
  34. package/templates/artpacks/kCz/skindrips_600px.webp +0 -0
  35. package/templates/artpacks/kCz/slimetime_1080px.webp +0 -0
  36. package/templates/artpacks/kCz/slimetime_1920px.webp +0 -0
  37. package/templates/artpacks/kCz/slimetime_600px.webp +0 -0
  38. package/templates/artpacks/kCz/snake_1080px.webp +0 -0
  39. package/templates/artpacks/kCz/snake_1920px.webp +0 -0
  40. package/templates/artpacks/kCz/snake_600px.webp +0 -0
  41. package/templates/artpacks/kCz/toxicshock_1080px.webp +0 -0
  42. package/templates/artpacks/kCz/toxicshock_1920px.webp +0 -0
  43. package/templates/artpacks/kCz/toxicshock_600px.webp +0 -0
  44. package/templates/artpacks/kCz/tractstack_1080px.webp +0 -0
  45. package/templates/artpacks/kCz/tractstack_1920px.webp +0 -0
  46. package/templates/artpacks/kCz/tractstack_600px.webp +0 -0
  47. package/templates/artpacks/kCz/tripdrips_1080px.webp +0 -0
  48. package/templates/artpacks/kCz/tripdrips_1920px.webp +0 -0
  49. package/templates/artpacks/kCz/tripdrips_600px.webp +0 -0
  50. package/templates/artpacks/kCz/wavedrips_1080px.webp +0 -0
  51. package/templates/artpacks/kCz/wavedrips_1920px.webp +0 -0
  52. package/templates/artpacks/kCz/wavedrips_600px.webp +0 -0
  53. package/templates/artpacks/t8k/beach_1080px.webp +0 -0
  54. package/templates/artpacks/t8k/beach_1920px.webp +0 -0
  55. package/templates/artpacks/t8k/beach_600px.webp +0 -0
  56. package/templates/artpacks/t8k/blast_1080px.webp +0 -0
  57. package/templates/artpacks/t8k/blast_1920px.webp +0 -0
  58. package/templates/artpacks/t8k/blast_600px.webp +0 -0
  59. package/templates/artpacks/t8k/bokeh_1080px.webp +0 -0
  60. package/templates/artpacks/t8k/bokeh_1920px.webp +0 -0
  61. package/templates/artpacks/t8k/bokeh_600px.webp +0 -0
  62. package/templates/artpacks/t8k/cartoon_1080px.webp +0 -0
  63. package/templates/artpacks/t8k/cartoon_1920px.webp +0 -0
  64. package/templates/artpacks/t8k/cartoon_600px.webp +0 -0
  65. package/templates/artpacks/t8k/darkeggshell_1080px.webp +0 -0
  66. package/templates/artpacks/t8k/darkeggshell_1920px.webp +0 -0
  67. package/templates/artpacks/t8k/darkeggshell_600px.webp +0 -0
  68. package/templates/artpacks/t8k/explosion_1080px.webp +0 -0
  69. package/templates/artpacks/t8k/explosion_1920px.webp +0 -0
  70. package/templates/artpacks/t8k/explosion_600px.webp +0 -0
  71. package/templates/artpacks/t8k/floral_1080px.webp +0 -0
  72. package/templates/artpacks/t8k/floral_1920px.webp +0 -0
  73. package/templates/artpacks/t8k/floral_600px.webp +0 -0
  74. package/templates/artpacks/t8k/flower_1080px.webp +0 -0
  75. package/templates/artpacks/t8k/flower_1920px.webp +0 -0
  76. package/templates/artpacks/t8k/flower_600px.webp +0 -0
  77. package/templates/artpacks/t8k/foliage_1080px.webp +0 -0
  78. package/templates/artpacks/t8k/foliage_1920px.webp +0 -0
  79. package/templates/artpacks/t8k/foliage_600px.webp +0 -0
  80. package/templates/artpacks/t8k/mist_1080px.webp +0 -0
  81. package/templates/artpacks/t8k/mist_1920px.webp +0 -0
  82. package/templates/artpacks/t8k/mist_600px.webp +0 -0
  83. package/templates/artpacks/t8k/portal_1080px.webp +0 -0
  84. package/templates/artpacks/t8k/portal_1920px.webp +0 -0
  85. package/templates/artpacks/t8k/portal_600px.webp +0 -0
  86. package/templates/artpacks/t8k/storytime_1080px.webp +0 -0
  87. package/templates/artpacks/t8k/storytime_1920px.webp +0 -0
  88. package/templates/artpacks/t8k/storytime_600px.webp +0 -0
  89. package/templates/artpacks/t8k/tacky_1080px.webp +0 -0
  90. package/templates/artpacks/t8k/tacky_1920px.webp +0 -0
  91. package/templates/artpacks/t8k/tacky_600px.webp +0 -0
  92. package/templates/artpacks/t8k/wallpaper_1080px.webp +0 -0
  93. package/templates/artpacks/t8k/wallpaper_1920px.webp +0 -0
  94. package/templates/artpacks/t8k/wallpaper_600px.webp +0 -0
  95. package/templates/brand/favicon.ico +0 -0
  96. package/templates/brand/logo.svg +19 -0
  97. package/templates/brand/static.jpg +0 -0
  98. package/templates/brand/wordmark.svg +4 -0
  99. package/templates/css/custom.css +51 -0
  100. package/templates/css/frontend.css +3519 -0
  101. package/templates/css/storykeep.css +92872 -0
  102. package/templates/custom/minimal/CodeHook.astro +53 -0
  103. package/templates/custom/minimal/CustomRoutes.astro +46 -0
  104. package/templates/custom/with-examples/CodeHook.astro +49 -0
  105. package/templates/custom/with-examples/CustomHero.astro +13 -0
  106. package/templates/custom/with-examples/CustomRoutes.astro +39 -0
  107. package/templates/custom/with-examples/pages/Collections.astro +110 -0
  108. package/templates/env.example +8 -0
  109. package/templates/fonts/Inter-Black.woff2 +0 -0
  110. package/templates/fonts/Inter-Bold.woff2 +0 -0
  111. package/templates/fonts/Inter-Regular.woff2 +0 -0
  112. package/templates/icons/h2.svg +1 -0
  113. package/templates/icons/h3.svg +1 -0
  114. package/templates/icons/h4.svg +1 -0
  115. package/templates/icons/h5.svg +1 -0
  116. package/templates/icons/image.svg +7 -0
  117. package/templates/icons/text.svg +6 -0
  118. package/templates/socials/codepen.svg +1 -0
  119. package/templates/socials/discord.svg +1 -0
  120. package/templates/socials/facebook.svg +1 -0
  121. package/templates/socials/github.svg +1 -0
  122. package/templates/socials/instagram.svg +1 -0
  123. package/templates/socials/linkedin.svg +1 -0
  124. package/templates/socials/mail.svg +1 -0
  125. package/templates/socials/rumble.svg +1 -0
  126. package/templates/socials/tiktok.svg +1 -0
  127. package/templates/socials/twitch.svg +1 -0
  128. package/templates/socials/twitter.svg +1 -0
  129. package/templates/socials/x.svg +1 -0
  130. package/templates/socials/youtube.svg +1 -0
  131. package/templates/src/client/analytics-events.ts +213 -0
  132. package/templates/src/client/belief-events.ts +205 -0
  133. package/templates/src/client/sse.ts +667 -0
  134. package/templates/src/components/Footer.astro +246 -0
  135. package/templates/src/components/Fragment.astro +70 -0
  136. package/templates/src/components/Header.astro +458 -0
  137. package/templates/src/components/Menu.tsx +196 -0
  138. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +692 -0
  139. package/templates/src/components/codehooks/BunnyVideoWrapper.astro +78 -0
  140. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +1020 -0
  141. package/templates/src/components/codehooks/EpinetTableView.tsx +594 -0
  142. package/templates/src/components/codehooks/EpinetWrapper.tsx +424 -0
  143. package/templates/src/components/codehooks/FeaturedContent.astro +273 -0
  144. package/templates/src/components/codehooks/FeaturedContentSetup.tsx +738 -0
  145. package/templates/src/components/codehooks/ListContent.astro +460 -0
  146. package/templates/src/components/codehooks/ListContentSetup.tsx +649 -0
  147. package/templates/src/components/codehooks/SankeyDiagram.tsx +359 -0
  148. package/templates/src/components/compositor/Compositor.tsx +144 -0
  149. package/templates/src/components/compositor/Node.tsx +415 -0
  150. package/templates/src/components/compositor/NodeWithGuid.tsx +25 -0
  151. package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +87 -0
  152. package/templates/src/components/compositor/elements/Belief.tsx +148 -0
  153. package/templates/src/components/compositor/elements/BgImage.tsx +118 -0
  154. package/templates/src/components/compositor/elements/BgVisualBreak.tsx +102 -0
  155. package/templates/src/components/compositor/elements/BunnyVideo.tsx +63 -0
  156. package/templates/src/components/compositor/elements/IdentifyAs.tsx +66 -0
  157. package/templates/src/components/compositor/elements/PlayButton.tsx +19 -0
  158. package/templates/src/components/compositor/elements/SignUp.tsx +179 -0
  159. package/templates/src/components/compositor/elements/Svg.tsx +33 -0
  160. package/templates/src/components/compositor/elements/ToggleBelief.tsx +36 -0
  161. package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +33 -0
  162. package/templates/src/components/compositor/nodes/BgPaneWrapper.tsx +35 -0
  163. package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +189 -0
  164. package/templates/src/components/compositor/nodes/Markdown.tsx +179 -0
  165. package/templates/src/components/compositor/nodes/Pane.tsx +277 -0
  166. package/templates/src/components/compositor/nodes/Pane_eraser.tsx +69 -0
  167. package/templates/src/components/compositor/nodes/Pane_layout.tsx +77 -0
  168. package/templates/src/components/compositor/nodes/RenderChildren.tsx +19 -0
  169. package/templates/src/components/compositor/nodes/StoryFragment.tsx +35 -0
  170. package/templates/src/components/compositor/nodes/TagElement.tsx +14 -0
  171. package/templates/src/components/compositor/nodes/Widget.tsx +115 -0
  172. package/templates/src/components/compositor/nodes/tagElements/NodeA.tsx +4 -0
  173. package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +26 -0
  174. package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +248 -0
  175. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +684 -0
  176. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +62 -0
  177. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +120 -0
  178. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +62 -0
  179. package/templates/src/components/compositor/nodes/tagElements/NodeButton.tsx +5 -0
  180. package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +26 -0
  181. package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +28 -0
  182. package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +18 -0
  183. package/templates/src/components/compositor/nodes/tagElements/TabIndicator.tsx +51 -0
  184. package/templates/src/components/compositor/preview/FeaturedContentPreview.tsx +128 -0
  185. package/templates/src/components/compositor/preview/ListContentPreview.tsx +213 -0
  186. package/templates/src/components/compositor/preview/OgImagePreview.tsx +223 -0
  187. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +199 -0
  188. package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +123 -0
  189. package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +154 -0
  190. package/templates/src/components/edit/Header.tsx +181 -0
  191. package/templates/src/components/edit/PanelSwitch.tsx +446 -0
  192. package/templates/src/components/edit/SettingsPanel.tsx +70 -0
  193. package/templates/src/components/edit/ToolBar.tsx +101 -0
  194. package/templates/src/components/edit/ToolMode.tsx +121 -0
  195. package/templates/src/components/edit/context/ContextPaneConfig.tsx +91 -0
  196. package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +174 -0
  197. package/templates/src/components/edit/context/ContextPaneConfig_title.tsx +186 -0
  198. package/templates/src/components/edit/pane/AddPanePanel.tsx +136 -0
  199. package/templates/src/components/edit/pane/AddPanePanel_break.tsx +470 -0
  200. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +264 -0
  201. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +623 -0
  202. package/templates/src/components/edit/pane/AddPanePanel_newAICopy.tsx +107 -0
  203. package/templates/src/components/edit/pane/AddPanePanel_newAICopy_modal.tsx +217 -0
  204. package/templates/src/components/edit/pane/AddPanePanel_newCopyMode.tsx +109 -0
  205. package/templates/src/components/edit/pane/AddPanePanel_newCustomCopy.tsx +39 -0
  206. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +445 -0
  207. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +245 -0
  208. package/templates/src/components/edit/pane/PageGen.tsx +485 -0
  209. package/templates/src/components/edit/pane/PageGenSelector.tsx +238 -0
  210. package/templates/src/components/edit/pane/PageGenSpecial.tsx +362 -0
  211. package/templates/src/components/edit/pane/PageGen_preview.tsx +495 -0
  212. package/templates/src/components/edit/pane/PanePanel_impression.tsx +258 -0
  213. package/templates/src/components/edit/pane/PanePanel_path.tsx +268 -0
  214. package/templates/src/components/edit/pane/PanePanel_slug.tsx +219 -0
  215. package/templates/src/components/edit/pane/PanePanel_title.tsx +142 -0
  216. package/templates/src/components/edit/panels/StyleBreakPanel.tsx +182 -0
  217. package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +439 -0
  218. package/templates/src/components/edit/panels/StyleElementPanel.tsx +177 -0
  219. package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +349 -0
  220. package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +159 -0
  221. package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +320 -0
  222. package/templates/src/components/edit/panels/StyleImagePanel.tsx +460 -0
  223. package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +296 -0
  224. package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +153 -0
  225. package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +312 -0
  226. package/templates/src/components/edit/panels/StyleLiElementPanel.tsx +273 -0
  227. package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +301 -0
  228. package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +132 -0
  229. package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +313 -0
  230. package/templates/src/components/edit/panels/StyleLinkPanel.tsx +346 -0
  231. package/templates/src/components/edit/panels/StyleLinkPanel_add.tsx +265 -0
  232. package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +240 -0
  233. package/templates/src/components/edit/panels/StyleLinkPanel_remove.tsx +94 -0
  234. package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +110 -0
  235. package/templates/src/components/edit/panels/StyleParentPanel.tsx +263 -0
  236. package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +275 -0
  237. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +112 -0
  238. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +87 -0
  239. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +141 -0
  240. package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +428 -0
  241. package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +292 -0
  242. package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +190 -0
  243. package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +152 -0
  244. package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +308 -0
  245. package/templates/src/components/edit/state/SaveModal.tsx +811 -0
  246. package/templates/src/components/edit/state/StylesMemory.tsx +310 -0
  247. package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +289 -0
  248. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +320 -0
  249. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +888 -0
  250. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +269 -0
  251. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_title.tsx +190 -0
  252. package/templates/src/components/edit/widgets/BeliefWidget.tsx +183 -0
  253. package/templates/src/components/edit/widgets/BunnyWidget.tsx +134 -0
  254. package/templates/src/components/edit/widgets/IdentifyAsWidget.tsx +193 -0
  255. package/templates/src/components/edit/widgets/SignupWidget.tsx +177 -0
  256. package/templates/src/components/edit/widgets/ToggleWidget.tsx +152 -0
  257. package/templates/src/components/edit/widgets/YouTubeWidget.tsx +65 -0
  258. package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +353 -0
  259. package/templates/src/components/fields/ArtpackImage.tsx +480 -0
  260. package/templates/src/components/fields/BackgroundImage.tsx +530 -0
  261. package/templates/src/components/fields/BackgroundImageWrapper.tsx +192 -0
  262. package/templates/src/components/fields/BooleanParam.tsx +67 -0
  263. package/templates/src/components/fields/BunnyMomentSelector.tsx +56 -0
  264. package/templates/src/components/fields/ColorPickerCombo.tsx +284 -0
  265. package/templates/src/components/fields/ImageUpload.tsx +405 -0
  266. package/templates/src/components/fields/MultiParam.tsx +75 -0
  267. package/templates/src/components/fields/PaneBreakCollectionSelector.tsx +97 -0
  268. package/templates/src/components/fields/PaneBreakShapeSelector.tsx +134 -0
  269. package/templates/src/components/fields/SelectedTailwindClass.tsx +44 -0
  270. package/templates/src/components/fields/SingleParam.tsx +73 -0
  271. package/templates/src/components/fields/ViewportComboBox.tsx +252 -0
  272. package/templates/src/components/form/ActionBuilderField.tsx +282 -0
  273. package/templates/src/components/form/ActionBuilderSlugSelector.tsx +182 -0
  274. package/templates/src/components/form/BooleanToggle.tsx +94 -0
  275. package/templates/src/components/form/ColorPicker.tsx +153 -0
  276. package/templates/src/components/form/DateTimeInput.tsx +638 -0
  277. package/templates/src/components/form/EnumSelect.tsx +88 -0
  278. package/templates/src/components/form/FileUpload.tsx +465 -0
  279. package/templates/src/components/form/MagicPathBuilder.tsx +546 -0
  280. package/templates/src/components/form/NumberInput.tsx +101 -0
  281. package/templates/src/components/form/ParagraphArrayInput.tsx +207 -0
  282. package/templates/src/components/form/StringArrayInput.tsx +163 -0
  283. package/templates/src/components/form/StringInput.tsx +88 -0
  284. package/templates/src/components/form/UnsavedChangesBar.tsx +295 -0
  285. package/templates/src/components/form/advanced/APIConfigSection.tsx +69 -0
  286. package/templates/src/components/form/advanced/AuthConfigSection.tsx +97 -0
  287. package/templates/src/components/form/brand/BrandAssetsSection.tsx +93 -0
  288. package/templates/src/components/form/brand/BrandColorsSection.tsx +201 -0
  289. package/templates/src/components/form/brand/SEOSection.tsx +101 -0
  290. package/templates/src/components/form/brand/SiteConfigSection.tsx +61 -0
  291. package/templates/src/components/form/brand/SocialLinksSection.tsx +393 -0
  292. package/templates/src/components/profile/ProfileConsent.tsx +65 -0
  293. package/templates/src/components/profile/ProfileCreate.tsx +462 -0
  294. package/templates/src/components/profile/ProfileEdit.tsx +409 -0
  295. package/templates/src/components/profile/ProfileSwitch.tsx +255 -0
  296. package/templates/src/components/profile/ProfileUnlock.tsx +221 -0
  297. package/templates/src/components/storykeep/Dashboard.tsx +160 -0
  298. package/templates/src/components/storykeep/Dashboard_Activity.tsx +56 -0
  299. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +165 -0
  300. package/templates/src/components/storykeep/Dashboard_Analytics.tsx +451 -0
  301. package/templates/src/components/storykeep/Dashboard_Branding.tsx +95 -0
  302. package/templates/src/components/storykeep/Dashboard_Content.tsx +191 -0
  303. package/templates/src/components/storykeep/controls/UsageCell.tsx +71 -0
  304. package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +378 -0
  305. package/templates/src/components/storykeep/controls/content/BeliefTable.tsx +329 -0
  306. package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +385 -0
  307. package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +149 -0
  308. package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +397 -0
  309. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +260 -0
  310. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +439 -0
  311. package/templates/src/components/storykeep/controls/content/MenuForm.tsx +239 -0
  312. package/templates/src/components/storykeep/controls/content/MenuTable.tsx +332 -0
  313. package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +724 -0
  314. package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +355 -0
  315. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +222 -0
  316. package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +482 -0
  317. package/templates/src/components/storykeep/state/BrandingWrapper.tsx +42 -0
  318. package/templates/src/components/storykeep/state/FetchAnalytics.tsx +350 -0
  319. package/templates/src/components/storykeep/widgets/ResponsiveLine.tsx +319 -0
  320. package/templates/src/components/storykeep/widgets/Wizard.tsx +278 -0
  321. package/templates/src/components/tenant/RegistrationForm.tsx +447 -0
  322. package/templates/src/components/widgets/BunnyVideoHero.astro +775 -0
  323. package/templates/src/components/widgets/Impression.tsx +102 -0
  324. package/templates/src/components/widgets/ImpressionWrapper.tsx +214 -0
  325. package/templates/src/constants/beliefs.ts +61 -0
  326. package/templates/src/constants/brandThemes.ts +133 -0
  327. package/templates/src/constants/prompts.json +55 -0
  328. package/templates/src/constants/shapes.ts +556 -0
  329. package/templates/src/constants/stopWords.ts +116 -0
  330. package/templates/src/constants/tailwindColors.json +344 -0
  331. package/templates/src/constants.ts +274 -0
  332. package/templates/src/hooks/useFormState.ts +203 -0
  333. package/templates/src/layouts/Layout.astro +290 -0
  334. package/templates/src/lib/session.ts +126 -0
  335. package/templates/src/lib/storyData.ts +56 -0
  336. package/templates/src/middleware.ts +52 -0
  337. package/templates/src/pages/404.astro +54 -0
  338. package/templates/src/pages/[...slug]/edit.astro +216 -0
  339. package/templates/src/pages/[...slug].astro +148 -0
  340. package/templates/src/pages/api/auth/decode.ts +101 -0
  341. package/templates/src/pages/api/auth/login.ts +122 -0
  342. package/templates/src/pages/api/auth/logout.ts +37 -0
  343. package/templates/src/pages/api/auth/profile.ts +76 -0
  344. package/templates/src/pages/api/orphan-analysis.ts +106 -0
  345. package/templates/src/pages/api/tailwind.ts +116 -0
  346. package/templates/src/pages/collections/[param1].astro +65 -0
  347. package/templates/src/pages/context/[...contextSlug]/edit.astro +207 -0
  348. package/templates/src/pages/context/[...contextSlug].astro +161 -0
  349. package/templates/src/pages/llms.txt.ts +122 -0
  350. package/templates/src/pages/maint.astro +183 -0
  351. package/templates/src/pages/media/[...slug].astro +67 -0
  352. package/templates/src/pages/robots.txt.ts +36 -0
  353. package/templates/src/pages/sandbox/activate.astro +258 -0
  354. package/templates/src/pages/sandbox/register.astro +44 -0
  355. package/templates/src/pages/sandbox/success.astro +179 -0
  356. package/templates/src/pages/sitemap.xml.ts +119 -0
  357. package/templates/src/pages/storykeep/advanced.astro +69 -0
  358. package/templates/src/pages/storykeep/branding.astro +57 -0
  359. package/templates/src/pages/storykeep/content.astro +71 -0
  360. package/templates/src/pages/storykeep/init.astro +36 -0
  361. package/templates/src/pages/storykeep/login.astro +266 -0
  362. package/templates/src/pages/storykeep/logout.astro +84 -0
  363. package/templates/src/pages/storykeep/profile.astro +98 -0
  364. package/templates/src/pages/storykeep.astro +81 -0
  365. package/templates/src/stores/analytics.ts +171 -0
  366. package/templates/src/stores/backend.ts +16 -0
  367. package/templates/src/stores/navigation.ts +149 -0
  368. package/templates/src/stores/nodes.ts +2390 -0
  369. package/templates/src/stores/nodesHistory.ts +85 -0
  370. package/templates/src/stores/notificationSystem.ts +41 -0
  371. package/templates/src/stores/orphanAnalysis.ts +409 -0
  372. package/templates/src/stores/storykeep.ts +247 -0
  373. package/templates/src/types/astro.ts +86 -0
  374. package/templates/src/types/compositorTypes.ts +456 -0
  375. package/templates/src/types/formTypes.ts +281 -0
  376. package/templates/src/types/multiTenant.ts +77 -0
  377. package/templates/src/types/nodeProps.ts +66 -0
  378. package/templates/src/types/tractstack.ts +445 -0
  379. package/templates/src/utils/aai/getTitleSlug.ts +72 -0
  380. package/templates/src/utils/actions/actionButton.ts +101 -0
  381. package/templates/src/utils/actions/lispLexer.ts +57 -0
  382. package/templates/src/utils/actions/preParse_Action.ts +85 -0
  383. package/templates/src/utils/actions/preParse_Bunny.ts +50 -0
  384. package/templates/src/utils/actions/preParse_Clicked.ts +87 -0
  385. package/templates/src/utils/actions/preParse_Impression.ts +71 -0
  386. package/templates/src/utils/api/advancedConfig.ts +66 -0
  387. package/templates/src/utils/api/advancedHelpers.ts +134 -0
  388. package/templates/src/utils/api/beliefConfig.ts +87 -0
  389. package/templates/src/utils/api/beliefHelpers.ts +196 -0
  390. package/templates/src/utils/api/brandConfig.ts +126 -0
  391. package/templates/src/utils/api/brandHelpers.ts +155 -0
  392. package/templates/src/utils/api/fileHelpers.ts +306 -0
  393. package/templates/src/utils/api/menuConfig.ts +57 -0
  394. package/templates/src/utils/api/menuHelpers.ts +156 -0
  395. package/templates/src/utils/api/resourceConfig.ts +158 -0
  396. package/templates/src/utils/api/resourceHelpers.ts +72 -0
  397. package/templates/src/utils/api/tenantConfig.ts +97 -0
  398. package/templates/src/utils/api/tenantHelpers.ts +172 -0
  399. package/templates/src/utils/api.ts +183 -0
  400. package/templates/src/utils/auth.ts +150 -0
  401. package/templates/src/utils/backend.ts +243 -0
  402. package/templates/src/utils/compositor/TemplateMarkdowns.ts +118 -0
  403. package/templates/src/utils/compositor/TemplateNodes.ts +138 -0
  404. package/templates/src/utils/compositor/TemplatePanes.ts +100 -0
  405. package/templates/src/utils/compositor/allowInsert.ts +100 -0
  406. package/templates/src/utils/compositor/domHelpers.ts +37 -0
  407. package/templates/src/utils/compositor/handleClickEvent.ts +131 -0
  408. package/templates/src/utils/compositor/nodesHelper.ts +491 -0
  409. package/templates/src/utils/compositor/nodesMarkdownGenerator.ts +292 -0
  410. package/templates/src/utils/compositor/processMarkdown.ts +431 -0
  411. package/templates/src/utils/compositor/reduceNodesClassNames.ts +192 -0
  412. package/templates/src/utils/compositor/tailwindClasses.ts +1795 -0
  413. package/templates/src/utils/compositor/tailwindColors.ts +227 -0
  414. package/templates/src/utils/compositor/templateMarkdownStyles.ts +1265 -0
  415. package/templates/src/utils/compositor/typeGuards.ts +193 -0
  416. package/templates/src/utils/etl/extractor.ts +119 -0
  417. package/templates/src/utils/etl/index.ts +88 -0
  418. package/templates/src/utils/etl/loader.ts +36 -0
  419. package/templates/src/utils/etl/transformer.ts +286 -0
  420. package/templates/src/utils/helpers.ts +435 -0
  421. package/templates/src/utils/layout.ts +209 -0
  422. package/templates/src/utils/profileStorage.ts +306 -0
  423. package/templates/src/utils/useInterval.ts +27 -0
  424. package/templates/tailwind.config.cjs +169 -0
  425. package/utils/create-resolver.ts +10 -0
  426. package/utils/inject-files.ts +2140 -0
  427. package/utils/validate-config.ts +43 -0
@@ -0,0 +1,134 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { getCtx } from '@/stores/nodes';
3
+ import SingleParam from '@/components/fields/SingleParam';
4
+ import { widgetMeta } from '@/constants';
5
+ import type { FlatNode } from '@/types/compositorTypes';
6
+
7
+ interface BunnyWidgetProps {
8
+ node: FlatNode;
9
+ onUpdate: (params: string[]) => void;
10
+ }
11
+
12
+ function BunnyWidget({ node, onUpdate }: BunnyWidgetProps) {
13
+ const [embedUrl, setEmbedUrl] = useState(
14
+ String(node.codeHookParams?.[0] || '')
15
+ );
16
+ const [title, setTitle] = useState(String(node.codeHookParams?.[1] || ''));
17
+ const [isDuplicate, setIsDuplicate] = useState(false);
18
+ const [validationError, setValidationError] = useState<string | null>(null);
19
+
20
+ const widgetInfo = widgetMeta.bunny;
21
+
22
+ useEffect(() => {
23
+ setEmbedUrl(String(node.codeHookParams?.[0] || ''));
24
+ setTitle(String(node.codeHookParams?.[1] || ''));
25
+ validateUrl(String(node.codeHookParams?.[0] || ''));
26
+ }, [node]);
27
+
28
+ const checkForDuplicates = (url: string): boolean => {
29
+ if (!url) return false;
30
+
31
+ try {
32
+ const videoId = extractVideoId(url);
33
+ if (!videoId) return false;
34
+
35
+ const ctx = getCtx();
36
+ const existingVideos = ctx.getAllBunnyVideoInfo();
37
+
38
+ // Check if this video ID already exists in another node
39
+ return existingVideos.some(
40
+ (video) =>
41
+ video.videoId === videoId &&
42
+ !(node.codeHookParams?.[0] || '').includes(videoId)
43
+ );
44
+ } catch (e) {
45
+ console.error('Error checking for duplicates:', e);
46
+ return false;
47
+ }
48
+ };
49
+
50
+ const extractVideoId = (url: string): string | null => {
51
+ try {
52
+ const match = url.match(/embed\/([^/]+\/[^/?]+)/);
53
+ return match ? match[1] : null;
54
+ } catch (e) {
55
+ console.error('Error extracting video ID:', e);
56
+ return null;
57
+ }
58
+ };
59
+
60
+ // Validate URL format and check for duplicates
61
+ const validateUrl = (url: string): void => {
62
+ if (!url) {
63
+ setValidationError(null);
64
+ setIsDuplicate(false);
65
+ return;
66
+ }
67
+
68
+ const isValid = isValidUrl(url);
69
+ if (!isValid) {
70
+ setValidationError('URL should be a valid Bunny embed URL');
71
+ setIsDuplicate(false);
72
+ return;
73
+ }
74
+
75
+ const duplicate = checkForDuplicates(url);
76
+ setIsDuplicate(duplicate);
77
+ setValidationError(
78
+ duplicate ? 'This video is already used elsewhere in this page' : null
79
+ );
80
+ };
81
+
82
+ const handleEmbedUrlChange = (value: string) => {
83
+ setEmbedUrl(value);
84
+ validateUrl(value);
85
+ onUpdate([value, title]);
86
+ };
87
+
88
+ const handleTitleChange = (value: string) => {
89
+ setTitle(value);
90
+ onUpdate([embedUrl, value]);
91
+ };
92
+
93
+ // Validate URL format
94
+ const isValidUrl = (url: string): boolean => {
95
+ try {
96
+ if (!url) return false;
97
+ new URL(url);
98
+ return (
99
+ url.includes('//iframe.mediadelivery.net/embed/') ||
100
+ url.includes('//video.bunnycdn.com/')
101
+ );
102
+ } catch (e) {
103
+ return false;
104
+ }
105
+ };
106
+
107
+ return (
108
+ <div className="space-y-4">
109
+ <SingleParam
110
+ label={widgetInfo.parameters[0].label}
111
+ value={embedUrl}
112
+ onChange={handleEmbedUrlChange}
113
+ />
114
+ {validationError && embedUrl && (
115
+ <div className="mt-1 text-xs text-red-500">{validationError}</div>
116
+ )}
117
+ {isDuplicate && (
118
+ <div className="rounded border border-yellow-200 bg-yellow-50 p-2 text-xs text-yellow-800">
119
+ Warning: This video is already used elsewhere in this page. Using the
120
+ same video multiple times may cause playback conflicts. Consider using
121
+ a single video with chapter navigation instead.
122
+ </div>
123
+ )}
124
+
125
+ <SingleParam
126
+ label={widgetInfo.parameters[1].label}
127
+ value={title}
128
+ onChange={handleTitleChange}
129
+ />
130
+ </div>
131
+ );
132
+ }
133
+
134
+ export default BunnyWidget;
@@ -0,0 +1,193 @@
1
+ import { useState, useEffect } from 'react';
2
+ import SingleParam from '@/components/fields/SingleParam';
3
+ import { TractStackAPI } from '@/utils/api';
4
+ import type { FlatNode, BeliefNode } from '@/types/compositorTypes';
5
+
6
+ interface IdentifyAsWidgetProps {
7
+ node: FlatNode;
8
+ onUpdate: (params: string[]) => void;
9
+ }
10
+
11
+ export default function IdentifyAsWidget({
12
+ node,
13
+ onUpdate,
14
+ }: IdentifyAsWidgetProps) {
15
+ const [beliefs, setBeliefs] = useState<BeliefNode[]>([]);
16
+ const [selectedBeliefTag, setSelectedBeliefTag] = useState<string>('');
17
+ const [targetValues, setTargetValues] = useState<string[]>([]);
18
+ const [currentPrompt, setCurrentPrompt] = useState<string>('');
19
+
20
+ // Sync state with node.codeHookParams
21
+ useEffect(() => {
22
+ const params = node.codeHookParams || [];
23
+ const beliefTag = String(params[0] || 'BeliefTag');
24
+ const matchingValues = params[1] || 'TARGET_VALUE';
25
+ const prompt = String(params[2] || '');
26
+
27
+ // Set selected belief tag
28
+ if (beliefTag !== 'BeliefTag') {
29
+ setSelectedBeliefTag(beliefTag);
30
+ } else {
31
+ setSelectedBeliefTag('');
32
+ }
33
+
34
+ // Parse target values only if we have a real belief selected and real values
35
+ if (beliefTag !== 'BeliefTag' && matchingValues !== 'TARGET_VALUE') {
36
+ if (Array.isArray(matchingValues)) {
37
+ setTargetValues(matchingValues.map(String));
38
+ } else if (typeof matchingValues === 'string') {
39
+ setTargetValues(
40
+ matchingValues
41
+ .split(',')
42
+ .map((val) => val.trim())
43
+ .filter(Boolean)
44
+ );
45
+ }
46
+ } else {
47
+ setTargetValues([]);
48
+ }
49
+
50
+ setCurrentPrompt(prompt);
51
+ }, [node]);
52
+
53
+ // Fetch beliefs using new Go backend pattern
54
+ useEffect(() => {
55
+ const fetchData = async () => {
56
+ try {
57
+ const api = new TractStackAPI();
58
+
59
+ // Step 1: Get all belief IDs
60
+ const idsResponse = await api.get('/api/v1/nodes/beliefs');
61
+
62
+ if (!idsResponse.success) {
63
+ throw new Error(`Failed to fetch belief IDs: ${idsResponse.error}`);
64
+ }
65
+ const { beliefIds } = idsResponse.data;
66
+
67
+ if (!beliefIds || beliefIds.length === 0) {
68
+ setBeliefs([]);
69
+ return;
70
+ }
71
+
72
+ // Step 2: Get belief data by IDs
73
+ const beliefsResponse = await api.post('/api/v1/nodes/beliefs', {
74
+ beliefIds,
75
+ });
76
+
77
+ if (!beliefsResponse.success) {
78
+ throw new Error(`Failed to fetch beliefs: ${beliefsResponse.error}`);
79
+ }
80
+
81
+ const { beliefs } = beliefsResponse.data;
82
+ setBeliefs(beliefs || []);
83
+ } catch (error) {
84
+ console.error('Error fetching beliefs:', error);
85
+ setBeliefs([]);
86
+ }
87
+ };
88
+
89
+ fetchData();
90
+ }, []);
91
+
92
+ const handleBeliefChange = (selectedValue: string) => {
93
+ setSelectedBeliefTag(selectedValue);
94
+
95
+ // When a belief is selected, initialize target values with ALL customValues from that belief
96
+ if (selectedValue) {
97
+ const selectedBelief = beliefs.find((b) => b.slug === selectedValue);
98
+ if (selectedBelief && selectedBelief.customValues) {
99
+ setTargetValues(selectedBelief.customValues);
100
+ // Update with all custom values selected by default
101
+ onUpdate([
102
+ selectedValue,
103
+ selectedBelief.customValues.join(','),
104
+ currentPrompt,
105
+ ]);
106
+ } else {
107
+ setTargetValues([]);
108
+ onUpdate([selectedValue, '', currentPrompt]);
109
+ }
110
+ } else {
111
+ setTargetValues([]);
112
+ onUpdate(['BeliefTag', 'TARGET_VALUE', currentPrompt]);
113
+ }
114
+ };
115
+
116
+ const handleTargetValueToggle = (value: string) => {
117
+ const newTargetValues = targetValues.includes(value)
118
+ ? targetValues.filter((v) => v !== value)
119
+ : [...targetValues, value];
120
+
121
+ setTargetValues(newTargetValues);
122
+ const beliefTagToUse = selectedBeliefTag || 'BeliefTag';
123
+ const targetParam =
124
+ newTargetValues.length > 0 ? newTargetValues.join(',') : 'TARGET_VALUE';
125
+ onUpdate([beliefTagToUse, targetParam, currentPrompt]);
126
+ };
127
+
128
+ const handlePromptChange = (value: string) => {
129
+ const sanitizedValue = value.replace(/[\n\r|]/g, '');
130
+ setCurrentPrompt(sanitizedValue);
131
+ const beliefTagToUse = selectedBeliefTag || 'BeliefTag';
132
+ const targetParam =
133
+ targetValues.length > 0 ? targetValues.join(',') : 'TARGET_VALUE';
134
+ onUpdate([beliefTagToUse, targetParam, sanitizedValue]);
135
+ };
136
+
137
+ const filteredBeliefs = beliefs.filter((b) => b.scale === 'custom');
138
+ const selectedBelief = beliefs.find((b) => b.slug === selectedBeliefTag);
139
+ const hasRealSelection = !!selectedBelief;
140
+
141
+ return (
142
+ <div className="space-y-4">
143
+ <div className="flex items-center gap-2">
144
+ <select
145
+ value={selectedBeliefTag}
146
+ onChange={(e) => handleBeliefChange(e.target.value)}
147
+ className="flex-1 rounded-md border-0 px-2.5 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-cyan-700"
148
+ disabled={hasRealSelection}
149
+ >
150
+ <option value="">Select a belief</option>
151
+ {filteredBeliefs.map((b) => (
152
+ <option key={b.slug} value={b.slug}>
153
+ {b.title}
154
+ </option>
155
+ ))}
156
+ </select>
157
+ </div>
158
+
159
+ {hasRealSelection && selectedBelief && (
160
+ <>
161
+ <div className="space-y-2">
162
+ <label className="text-sm font-bold text-gray-700">
163
+ Target Values (select which options to include)
164
+ </label>
165
+ <div className="space-y-2">
166
+ {selectedBelief.customValues?.map((value) => (
167
+ <label key={value} className="flex items-center space-x-2">
168
+ <input
169
+ type="checkbox"
170
+ checked={targetValues.includes(value)}
171
+ onChange={() => handleTargetValueToggle(value)}
172
+ className="rounded border-gray-300 text-cyan-600 focus:ring-cyan-500"
173
+ />
174
+ <span className="text-sm text-gray-700">{value}</span>
175
+ </label>
176
+ )) || (
177
+ <div className="text-sm italic text-gray-500">
178
+ This belief has no custom values defined.
179
+ </div>
180
+ )}
181
+ </div>
182
+ </div>
183
+
184
+ <SingleParam
185
+ label="Prompt"
186
+ value={currentPrompt}
187
+ onChange={handlePromptChange}
188
+ />
189
+ </>
190
+ )}
191
+ </div>
192
+ );
193
+ }
@@ -0,0 +1,177 @@
1
+ import { useState, useEffect, useMemo } from 'react';
2
+ import { Combobox } from '@ark-ui/react';
3
+ import { createListCollection } from '@ark-ui/react/collection';
4
+ import ChevronUpDownIcon from '@heroicons/react/24/outline/ChevronUpDownIcon';
5
+ import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
6
+ import SingleParam from '@/components/fields/SingleParam';
7
+ import BooleanParam from '@/components/fields/BooleanParam';
8
+ import { widgetMeta } from '@/constants';
9
+ import { contactPersona } from '@/constants';
10
+ import type { FlatNode } from '@/types/compositorTypes';
11
+
12
+ interface SignupWidgetProps {
13
+ node: FlatNode;
14
+ onUpdate: (params: string[]) => void;
15
+ }
16
+
17
+ interface ContactPersona {
18
+ id: string;
19
+ title: string;
20
+ description: string;
21
+ disabled?: boolean;
22
+ }
23
+
24
+ // Hard coded contact personas - matches other components
25
+ const contactPersonas: ContactPersona[] = contactPersona;
26
+
27
+ function SignupWidget({ node, onUpdate }: SignupWidgetProps) {
28
+ const [contactPersona, setContactPersona] = useState(
29
+ String(node.codeHookParams?.[0] || contactPersonas[0].id)
30
+ );
31
+ const [promptText, setPromptText] = useState(
32
+ String(node.codeHookParams?.[1] || '')
33
+ );
34
+ const [clarifyConsent, setClarifyConsent] = useState(
35
+ node.codeHookParams?.[2] === 'true'
36
+ );
37
+ const [query, setQuery] = useState('');
38
+
39
+ const widgetInfo = widgetMeta.signup;
40
+
41
+ // Create collection for Combobox - filter out disabled personas
42
+ const collection = useMemo(() => {
43
+ const enabledPersonas = contactPersonas.filter(
44
+ (persona) => !persona.disabled
45
+ );
46
+
47
+ const filteredPersonas =
48
+ query === ''
49
+ ? enabledPersonas
50
+ : enabledPersonas.filter((persona) =>
51
+ persona.title.toLowerCase().includes(query.toLowerCase())
52
+ );
53
+
54
+ return createListCollection({
55
+ items: filteredPersonas,
56
+ itemToValue: (item) => item.id,
57
+ itemToString: (item) => item.title,
58
+ });
59
+ }, [query]);
60
+
61
+ // Sync local state with node prop changes
62
+ useEffect(() => {
63
+ setContactPersona(
64
+ String(node.codeHookParams?.[0] || contactPersonas[0].id)
65
+ );
66
+ setPromptText(String(node.codeHookParams?.[1] || ''));
67
+ setClarifyConsent(node.codeHookParams?.[2] === 'true');
68
+ }, [node]);
69
+
70
+ const handleContactPersonaChange = (details: { value: string[] }) => {
71
+ const value = details.value[0] || contactPersonas[0].id;
72
+ setContactPersona(value);
73
+ onUpdate([value, promptText, clarifyConsent ? 'true' : 'false']);
74
+ };
75
+
76
+ const handlePromptTextChange = (value: string) => {
77
+ setPromptText(value);
78
+ onUpdate([contactPersona, value, clarifyConsent ? 'true' : 'false']);
79
+ };
80
+
81
+ const handleClarifyConsentChange = (value: boolean) => {
82
+ setClarifyConsent(value);
83
+ onUpdate([contactPersona, promptText, value ? 'true' : 'false']);
84
+ };
85
+
86
+ // Get the selected persona's display name
87
+ const selectedPersonaTitle = useMemo(() => {
88
+ const selected = contactPersonas.find((p) => p.id === contactPersona);
89
+ return selected ? selected.title : 'Select a contact persona';
90
+ }, [contactPersona]);
91
+
92
+ // CSS for styling combobox items
93
+ const comboboxItemStyles = `
94
+ .persona-item[data-highlighted] {
95
+ background-color: #0891b2; /* bg-cyan-600 */
96
+ color: white;
97
+ }
98
+ .persona-item[data-highlighted] .persona-indicator {
99
+ color: white;
100
+ }
101
+ .persona-item[data-state="checked"] .persona-indicator {
102
+ display: flex;
103
+ }
104
+ .persona-item .persona-indicator {
105
+ display: none;
106
+ }
107
+ .persona-item[data-state="checked"] {
108
+ font-weight: bold;
109
+ }
110
+ `;
111
+
112
+ return (
113
+ <div className="space-y-4">
114
+ <style>{comboboxItemStyles}</style>
115
+ <div>
116
+ <label className="block text-sm font-bold text-gray-700">
117
+ {widgetInfo.parameters[0].label}
118
+ </label>
119
+ <Combobox.Root
120
+ collection={collection}
121
+ defaultValue={[contactPersona]}
122
+ onValueChange={handleContactPersonaChange}
123
+ onInputValueChange={(details) => setQuery(details.inputValue)}
124
+ >
125
+ <div className="relative mt-1">
126
+ <Combobox.Input
127
+ className="focus:border-myblue focus:ring-myblue w-full rounded-md border border-gray-300 py-2 pl-3 pr-10 text-sm shadow-sm"
128
+ placeholder="Select contact persona..."
129
+ defaultValue={selectedPersonaTitle}
130
+ />
131
+ <Combobox.Trigger className="absolute inset-y-0 right-0 flex items-center pr-2">
132
+ <ChevronUpDownIcon
133
+ className="h-5 w-5 text-gray-400"
134
+ aria-hidden="true"
135
+ />
136
+ </Combobox.Trigger>
137
+ </div>
138
+ <Combobox.Content className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
139
+ {collection.items.length === 0 ? (
140
+ <div className="relative cursor-default select-none px-4 py-2 text-gray-700">
141
+ Nothing found.
142
+ </div>
143
+ ) : (
144
+ collection.items.map((persona) => (
145
+ <Combobox.Item
146
+ key={persona.id}
147
+ item={persona}
148
+ className="persona-item relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900"
149
+ >
150
+ <span className="block truncate">{persona.title}</span>
151
+ <span className="block text-sm text-gray-500">
152
+ {persona.description}
153
+ </span>
154
+ <span className="persona-indicator text-myblue absolute inset-y-0 left-0 flex items-center pl-3">
155
+ <CheckIcon className="h-5 w-5" aria-hidden="true" />
156
+ </span>
157
+ </Combobox.Item>
158
+ ))
159
+ )}
160
+ </Combobox.Content>
161
+ </Combobox.Root>
162
+ </div>
163
+ <SingleParam
164
+ label={widgetInfo.parameters[1].label}
165
+ value={promptText}
166
+ onChange={handlePromptTextChange}
167
+ />
168
+ <BooleanParam
169
+ label={widgetInfo.parameters[2].label}
170
+ value={clarifyConsent}
171
+ onChange={handleClarifyConsentChange}
172
+ />
173
+ </div>
174
+ );
175
+ }
176
+
177
+ export default SignupWidget;
@@ -0,0 +1,152 @@
1
+ import { useState, useEffect } from 'react';
2
+ import SingleParam from '@/components/fields/SingleParam';
3
+ import { widgetMeta } from '@/constants';
4
+ import type { FlatNode, BeliefNode } from '@/types/compositorTypes';
5
+
6
+ interface ToggleWidgetProps {
7
+ node: FlatNode;
8
+ onUpdate: (params: string[]) => void;
9
+ }
10
+
11
+ export default function ToggleWidget({ node, onUpdate }: ToggleWidgetProps) {
12
+ const [beliefs, setBeliefs] = useState<BeliefNode[]>([]);
13
+ const [selectedBeliefTag, setSelectedBeliefTag] = useState<string>('');
14
+ const [currentPrompt, setCurrentPrompt] = useState<string>('');
15
+ const [isInitialized, setIsInitialized] = useState(false);
16
+
17
+ // Get parameter metadata from the widgetMeta constant
18
+ const widgetInfo = widgetMeta.toggle;
19
+
20
+ const params = node.codeHookParams || [];
21
+ const beliefTag = String(params[0] || '');
22
+ const prompt = String(params[1] || '');
23
+
24
+ // Check if beliefTag is the placeholder value
25
+ const isPlaceholder = beliefTag === 'BeliefTag';
26
+
27
+ // Update local state when props change
28
+ useEffect(() => {
29
+ if (!isPlaceholder && beliefTag) {
30
+ setSelectedBeliefTag(beliefTag);
31
+ }
32
+ setCurrentPrompt(prompt);
33
+ setIsInitialized(true);
34
+ }, [beliefTag, prompt, isPlaceholder]);
35
+
36
+ // Fetch beliefs using new Go backend pattern
37
+ useEffect(() => {
38
+ const fetchData = async () => {
39
+ try {
40
+ const goBackend =
41
+ import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
42
+ const tenantId = import.meta.env.PUBLIC_TENANTID || 'default';
43
+
44
+ // Step 1: Get all belief IDs
45
+ const idsResponse = await fetch(`${goBackend}/api/v1/nodes/beliefs`, {
46
+ headers: {
47
+ 'X-Tenant-ID': tenantId,
48
+ },
49
+ });
50
+
51
+ if (!idsResponse.ok) {
52
+ throw new Error(
53
+ `Failed to fetch belief IDs: ${idsResponse.statusText}`
54
+ );
55
+ }
56
+ const { beliefIds } = await idsResponse.json();
57
+
58
+ if (!beliefIds || beliefIds.length === 0) {
59
+ setBeliefs([]);
60
+ return;
61
+ }
62
+
63
+ // Step 2: Get belief data by IDs
64
+ const beliefsResponse = await fetch(
65
+ `${goBackend}/api/v1/nodes/beliefs`,
66
+ {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ 'X-Tenant-ID': tenantId,
71
+ },
72
+ body: JSON.stringify({ beliefIds }),
73
+ }
74
+ );
75
+
76
+ if (!beliefsResponse.ok) {
77
+ throw new Error(
78
+ `Failed to fetch beliefs: ${beliefsResponse.statusText}`
79
+ );
80
+ }
81
+
82
+ const { beliefs } = await beliefsResponse.json();
83
+ setBeliefs(beliefs || []);
84
+ } catch (err) {
85
+ console.error('Failed to fetch beliefs:', err);
86
+ }
87
+ };
88
+
89
+ fetchData();
90
+ }, []);
91
+
92
+ const handleBeliefChange = (selectedValue: string) => {
93
+ if (!isInitialized) return;
94
+ setSelectedBeliefTag(selectedValue);
95
+ onUpdate([selectedValue, currentPrompt]);
96
+ };
97
+
98
+ const handlePromptChange = (value: string) => {
99
+ if (!isInitialized) return;
100
+ // Sanitize the input value (remove newlines and pipe characters)
101
+ const sanitizedValue = value.replace(/[\n\r|]/g, '');
102
+ setCurrentPrompt(sanitizedValue);
103
+
104
+ // Use the actual selected tag (from state) or the original belief tag as fallback
105
+ const tagToUse = selectedBeliefTag || (isPlaceholder ? '' : beliefTag);
106
+ onUpdate([tagToUse, sanitizedValue]);
107
+ };
108
+
109
+ // Show beliefs that can be selected for the toggle
110
+ const filteredBeliefs = beliefs.filter(
111
+ (b) => b.scale === 'yn' || b.scale === 'tf'
112
+ );
113
+
114
+ // Find the selected belief (if any)
115
+ const selectedBelief = beliefs.find(
116
+ (b) => b.slug === (selectedBeliefTag || (isPlaceholder ? '' : beliefTag))
117
+ );
118
+
119
+ // Determine if we have a real selection - either from state or props
120
+ const hasRealSelection = !!selectedBelief || (!isPlaceholder && !!beliefTag);
121
+
122
+ // Calculate the current value to show in the select dropdown
123
+ const selectValue = selectedBeliefTag || (isPlaceholder ? '' : beliefTag);
124
+
125
+ return (
126
+ <div className="space-y-4">
127
+ <div className="flex items-center gap-2">
128
+ <select
129
+ value={selectValue}
130
+ onChange={(e) => handleBeliefChange(e.target.value)}
131
+ className="flex-1 rounded-md border-0 px-2.5 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-cyan-700"
132
+ disabled={hasRealSelection && !isPlaceholder}
133
+ >
134
+ <option value="">Select a belief</option>
135
+ {filteredBeliefs.map((b) => (
136
+ <option key={b.slug} value={b.slug}>
137
+ {b.title}
138
+ </option>
139
+ ))}
140
+ </select>
141
+ </div>
142
+
143
+ {(hasRealSelection || selectedBeliefTag) && (
144
+ <SingleParam
145
+ label={widgetInfo.parameters[1].label}
146
+ value={currentPrompt}
147
+ onChange={handlePromptChange}
148
+ />
149
+ )}
150
+ </div>
151
+ );
152
+ }