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.
- package/LICENSE +110 -0
- package/README.md +56 -0
- package/astro.d.ts +64 -0
- package/bin/create-tractstack.js +483 -0
- package/dist/config.js +80 -0
- package/dist/index.js +2129 -0
- package/package.json +89 -0
- package/templates/artpacks/kCz/captainBreakfast_1080px.webp +0 -0
- package/templates/artpacks/kCz/captainBreakfast_1920px.webp +0 -0
- package/templates/artpacks/kCz/captainBreakfast_600px.webp +0 -0
- package/templates/artpacks/kCz/cleanDrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/cleanDrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/cleanDrips_600px.webp +0 -0
- package/templates/artpacks/kCz/crispwaves_1080px.webp +0 -0
- package/templates/artpacks/kCz/crispwaves_1920px.webp +0 -0
- package/templates/artpacks/kCz/crispwaves_600px.webp +0 -0
- package/templates/artpacks/kCz/dragonSkin_1080px.webp +0 -0
- package/templates/artpacks/kCz/dragonSkin_1920px.webp +0 -0
- package/templates/artpacks/kCz/dragonSkin_600px.webp +0 -0
- package/templates/artpacks/kCz/dragon_1080px.webp +0 -0
- package/templates/artpacks/kCz/dragon_1920px.webp +0 -0
- package/templates/artpacks/kCz/dragon_600px.webp +0 -0
- package/templates/artpacks/kCz/nightcity_1080px.webp +0 -0
- package/templates/artpacks/kCz/nightcity_1920px.webp +0 -0
- package/templates/artpacks/kCz/nightcity_600px.webp +0 -0
- package/templates/artpacks/kCz/pattern1_1080px.webp +0 -0
- package/templates/artpacks/kCz/pattern1_1920px.webp +0 -0
- package/templates/artpacks/kCz/pattern1_600px.webp +0 -0
- package/templates/artpacks/kCz/pattern2_1080px.webp +0 -0
- package/templates/artpacks/kCz/pattern2_1920px.webp +0 -0
- package/templates/artpacks/kCz/pattern2_600px.webp +0 -0
- package/templates/artpacks/kCz/skindrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/skindrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/skindrips_600px.webp +0 -0
- package/templates/artpacks/kCz/slimetime_1080px.webp +0 -0
- package/templates/artpacks/kCz/slimetime_1920px.webp +0 -0
- package/templates/artpacks/kCz/slimetime_600px.webp +0 -0
- package/templates/artpacks/kCz/snake_1080px.webp +0 -0
- package/templates/artpacks/kCz/snake_1920px.webp +0 -0
- package/templates/artpacks/kCz/snake_600px.webp +0 -0
- package/templates/artpacks/kCz/toxicshock_1080px.webp +0 -0
- package/templates/artpacks/kCz/toxicshock_1920px.webp +0 -0
- package/templates/artpacks/kCz/toxicshock_600px.webp +0 -0
- package/templates/artpacks/kCz/tractstack_1080px.webp +0 -0
- package/templates/artpacks/kCz/tractstack_1920px.webp +0 -0
- package/templates/artpacks/kCz/tractstack_600px.webp +0 -0
- package/templates/artpacks/kCz/tripdrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/tripdrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/tripdrips_600px.webp +0 -0
- package/templates/artpacks/kCz/wavedrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/wavedrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/wavedrips_600px.webp +0 -0
- package/templates/artpacks/t8k/beach_1080px.webp +0 -0
- package/templates/artpacks/t8k/beach_1920px.webp +0 -0
- package/templates/artpacks/t8k/beach_600px.webp +0 -0
- package/templates/artpacks/t8k/blast_1080px.webp +0 -0
- package/templates/artpacks/t8k/blast_1920px.webp +0 -0
- package/templates/artpacks/t8k/blast_600px.webp +0 -0
- package/templates/artpacks/t8k/bokeh_1080px.webp +0 -0
- package/templates/artpacks/t8k/bokeh_1920px.webp +0 -0
- package/templates/artpacks/t8k/bokeh_600px.webp +0 -0
- package/templates/artpacks/t8k/cartoon_1080px.webp +0 -0
- package/templates/artpacks/t8k/cartoon_1920px.webp +0 -0
- package/templates/artpacks/t8k/cartoon_600px.webp +0 -0
- package/templates/artpacks/t8k/darkeggshell_1080px.webp +0 -0
- package/templates/artpacks/t8k/darkeggshell_1920px.webp +0 -0
- package/templates/artpacks/t8k/darkeggshell_600px.webp +0 -0
- package/templates/artpacks/t8k/explosion_1080px.webp +0 -0
- package/templates/artpacks/t8k/explosion_1920px.webp +0 -0
- package/templates/artpacks/t8k/explosion_600px.webp +0 -0
- package/templates/artpacks/t8k/floral_1080px.webp +0 -0
- package/templates/artpacks/t8k/floral_1920px.webp +0 -0
- package/templates/artpacks/t8k/floral_600px.webp +0 -0
- package/templates/artpacks/t8k/flower_1080px.webp +0 -0
- package/templates/artpacks/t8k/flower_1920px.webp +0 -0
- package/templates/artpacks/t8k/flower_600px.webp +0 -0
- package/templates/artpacks/t8k/foliage_1080px.webp +0 -0
- package/templates/artpacks/t8k/foliage_1920px.webp +0 -0
- package/templates/artpacks/t8k/foliage_600px.webp +0 -0
- package/templates/artpacks/t8k/mist_1080px.webp +0 -0
- package/templates/artpacks/t8k/mist_1920px.webp +0 -0
- package/templates/artpacks/t8k/mist_600px.webp +0 -0
- package/templates/artpacks/t8k/portal_1080px.webp +0 -0
- package/templates/artpacks/t8k/portal_1920px.webp +0 -0
- package/templates/artpacks/t8k/portal_600px.webp +0 -0
- package/templates/artpacks/t8k/storytime_1080px.webp +0 -0
- package/templates/artpacks/t8k/storytime_1920px.webp +0 -0
- package/templates/artpacks/t8k/storytime_600px.webp +0 -0
- package/templates/artpacks/t8k/tacky_1080px.webp +0 -0
- package/templates/artpacks/t8k/tacky_1920px.webp +0 -0
- package/templates/artpacks/t8k/tacky_600px.webp +0 -0
- package/templates/artpacks/t8k/wallpaper_1080px.webp +0 -0
- package/templates/artpacks/t8k/wallpaper_1920px.webp +0 -0
- package/templates/artpacks/t8k/wallpaper_600px.webp +0 -0
- package/templates/brand/favicon.ico +0 -0
- package/templates/brand/logo.svg +19 -0
- package/templates/brand/static.jpg +0 -0
- package/templates/brand/wordmark.svg +4 -0
- package/templates/css/custom.css +51 -0
- package/templates/css/frontend.css +3519 -0
- package/templates/css/storykeep.css +92872 -0
- package/templates/custom/minimal/CodeHook.astro +53 -0
- package/templates/custom/minimal/CustomRoutes.astro +46 -0
- package/templates/custom/with-examples/CodeHook.astro +49 -0
- package/templates/custom/with-examples/CustomHero.astro +13 -0
- package/templates/custom/with-examples/CustomRoutes.astro +39 -0
- package/templates/custom/with-examples/pages/Collections.astro +110 -0
- package/templates/env.example +8 -0
- package/templates/fonts/Inter-Black.woff2 +0 -0
- package/templates/fonts/Inter-Bold.woff2 +0 -0
- package/templates/fonts/Inter-Regular.woff2 +0 -0
- package/templates/icons/h2.svg +1 -0
- package/templates/icons/h3.svg +1 -0
- package/templates/icons/h4.svg +1 -0
- package/templates/icons/h5.svg +1 -0
- package/templates/icons/image.svg +7 -0
- package/templates/icons/text.svg +6 -0
- package/templates/socials/codepen.svg +1 -0
- package/templates/socials/discord.svg +1 -0
- package/templates/socials/facebook.svg +1 -0
- package/templates/socials/github.svg +1 -0
- package/templates/socials/instagram.svg +1 -0
- package/templates/socials/linkedin.svg +1 -0
- package/templates/socials/mail.svg +1 -0
- package/templates/socials/rumble.svg +1 -0
- package/templates/socials/tiktok.svg +1 -0
- package/templates/socials/twitch.svg +1 -0
- package/templates/socials/twitter.svg +1 -0
- package/templates/socials/x.svg +1 -0
- package/templates/socials/youtube.svg +1 -0
- package/templates/src/client/analytics-events.ts +213 -0
- package/templates/src/client/belief-events.ts +205 -0
- package/templates/src/client/sse.ts +667 -0
- package/templates/src/components/Footer.astro +246 -0
- package/templates/src/components/Fragment.astro +70 -0
- package/templates/src/components/Header.astro +458 -0
- package/templates/src/components/Menu.tsx +196 -0
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +692 -0
- package/templates/src/components/codehooks/BunnyVideoWrapper.astro +78 -0
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +1020 -0
- package/templates/src/components/codehooks/EpinetTableView.tsx +594 -0
- package/templates/src/components/codehooks/EpinetWrapper.tsx +424 -0
- package/templates/src/components/codehooks/FeaturedContent.astro +273 -0
- package/templates/src/components/codehooks/FeaturedContentSetup.tsx +738 -0
- package/templates/src/components/codehooks/ListContent.astro +460 -0
- package/templates/src/components/codehooks/ListContentSetup.tsx +649 -0
- package/templates/src/components/codehooks/SankeyDiagram.tsx +359 -0
- package/templates/src/components/compositor/Compositor.tsx +144 -0
- package/templates/src/components/compositor/Node.tsx +415 -0
- package/templates/src/components/compositor/NodeWithGuid.tsx +25 -0
- package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +87 -0
- package/templates/src/components/compositor/elements/Belief.tsx +148 -0
- package/templates/src/components/compositor/elements/BgImage.tsx +118 -0
- package/templates/src/components/compositor/elements/BgVisualBreak.tsx +102 -0
- package/templates/src/components/compositor/elements/BunnyVideo.tsx +63 -0
- package/templates/src/components/compositor/elements/IdentifyAs.tsx +66 -0
- package/templates/src/components/compositor/elements/PlayButton.tsx +19 -0
- package/templates/src/components/compositor/elements/SignUp.tsx +179 -0
- package/templates/src/components/compositor/elements/Svg.tsx +33 -0
- package/templates/src/components/compositor/elements/ToggleBelief.tsx +36 -0
- package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +33 -0
- package/templates/src/components/compositor/nodes/BgPaneWrapper.tsx +35 -0
- package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +189 -0
- package/templates/src/components/compositor/nodes/Markdown.tsx +179 -0
- package/templates/src/components/compositor/nodes/Pane.tsx +277 -0
- package/templates/src/components/compositor/nodes/Pane_eraser.tsx +69 -0
- package/templates/src/components/compositor/nodes/Pane_layout.tsx +77 -0
- package/templates/src/components/compositor/nodes/RenderChildren.tsx +19 -0
- package/templates/src/components/compositor/nodes/StoryFragment.tsx +35 -0
- package/templates/src/components/compositor/nodes/TagElement.tsx +14 -0
- package/templates/src/components/compositor/nodes/Widget.tsx +115 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeA.tsx +4 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +26 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +248 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +684 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +62 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +120 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +62 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeButton.tsx +5 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +26 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +28 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +18 -0
- package/templates/src/components/compositor/nodes/tagElements/TabIndicator.tsx +51 -0
- package/templates/src/components/compositor/preview/FeaturedContentPreview.tsx +128 -0
- package/templates/src/components/compositor/preview/ListContentPreview.tsx +213 -0
- package/templates/src/components/compositor/preview/OgImagePreview.tsx +223 -0
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +199 -0
- package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +123 -0
- package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +154 -0
- package/templates/src/components/edit/Header.tsx +181 -0
- package/templates/src/components/edit/PanelSwitch.tsx +446 -0
- package/templates/src/components/edit/SettingsPanel.tsx +70 -0
- package/templates/src/components/edit/ToolBar.tsx +101 -0
- package/templates/src/components/edit/ToolMode.tsx +121 -0
- package/templates/src/components/edit/context/ContextPaneConfig.tsx +91 -0
- package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +174 -0
- package/templates/src/components/edit/context/ContextPaneConfig_title.tsx +186 -0
- package/templates/src/components/edit/pane/AddPanePanel.tsx +136 -0
- package/templates/src/components/edit/pane/AddPanePanel_break.tsx +470 -0
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +264 -0
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +623 -0
- package/templates/src/components/edit/pane/AddPanePanel_newAICopy.tsx +107 -0
- package/templates/src/components/edit/pane/AddPanePanel_newAICopy_modal.tsx +217 -0
- package/templates/src/components/edit/pane/AddPanePanel_newCopyMode.tsx +109 -0
- package/templates/src/components/edit/pane/AddPanePanel_newCustomCopy.tsx +39 -0
- package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +445 -0
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +245 -0
- package/templates/src/components/edit/pane/PageGen.tsx +485 -0
- package/templates/src/components/edit/pane/PageGenSelector.tsx +238 -0
- package/templates/src/components/edit/pane/PageGenSpecial.tsx +362 -0
- package/templates/src/components/edit/pane/PageGen_preview.tsx +495 -0
- package/templates/src/components/edit/pane/PanePanel_impression.tsx +258 -0
- package/templates/src/components/edit/pane/PanePanel_path.tsx +268 -0
- package/templates/src/components/edit/pane/PanePanel_slug.tsx +219 -0
- package/templates/src/components/edit/pane/PanePanel_title.tsx +142 -0
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +182 -0
- package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +439 -0
- package/templates/src/components/edit/panels/StyleElementPanel.tsx +177 -0
- package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +349 -0
- package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +159 -0
- package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +320 -0
- package/templates/src/components/edit/panels/StyleImagePanel.tsx +460 -0
- package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +296 -0
- package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +153 -0
- package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +312 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel.tsx +273 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +301 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +132 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +313 -0
- package/templates/src/components/edit/panels/StyleLinkPanel.tsx +346 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_add.tsx +265 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +240 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_remove.tsx +94 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +110 -0
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +263 -0
- package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +275 -0
- package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +112 -0
- package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +87 -0
- package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +141 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +428 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +292 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +190 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +152 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +308 -0
- package/templates/src/components/edit/state/SaveModal.tsx +811 -0
- package/templates/src/components/edit/state/StylesMemory.tsx +310 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +289 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +320 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +888 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +269 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_title.tsx +190 -0
- package/templates/src/components/edit/widgets/BeliefWidget.tsx +183 -0
- package/templates/src/components/edit/widgets/BunnyWidget.tsx +134 -0
- package/templates/src/components/edit/widgets/IdentifyAsWidget.tsx +193 -0
- package/templates/src/components/edit/widgets/SignupWidget.tsx +177 -0
- package/templates/src/components/edit/widgets/ToggleWidget.tsx +152 -0
- package/templates/src/components/edit/widgets/YouTubeWidget.tsx +65 -0
- package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +353 -0
- package/templates/src/components/fields/ArtpackImage.tsx +480 -0
- package/templates/src/components/fields/BackgroundImage.tsx +530 -0
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +192 -0
- package/templates/src/components/fields/BooleanParam.tsx +67 -0
- package/templates/src/components/fields/BunnyMomentSelector.tsx +56 -0
- package/templates/src/components/fields/ColorPickerCombo.tsx +284 -0
- package/templates/src/components/fields/ImageUpload.tsx +405 -0
- package/templates/src/components/fields/MultiParam.tsx +75 -0
- package/templates/src/components/fields/PaneBreakCollectionSelector.tsx +97 -0
- package/templates/src/components/fields/PaneBreakShapeSelector.tsx +134 -0
- package/templates/src/components/fields/SelectedTailwindClass.tsx +44 -0
- package/templates/src/components/fields/SingleParam.tsx +73 -0
- package/templates/src/components/fields/ViewportComboBox.tsx +252 -0
- package/templates/src/components/form/ActionBuilderField.tsx +282 -0
- package/templates/src/components/form/ActionBuilderSlugSelector.tsx +182 -0
- package/templates/src/components/form/BooleanToggle.tsx +94 -0
- package/templates/src/components/form/ColorPicker.tsx +153 -0
- package/templates/src/components/form/DateTimeInput.tsx +638 -0
- package/templates/src/components/form/EnumSelect.tsx +88 -0
- package/templates/src/components/form/FileUpload.tsx +465 -0
- package/templates/src/components/form/MagicPathBuilder.tsx +546 -0
- package/templates/src/components/form/NumberInput.tsx +101 -0
- package/templates/src/components/form/ParagraphArrayInput.tsx +207 -0
- package/templates/src/components/form/StringArrayInput.tsx +163 -0
- package/templates/src/components/form/StringInput.tsx +88 -0
- package/templates/src/components/form/UnsavedChangesBar.tsx +295 -0
- package/templates/src/components/form/advanced/APIConfigSection.tsx +69 -0
- package/templates/src/components/form/advanced/AuthConfigSection.tsx +97 -0
- package/templates/src/components/form/brand/BrandAssetsSection.tsx +93 -0
- package/templates/src/components/form/brand/BrandColorsSection.tsx +201 -0
- package/templates/src/components/form/brand/SEOSection.tsx +101 -0
- package/templates/src/components/form/brand/SiteConfigSection.tsx +61 -0
- package/templates/src/components/form/brand/SocialLinksSection.tsx +393 -0
- package/templates/src/components/profile/ProfileConsent.tsx +65 -0
- package/templates/src/components/profile/ProfileCreate.tsx +462 -0
- package/templates/src/components/profile/ProfileEdit.tsx +409 -0
- package/templates/src/components/profile/ProfileSwitch.tsx +255 -0
- package/templates/src/components/profile/ProfileUnlock.tsx +221 -0
- package/templates/src/components/storykeep/Dashboard.tsx +160 -0
- package/templates/src/components/storykeep/Dashboard_Activity.tsx +56 -0
- package/templates/src/components/storykeep/Dashboard_Advanced.tsx +165 -0
- package/templates/src/components/storykeep/Dashboard_Analytics.tsx +451 -0
- package/templates/src/components/storykeep/Dashboard_Branding.tsx +95 -0
- package/templates/src/components/storykeep/Dashboard_Content.tsx +191 -0
- package/templates/src/components/storykeep/controls/UsageCell.tsx +71 -0
- package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +378 -0
- package/templates/src/components/storykeep/controls/content/BeliefTable.tsx +329 -0
- package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +385 -0
- package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +149 -0
- package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +397 -0
- package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +260 -0
- package/templates/src/components/storykeep/controls/content/ManageContent.tsx +439 -0
- package/templates/src/components/storykeep/controls/content/MenuForm.tsx +239 -0
- package/templates/src/components/storykeep/controls/content/MenuTable.tsx +332 -0
- package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +724 -0
- package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +355 -0
- package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +222 -0
- package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +482 -0
- package/templates/src/components/storykeep/state/BrandingWrapper.tsx +42 -0
- package/templates/src/components/storykeep/state/FetchAnalytics.tsx +350 -0
- package/templates/src/components/storykeep/widgets/ResponsiveLine.tsx +319 -0
- package/templates/src/components/storykeep/widgets/Wizard.tsx +278 -0
- package/templates/src/components/tenant/RegistrationForm.tsx +447 -0
- package/templates/src/components/widgets/BunnyVideoHero.astro +775 -0
- package/templates/src/components/widgets/Impression.tsx +102 -0
- package/templates/src/components/widgets/ImpressionWrapper.tsx +214 -0
- package/templates/src/constants/beliefs.ts +61 -0
- package/templates/src/constants/brandThemes.ts +133 -0
- package/templates/src/constants/prompts.json +55 -0
- package/templates/src/constants/shapes.ts +556 -0
- package/templates/src/constants/stopWords.ts +116 -0
- package/templates/src/constants/tailwindColors.json +344 -0
- package/templates/src/constants.ts +274 -0
- package/templates/src/hooks/useFormState.ts +203 -0
- package/templates/src/layouts/Layout.astro +290 -0
- package/templates/src/lib/session.ts +126 -0
- package/templates/src/lib/storyData.ts +56 -0
- package/templates/src/middleware.ts +52 -0
- package/templates/src/pages/404.astro +54 -0
- package/templates/src/pages/[...slug]/edit.astro +216 -0
- package/templates/src/pages/[...slug].astro +148 -0
- package/templates/src/pages/api/auth/decode.ts +101 -0
- package/templates/src/pages/api/auth/login.ts +122 -0
- package/templates/src/pages/api/auth/logout.ts +37 -0
- package/templates/src/pages/api/auth/profile.ts +76 -0
- package/templates/src/pages/api/orphan-analysis.ts +106 -0
- package/templates/src/pages/api/tailwind.ts +116 -0
- package/templates/src/pages/collections/[param1].astro +65 -0
- package/templates/src/pages/context/[...contextSlug]/edit.astro +207 -0
- package/templates/src/pages/context/[...contextSlug].astro +161 -0
- package/templates/src/pages/llms.txt.ts +122 -0
- package/templates/src/pages/maint.astro +183 -0
- package/templates/src/pages/media/[...slug].astro +67 -0
- package/templates/src/pages/robots.txt.ts +36 -0
- package/templates/src/pages/sandbox/activate.astro +258 -0
- package/templates/src/pages/sandbox/register.astro +44 -0
- package/templates/src/pages/sandbox/success.astro +179 -0
- package/templates/src/pages/sitemap.xml.ts +119 -0
- package/templates/src/pages/storykeep/advanced.astro +69 -0
- package/templates/src/pages/storykeep/branding.astro +57 -0
- package/templates/src/pages/storykeep/content.astro +71 -0
- package/templates/src/pages/storykeep/init.astro +36 -0
- package/templates/src/pages/storykeep/login.astro +266 -0
- package/templates/src/pages/storykeep/logout.astro +84 -0
- package/templates/src/pages/storykeep/profile.astro +98 -0
- package/templates/src/pages/storykeep.astro +81 -0
- package/templates/src/stores/analytics.ts +171 -0
- package/templates/src/stores/backend.ts +16 -0
- package/templates/src/stores/navigation.ts +149 -0
- package/templates/src/stores/nodes.ts +2390 -0
- package/templates/src/stores/nodesHistory.ts +85 -0
- package/templates/src/stores/notificationSystem.ts +41 -0
- package/templates/src/stores/orphanAnalysis.ts +409 -0
- package/templates/src/stores/storykeep.ts +247 -0
- package/templates/src/types/astro.ts +86 -0
- package/templates/src/types/compositorTypes.ts +456 -0
- package/templates/src/types/formTypes.ts +281 -0
- package/templates/src/types/multiTenant.ts +77 -0
- package/templates/src/types/nodeProps.ts +66 -0
- package/templates/src/types/tractstack.ts +445 -0
- package/templates/src/utils/aai/getTitleSlug.ts +72 -0
- package/templates/src/utils/actions/actionButton.ts +101 -0
- package/templates/src/utils/actions/lispLexer.ts +57 -0
- package/templates/src/utils/actions/preParse_Action.ts +85 -0
- package/templates/src/utils/actions/preParse_Bunny.ts +50 -0
- package/templates/src/utils/actions/preParse_Clicked.ts +87 -0
- package/templates/src/utils/actions/preParse_Impression.ts +71 -0
- package/templates/src/utils/api/advancedConfig.ts +66 -0
- package/templates/src/utils/api/advancedHelpers.ts +134 -0
- package/templates/src/utils/api/beliefConfig.ts +87 -0
- package/templates/src/utils/api/beliefHelpers.ts +196 -0
- package/templates/src/utils/api/brandConfig.ts +126 -0
- package/templates/src/utils/api/brandHelpers.ts +155 -0
- package/templates/src/utils/api/fileHelpers.ts +306 -0
- package/templates/src/utils/api/menuConfig.ts +57 -0
- package/templates/src/utils/api/menuHelpers.ts +156 -0
- package/templates/src/utils/api/resourceConfig.ts +158 -0
- package/templates/src/utils/api/resourceHelpers.ts +72 -0
- package/templates/src/utils/api/tenantConfig.ts +97 -0
- package/templates/src/utils/api/tenantHelpers.ts +172 -0
- package/templates/src/utils/api.ts +183 -0
- package/templates/src/utils/auth.ts +150 -0
- package/templates/src/utils/backend.ts +243 -0
- package/templates/src/utils/compositor/TemplateMarkdowns.ts +118 -0
- package/templates/src/utils/compositor/TemplateNodes.ts +138 -0
- package/templates/src/utils/compositor/TemplatePanes.ts +100 -0
- package/templates/src/utils/compositor/allowInsert.ts +100 -0
- package/templates/src/utils/compositor/domHelpers.ts +37 -0
- package/templates/src/utils/compositor/handleClickEvent.ts +131 -0
- package/templates/src/utils/compositor/nodesHelper.ts +491 -0
- package/templates/src/utils/compositor/nodesMarkdownGenerator.ts +292 -0
- package/templates/src/utils/compositor/processMarkdown.ts +431 -0
- package/templates/src/utils/compositor/reduceNodesClassNames.ts +192 -0
- package/templates/src/utils/compositor/tailwindClasses.ts +1795 -0
- package/templates/src/utils/compositor/tailwindColors.ts +227 -0
- package/templates/src/utils/compositor/templateMarkdownStyles.ts +1265 -0
- package/templates/src/utils/compositor/typeGuards.ts +193 -0
- package/templates/src/utils/etl/extractor.ts +119 -0
- package/templates/src/utils/etl/index.ts +88 -0
- package/templates/src/utils/etl/loader.ts +36 -0
- package/templates/src/utils/etl/transformer.ts +286 -0
- package/templates/src/utils/helpers.ts +435 -0
- package/templates/src/utils/layout.ts +209 -0
- package/templates/src/utils/profileStorage.ts +306 -0
- package/templates/src/utils/useInterval.ts +27 -0
- package/templates/tailwind.config.cjs +169 -0
- package/utils/create-resolver.ts +10 -0
- package/utils/inject-files.ts +2140 -0
- package/utils/validate-config.ts +43 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { classNames } from '@/utils/helpers';
|
|
3
|
+
import { TractStackAPI } from '@/utils/api';
|
|
4
|
+
import {
|
|
5
|
+
handleContentSubtabChange,
|
|
6
|
+
restoreTabNavigation,
|
|
7
|
+
} from '@/stores/navigation';
|
|
8
|
+
import ContentBrowser from './controls/content/ContentBrowser';
|
|
9
|
+
import ManageContent from './controls/content/ManageContent';
|
|
10
|
+
import type { FullContentMapItem } from '@/types/tractstack';
|
|
11
|
+
|
|
12
|
+
interface StoryKeepDashboardContentProps {
|
|
13
|
+
fullContentMap: FullContentMapItem[];
|
|
14
|
+
homeSlug: string;
|
|
15
|
+
createMenu: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ContentTab {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const contentTabs: ContentTab[] = [
|
|
24
|
+
{ id: 'webpages', name: 'Web Pages' },
|
|
25
|
+
{ id: 'manage', name: 'Manage Content' },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const StoryKeepDashboard_Content = ({
|
|
29
|
+
fullContentMap,
|
|
30
|
+
homeSlug,
|
|
31
|
+
createMenu,
|
|
32
|
+
}: StoryKeepDashboardContentProps) => {
|
|
33
|
+
const [activeContentTab, setActiveContentTab] = useState('webpages');
|
|
34
|
+
const [navigationRestored, setNavigationRestored] = useState(false);
|
|
35
|
+
|
|
36
|
+
// Lightweight analytics data state - only for hotContent
|
|
37
|
+
const [analytics, setAnalytics] = useState<{
|
|
38
|
+
dashboard: {
|
|
39
|
+
hotContent?: Array<{ id: string; totalEvents: number }>;
|
|
40
|
+
} | null;
|
|
41
|
+
isLoading: boolean;
|
|
42
|
+
status: string;
|
|
43
|
+
error: string | null;
|
|
44
|
+
}>({
|
|
45
|
+
dashboard: null,
|
|
46
|
+
isLoading: false,
|
|
47
|
+
status: 'idle',
|
|
48
|
+
error: null,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Restore navigation state when component mounts or when returning to Content tab
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!navigationRestored) {
|
|
54
|
+
const contentNavigation = restoreTabNavigation();
|
|
55
|
+
if (contentNavigation) {
|
|
56
|
+
setActiveContentTab(contentNavigation.subtab);
|
|
57
|
+
}
|
|
58
|
+
setNavigationRestored(true);
|
|
59
|
+
}
|
|
60
|
+
}, [navigationRestored]);
|
|
61
|
+
|
|
62
|
+
// Enhanced content tab change with navigation tracking
|
|
63
|
+
const handleContentTabChange = (tabId: string) => {
|
|
64
|
+
handleContentSubtabChange(tabId as any, setActiveContentTab);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Lightweight content summary fetch with retry logic
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
let retryCount = 0;
|
|
70
|
+
const maxRetries = 2;
|
|
71
|
+
|
|
72
|
+
const fetchContentSummary = async () => {
|
|
73
|
+
try {
|
|
74
|
+
setAnalytics((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
75
|
+
|
|
76
|
+
// Use TractStackAPI like FetchAnalytics does
|
|
77
|
+
const api = new TractStackAPI(
|
|
78
|
+
window.TRACTSTACK_CONFIG?.tenantId || 'default'
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const response = await api.get('/api/v1/analytics/content-summary');
|
|
82
|
+
|
|
83
|
+
if (!response.success) {
|
|
84
|
+
throw new Error(response.error || 'Failed to fetch content summary');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const data = response.data;
|
|
88
|
+
|
|
89
|
+
// Check if we got actual data
|
|
90
|
+
const hasData = data.hotContent && data.hotContent.length > 0;
|
|
91
|
+
|
|
92
|
+
setAnalytics({
|
|
93
|
+
dashboard: { hotContent: data.hotContent || [] },
|
|
94
|
+
isLoading: false,
|
|
95
|
+
status: hasData ? 'complete' : 'empty',
|
|
96
|
+
error: null,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// If no data and we have retries left, try again after delay
|
|
100
|
+
if (!hasData && retryCount < maxRetries) {
|
|
101
|
+
retryCount++;
|
|
102
|
+
const delayMs = retryCount === 1 ? 3000 : 6000; // 3s, then 6s
|
|
103
|
+
setTimeout(fetchContentSummary, delayMs);
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Content summary fetch error:', error);
|
|
107
|
+
|
|
108
|
+
// If we have retries left, try again
|
|
109
|
+
if (retryCount < maxRetries) {
|
|
110
|
+
retryCount++;
|
|
111
|
+
const delayMs = retryCount === 1 ? 3000 : 6000;
|
|
112
|
+
setAnalytics((prev) => ({
|
|
113
|
+
...prev,
|
|
114
|
+
isLoading: false,
|
|
115
|
+
status: 'retrying',
|
|
116
|
+
error: `Attempt ${retryCount} failed, retrying in ${delayMs / 1000}s...`,
|
|
117
|
+
}));
|
|
118
|
+
setTimeout(fetchContentSummary, delayMs);
|
|
119
|
+
} else {
|
|
120
|
+
// Max retries reached
|
|
121
|
+
setAnalytics({
|
|
122
|
+
dashboard: { hotContent: [] },
|
|
123
|
+
isLoading: false,
|
|
124
|
+
status: 'error',
|
|
125
|
+
error:
|
|
126
|
+
error instanceof Error
|
|
127
|
+
? error.message
|
|
128
|
+
: 'Failed to load content analytics',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
fetchContentSummary();
|
|
135
|
+
}, []);
|
|
136
|
+
|
|
137
|
+
const renderContentTabContent = () => {
|
|
138
|
+
switch (activeContentTab) {
|
|
139
|
+
case 'webpages':
|
|
140
|
+
return (
|
|
141
|
+
<ContentBrowser
|
|
142
|
+
analytics={analytics}
|
|
143
|
+
fullContentMap={fullContentMap}
|
|
144
|
+
homeSlug={homeSlug}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
case 'manage':
|
|
148
|
+
return (
|
|
149
|
+
<ManageContent
|
|
150
|
+
fullContentMap={fullContentMap}
|
|
151
|
+
homeSlug={homeSlug}
|
|
152
|
+
createMenu={createMenu}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
default:
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div className="w-full">
|
|
162
|
+
{/* Content Sub-Navigation */}
|
|
163
|
+
<div className="mb-6">
|
|
164
|
+
<div className="border-b border-gray-200">
|
|
165
|
+
<nav className="-mb-px flex gap-x-6" aria-label="Content tabs">
|
|
166
|
+
{contentTabs.map((tab) => (
|
|
167
|
+
<button
|
|
168
|
+
key={tab.id}
|
|
169
|
+
onClick={() => handleContentTabChange(tab.id)}
|
|
170
|
+
className={classNames(
|
|
171
|
+
activeContentTab === tab.id
|
|
172
|
+
? 'border-cyan-500 text-cyan-600'
|
|
173
|
+
: 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700',
|
|
174
|
+
'whitespace-nowrap border-b-2 px-1 py-3 text-sm font-bold'
|
|
175
|
+
)}
|
|
176
|
+
aria-current={activeContentTab === tab.id ? 'page' : undefined}
|
|
177
|
+
>
|
|
178
|
+
{tab.name}
|
|
179
|
+
</button>
|
|
180
|
+
))}
|
|
181
|
+
</nav>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
{/* Content Tab Content */}
|
|
186
|
+
{renderContentTabContent()}
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export default StoryKeepDashboard_Content;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useStore } from '@nanostores/react';
|
|
2
|
+
import { orphanAnalysisStore } from '@/stores/orphanAnalysis';
|
|
3
|
+
import type { FullContentMapItem } from '@/types/tractstack';
|
|
4
|
+
|
|
5
|
+
interface UsageCellProps {
|
|
6
|
+
itemId: string;
|
|
7
|
+
fullContentMap: FullContentMapItem[];
|
|
8
|
+
usageType: 'storyFragments' | 'menus' | 'beliefs';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const UsageCell = ({ itemId, fullContentMap, usageType }: UsageCellProps) => {
|
|
12
|
+
const orphanState = useStore(orphanAnalysisStore);
|
|
13
|
+
|
|
14
|
+
// Force loading until we have actual data - no exceptions
|
|
15
|
+
if (
|
|
16
|
+
orphanState?.data?.status === `loading` ||
|
|
17
|
+
!orphanState ||
|
|
18
|
+
!orphanState.data ||
|
|
19
|
+
!orphanState.data[usageType] ||
|
|
20
|
+
orphanState.isLoading
|
|
21
|
+
) {
|
|
22
|
+
return (
|
|
23
|
+
<div className="flex items-center gap-2">
|
|
24
|
+
<div
|
|
25
|
+
className="h-2 w-2 animate-pulse rounded-full bg-gray-400"
|
|
26
|
+
style={{
|
|
27
|
+
animationDuration: window.matchMedia(
|
|
28
|
+
'(prefers-reduced-motion: reduce)'
|
|
29
|
+
).matches
|
|
30
|
+
? '2s'
|
|
31
|
+
: '1s',
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const usage = orphanState.data[usageType][itemId] || [];
|
|
39
|
+
|
|
40
|
+
if (usage.length === 0) {
|
|
41
|
+
return (
|
|
42
|
+
<span className="inline-flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-bold text-gray-800">
|
|
43
|
+
Unused
|
|
44
|
+
</span>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Get titles for dependencies
|
|
49
|
+
const usageDetails = usage.map((id) => {
|
|
50
|
+
const dependentItem = fullContentMap.find((content) => content.id === id);
|
|
51
|
+
return dependentItem
|
|
52
|
+
? `${dependentItem.title} (${dependentItem.type})`
|
|
53
|
+
: `Unknown (${id})`;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="group relative">
|
|
58
|
+
<span className="inline-flex cursor-help items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-bold text-green-800">
|
|
59
|
+
{usage.length} dependent{usage.length !== 1 ? 's' : ''}
|
|
60
|
+
</span>
|
|
61
|
+
{/* Tooltip */}
|
|
62
|
+
<div className="invisible absolute bottom-full left-1/2 z-10 mb-2 -translate-x-1/2 transform whitespace-nowrap rounded-lg bg-gray-900 px-3 py-2 text-sm text-white shadow-lg group-hover:visible">
|
|
63
|
+
Dependencies: {usageDetails.slice(0, 3).join(', ')}
|
|
64
|
+
{usageDetails.length > 3 && ` +${usageDetails.length - 3} more`}
|
|
65
|
+
<div className="absolute left-1/2 top-full -translate-x-1/2 transform border-4 border-transparent border-t-gray-900"></div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default UsageCell;
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useStore } from '@nanostores/react';
|
|
3
|
+
import { useFormState } from '@/hooks/useFormState';
|
|
4
|
+
import {
|
|
5
|
+
convertToLocalState,
|
|
6
|
+
validateBeliefNode,
|
|
7
|
+
beliefStateIntercept,
|
|
8
|
+
addCustomValue,
|
|
9
|
+
removeCustomValue,
|
|
10
|
+
SCALE_OPTIONS,
|
|
11
|
+
getScalePreview,
|
|
12
|
+
} from '@/utils/api/beliefHelpers';
|
|
13
|
+
import { saveBeliefWithStateUpdate } from '@/utils/api/beliefConfig';
|
|
14
|
+
import {
|
|
15
|
+
orphanAnalysisStore,
|
|
16
|
+
loadOrphanAnalysis,
|
|
17
|
+
} from '@/stores/orphanAnalysis';
|
|
18
|
+
import StringInput from '@/components/form/StringInput';
|
|
19
|
+
import EnumSelect from '@/components/form/EnumSelect';
|
|
20
|
+
import UnsavedChangesBar from '@/components/form/UnsavedChangesBar';
|
|
21
|
+
import {
|
|
22
|
+
PlusIcon,
|
|
23
|
+
XMarkIcon,
|
|
24
|
+
LockClosedIcon,
|
|
25
|
+
} from '@heroicons/react/24/outline';
|
|
26
|
+
import type { BeliefNode, BeliefNodeState } from '@/types/tractstack';
|
|
27
|
+
|
|
28
|
+
interface BeliefFormProps {
|
|
29
|
+
belief?: BeliefNode;
|
|
30
|
+
isCreate?: boolean;
|
|
31
|
+
onClose?: (saved: boolean) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default function BeliefForm({
|
|
35
|
+
belief,
|
|
36
|
+
isCreate = false,
|
|
37
|
+
onClose,
|
|
38
|
+
}: BeliefFormProps) {
|
|
39
|
+
const [customValue, setCustomValue] = useState('');
|
|
40
|
+
|
|
41
|
+
// Subscribe to orphan analysis store
|
|
42
|
+
const orphanState = useStore(orphanAnalysisStore);
|
|
43
|
+
|
|
44
|
+
// Load orphan analysis on component mount
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
loadOrphanAnalysis();
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
// Get usage information for this belief
|
|
50
|
+
const getBeliefUsage = (): string[] => {
|
|
51
|
+
if (!belief?.id || !orphanState.data || !orphanState.data.beliefs) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
return orphanState.data.beliefs[belief.id] || [];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Check if belief is in use
|
|
58
|
+
const isBeliefInUse = (): boolean => {
|
|
59
|
+
if (isCreate || !belief?.id) return false;
|
|
60
|
+
return getBeliefUsage().length > 0;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const beliefInUse = isBeliefInUse();
|
|
64
|
+
const usageCount = getBeliefUsage().length;
|
|
65
|
+
|
|
66
|
+
// Initialize form state
|
|
67
|
+
const initialState: BeliefNodeState = belief
|
|
68
|
+
? convertToLocalState(belief)
|
|
69
|
+
: {
|
|
70
|
+
id: '',
|
|
71
|
+
title: '',
|
|
72
|
+
slug: '',
|
|
73
|
+
scale: '',
|
|
74
|
+
customValues: [],
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const formState = useFormState({
|
|
78
|
+
initialData: initialState,
|
|
79
|
+
interceptor: beliefStateIntercept,
|
|
80
|
+
validator: validateBeliefNode,
|
|
81
|
+
onSave: async (data) => {
|
|
82
|
+
try {
|
|
83
|
+
const updatedState = await saveBeliefWithStateUpdate(
|
|
84
|
+
window.TRACTSTACK_CONFIG?.tenantId || 'default',
|
|
85
|
+
data
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Call success callback after save (original pattern)
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
onClose?.(true);
|
|
91
|
+
}, 1000);
|
|
92
|
+
|
|
93
|
+
return updatedState;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error('Belief save failed:', error);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
unsavedChanges: {
|
|
100
|
+
enableBrowserWarning: true,
|
|
101
|
+
browserWarningMessage: 'Your belief changes will be lost!',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const handleAddCustomValue = () => {
|
|
106
|
+
if (!customValue.trim()) return;
|
|
107
|
+
|
|
108
|
+
const newState = addCustomValue(formState.state, customValue);
|
|
109
|
+
formState.updateField('customValues', newState.customValues);
|
|
110
|
+
setCustomValue('');
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleRemoveCustomValue = (index: number) => {
|
|
114
|
+
// Check if this is a newly added value (not saved yet)
|
|
115
|
+
const currentValue = formState.state.customValues[index];
|
|
116
|
+
const originalValues = formState.originalState.customValues || [];
|
|
117
|
+
const isNewValue = !originalValues.includes(currentValue);
|
|
118
|
+
|
|
119
|
+
// Allow removal if:
|
|
120
|
+
// 1. Belief is not in use, OR
|
|
121
|
+
// 2. This is a new value that hasn't been saved yet
|
|
122
|
+
if (!beliefInUse || isNewValue) {
|
|
123
|
+
const newState = removeCustomValue(formState.state, index);
|
|
124
|
+
formState.updateField('customValues', newState.customValues);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
129
|
+
if (e.key === 'Enter') {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
handleAddCustomValue();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleCancel = () => {
|
|
136
|
+
onClose?.(false);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const renderScalePreview = () => {
|
|
140
|
+
if (!formState.state.scale || formState.state.scale === 'custom')
|
|
141
|
+
return null;
|
|
142
|
+
|
|
143
|
+
const preview = getScalePreview(formState.state.scale);
|
|
144
|
+
if (!preview) return null;
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div className="mt-4 rounded-md border border-gray-200 bg-gray-50 p-4">
|
|
148
|
+
<h4 className="mb-2 text-sm font-bold text-gray-700">Scale Preview:</h4>
|
|
149
|
+
<div className="flex flex-wrap gap-2">
|
|
150
|
+
{preview.map((option) => (
|
|
151
|
+
<div
|
|
152
|
+
key={option.id}
|
|
153
|
+
className={`rounded-full px-3 py-1 text-sm font-bold text-gray-800 ${option.color}`}
|
|
154
|
+
>
|
|
155
|
+
{option.name}
|
|
156
|
+
</div>
|
|
157
|
+
))}
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const renderUsageWarning = () => {
|
|
164
|
+
if (!beliefInUse) return null;
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<div className="rounded-md border border-amber-200 bg-amber-50 p-4">
|
|
168
|
+
<div className="flex">
|
|
169
|
+
<div className="flex-shrink-0">
|
|
170
|
+
<LockClosedIcon className="h-5 w-5 text-amber-400" />
|
|
171
|
+
</div>
|
|
172
|
+
<div className="ml-3">
|
|
173
|
+
<h3 className="text-sm font-bold text-amber-800">
|
|
174
|
+
Belief In Use - Limited Editing
|
|
175
|
+
</h3>
|
|
176
|
+
<div className="mt-2 text-sm text-amber-700">
|
|
177
|
+
<p>
|
|
178
|
+
This belief is currently used by <strong>{usageCount}</strong>{' '}
|
|
179
|
+
item{usageCount !== 1 ? 's' : ''}. Some fields are locked to
|
|
180
|
+
prevent breaking existing content.
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div className="space-y-8">
|
|
191
|
+
{/* Header */}
|
|
192
|
+
<div className="border-b border-gray-200 pb-4">
|
|
193
|
+
<h2 className="text-2xl font-bold text-gray-900">
|
|
194
|
+
{isCreate ? 'Create Belief' : 'Edit Belief'}
|
|
195
|
+
</h2>
|
|
196
|
+
<p className="mt-2 text-sm text-gray-600">
|
|
197
|
+
{isCreate
|
|
198
|
+
? 'Create a new belief to power adaptive content and magic paths.'
|
|
199
|
+
: 'Edit the belief configuration and scale options.'}
|
|
200
|
+
</p>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
{/* Usage Warning */}
|
|
204
|
+
{renderUsageWarning()}
|
|
205
|
+
|
|
206
|
+
{/* Info Box */}
|
|
207
|
+
<div className="rounded-md bg-blue-50 p-4">
|
|
208
|
+
<div className="text-sm text-blue-700">
|
|
209
|
+
<p className="font-bold">What are Beliefs?</p>
|
|
210
|
+
<p className="mt-1">
|
|
211
|
+
Beliefs power "magic paths" and adaptive content. They track visitor
|
|
212
|
+
preferences and enable personalized experiences based on user
|
|
213
|
+
interactions.
|
|
214
|
+
</p>
|
|
215
|
+
<ul className="mt-2 list-inside list-disc space-y-1">
|
|
216
|
+
<li>
|
|
217
|
+
Use <strong>Custom Values</strong> for "Identify As" widgets (one
|
|
218
|
+
value per persona)
|
|
219
|
+
</li>
|
|
220
|
+
<li>
|
|
221
|
+
Use <strong>Yes/No</strong> scale for "Toggle Belief" widgets
|
|
222
|
+
</li>
|
|
223
|
+
<li>Link pane visibility to belief states for adaptive content</li>
|
|
224
|
+
</ul>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
{/* Basic Fields */}
|
|
229
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
230
|
+
<StringInput
|
|
231
|
+
value={formState.state.title}
|
|
232
|
+
onChange={(value) => formState.updateField('title', value)}
|
|
233
|
+
label="Title"
|
|
234
|
+
placeholder="Enter belief title"
|
|
235
|
+
error={formState.errors.title}
|
|
236
|
+
required
|
|
237
|
+
/>
|
|
238
|
+
|
|
239
|
+
<div className="relative">
|
|
240
|
+
<StringInput
|
|
241
|
+
value={formState.state.slug}
|
|
242
|
+
onChange={(value) => formState.updateField('slug', value)}
|
|
243
|
+
label="Slug"
|
|
244
|
+
placeholder="Enter belief slug"
|
|
245
|
+
error={formState.errors.slug}
|
|
246
|
+
disabled={beliefInUse}
|
|
247
|
+
required
|
|
248
|
+
/>
|
|
249
|
+
{beliefInUse && (
|
|
250
|
+
<div className="absolute right-2 top-8 flex items-center">
|
|
251
|
+
<LockClosedIcon className="h-4 w-4 text-gray-400" />
|
|
252
|
+
</div>
|
|
253
|
+
)}
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
{/* Scale Selection */}
|
|
258
|
+
<div className="space-y-4">
|
|
259
|
+
<div className="relative">
|
|
260
|
+
<EnumSelect
|
|
261
|
+
value={formState.state.scale}
|
|
262
|
+
onChange={(value) => formState.updateField('scale', value)}
|
|
263
|
+
label="Scale Type"
|
|
264
|
+
options={SCALE_OPTIONS}
|
|
265
|
+
error={formState.errors.scale}
|
|
266
|
+
disabled={beliefInUse}
|
|
267
|
+
required
|
|
268
|
+
/>
|
|
269
|
+
{beliefInUse && (
|
|
270
|
+
<div className="absolute right-8 top-8 flex items-center">
|
|
271
|
+
<LockClosedIcon className="h-4 w-4 text-gray-400" />
|
|
272
|
+
</div>
|
|
273
|
+
)}
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
{renderScalePreview()}
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
{/* Custom Values Section */}
|
|
280
|
+
{formState.state.scale === 'custom' && (
|
|
281
|
+
<div className="space-y-4">
|
|
282
|
+
<div>
|
|
283
|
+
<h3 className="text-lg font-bold text-gray-900">Custom Values</h3>
|
|
284
|
+
<p className="text-sm text-gray-600">
|
|
285
|
+
Define custom options for this belief scale.
|
|
286
|
+
</p>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
{/* Add Custom Value */}
|
|
290
|
+
<div className="flex gap-2">
|
|
291
|
+
<div className="flex-1">
|
|
292
|
+
<div className="flex-1">
|
|
293
|
+
<input
|
|
294
|
+
type="text"
|
|
295
|
+
value={customValue}
|
|
296
|
+
onChange={(e) => setCustomValue(e.target.value)}
|
|
297
|
+
onKeyDown={handleKeyDown}
|
|
298
|
+
placeholder="Enter custom value"
|
|
299
|
+
className="block w-full rounded-md border-0 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 focus:ring-cyan-600 sm:text-sm sm:leading-6"
|
|
300
|
+
/>
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
<button
|
|
304
|
+
type="button"
|
|
305
|
+
onClick={handleAddCustomValue}
|
|
306
|
+
disabled={!customValue.trim()}
|
|
307
|
+
className="inline-flex items-center rounded-md bg-cyan-600 px-3 py-2 text-sm font-bold text-white shadow-sm hover:bg-cyan-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cyan-600 disabled:cursor-not-allowed disabled:opacity-50"
|
|
308
|
+
>
|
|
309
|
+
<PlusIcon className="h-4 w-4" />
|
|
310
|
+
</button>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
{/* Custom Values List */}
|
|
314
|
+
{formState.state.customValues.length > 0 && (
|
|
315
|
+
<div className="space-y-2">
|
|
316
|
+
{formState.state.customValues.map((value, index) => {
|
|
317
|
+
const originalValues =
|
|
318
|
+
formState.originalState.customValues || [];
|
|
319
|
+
const isNewValue = !originalValues.includes(value);
|
|
320
|
+
const canRemove = !beliefInUse || isNewValue;
|
|
321
|
+
|
|
322
|
+
return (
|
|
323
|
+
<div
|
|
324
|
+
key={index}
|
|
325
|
+
className="flex items-center justify-between rounded-md border border-gray-200 bg-gray-50 px-3 py-2"
|
|
326
|
+
>
|
|
327
|
+
<span className="text-sm text-gray-900">{value}</span>
|
|
328
|
+
<div className="flex items-center gap-2">
|
|
329
|
+
{beliefInUse && !isNewValue && (
|
|
330
|
+
<LockClosedIcon className="h-4 w-4 text-gray-400" />
|
|
331
|
+
)}
|
|
332
|
+
<button
|
|
333
|
+
type="button"
|
|
334
|
+
onClick={() => handleRemoveCustomValue(index)}
|
|
335
|
+
disabled={!canRemove}
|
|
336
|
+
className="text-red-600 hover:text-red-800 disabled:cursor-not-allowed disabled:text-gray-400"
|
|
337
|
+
>
|
|
338
|
+
<XMarkIcon className="h-4 w-4" />
|
|
339
|
+
</button>
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
);
|
|
343
|
+
})}
|
|
344
|
+
</div>
|
|
345
|
+
)}
|
|
346
|
+
|
|
347
|
+
{beliefInUse && (
|
|
348
|
+
<div className="text-sm text-amber-700">
|
|
349
|
+
<p>
|
|
350
|
+
⚠️ You can add new values, but cannot remove existing ones while
|
|
351
|
+
this belief is in use.
|
|
352
|
+
</p>
|
|
353
|
+
</div>
|
|
354
|
+
)}
|
|
355
|
+
</div>
|
|
356
|
+
)}
|
|
357
|
+
|
|
358
|
+
{/* Save/Cancel Bar */}
|
|
359
|
+
<UnsavedChangesBar
|
|
360
|
+
formState={formState}
|
|
361
|
+
message="You have unsaved belief changes"
|
|
362
|
+
saveLabel="Save Belief"
|
|
363
|
+
cancelLabel="Discard Changes"
|
|
364
|
+
/>
|
|
365
|
+
|
|
366
|
+
{/* Cancel Navigation Button */}
|
|
367
|
+
<div className="flex justify-start">
|
|
368
|
+
<button
|
|
369
|
+
type="button"
|
|
370
|
+
onClick={handleCancel}
|
|
371
|
+
className="text-sm font-bold text-gray-600 hover:text-gray-800"
|
|
372
|
+
>
|
|
373
|
+
← Back to Belief List
|
|
374
|
+
</button>
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
);
|
|
378
|
+
}
|