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