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,546 @@
1
+ import { useState, useCallback, useMemo } from 'react';
2
+ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
3
+ import PlusIcon from '@heroicons/react/24/outline/PlusIcon';
4
+ import BeakerIcon from '@heroicons/react/24/outline/BeakerIcon';
5
+ import LinkIcon from '@heroicons/react/24/outline/LinkIcon';
6
+ import type { BeliefNode } from '@/types/compositorTypes';
7
+ import { heldBeliefsScales } from '@/constants/beliefs';
8
+
9
+ interface MagicPathBuilderProps {
10
+ paths: Record<string, string[]>;
11
+ setPaths: (paths: Record<string, string[]>) => void;
12
+ availableBeliefs: BeliefNode[];
13
+ isShowCondition: boolean;
14
+ onSaveCustomValue?: (beliefId: string, customValues: string[]) => void;
15
+ }
16
+
17
+ const MagicPathBuilder = ({
18
+ paths,
19
+ setPaths,
20
+ availableBeliefs,
21
+ isShowCondition,
22
+ onSaveCustomValue,
23
+ }: MagicPathBuilderProps) => {
24
+ const [editingCustomBeliefId, setEditingCustomBeliefId] = useState<
25
+ string | null
26
+ >(null);
27
+ const [customValue, setCustomValue] = useState('');
28
+ const [customValues, setCustomValues] = useState<string[]>([]);
29
+ const [selectedLinkedBelief, setSelectedLinkedBelief] = useState<string>('');
30
+
31
+ // Get belief keys (excluding special keys)
32
+ const beliefKeys = Object.keys(paths).filter(
33
+ (key) => key !== 'MATCH-ACROSS' && key !== 'LINKED-BELIEFS'
34
+ );
35
+
36
+ // Get linked beliefs array
37
+ const linkedBeliefs = useMemo(() => {
38
+ return Array.isArray(paths['LINKED-BELIEFS'])
39
+ ? paths['LINKED-BELIEFS']
40
+ : [];
41
+ }, [paths]);
42
+
43
+ // Calculate available beliefs for linking (beliefs not in current path)
44
+ const availableLinkedBeliefs = useMemo(() => {
45
+ return availableBeliefs.filter(
46
+ (belief) =>
47
+ // Not already selected in the current path
48
+ !beliefKeys.includes(belief.slug) &&
49
+ // Not already in the linked beliefs
50
+ !linkedBeliefs.includes(belief.slug)
51
+ );
52
+ }, [availableBeliefs, beliefKeys, linkedBeliefs]);
53
+
54
+ // Handle entering custom value edit mode
55
+ const handleEditCustomValues = useCallback(
56
+ (beliefId: string, currentValues: string[]) => {
57
+ setEditingCustomBeliefId(beliefId);
58
+ setCustomValues(currentValues);
59
+ },
60
+ []
61
+ );
62
+
63
+ // Handle saving custom values
64
+ const handleSaveCustomValues = useCallback(async () => {
65
+ if (!editingCustomBeliefId || !onSaveCustomValue) return;
66
+
67
+ const belief = availableBeliefs.find((b) => b.id === editingCustomBeliefId);
68
+ if (!belief) return;
69
+
70
+ // Save custom values through the provided callback
71
+ onSaveCustomValue(editingCustomBeliefId, customValues);
72
+ setEditingCustomBeliefId(null);
73
+ setCustomValues([]);
74
+ }, [
75
+ editingCustomBeliefId,
76
+ customValues,
77
+ availableBeliefs,
78
+ onSaveCustomValue,
79
+ ]);
80
+
81
+ // Get valid values for a belief
82
+ const getValidValuesForBelief = useCallback(
83
+ (beliefSlug: string): string[] => {
84
+ const belief = availableBeliefs.find((b) => b.slug === beliefSlug);
85
+ if (!belief) return [];
86
+
87
+ if (belief.scale === 'custom' && belief.customValues) {
88
+ return ['*', ...belief.customValues];
89
+ }
90
+
91
+ const scaleKey = belief.scale as keyof typeof heldBeliefsScales;
92
+ const scale = heldBeliefsScales[scaleKey];
93
+ return ['*', ...(scale ? scale.map((option) => option.slug) : [])];
94
+ },
95
+ [availableBeliefs]
96
+ );
97
+
98
+ // Handle adding a new belief path
99
+ const handleAddPath = useCallback(() => {
100
+ setPaths({
101
+ ...paths,
102
+ '': ['*'],
103
+ });
104
+ }, [paths, setPaths]);
105
+
106
+ // Handle changing the belief selection
107
+ const handleBeliefChange = useCallback(
108
+ (oldKey: string, newKey: string) => {
109
+ const updatedPaths = { ...paths };
110
+ delete updatedPaths[oldKey];
111
+ if (newKey) {
112
+ updatedPaths[newKey] = ['*'];
113
+
114
+ // If this belief was in LINKED-BELIEFS, remove it
115
+ if (
116
+ updatedPaths['LINKED-BELIEFS'] &&
117
+ Array.isArray(updatedPaths['LINKED-BELIEFS'])
118
+ ) {
119
+ updatedPaths['LINKED-BELIEFS'] = updatedPaths[
120
+ 'LINKED-BELIEFS'
121
+ ].filter((slug) => slug !== newKey);
122
+
123
+ // Remove the LINKED-BELIEFS key if it's empty
124
+ if (updatedPaths['LINKED-BELIEFS'].length === 0) {
125
+ delete updatedPaths['LINKED-BELIEFS'];
126
+ }
127
+ }
128
+ }
129
+ setPaths(updatedPaths);
130
+ },
131
+ [paths, setPaths]
132
+ );
133
+
134
+ // Handle changing value selection for a belief
135
+ const handleValueChange = useCallback(
136
+ (beliefKey: string, valueIndex: number, newValue: string) => {
137
+ const values = paths[beliefKey];
138
+ const updatedPaths = { ...paths };
139
+ updatedPaths[beliefKey] = [...values];
140
+ updatedPaths[beliefKey][valueIndex] = newValue;
141
+ setPaths(updatedPaths);
142
+ },
143
+ [paths, setPaths]
144
+ );
145
+
146
+ // Handle removing a value from a belief
147
+ const handleRemoveValue = useCallback(
148
+ (beliefKey: string, valueIndex: number) => {
149
+ const values = paths[beliefKey];
150
+ const updatedPaths = { ...paths };
151
+ updatedPaths[beliefKey] = values.filter((_, i) => i !== valueIndex);
152
+
153
+ if (updatedPaths[beliefKey].length === 0) {
154
+ delete updatedPaths[beliefKey];
155
+ }
156
+ setPaths(updatedPaths);
157
+ },
158
+ [paths, setPaths]
159
+ );
160
+
161
+ // Get the current match-across beliefs array
162
+ const getMatchAcrossBeliefsArray = useCallback((): string[] => {
163
+ return paths['MATCH-ACROSS'] || [];
164
+ }, [paths]);
165
+
166
+ // Handle toggling a belief in match-across
167
+ const handleToggleMatchAcross = useCallback(
168
+ (beliefKey: string) => {
169
+ const currentMatchAcross = getMatchAcrossBeliefsArray();
170
+ const updatedPaths = { ...paths };
171
+
172
+ if (currentMatchAcross.includes(beliefKey)) {
173
+ // Remove from match-across
174
+ updatedPaths['MATCH-ACROSS'] = currentMatchAcross.filter(
175
+ (key) => key !== beliefKey
176
+ );
177
+ if (updatedPaths['MATCH-ACROSS'].length === 0) {
178
+ delete updatedPaths['MATCH-ACROSS'];
179
+ }
180
+ } else {
181
+ // Add to match-across
182
+ updatedPaths['MATCH-ACROSS'] = [...currentMatchAcross, beliefKey];
183
+ }
184
+
185
+ setPaths(updatedPaths);
186
+ },
187
+ [paths, setPaths, getMatchAcrossBeliefsArray]
188
+ );
189
+
190
+ // Add a belief to the linked beliefs array
191
+ const handleAddLinkedBelief = useCallback(() => {
192
+ if (!selectedLinkedBelief) return;
193
+
194
+ const updatedPaths = { ...paths };
195
+ if (!updatedPaths['LINKED-BELIEFS']) {
196
+ updatedPaths['LINKED-BELIEFS'] = [];
197
+ }
198
+
199
+ // Add the selected belief to the linked beliefs array if not already present
200
+ if (!updatedPaths['LINKED-BELIEFS'].includes(selectedLinkedBelief)) {
201
+ updatedPaths['LINKED-BELIEFS'] = [
202
+ ...updatedPaths['LINKED-BELIEFS'],
203
+ selectedLinkedBelief,
204
+ ];
205
+ }
206
+
207
+ setPaths(updatedPaths);
208
+ setSelectedLinkedBelief('');
209
+ }, [paths, setPaths, selectedLinkedBelief]);
210
+
211
+ // Remove a belief from the linked beliefs array
212
+ const handleRemoveLinkedBelief = useCallback(
213
+ (beliefSlug: string) => {
214
+ const updatedPaths = { ...paths };
215
+ if (updatedPaths['LINKED-BELIEFS']) {
216
+ updatedPaths['LINKED-BELIEFS'] = updatedPaths['LINKED-BELIEFS'].filter(
217
+ (slug) => slug !== beliefSlug
218
+ );
219
+
220
+ // Remove the LINKED-BELIEFS key if it's empty
221
+ if (updatedPaths['LINKED-BELIEFS'].length === 0) {
222
+ delete updatedPaths['LINKED-BELIEFS'];
223
+ }
224
+ }
225
+
226
+ setPaths(updatedPaths);
227
+ },
228
+ [paths, setPaths]
229
+ );
230
+
231
+ // Check if a belief is in match-across
232
+ const isBeliefInMatchAcross = useCallback(
233
+ (beliefKey: string): boolean => {
234
+ return getMatchAcrossBeliefsArray().includes(beliefKey);
235
+ },
236
+ [getMatchAcrossBeliefsArray]
237
+ );
238
+
239
+ // Render custom value editor mode
240
+ if (editingCustomBeliefId) {
241
+ const belief = availableBeliefs.find((b) => b.id === editingCustomBeliefId);
242
+ if (!belief) return null;
243
+
244
+ return (
245
+ <div className="rounded-lg border bg-white p-4">
246
+ <div className="mb-4 flex items-center justify-between">
247
+ <h3 className="text-lg font-bold">
248
+ Edit Custom Values for {belief.title}
249
+ </h3>
250
+ <button
251
+ onClick={() => setEditingCustomBeliefId(null)}
252
+ className="text-gray-500 hover:text-gray-700"
253
+ >
254
+ <XMarkIcon className="h-5 w-5" />
255
+ </button>
256
+ </div>
257
+
258
+ <div className="space-y-4">
259
+ <div className="flex gap-2">
260
+ <input
261
+ type="text"
262
+ value={customValue}
263
+ onChange={(e) => setCustomValue(e.target.value)}
264
+ placeholder="Add a custom value..."
265
+ className="flex-1 rounded-md border px-3 py-2"
266
+ />
267
+ <button
268
+ onClick={() => {
269
+ if (customValue.trim()) {
270
+ setCustomValues((prev) => [...prev, customValue.trim()]);
271
+ setCustomValue('');
272
+ }
273
+ }}
274
+ className="rounded-md bg-cyan-700 p-2 text-white hover:bg-cyan-800"
275
+ >
276
+ <PlusIcon className="h-5 w-5" />
277
+ </button>
278
+ </div>
279
+
280
+ <div className="flex flex-wrap gap-2">
281
+ {customValues.map((value, index) => (
282
+ <div
283
+ key={index}
284
+ className="flex items-center gap-2 rounded-full bg-gray-100 px-3 py-1"
285
+ >
286
+ <span>{value}</span>
287
+ <button
288
+ onClick={() =>
289
+ setCustomValues((prev) =>
290
+ prev.filter((_, i) => i !== index)
291
+ )
292
+ }
293
+ className="text-gray-500 hover:text-gray-700"
294
+ >
295
+ <XMarkIcon className="h-4 w-4" />
296
+ </button>
297
+ </div>
298
+ ))}
299
+ </div>
300
+
301
+ <div className="flex justify-end gap-2">
302
+ <button
303
+ onClick={() => setEditingCustomBeliefId(null)}
304
+ className="rounded bg-gray-200 px-4 py-2 text-gray-800 hover:bg-gray-300"
305
+ >
306
+ Cancel
307
+ </button>
308
+ <button
309
+ onClick={handleSaveCustomValues}
310
+ className="rounded bg-cyan-700 px-4 py-2 text-white hover:bg-cyan-800"
311
+ >
312
+ Save Custom Values
313
+ </button>
314
+ </div>
315
+ </div>
316
+ </div>
317
+ );
318
+ }
319
+
320
+ // Determine if we have completed belief selections (no empty entries)
321
+ const hasCompletedBeliefSelections = beliefKeys.every((key) => key !== '');
322
+
323
+ // Count the number of valid beliefs (non-empty keys)
324
+ const validBeliefCount = beliefKeys.filter((key) => key !== '').length;
325
+
326
+ return (
327
+ <div className="space-y-4">
328
+ <div className="flex items-center justify-between">
329
+ <h3 className="text-lg font-bold">
330
+ {isShowCondition ? 'Show Content When' : 'Hide Content When'}
331
+ </h3>
332
+ <button
333
+ onClick={handleAddPath}
334
+ className="rounded-md bg-cyan-700 p-1 text-white hover:bg-cyan-800"
335
+ title={`Add ${isShowCondition ? 'Show' : 'Hide'} Condition`}
336
+ >
337
+ <PlusIcon className="h-5 w-5" />
338
+ </button>
339
+ </div>
340
+
341
+ {/* Only show Match Across section for Show Conditions with multiple VALID beliefs */}
342
+ {isShowCondition &&
343
+ validBeliefCount > 1 &&
344
+ hasCompletedBeliefSelections && (
345
+ <div className="mb-4 rounded-lg border bg-white p-4">
346
+ <div className="mb-2 flex items-center">
347
+ <h4 className="text-md font-bold">Match Across Logic</h4>
348
+ <span className="ml-2 rounded bg-gray-100 px-2 py-1 text-xs text-gray-500">
349
+ OR between selected beliefs
350
+ </span>
351
+ </div>
352
+ <p className="mb-3 text-sm text-gray-600">
353
+ Select beliefs to match with OR logic (any one can match).
354
+ Unselected beliefs use AND logic (all must match).
355
+ </p>
356
+ <div className="flex flex-wrap gap-2">
357
+ {beliefKeys
358
+ .filter((key) => key !== '')
359
+ .map((key) => (
360
+ <button
361
+ key={key}
362
+ onClick={() => handleToggleMatchAcross(key)}
363
+ className={`rounded-full px-3 py-1 text-sm transition-colors ${
364
+ isBeliefInMatchAcross(key)
365
+ ? 'bg-cyan-600 text-white hover:bg-cyan-700'
366
+ : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
367
+ }`}
368
+ >
369
+ {availableBeliefs.find((b) => b.slug === key)?.title || key}
370
+ </button>
371
+ ))}
372
+ </div>
373
+ </div>
374
+ )}
375
+
376
+ {beliefKeys.map((key) => (
377
+ <div key={key} className="rounded-lg border bg-white p-4">
378
+ <div className="space-y-4">
379
+ <div>
380
+ <label className="mb-1 block text-sm text-gray-600">
381
+ Select Belief
382
+ </label>
383
+ <select
384
+ value={key}
385
+ onChange={(e) => handleBeliefChange(key, e.target.value)}
386
+ className="w-full rounded-md border px-3 py-2"
387
+ >
388
+ <option value="">Select a belief</option>
389
+ {availableBeliefs.map((belief) => (
390
+ <option key={belief.slug} value={belief.slug}>
391
+ {belief.title}
392
+ </option>
393
+ ))}
394
+ </select>
395
+ </div>
396
+
397
+ {key && (
398
+ <div>
399
+ <label className="mb-1 block text-sm text-gray-600">
400
+ Select Values
401
+ </label>
402
+ <div className="flex flex-wrap gap-2">
403
+ {paths[key].map((value, valueIndex) => {
404
+ const validValues = getValidValuesForBelief(key);
405
+ const belief = availableBeliefs.find((b) => b.slug === key);
406
+
407
+ return (
408
+ <div key={valueIndex} className="flex items-center gap-1">
409
+ <select
410
+ value={value}
411
+ onChange={(e) =>
412
+ handleValueChange(key, valueIndex, e.target.value)
413
+ }
414
+ className="rounded-md border px-3 py-2"
415
+ >
416
+ {validValues.map((val) => (
417
+ <option key={val} value={val}>
418
+ {val === '*' ? 'Match Any Value' : val}
419
+ </option>
420
+ ))}
421
+ </select>
422
+
423
+ <div className="flex gap-1">
424
+ <button
425
+ onClick={() => handleRemoveValue(key, valueIndex)}
426
+ className="text-gray-500 hover:text-gray-700"
427
+ title="Remove value"
428
+ >
429
+ <XMarkIcon className="h-5 w-5" />
430
+ </button>
431
+ {valueIndex === paths[key].length - 1 && (
432
+ <button
433
+ onClick={() => {
434
+ const updatedPaths = { ...paths };
435
+ updatedPaths[key] = [...paths[key], '*'];
436
+ setPaths(updatedPaths);
437
+ }}
438
+ className="text-gray-500 hover:text-gray-700"
439
+ title="Add value"
440
+ >
441
+ <PlusIcon className="h-5 w-5" />
442
+ </button>
443
+ )}
444
+ </div>
445
+
446
+ {belief?.scale === 'custom' && valueIndex === 0 && (
447
+ <button
448
+ onClick={() =>
449
+ handleEditCustomValues(
450
+ belief.id,
451
+ belief.customValues || []
452
+ )
453
+ }
454
+ className="ml-2 text-cyan-700 hover:text-cyan-800"
455
+ title="Edit custom values"
456
+ >
457
+ <BeakerIcon className="h-5 w-5" />
458
+ </button>
459
+ )}
460
+ </div>
461
+ );
462
+ })}
463
+ </div>
464
+ </div>
465
+ )}
466
+ </div>
467
+ </div>
468
+ ))}
469
+
470
+ {/* Linked Beliefs section - always show */}
471
+ {isShowCondition && (
472
+ <div className="mb-4 rounded-lg border bg-white p-4">
473
+ <div className="mb-2 flex items-center">
474
+ <h4 className="text-md font-bold">Linked Beliefs</h4>
475
+ <span className="ml-2 flex items-center rounded bg-gray-100 px-2 py-1 text-xs text-gray-500">
476
+ <LinkIcon className="mr-1 h-3 w-3" />
477
+ Unset together
478
+ </span>
479
+ </div>
480
+ <p className="mb-3 text-sm text-gray-600">
481
+ Select beliefs to link with this condition. When any belief is
482
+ unset, all linked beliefs will be unset together.
483
+ </p>
484
+
485
+ {/* Dropdown to select new linked beliefs */}
486
+ <div className="mb-3 flex gap-2">
487
+ <select
488
+ value={selectedLinkedBelief}
489
+ onChange={(e) => setSelectedLinkedBelief(e.target.value)}
490
+ className="flex-1 rounded-md border px-3 py-2"
491
+ >
492
+ <option value="">Select a belief to link</option>
493
+ {availableLinkedBeliefs.map((belief) => (
494
+ <option key={belief.slug} value={belief.slug}>
495
+ {belief.title}
496
+ </option>
497
+ ))}
498
+ </select>
499
+ <button
500
+ onClick={handleAddLinkedBelief}
501
+ disabled={!selectedLinkedBelief}
502
+ className={`rounded-md p-2 ${
503
+ selectedLinkedBelief
504
+ ? 'bg-cyan-600 text-white hover:bg-cyan-700'
505
+ : 'cursor-not-allowed bg-gray-200 text-gray-500'
506
+ }`}
507
+ >
508
+ <PlusIcon className="h-5 w-5" />
509
+ </button>
510
+ </div>
511
+
512
+ {/* Display linked beliefs as tags */}
513
+ <div className="flex flex-wrap gap-2">
514
+ {linkedBeliefs.map((beliefSlug) => {
515
+ const belief = availableBeliefs.find(
516
+ (b) => b.slug === beliefSlug
517
+ );
518
+ return (
519
+ <div
520
+ key={beliefSlug}
521
+ className="flex items-center gap-2 rounded-full bg-cyan-100 px-3 py-1 text-cyan-800"
522
+ >
523
+ <LinkIcon className="h-3 w-3" />
524
+ <span>{belief?.title || beliefSlug}</span>
525
+ <button
526
+ onClick={() => handleRemoveLinkedBelief(beliefSlug)}
527
+ className="text-cyan-600 hover:text-cyan-800"
528
+ >
529
+ <XMarkIcon className="h-4 w-4" />
530
+ </button>
531
+ </div>
532
+ );
533
+ })}
534
+ {linkedBeliefs.length === 0 && (
535
+ <p className="text-sm italic text-gray-500">
536
+ No linked beliefs selected
537
+ </p>
538
+ )}
539
+ </div>
540
+ </div>
541
+ )}
542
+ </div>
543
+ );
544
+ };
545
+
546
+ export default MagicPathBuilder;
@@ -0,0 +1,101 @@
1
+ import { forwardRef, useId } from 'react';
2
+ import { classNames } from '@/utils/helpers';
3
+
4
+ interface NumberInputProps {
5
+ value: number;
6
+ onChange: (value: number) => void;
7
+ label?: string;
8
+ error?: string;
9
+ disabled?: boolean;
10
+ placeholder?: string;
11
+ required?: boolean;
12
+ min?: number;
13
+ max?: number;
14
+ step?: number;
15
+ className?: string;
16
+ id?: string;
17
+ name?: string;
18
+ }
19
+
20
+ const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
21
+ (
22
+ {
23
+ value,
24
+ onChange,
25
+ label,
26
+ error,
27
+ disabled = false,
28
+ placeholder,
29
+ required = false,
30
+ min,
31
+ max,
32
+ step = 1,
33
+ className,
34
+ id: customId,
35
+ name: customName,
36
+ },
37
+ ref
38
+ ) => {
39
+ // Generate unique IDs for accessibility
40
+ const defaultId = useId();
41
+ const inputId = customId || defaultId;
42
+ const errorId = `${inputId}-error`;
43
+ const inputName = customName || inputId;
44
+
45
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
46
+ const newValue = parseFloat(e.target.value);
47
+ if (!isNaN(newValue)) {
48
+ onChange(newValue);
49
+ } else if (e.target.value === '') {
50
+ onChange(0);
51
+ }
52
+ };
53
+
54
+ return (
55
+ <div className={classNames('space-y-1', className || '')}>
56
+ {label && (
57
+ <label
58
+ htmlFor={inputId}
59
+ className="block text-sm font-bold text-gray-700"
60
+ >
61
+ {label}
62
+ {required && <span className="ml-1 text-red-500">*</span>}
63
+ </label>
64
+ )}
65
+ <input
66
+ ref={ref}
67
+ id={inputId}
68
+ name={inputName}
69
+ type="number"
70
+ value={value}
71
+ onChange={handleChange}
72
+ disabled={disabled}
73
+ placeholder={placeholder}
74
+ required={required}
75
+ min={min}
76
+ max={max}
77
+ step={step}
78
+ aria-invalid={!!error}
79
+ aria-describedby={error ? errorId : undefined}
80
+ className={classNames(
81
+ 'block w-full rounded-md border-0 px-3 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset',
82
+ error ? 'ring-red-300 focus:ring-red-500' : 'focus:ring-cyan-600',
83
+ disabled
84
+ ? 'cursor-not-allowed bg-gray-50 text-gray-500'
85
+ : 'bg-white',
86
+ 'sm:text-sm sm:leading-6'
87
+ )}
88
+ />
89
+ {error && (
90
+ <p id={errorId} className="text-sm text-red-600" role="alert">
91
+ {error}
92
+ </p>
93
+ )}
94
+ </div>
95
+ );
96
+ }
97
+ );
98
+
99
+ NumberInput.displayName = 'NumberInput';
100
+
101
+ export default NumberInput;