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,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { isAuthenticated } from '@/utils/auth';
|
|
3
|
+
import { preHealthCheck } from '@/utils/backend';
|
|
4
|
+
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
5
|
+
import { freshInstallStore } from '@/stores/backend';
|
|
6
|
+
|
|
7
|
+
const tenantId =
|
|
8
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
|
|
9
|
+
|
|
10
|
+
const healthCheckRedirect = await preHealthCheck(tenantId);
|
|
11
|
+
if (healthCheckRedirect !== undefined) {
|
|
12
|
+
return healthCheckRedirect;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const url = new URL(Astro.request.url);
|
|
16
|
+
const redirectPath = url.searchParams.get('redirect') || '/storykeep';
|
|
17
|
+
const forceLogin = url.searchParams.get('force') === 'true';
|
|
18
|
+
|
|
19
|
+
if (isAuthenticated(Astro) && !forceLogin) {
|
|
20
|
+
return Astro.redirect(redirectPath);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const isDev = import.meta.env.DEV;
|
|
24
|
+
const isInitialized = !freshInstallStore.get().needsSetup;
|
|
25
|
+
const brandConfig = await getBrandConfig(tenantId);
|
|
26
|
+
const cssBasePath = isInitialized ? '/media/css' : '/styles';
|
|
27
|
+
const getAssetPath = (configPath: string, fallback: string) => {
|
|
28
|
+
// Always prioritize brandConfig values when they exist
|
|
29
|
+
if (configPath && configPath !== '') {
|
|
30
|
+
return configPath;
|
|
31
|
+
}
|
|
32
|
+
return fallback;
|
|
33
|
+
};
|
|
34
|
+
const logo = getAssetPath(brandConfig?.LOGO, '/brand/logo.svg');
|
|
35
|
+
const wordmark = getAssetPath(brandConfig?.WORDMARK, '/brand/wordmark.svg');
|
|
36
|
+
const mainStylesUrl = isDev
|
|
37
|
+
? `${cssBasePath}/storykeep.css`
|
|
38
|
+
: `${cssBasePath}/frontend.css`;
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
<!doctype html>
|
|
42
|
+
<html lang="en" class="bg-mywhite h-full">
|
|
43
|
+
<head>
|
|
44
|
+
<meta charset="UTF-8" />
|
|
45
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
46
|
+
<title>Login | TractStack</title>
|
|
47
|
+
<link rel="stylesheet" href={`${cssBasePath}/custom.css`} />
|
|
48
|
+
<link rel="stylesheet" href={mainStylesUrl} />
|
|
49
|
+
</head>
|
|
50
|
+
<body class="h-full">
|
|
51
|
+
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
|
52
|
+
<div class="mx-auto pb-6">
|
|
53
|
+
<!-- Logo and Wordmark -->
|
|
54
|
+
<div class="flex flex-col items-center justify-center gap-4">
|
|
55
|
+
<div class="h-16 w-auto">
|
|
56
|
+
<img
|
|
57
|
+
src={logo}
|
|
58
|
+
class="pointer-events-none h-full w-auto"
|
|
59
|
+
alt="Logo"
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="h-16 w-auto">
|
|
63
|
+
<img
|
|
64
|
+
src={wordmark}
|
|
65
|
+
class="pointer-events-none h-full w-auto max-w-48 md:max-w-72"
|
|
66
|
+
alt="Wordmark"
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<h2
|
|
72
|
+
class="text-mydarkgrey mt-6 text-center text-2xl font-bold leading-9 tracking-tight"
|
|
73
|
+
>
|
|
74
|
+
Sign in to your Storykeep
|
|
75
|
+
</h2>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="mx-auto">
|
|
79
|
+
<div class="rounded-lg bg-white px-6 py-12 shadow-inner">
|
|
80
|
+
<!-- Error message -->
|
|
81
|
+
<div
|
|
82
|
+
id="loginError"
|
|
83
|
+
class="bg-myred/10 mb-6 rounded-md p-4"
|
|
84
|
+
style="display: none;"
|
|
85
|
+
>
|
|
86
|
+
<div class="flex">
|
|
87
|
+
<div class="flex-shrink-0">
|
|
88
|
+
<svg
|
|
89
|
+
class="text-myred h-5 w-5"
|
|
90
|
+
viewBox="0 0 20 20"
|
|
91
|
+
fill="currentColor"
|
|
92
|
+
aria-hidden="true"
|
|
93
|
+
>
|
|
94
|
+
<path
|
|
95
|
+
fill-rule="evenodd"
|
|
96
|
+
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
|
|
97
|
+
clip-rule="evenodd"></path>
|
|
98
|
+
</svg>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="ml-3">
|
|
101
|
+
<h3 class="text-myred text-sm font-bold">
|
|
102
|
+
Invalid credentials
|
|
103
|
+
</h3>
|
|
104
|
+
<div class="text-myred/90 mt-2 text-sm">
|
|
105
|
+
<p>Please check your password and try again.</p>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<!-- Login form -->
|
|
112
|
+
<div id="loginForm" class="space-y-6">
|
|
113
|
+
<div>
|
|
114
|
+
<label
|
|
115
|
+
for="password"
|
|
116
|
+
class="text-mydarkgrey block text-sm font-bold leading-6"
|
|
117
|
+
>
|
|
118
|
+
Password
|
|
119
|
+
</label>
|
|
120
|
+
<div class="mt-2">
|
|
121
|
+
<input
|
|
122
|
+
id="password"
|
|
123
|
+
name="password"
|
|
124
|
+
type="password"
|
|
125
|
+
required
|
|
126
|
+
class="text-mydarkgrey ring-mylightgrey placeholder:text-mylightgrey focus:ring-myorange block w-full rounded-md border-0 px-3 py-1.5 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6"
|
|
127
|
+
/>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<input
|
|
132
|
+
type="hidden"
|
|
133
|
+
id="redirectPath"
|
|
134
|
+
name="redirect"
|
|
135
|
+
value={redirectPath}
|
|
136
|
+
/>
|
|
137
|
+
|
|
138
|
+
<div>
|
|
139
|
+
<button
|
|
140
|
+
type="button"
|
|
141
|
+
id="submitButton"
|
|
142
|
+
class="bg-myblue hover:bg-myorange focus-visible:outline-myorange flex w-full justify-center rounded-md px-3 py-1.5 text-sm font-bold leading-6 text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
|
|
143
|
+
>
|
|
144
|
+
Sign in
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<!-- Success message -->
|
|
150
|
+
<div id="loginSuccess" class="space-y-6" style="display: none;">
|
|
151
|
+
<div class="rounded-md bg-green-50 p-4">
|
|
152
|
+
<div class="flex">
|
|
153
|
+
<div class="flex-shrink-0">
|
|
154
|
+
<svg
|
|
155
|
+
class="h-5 w-5 text-green-400"
|
|
156
|
+
viewBox="0 0 20 20"
|
|
157
|
+
fill="currentColor"
|
|
158
|
+
aria-hidden="true"
|
|
159
|
+
>
|
|
160
|
+
<path
|
|
161
|
+
fill-rule="evenodd"
|
|
162
|
+
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.236 4.53L7.53 10.25a.75.75 0 00-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
|
163
|
+
clip-rule="evenodd"></path>
|
|
164
|
+
</svg>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="ml-3">
|
|
167
|
+
<h3 class="text-sm font-bold text-green-800">
|
|
168
|
+
Login successful!
|
|
169
|
+
</h3>
|
|
170
|
+
<div class="mt-2 text-sm text-green-700">
|
|
171
|
+
<p>Role: <span id="userRole"></span></p>
|
|
172
|
+
<p>Redirecting...</p>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<script is:inline>
|
|
183
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
184
|
+
const submitButton = document.getElementById('submitButton');
|
|
185
|
+
const passwordInput = document.getElementById('password');
|
|
186
|
+
const redirectInput = document.getElementById('redirectPath');
|
|
187
|
+
const loginErrorDiv = document.getElementById('loginError');
|
|
188
|
+
const loginFormDiv = document.getElementById('loginForm');
|
|
189
|
+
const loginSuccessDiv = document.getElementById('loginSuccess');
|
|
190
|
+
const userRoleSpan = document.getElementById('userRole');
|
|
191
|
+
|
|
192
|
+
if (submitButton && passwordInput && redirectInput) {
|
|
193
|
+
const buttonText = submitButton.textContent.trim();
|
|
194
|
+
|
|
195
|
+
submitButton.addEventListener('click', async function () {
|
|
196
|
+
// Hide error message
|
|
197
|
+
if (loginErrorDiv) loginErrorDiv.style.display = 'none';
|
|
198
|
+
|
|
199
|
+
// Show loading state
|
|
200
|
+
submitButton.disabled = true;
|
|
201
|
+
submitButton.textContent = 'Signing in...';
|
|
202
|
+
|
|
203
|
+
const password = passwordInput.value;
|
|
204
|
+
const redirectPath = redirectInput.value;
|
|
205
|
+
|
|
206
|
+
if (!password) {
|
|
207
|
+
if (loginErrorDiv) loginErrorDiv.style.display = 'block';
|
|
208
|
+
submitButton.disabled = false;
|
|
209
|
+
submitButton.textContent = buttonText;
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const response = await fetch('/api/auth/login', {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
headers: {
|
|
217
|
+
'Content-Type': 'application/json',
|
|
218
|
+
Accept: 'application/json',
|
|
219
|
+
},
|
|
220
|
+
body: JSON.stringify({
|
|
221
|
+
password,
|
|
222
|
+
redirect: redirectPath,
|
|
223
|
+
}),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const result = await response.json();
|
|
227
|
+
|
|
228
|
+
if (result.success) {
|
|
229
|
+
// Show success message with role
|
|
230
|
+
if (loginFormDiv) loginFormDiv.style.display = 'none';
|
|
231
|
+
if (loginSuccessDiv) loginSuccessDiv.style.display = 'block';
|
|
232
|
+
if (userRoleSpan)
|
|
233
|
+
userRoleSpan.textContent = result.role || 'authenticated';
|
|
234
|
+
|
|
235
|
+
// Console log for debugging
|
|
236
|
+
console.log('Login successful:', result);
|
|
237
|
+
console.log('User role:', result.role);
|
|
238
|
+
|
|
239
|
+
// Redirect after short delay
|
|
240
|
+
setTimeout(() => {
|
|
241
|
+
window.location.href = result.redirect || redirectPath;
|
|
242
|
+
}, 1500);
|
|
243
|
+
} else {
|
|
244
|
+
if (loginErrorDiv) loginErrorDiv.style.display = 'block';
|
|
245
|
+
submitButton.disabled = false;
|
|
246
|
+
submitButton.textContent = buttonText;
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error('Login error:', error);
|
|
250
|
+
if (loginErrorDiv) loginErrorDiv.style.display = 'block';
|
|
251
|
+
submitButton.disabled = false;
|
|
252
|
+
submitButton.textContent = buttonText;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
passwordInput.addEventListener('keypress', function (event) {
|
|
257
|
+
if (event.key === 'Enter') {
|
|
258
|
+
event.preventDefault();
|
|
259
|
+
submitButton.click();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
</script>
|
|
265
|
+
</body>
|
|
266
|
+
</html>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Cookie-based logout - server-side cookie removal
|
|
3
|
+
// Clears HTTP-only admin/editor auth cookies
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!doctype html>
|
|
7
|
+
<html lang="en">
|
|
8
|
+
<head>
|
|
9
|
+
<meta charset="UTF-8" />
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
11
|
+
<title>Logging out...</title>
|
|
12
|
+
<style>
|
|
13
|
+
body {
|
|
14
|
+
font-family: system-ui, sans-serif;
|
|
15
|
+
display: flex;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
align-items: center;
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
margin: 0;
|
|
20
|
+
background-color: #f3f4f6;
|
|
21
|
+
}
|
|
22
|
+
.logout-container {
|
|
23
|
+
text-align: center;
|
|
24
|
+
background: white;
|
|
25
|
+
padding: 2rem;
|
|
26
|
+
border-radius: 0.5rem;
|
|
27
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
30
|
+
</head>
|
|
31
|
+
<body>
|
|
32
|
+
<div class="logout-container">
|
|
33
|
+
<h1>Logging out...</h1>
|
|
34
|
+
<p>Please wait while we clear your session.</p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
// Clear authentication data
|
|
39
|
+
async function logout() {
|
|
40
|
+
try {
|
|
41
|
+
// Call server-side logout API to clear HTTP-only cookies
|
|
42
|
+
const response = await fetch('/api/auth/logout', {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const result = await response.json();
|
|
50
|
+
|
|
51
|
+
if (result.success) {
|
|
52
|
+
console.log('StoryKeep: Admin logout successful');
|
|
53
|
+
} else {
|
|
54
|
+
console.error('StoryKeep: Admin logout failed:', result.error);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Also clear any remaining TractStack user profile data
|
|
58
|
+
const tractStackKeys = [];
|
|
59
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
60
|
+
const key = localStorage.key(i);
|
|
61
|
+
if (key && key.startsWith('tractstack_')) {
|
|
62
|
+
tractStackKeys.push(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
tractStackKeys.forEach((key) => localStorage.removeItem(key));
|
|
66
|
+
|
|
67
|
+
console.log('TractStack: Complete logout finished');
|
|
68
|
+
|
|
69
|
+
// Redirect to home page
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
window.location.href = '/';
|
|
72
|
+
}, 1000);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error('Logout error:', error);
|
|
75
|
+
// Still redirect even if logout API fails
|
|
76
|
+
window.location.href = '/';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Execute logout immediately
|
|
81
|
+
logout();
|
|
82
|
+
</script>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import { ProfileSwitch } from '@/components/profile/ProfileSwitch';
|
|
4
|
+
import { ProfileConsent } from '@/components/profile/ProfileConsent';
|
|
5
|
+
import { preHealthCheck } from '@/utils/backend';
|
|
6
|
+
|
|
7
|
+
const tenantId =
|
|
8
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
|
|
9
|
+
|
|
10
|
+
const healthCheckRedirect = await preHealthCheck(tenantId);
|
|
11
|
+
if (healthCheckRedirect !== undefined) {
|
|
12
|
+
return healthCheckRedirect;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const config = {
|
|
16
|
+
title: 'Configure your Session',
|
|
17
|
+
description: 'Manage your TractStack profile and session preferences',
|
|
18
|
+
};
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<Layout
|
|
22
|
+
title={config.title}
|
|
23
|
+
slug="profile"
|
|
24
|
+
isContext={false}
|
|
25
|
+
isStoryKeep={false}
|
|
26
|
+
isEditable={false}
|
|
27
|
+
>
|
|
28
|
+
<main id="main-content">
|
|
29
|
+
<div class="px-6 py-24 font-sans text-xl">
|
|
30
|
+
<div class="mx-auto max-w-3xl">
|
|
31
|
+
<div class="space-y-6">
|
|
32
|
+
<p class="text-black">
|
|
33
|
+
This website has been "pressed" with Tract Stack. As you read and
|
|
34
|
+
click around it will open up like a choose-your-own adventure book.
|
|
35
|
+
</p>
|
|
36
|
+
<p class="text-black">
|
|
37
|
+
Without your consent, no personal information will be collected from
|
|
38
|
+
your device.
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<h3 class="inline-flex items-center pt-12 text-xl text-gray-700">
|
|
42
|
+
Allow Tract Stack to retain memory of your session and preferences
|
|
43
|
+
<span
|
|
44
|
+
class="pl-2 text-gray-400"
|
|
45
|
+
title="We will use a few kilobytes of localStorage in your browser."
|
|
46
|
+
>
|
|
47
|
+
<svg
|
|
48
|
+
class="h-5 w-5"
|
|
49
|
+
fill="none"
|
|
50
|
+
stroke="currentColor"
|
|
51
|
+
viewBox="0 0 24 24"
|
|
52
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
53
|
+
>
|
|
54
|
+
<path
|
|
55
|
+
stroke-linecap="round"
|
|
56
|
+
stroke-linejoin="round"
|
|
57
|
+
stroke-width="2"
|
|
58
|
+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
59
|
+
></path>
|
|
60
|
+
</svg>
|
|
61
|
+
</span>
|
|
62
|
+
</h3>
|
|
63
|
+
|
|
64
|
+
<!-- Consent Toggle using Ark UI -->
|
|
65
|
+
<div class="py-4">
|
|
66
|
+
<ProfileConsent client:load />
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Profile Switch Component -->
|
|
70
|
+
<div class="pt-6">
|
|
71
|
+
<ProfileSwitch client:load />
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div class="pt-8 text-sm text-gray-600">
|
|
75
|
+
<p class="pb-4">
|
|
76
|
+
By enabling session memory, Tract Stack can provide a personalized
|
|
77
|
+
reading experience. This includes:
|
|
78
|
+
</p>
|
|
79
|
+
<ul class="space-y-2 pl-6 text-base">
|
|
80
|
+
<li class="list-disc">
|
|
81
|
+
Remembering your reading progress and preferences
|
|
82
|
+
</li>
|
|
83
|
+
<li class="list-disc">
|
|
84
|
+
Showing content tailored to your interests
|
|
85
|
+
</li>
|
|
86
|
+
<li class="list-disc">Maintaining your session across visits</li>
|
|
87
|
+
</ul>
|
|
88
|
+
<p class="pt-4 text-xs">
|
|
89
|
+
All data is stored locally in your browser. No personal
|
|
90
|
+
information is transmitted to external servers without your
|
|
91
|
+
explicit consent.
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</main>
|
|
98
|
+
</Layout>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import StoryKeepDashboard from '@/components/storykeep/Dashboard';
|
|
4
|
+
import StoryKeepDashboard_Analytics from '@/components/storykeep/Dashboard_Analytics';
|
|
5
|
+
import { requireAdminOrEditor, isAuthenticated, isAdmin } from '@/utils/auth';
|
|
6
|
+
import { getFullContentMap } from '@/stores/analytics';
|
|
7
|
+
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
8
|
+
import { preHealthCheck } from '@/utils/backend';
|
|
9
|
+
|
|
10
|
+
const tenantId =
|
|
11
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
|
|
12
|
+
|
|
13
|
+
const healthCheckRedirect = await preHealthCheck(tenantId);
|
|
14
|
+
if (healthCheckRedirect !== undefined) {
|
|
15
|
+
return healthCheckRedirect;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const authCheck = requireAdminOrEditor(Astro);
|
|
19
|
+
if (authCheck) {
|
|
20
|
+
return authCheck;
|
|
21
|
+
}
|
|
22
|
+
const userIsAuthenticated = isAuthenticated(Astro);
|
|
23
|
+
const userIsAdmin = isAdmin(Astro);
|
|
24
|
+
const role = userIsAdmin ? `admin` : userIsAuthenticated ? `editor` : null;
|
|
25
|
+
|
|
26
|
+
const brandConfig = await getBrandConfig(
|
|
27
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default'
|
|
28
|
+
);
|
|
29
|
+
const initializing = !brandConfig.SITE_INIT;
|
|
30
|
+
|
|
31
|
+
// Redirect to branding page during initial setup
|
|
32
|
+
if (initializing) {
|
|
33
|
+
return Astro.redirect('/storykeep/branding');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const title = 'Analytics | StoryKeep';
|
|
37
|
+
|
|
38
|
+
let fullContentMap;
|
|
39
|
+
let homeSlug = 'hello';
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
fullContentMap = await getFullContentMap(
|
|
43
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default'
|
|
44
|
+
);
|
|
45
|
+
homeSlug = fullContentMap.find((item) => item.isHome)?.slug || 'hello';
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return Astro.redirect(
|
|
48
|
+
`/maint?from=${encodeURIComponent(Astro.url.pathname)}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
<Layout title={title} isStoryKeep={true} slug="storykeep">
|
|
54
|
+
<main id="main-content" class="min-h-screen w-full">
|
|
55
|
+
<div class="p-3.5 md:p-8">
|
|
56
|
+
<StoryKeepDashboard
|
|
57
|
+
client:only="react"
|
|
58
|
+
fullContentMap={fullContentMap}
|
|
59
|
+
homeSlug={homeSlug}
|
|
60
|
+
activeTab="analytics"
|
|
61
|
+
role={role}
|
|
62
|
+
initializing={initializing}
|
|
63
|
+
/>
|
|
64
|
+
|
|
65
|
+
<!-- Only show Analytics content when home page has title -->
|
|
66
|
+
{
|
|
67
|
+
fullContentMap.find((item) => item.slug === homeSlug)?.title?.trim() ? (
|
|
68
|
+
<StoryKeepDashboard_Analytics
|
|
69
|
+
client:only="react"
|
|
70
|
+
fullContentMap={fullContentMap}
|
|
71
|
+
initializing={initializing}
|
|
72
|
+
/>
|
|
73
|
+
) : (
|
|
74
|
+
<div class="mt-8 text-gray-500">
|
|
75
|
+
<p>Complete the setup wizard above to unlock Analytics.</p>
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
</div>
|
|
80
|
+
</main>
|
|
81
|
+
</Layout>
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { atom } from 'nanostores';
|
|
2
|
+
import { TractStackAPI } from '@/utils/api';
|
|
3
|
+
|
|
4
|
+
// Internal tenant-keyed storage
|
|
5
|
+
const tenantEpinetCustomFilters = atom<
|
|
6
|
+
Record<
|
|
7
|
+
string,
|
|
8
|
+
{
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
visitorType: 'all' | 'anonymous' | 'known';
|
|
11
|
+
selectedUserId: string | null;
|
|
12
|
+
startTimeUTC: string | null;
|
|
13
|
+
endTimeUTC: string | null;
|
|
14
|
+
userCounts: Array<{ id: string; count: number; isKnown: boolean }>;
|
|
15
|
+
hourlyNodeActivity: Record<
|
|
16
|
+
string,
|
|
17
|
+
Record<
|
|
18
|
+
string,
|
|
19
|
+
{
|
|
20
|
+
events: Record<string, number>;
|
|
21
|
+
visitorIds: string[];
|
|
22
|
+
}
|
|
23
|
+
>
|
|
24
|
+
>;
|
|
25
|
+
}
|
|
26
|
+
>
|
|
27
|
+
>({});
|
|
28
|
+
|
|
29
|
+
const tenantFullContentMaps = atom<
|
|
30
|
+
Record<
|
|
31
|
+
string,
|
|
32
|
+
{
|
|
33
|
+
data: any[];
|
|
34
|
+
lastUpdated: number;
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
>({});
|
|
38
|
+
|
|
39
|
+
// Helper to get current tenant ID
|
|
40
|
+
function getCurrentTenantId(): string {
|
|
41
|
+
if (typeof window !== 'undefined' && window.TRACTSTACK_CONFIG?.tenantId) {
|
|
42
|
+
return window.TRACTSTACK_CONFIG.tenantId;
|
|
43
|
+
}
|
|
44
|
+
return import.meta.env.PUBLIC_TENANTID || 'default';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Default filter state
|
|
48
|
+
const defaultEpinetFilters = {
|
|
49
|
+
enabled: false,
|
|
50
|
+
visitorType: 'all' as 'all' | 'anonymous' | 'known',
|
|
51
|
+
selectedUserId: null,
|
|
52
|
+
startTimeUTC: null,
|
|
53
|
+
endTimeUTC: null,
|
|
54
|
+
userCounts: [],
|
|
55
|
+
hourlyNodeActivity: {},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Create tenant-aware atoms that work with useStore
|
|
59
|
+
const createEpinetFiltersStore = () => {
|
|
60
|
+
const store = {
|
|
61
|
+
get: () => {
|
|
62
|
+
const tenantId = getCurrentTenantId();
|
|
63
|
+
return tenantEpinetCustomFilters.get()[tenantId] || defaultEpinetFilters;
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
set: (tenantId: string, updates: any) => {
|
|
67
|
+
const currentFilters =
|
|
68
|
+
tenantEpinetCustomFilters.get()[tenantId] || defaultEpinetFilters;
|
|
69
|
+
tenantEpinetCustomFilters.set({
|
|
70
|
+
...tenantEpinetCustomFilters.get(),
|
|
71
|
+
[tenantId]: {
|
|
72
|
+
...currentFilters,
|
|
73
|
+
...updates,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
subscribe: (callback: (value: any) => void) => {
|
|
79
|
+
const tenantId = getCurrentTenantId();
|
|
80
|
+
return tenantEpinetCustomFilters.subscribe((filters) => {
|
|
81
|
+
callback(filters[tenantId] || defaultEpinetFilters);
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Required nanostore properties for useStore
|
|
86
|
+
lc: 0,
|
|
87
|
+
listen: function (callback: any) {
|
|
88
|
+
return this.subscribe(callback);
|
|
89
|
+
},
|
|
90
|
+
notify: function () {},
|
|
91
|
+
off: function () {},
|
|
92
|
+
get value() {
|
|
93
|
+
return this.get();
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return store;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const createFullContentMapStore = () => {
|
|
101
|
+
const store = {
|
|
102
|
+
get: () => {
|
|
103
|
+
const tenantId = getCurrentTenantId();
|
|
104
|
+
return tenantFullContentMaps.get()[tenantId] || null;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
set: (tenantId: string, data: { data: any[]; lastUpdated: number }) => {
|
|
108
|
+
tenantFullContentMaps.set({
|
|
109
|
+
...tenantFullContentMaps.get(),
|
|
110
|
+
[tenantId]: data,
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
subscribe: (callback: (value: any) => void) => {
|
|
115
|
+
const tenantId = getCurrentTenantId();
|
|
116
|
+
return tenantFullContentMaps.subscribe((maps) => {
|
|
117
|
+
callback(maps[tenantId] || null);
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
// Required nanostore properties for useStore
|
|
122
|
+
lc: 0,
|
|
123
|
+
listen: function (callback: any) {
|
|
124
|
+
return this.subscribe(callback);
|
|
125
|
+
},
|
|
126
|
+
notify: function () {},
|
|
127
|
+
off: function () {},
|
|
128
|
+
get value() {
|
|
129
|
+
return this.get();
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return store;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const epinetCustomFilters = createEpinetFiltersStore();
|
|
137
|
+
export const fullContentMapStore = createFullContentMapStore();
|
|
138
|
+
|
|
139
|
+
export async function getFullContentMap(tenantId: string): Promise<any[]> {
|
|
140
|
+
const api = new TractStackAPI(tenantId);
|
|
141
|
+
|
|
142
|
+
// Check tenant-specific cache
|
|
143
|
+
const cached = tenantFullContentMaps.get()[tenantId];
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const response = await api.getContentMapWithTimestamp(cached?.lastUpdated);
|
|
147
|
+
|
|
148
|
+
if (response.success && response.data) {
|
|
149
|
+
// Update tenant-specific cache
|
|
150
|
+
const newData = {
|
|
151
|
+
data: response.data.data,
|
|
152
|
+
lastUpdated: response.data.lastUpdated,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
tenantFullContentMaps.set({
|
|
156
|
+
...tenantFullContentMaps.get(),
|
|
157
|
+
[tenantId]: newData,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return newData.data;
|
|
161
|
+
} else {
|
|
162
|
+
const errorMsg = response.error || '';
|
|
163
|
+
if (errorMsg.includes('304')) {
|
|
164
|
+
return cached?.data || [];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error('Failed to fetch content map:', error);
|
|
169
|
+
}
|
|
170
|
+
return cached?.data || [];
|
|
171
|
+
}
|