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,269 @@
1
+ import { useState, useEffect, type ChangeEvent } from 'react';
2
+ import ExclamationTriangleIcon from '@heroicons/react/24/outline/ExclamationTriangleIcon';
3
+ import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
4
+ import LockClosedIcon from '@heroicons/react/24/outline/LockClosedIcon';
5
+ import { getCtx } from '@/stores/nodes';
6
+ import { cloneDeep } from '@/utils/helpers';
7
+ import type { BrandConfig } from '@/types/tractstack';
8
+ import {
9
+ StoryFragmentMode,
10
+ type StoryFragmentNode,
11
+ } from '@/types/compositorTypes';
12
+
13
+ interface StoryFragmentSlugPanelProps {
14
+ nodeId: string;
15
+ setMode: (mode: StoryFragmentMode) => void;
16
+ config: BrandConfig;
17
+ }
18
+
19
+ const StoryFragmentSlugPanel = ({
20
+ nodeId,
21
+ setMode,
22
+ config,
23
+ }: StoryFragmentSlugPanelProps) => {
24
+ const [slug, setSlug] = useState('');
25
+ const [isValid, setIsValid] = useState(false);
26
+ const [warning, setWarning] = useState(false);
27
+ const [charCount, setCharCount] = useState(0);
28
+ const [validationError, setValidationError] = useState<string | null>(null);
29
+ const [canSave, setCanSave] = useState(false);
30
+ const isHomeSlug = slug === config.HOME_SLUG;
31
+
32
+ const ctx = getCtx();
33
+ const allNodes = ctx.allNodes.get();
34
+ const storyfragmentNode = allNodes.get(nodeId) as StoryFragmentNode;
35
+ if (!storyfragmentNode) return null;
36
+
37
+ useEffect(() => {
38
+ setSlug(storyfragmentNode.slug);
39
+ setCharCount(storyfragmentNode.slug.length);
40
+ checkLiveValidity(storyfragmentNode.slug);
41
+ }, [storyfragmentNode.slug]);
42
+
43
+ // More permissive validation for typing
44
+ const checkLiveValidity = (value: string) => {
45
+ const length = value.length;
46
+ setCharCount(length);
47
+
48
+ // If it's the home slug, consider it valid but locked
49
+ if (value === config.HOME_SLUG) {
50
+ setIsValid(true);
51
+ setCanSave(false);
52
+ setValidationError(null);
53
+ return true;
54
+ }
55
+
56
+ // Basic format check for allowed characters
57
+ if (!/^[a-z0-9-]*$/.test(value)) {
58
+ setValidationError(
59
+ 'Only lowercase letters, numbers, and hyphens allowed'
60
+ );
61
+ setIsValid(false);
62
+ setCanSave(false);
63
+ return false;
64
+ }
65
+
66
+ // Length checks
67
+ setIsValid(length >= 3 && length <= 60);
68
+ setWarning(length > 60 && length <= 75);
69
+ setValidationError(null);
70
+
71
+ // Check if we can save
72
+ if (length >= 3) {
73
+ const saveValidation = checkSaveValidity(value);
74
+ setCanSave(saveValidation.isValid);
75
+ if (!saveValidation.isValid) {
76
+ setValidationError(saveValidation.error || null);
77
+ }
78
+ } else {
79
+ setCanSave(false);
80
+ }
81
+
82
+ return true;
83
+ };
84
+
85
+ // Strict validation for saving
86
+ const checkSaveValidity = (
87
+ value: string
88
+ ): { isValid: boolean; error?: string } => {
89
+ // Don't allow saving if it's the home slug
90
+ if (value === config.HOME_SLUG) {
91
+ return {
92
+ isValid: false,
93
+ error: 'Cannot modify the home page slug',
94
+ };
95
+ }
96
+
97
+ // Strict pattern that prevents leading/trailing hyphens and multiple consecutive hyphens
98
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value)) {
99
+ return {
100
+ isValid: false,
101
+ error:
102
+ 'Slug must start and end with letters or numbers, and no consecutive hyphens',
103
+ };
104
+ }
105
+
106
+ // Check duplicates and reserved slugs
107
+ return ctx.isSlugValid(value, nodeId);
108
+ };
109
+
110
+ const handleSlugChange = (e: ChangeEvent<HTMLInputElement>) => {
111
+ if (isHomeSlug) return; // Prevent changes if it's the home slug
112
+
113
+ const newSlug = e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '');
114
+ if (newSlug.length <= 75) {
115
+ setSlug(newSlug);
116
+ checkLiveValidity(newSlug);
117
+ }
118
+ };
119
+
120
+ const handleSlugBlur = () => {
121
+ if (canSave && !isHomeSlug) {
122
+ const ctx = getCtx();
123
+ const updatedNode = cloneDeep({
124
+ ...storyfragmentNode,
125
+ slug,
126
+ isChanged: true,
127
+ });
128
+ ctx.modifyNodes([updatedNode]);
129
+ }
130
+ };
131
+
132
+ return (
133
+ <div className="group mb-4 w-full rounded-b-md bg-white px-1.5 py-6">
134
+ <div className="px-3.5">
135
+ <div className="mb-4 flex justify-between">
136
+ <h3 className="text-lg font-bold">Slug (url)</h3>
137
+ <button
138
+ onClick={() => setMode(StoryFragmentMode.DEFAULT)}
139
+ className="text-myblue hover:text-black"
140
+ >
141
+ ← Close Panel
142
+ </button>
143
+ </div>
144
+
145
+ <div className="relative max-w-96">
146
+ <input
147
+ type="text"
148
+ value={slug}
149
+ onChange={handleSlugChange}
150
+ onBlur={handleSlugBlur}
151
+ onKeyDown={(e) => {
152
+ if (e.key === 'Enter') {
153
+ e.currentTarget.blur();
154
+ }
155
+ }}
156
+ readOnly={isHomeSlug}
157
+ className={`w-full rounded-md border px-2 py-1 pr-16 ${
158
+ isHomeSlug
159
+ ? 'cursor-not-allowed border-gray-300 bg-gray-100'
160
+ : validationError || charCount < 3
161
+ ? 'border-red-500 bg-red-50'
162
+ : isValid && canSave
163
+ ? 'border-green-500 bg-green-50'
164
+ : warning
165
+ ? 'border-yellow-500 bg-yellow-50'
166
+ : 'border-gray-300'
167
+ }`}
168
+ placeholder="Enter URL slug (3-60 characters recommended)"
169
+ />
170
+ <div className="absolute right-2 top-1/2 flex -translate-y-1/2 items-center gap-2">
171
+ {isHomeSlug ? (
172
+ <LockClosedIcon className="h-5 w-5 text-gray-500" />
173
+ ) : validationError || charCount < 3 ? (
174
+ <ExclamationTriangleIcon className="h-5 w-5 text-red-500" />
175
+ ) : isValid && canSave ? (
176
+ <CheckIcon className="h-5 w-5 text-green-500" />
177
+ ) : warning ? (
178
+ <ExclamationTriangleIcon className="h-5 w-5 text-yellow-500" />
179
+ ) : null}
180
+ <span
181
+ className={`text-sm ${
182
+ isHomeSlug
183
+ ? 'text-gray-500'
184
+ : validationError || charCount < 3
185
+ ? 'text-red-500'
186
+ : isValid && canSave
187
+ ? 'text-green-500'
188
+ : warning
189
+ ? 'text-yellow-500'
190
+ : 'text-gray-500'
191
+ }`}
192
+ >
193
+ {charCount}/75
194
+ </span>
195
+ </div>
196
+ </div>
197
+ {validationError && (
198
+ <div className="mt-2 text-sm text-red-600">
199
+ <ExclamationTriangleIcon className="mr-1 inline h-4 w-4" />
200
+ {validationError}
201
+ </div>
202
+ )}
203
+ {isHomeSlug && (
204
+ <div className="mt-2 text-sm text-gray-600">
205
+ <LockClosedIcon className="mr-1 inline h-4 w-4" />
206
+ This is your home page slug and cannot be modified
207
+ </div>
208
+ )}
209
+ <div className="mt-4 text-lg">
210
+ <div className="text-gray-600">
211
+ Create a clean, descriptive URL slug that helps users and search
212
+ engines understand the page content.
213
+ <ul className="ml-4 mt-1">
214
+ <li>
215
+ <CheckIcon className="inline h-4 w-4" /> Use hyphens to separate
216
+ words
217
+ </li>
218
+ <li>
219
+ <CheckIcon className="inline h-4 w-4" /> Keep it short and
220
+ descriptive
221
+ </li>
222
+ <li>
223
+ <CheckIcon className="inline h-4 w-4" /> Use only lowercase
224
+ letters, numbers, and hyphens
225
+ </li>
226
+ <li>
227
+ <CheckIcon className="inline h-4 w-4" /> Must start and end with
228
+ a letter or number
229
+ </li>
230
+ </ul>
231
+ </div>
232
+ <div className="py-4">
233
+ {!isHomeSlug && (
234
+ <>
235
+ {charCount < 3 && (
236
+ <span className="text-red-500">
237
+ Slug must be at least 3 characters
238
+ </span>
239
+ )}
240
+ {charCount >= 3 && charCount < 5 && !validationError && (
241
+ <span className="text-gray-500">
242
+ Consider adding more characters for better description
243
+ </span>
244
+ )}
245
+ {warning && !validationError && (
246
+ <span className="text-yellow-500">
247
+ Slug is getting long - consider shortening it
248
+ </span>
249
+ )}
250
+ {isValid && canSave && charCount >= 5 && !validationError && (
251
+ <span className="text-green-500">
252
+ Good URL length and format!
253
+ </span>
254
+ )}
255
+ {isValid && !canSave && !validationError && (
256
+ <span className="text-gray-500">
257
+ Valid characters but needs proper formatting to save
258
+ </span>
259
+ )}
260
+ </>
261
+ )}
262
+ </div>
263
+ </div>
264
+ </div>
265
+ </div>
266
+ );
267
+ };
268
+
269
+ export default StoryFragmentSlugPanel;
@@ -0,0 +1,190 @@
1
+ import { useState, useEffect, type ChangeEvent } from 'react';
2
+ import ExclamationTriangleIcon from '@heroicons/react/24/outline/ExclamationTriangleIcon';
3
+ import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
4
+ import { cloneDeep, titleToSlug, findUniqueSlug } from '@/utils/helpers';
5
+ import { getCtx } from '@/stores/nodes';
6
+ import { fullContentMapStore } from '@/stores/storykeep';
7
+ import {
8
+ StoryFragmentMode,
9
+ type StoryFragmentNode,
10
+ } from '@/types/compositorTypes';
11
+
12
+ interface StoryFragmentOpenGraphPanelProps {
13
+ nodeId: string;
14
+ setMode?: (mode: StoryFragmentMode) => void;
15
+ }
16
+
17
+ const StoryFragmentOpenGraphPanel = ({
18
+ nodeId,
19
+ setMode,
20
+ }: StoryFragmentOpenGraphPanelProps) => {
21
+ const [title, setTitle] = useState('');
22
+ const [isValid, setIsValid] = useState(false);
23
+ const [warning, setWarning] = useState(false);
24
+ const [charCount, setCharCount] = useState(0);
25
+
26
+ const ctx = getCtx();
27
+ const allNodes = ctx.allNodes.get();
28
+ const storyfragmentNode = allNodes.get(nodeId) as StoryFragmentNode;
29
+ if (!storyfragmentNode) return null;
30
+
31
+ useEffect(() => {
32
+ setTitle(storyfragmentNode.title);
33
+ setCharCount(storyfragmentNode.title.length);
34
+ }, [storyfragmentNode.title]);
35
+
36
+ const handleTitleChange = (e: ChangeEvent<HTMLInputElement>) => {
37
+ const newTitle = e.target.value;
38
+ if (newTitle.length <= 70) {
39
+ // Prevent more than 70 chars
40
+ setTitle(newTitle);
41
+ setCharCount(newTitle.length);
42
+ setIsValid(newTitle.length >= 35 && newTitle.length <= 60);
43
+ setWarning(newTitle.length > 60 && newTitle.length <= 70);
44
+ }
45
+ };
46
+
47
+ const handleTitleBlur = () => {
48
+ if (title.length >= 5) {
49
+ // Only update if meets minimum length
50
+ const ctx = getCtx();
51
+ const existingSlugs = fullContentMapStore
52
+ .get()
53
+ .filter((item) => ['Pane', 'StoryFragment'].includes(item.type))
54
+ .map((item) => item.slug);
55
+ const newSlug =
56
+ storyfragmentNode.slug === ``
57
+ ? findUniqueSlug(titleToSlug(title), existingSlugs)
58
+ : null;
59
+ const updatedNode = cloneDeep({
60
+ ...storyfragmentNode,
61
+ title,
62
+ ...(newSlug ? { slug: newSlug } : {}),
63
+ isChanged: true,
64
+ });
65
+ ctx.modifyNodes([updatedNode]);
66
+ }
67
+ };
68
+
69
+ return (
70
+ <div className="group mb-4 w-full rounded-b-md bg-white px-1.5 py-6">
71
+ <div className="px-3.5">
72
+ <div className="mb-4 flex justify-between">
73
+ <h3 className="text-lg font-bold">Page Title</h3>
74
+ {setMode && (
75
+ <button
76
+ onClick={() => setMode && setMode(StoryFragmentMode.DEFAULT)}
77
+ className="text-myblue hover:text-black"
78
+ >
79
+ ← Close Panel
80
+ </button>
81
+ )}
82
+ </div>
83
+
84
+ <div className="relative">
85
+ <input
86
+ type="text"
87
+ value={title}
88
+ onChange={handleTitleChange}
89
+ onBlur={handleTitleBlur}
90
+ onKeyDown={(e) => {
91
+ if (e.key === 'Enter') {
92
+ e.currentTarget.blur();
93
+ }
94
+ }}
95
+ className={`w-full rounded-md border px-2 py-1 pr-16 ${
96
+ charCount < 5
97
+ ? 'border-red-500 bg-red-50'
98
+ : isValid
99
+ ? 'border-green-500 bg-green-50'
100
+ : warning
101
+ ? 'border-yellow-500 bg-yellow-50'
102
+ : 'border-gray-300'
103
+ }`}
104
+ placeholder="Enter story fragment title (50-60 characters recommended)"
105
+ />
106
+ <div className="absolute right-2 top-1/2 flex -translate-y-1/2 items-center gap-2">
107
+ {charCount < 5 ? (
108
+ <ExclamationTriangleIcon className="h-5 w-5 text-red-500" />
109
+ ) : isValid ? (
110
+ <CheckIcon className="h-5 w-5 text-green-500" />
111
+ ) : warning ? (
112
+ <ExclamationTriangleIcon className="h-5 w-5 text-yellow-500" />
113
+ ) : null}
114
+ <span
115
+ className={`text-sm ${
116
+ charCount < 5
117
+ ? 'text-red-500'
118
+ : isValid
119
+ ? 'text-green-500'
120
+ : warning
121
+ ? 'text-yellow-500'
122
+ : 'text-gray-500'
123
+ }`}
124
+ >
125
+ {charCount}/70
126
+ </span>
127
+ </div>
128
+ </div>
129
+ <div className="mt-2 flex items-center gap-2">
130
+ <button
131
+ onClick={handleTitleBlur}
132
+ disabled={title.length < 5}
133
+ className={`rounded bg-cyan-700 px-3 py-1 text-sm text-white transition-colors hover:bg-cyan-800 ${
134
+ title !== storyfragmentNode.title ? 'inline-flex' : 'hidden'
135
+ } items-center ${title.length < 5 ? 'cursor-not-allowed opacity-50' : ''}`}
136
+ >
137
+ <CheckIcon className="mr-1 h-4 w-4" />
138
+ Save
139
+ </button>
140
+ <span
141
+ className={`text-sm ${title !== storyfragmentNode.title ? 'inline' : 'hidden'} text-gray-500`}
142
+ >
143
+ or press Enter
144
+ </span>
145
+ </div>
146
+ <div className="mt-4 text-lg">
147
+ <div className="text-gray-600">
148
+ Write a clear, descriptive title that accurately represents your
149
+ page content.
150
+ <ul className="ml-4 mt-1">
151
+ <li>
152
+ <CheckIcon className="inline h-4 w-4" /> Include relevant
153
+ keywords
154
+ </li>
155
+ <li>
156
+ <CheckIcon className="inline h-4 w-4" /> Avoid unnecessary words
157
+ like "welcome to" or "the"
158
+ </li>
159
+ <li>
160
+ <CheckIcon className="inline h-4 w-4" /> Unique titles across
161
+ your website
162
+ </li>
163
+ </ul>
164
+ </div>
165
+ <div className="py-4">
166
+ {charCount < 5 && (
167
+ <span className="text-red-500">
168
+ Title must be at least 5 characters
169
+ </span>
170
+ )}
171
+ {charCount >= 5 && charCount < 50 && (
172
+ <span className="text-gray-500">
173
+ Add {50 - charCount} more characters for optimal length
174
+ </span>
175
+ )}
176
+ {` `}
177
+ {warning && (
178
+ <span className="text-yellow-500">Title is getting long</span>
179
+ )}
180
+ {isValid && (
181
+ <span className="text-green-500">Perfect title length!</span>
182
+ )}
183
+ </div>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ );
188
+ };
189
+
190
+ export default StoryFragmentOpenGraphPanel;
@@ -0,0 +1,183 @@
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 BeliefWidgetProps {
7
+ node: FlatNode;
8
+ onUpdate: (params: string[]) => void;
9
+ }
10
+
11
+ export default function BeliefWidget({ node, onUpdate }: BeliefWidgetProps) {
12
+ const [beliefs, setBeliefs] = useState<BeliefNode[]>([]);
13
+ const [selectedBeliefTag, setSelectedBeliefTag] = useState<string>('');
14
+ const [currentScaleType, setCurrentScaleType] = useState<string>('');
15
+ const [currentPrompt, setCurrentPrompt] = useState<string>('');
16
+ const [isInitialized, setIsInitialized] = useState(false);
17
+
18
+ // Get parameter metadata from the widgetMeta constant
19
+ const widgetInfo = widgetMeta.belief;
20
+
21
+ // Ensure params are always strings
22
+ const params = node.codeHookParams || [];
23
+ const beliefTag = String(params[0] || '');
24
+ const scaleType = String(params[1] || '');
25
+ const prompt = String(params[2] || '');
26
+
27
+ // Check if beliefTag is the placeholder value
28
+ const isPlaceholder = beliefTag === 'BeliefTag';
29
+
30
+ // Update local state when props change
31
+ useEffect(() => {
32
+ if (!isPlaceholder && beliefTag) {
33
+ setSelectedBeliefTag(beliefTag);
34
+ }
35
+ setCurrentScaleType(scaleType);
36
+ setCurrentPrompt(prompt);
37
+ setIsInitialized(true);
38
+ }, [beliefTag, scaleType, prompt, isPlaceholder]);
39
+
40
+ // Fetch beliefs using new Go backend 2.0 pattern
41
+ useEffect(() => {
42
+ const fetchData = async () => {
43
+ try {
44
+ const goBackend =
45
+ import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
46
+ const tenantId = import.meta.env.PUBLIC_TENANTID || 'default';
47
+
48
+ // Step 1: Get all belief IDs
49
+ const idsResponse = await fetch(`${goBackend}/api/v1/nodes/beliefs`, {
50
+ headers: {
51
+ 'X-Tenant-ID': tenantId,
52
+ },
53
+ });
54
+
55
+ if (!idsResponse.ok) {
56
+ throw new Error(
57
+ `Failed to fetch belief IDs: ${idsResponse.statusText}`
58
+ );
59
+ }
60
+ const { beliefIds } = await idsResponse.json();
61
+
62
+ if (!beliefIds || beliefIds.length === 0) {
63
+ setBeliefs([]);
64
+ return;
65
+ }
66
+
67
+ // Step 2: Get belief data by IDs
68
+ const beliefsResponse = await fetch(
69
+ `${goBackend}/api/v1/nodes/beliefs`,
70
+ {
71
+ method: 'POST',
72
+ headers: {
73
+ 'Content-Type': 'application/json',
74
+ 'X-Tenant-ID': tenantId,
75
+ },
76
+ body: JSON.stringify({ beliefIds }),
77
+ }
78
+ );
79
+
80
+ if (!beliefsResponse.ok) {
81
+ throw new Error(
82
+ `Failed to fetch beliefs: ${beliefsResponse.statusText}`
83
+ );
84
+ }
85
+
86
+ const { beliefs } = await beliefsResponse.json();
87
+ setBeliefs(beliefs || []);
88
+ } catch (err) {
89
+ console.error('Failed to fetch beliefs:', err);
90
+ }
91
+ };
92
+
93
+ fetchData();
94
+ }, []);
95
+
96
+ const handleBeliefChange = (selectedValue: string) => {
97
+ if (!isInitialized) return;
98
+ setSelectedBeliefTag(selectedValue);
99
+ const selectedBelief = beliefs.find((b) => b.slug === selectedValue);
100
+ if (selectedBelief) {
101
+ setCurrentScaleType(selectedBelief.scale || '');
102
+ onUpdate([selectedValue, selectedBelief.scale || '', currentPrompt]);
103
+ } else {
104
+ onUpdate([selectedValue, '', currentPrompt]);
105
+ }
106
+ };
107
+
108
+ const handlePromptChange = (value: string) => {
109
+ if (!isInitialized) return;
110
+ // Sanitize the input value (remove newlines and pipe characters)
111
+ const sanitizedValue = value.replace(/[\n\r|]/g, '');
112
+ setCurrentPrompt(sanitizedValue);
113
+
114
+ // Use the actual selected tag (from state) or the original belief tag as fallback
115
+ const tagToUse = selectedBeliefTag || (isPlaceholder ? '' : beliefTag);
116
+ onUpdate([tagToUse, currentScaleType, sanitizedValue]);
117
+ };
118
+
119
+ // Filter beliefs to only show supported scale types (exclude custom)
120
+ const filteredBeliefs = beliefs.filter(
121
+ (b) =>
122
+ b.scale &&
123
+ ['likert', 'agreement', 'interest', 'yn', 'tf'].includes(b.scale)
124
+ );
125
+
126
+ // Find the selected belief (if any)
127
+ const selectedBelief = filteredBeliefs.find(
128
+ (b) => b.slug === (selectedBeliefTag || (isPlaceholder ? '' : beliefTag))
129
+ );
130
+
131
+ // Determine if we have a real selection - either from state or props
132
+ const hasRealSelection = !!selectedBelief || (!isPlaceholder && !!beliefTag);
133
+
134
+ // Calculate the current value to show in the select dropdown
135
+ const selectValue = selectedBeliefTag || (isPlaceholder ? '' : beliefTag);
136
+
137
+ // Get scale type display names
138
+ const scaleTypeNames: Record<string, string> = {
139
+ yn: 'Yes/No',
140
+ likert: 'Likert Scale (5-point)',
141
+ agreement: 'Agreement (2-point)',
142
+ interest: 'Interest (2-point)',
143
+ tf: 'True/False',
144
+ custom: 'Custom Values',
145
+ };
146
+
147
+ return (
148
+ <div className="space-y-4">
149
+ <div className="flex items-center gap-2">
150
+ <select
151
+ value={selectValue}
152
+ onChange={(e) => handleBeliefChange(e.target.value)}
153
+ 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"
154
+ disabled={hasRealSelection && !isPlaceholder}
155
+ >
156
+ <option value="">Select a belief</option>
157
+ {filteredBeliefs.map((b) => (
158
+ <option key={b.slug} value={b.slug}>
159
+ {b.title}
160
+ </option>
161
+ ))}
162
+ </select>
163
+ </div>
164
+
165
+ {selectedBelief && (
166
+ <div className="rounded-md bg-blue-50 p-3">
167
+ <p className="text-sm text-blue-700">
168
+ <strong>Scale:</strong>{' '}
169
+ {scaleTypeNames[selectedBelief.scale] || selectedBelief.scale}
170
+ </p>
171
+ </div>
172
+ )}
173
+
174
+ {(hasRealSelection || selectedBeliefTag) && (
175
+ <SingleParam
176
+ label={widgetInfo.parameters[2].label}
177
+ value={currentPrompt}
178
+ onChange={handlePromptChange}
179
+ />
180
+ )}
181
+ </div>
182
+ );
183
+ }