astro-tractstack 2.1.3 → 2.2.1
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/README.md +54 -266
- package/bin/create-tractstack.js +9 -6
- package/dist/index.js +109 -71
- package/package.json +4 -2
- package/templates/css/custom.css +5 -0
- package/templates/icons/code.svg +18 -0
- package/templates/icons/li.svg +4 -0
- package/templates/icons/link.svg +22 -0
- package/templates/icons/p.svg +3 -0
- package/templates/src/client/app.js +80 -1
- package/templates/src/components/Footer.astro +1 -1
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +6 -6
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +3 -3
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +1 -1
- package/templates/src/components/codehooks/ListContentSetup.tsx +2 -2
- package/templates/src/components/codehooks/ProductCardSetup.tsx +1 -1
- package/templates/src/components/codehooks/ProductGridSetup.tsx +2 -2
- package/templates/src/components/codehooks/SandboxRegisterForm.tsx +3 -3
- package/templates/src/components/compositor/Compositor.tsx +25 -9
- package/templates/src/components/compositor/Node.tsx +168 -496
- package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +1 -0
- package/templates/src/components/compositor/elements/SignUp.tsx +1 -1
- package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +2 -0
- package/templates/src/components/compositor/nodes/CreativePane.tsx +262 -0
- package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +4 -6
- package/templates/src/components/compositor/nodes/GridLayout.tsx +4 -2
- package/templates/src/components/compositor/nodes/Markdown.tsx +18 -3
- package/templates/src/components/compositor/nodes/Pane.tsx +11 -5
- package/templates/src/components/compositor/nodes/RenderChildren.tsx +1 -1
- package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +5 -5
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +90 -42
- package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +2 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +27 -1
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +10 -8
- package/templates/src/components/compositor/tools/NodeOverlay.tsx +224 -0
- package/templates/src/components/compositor/tools/PaneOverlay.tsx +122 -0
- package/templates/src/components/edit/Header.tsx +68 -9
- package/templates/src/components/edit/PanelSwitch.tsx +42 -4
- package/templates/src/components/edit/SettingsPanel.tsx +2 -3
- package/templates/src/components/edit/ToolMode.tsx +1 -31
- package/templates/src/components/edit/pane/AddPanePanel_break.tsx +2 -2
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +1 -1
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +193 -659
- package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +15 -82
- package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +95 -45
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +137 -49
- package/templates/src/components/edit/pane/RestylePaneModal.tsx +1 -1
- package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +375 -0
- package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +1 -23
- package/templates/src/components/edit/pane/steps/AiLibraryCopyStep.tsx +327 -0
- package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +267 -0
- package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +371 -0
- package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +201 -76
- package/templates/src/components/edit/pane/steps/CreativeInjectStep.tsx +141 -0
- package/templates/src/components/edit/panels/CreativeImagePanel.tsx +435 -0
- package/templates/src/components/edit/panels/CreativeLinkPanel.tsx +110 -0
- package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +1 -1
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +118 -126
- package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +3 -2
- package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +1 -0
- package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +3 -1
- package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +3 -1
- package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +1 -1
- package/templates/src/components/edit/state/SaveModal.tsx +19 -787
- package/templates/src/components/edit/state/SaveToLibraryModal.tsx +2 -2
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +1 -1
- package/templates/src/components/edit/widgets/BunnyWidget.tsx +5 -5
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +1 -1
- package/templates/src/components/edit/widgets/SignupWidget.tsx +1 -1
- package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +1 -1
- package/templates/src/components/fields/ArtpackImage.tsx +11 -3
- package/templates/src/components/fields/BackgroundImage.tsx +8 -0
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +15 -9
- package/templates/src/components/fields/ImageUpload.tsx +6 -0
- package/templates/src/components/form/ActionBuilderField.tsx +15 -5
- package/templates/src/components/form/ActionBuilderSlugSelector.tsx +1 -1
- package/templates/src/components/form/ColorPicker.tsx +1 -1
- package/templates/src/components/form/EnumSelect.tsx +1 -1
- package/templates/src/components/form/NumberInput.tsx +1 -1
- package/templates/src/components/form/StringArrayInput.tsx +1 -1
- package/templates/src/components/form/StringInput.tsx +1 -1
- package/templates/src/components/form/UnsavedChangesBar.tsx +1 -1
- package/templates/src/components/form/advanced/APIConfigSection.tsx +2 -2
- package/templates/src/components/form/advanced/AuthConfigSection.tsx +2 -2
- package/templates/src/components/profile/ProfileCreate.tsx +1 -1
- package/templates/src/components/profile/ProfileEdit.tsx +1 -1
- package/templates/src/components/storykeep/Dashboard_Advanced.tsx +2 -2
- package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +1 -1
- package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +2 -2
- package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +1 -1
- package/templates/src/components/storykeep/controls/content/ManageContent.tsx +6 -6
- package/templates/src/components/storykeep/controls/content/MenuForm.tsx +1 -1
- package/templates/src/components/storykeep/controls/content/PaneTable.tsx +358 -0
- package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +1 -1
- package/templates/src/constants/prompts.json +18 -10
- package/templates/src/constants.ts +3 -0
- package/templates/src/hooks/usePaneFragments.ts +60 -0
- package/templates/src/lib/session.ts +71 -16
- package/templates/src/pages/[...slug].astro +4 -46
- package/templates/src/pages/api/css.ts +149 -0
- package/templates/src/pages/maint.astro +1 -1
- package/templates/src/pages/storykeep/login.astro +2 -2
- package/templates/src/stores/nodes.ts +162 -49
- package/templates/src/stores/orphanAnalysis.ts +6 -30
- package/templates/src/stores/previews.ts +7 -0
- package/templates/src/stores/storykeep.ts +0 -8
- package/templates/src/types/compositorTypes.ts +53 -10
- package/templates/src/utils/compositor/aiGeneration.ts +93 -0
- package/templates/src/utils/compositor/allowInsert.ts +2 -0
- package/templates/src/utils/compositor/htmlAst.ts +704 -0
- package/templates/src/utils/compositor/nodesHelper.ts +281 -102
- package/templates/src/utils/compositor/savePipeline.ts +893 -0
- package/templates/src/utils/etl/index.ts +3 -0
- package/templates/src/utils/etl/transformer.ts +10 -0
- package/templates/src/utils/helpers.ts +101 -0
- package/utils/inject-files.ts +100 -62
- package/templates/icons/text.svg +0 -6
- package/templates/src/components/compositor/NodeWithGuid.tsx +0 -69
- package/templates/src/components/compositor/nodes/GridLayout_eraser.tsx +0 -33
- package/templates/src/components/compositor/nodes/Markdown_eraser.tsx +0 -56
- package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +0 -269
- package/templates/src/components/compositor/nodes/Pane_eraser.tsx +0 -186
- package/templates/src/components/compositor/nodes/Pane_layout.tsx +0 -79
- package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +0 -26
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +0 -61
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +0 -120
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +0 -62
- package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +0 -26
|
@@ -1,100 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
memo,
|
|
3
|
-
type ReactElement,
|
|
4
|
-
useEffect,
|
|
5
|
-
useState,
|
|
6
|
-
createElement,
|
|
7
|
-
type MouseEvent,
|
|
8
|
-
} from 'react';
|
|
1
|
+
import { memo, useEffect, type JSX, type ReactNode } from 'react';
|
|
9
2
|
import { useStore } from '@nanostores/react';
|
|
10
3
|
import { getCtx } from '@/stores/nodes';
|
|
4
|
+
import { viewportKeyStore } from '@/stores/storykeep';
|
|
11
5
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
import
|
|
6
|
+
isAddressableNode,
|
|
7
|
+
getNodeDisplayMode,
|
|
8
|
+
isTopLevelBlockNode,
|
|
9
|
+
parseCodeHook,
|
|
10
|
+
} from '@/utils/compositor/nodesHelper';
|
|
11
|
+
import { isPaneNode, isGridLayoutNode } from '@/utils/compositor/typeGuards';
|
|
12
|
+
import { PaneAddMode } from '@/types/compositorTypes';
|
|
13
|
+
import { NodeOverlay } from './tools/NodeOverlay';
|
|
14
|
+
import PanelVisibilityWrapper from '@/components/compositor/PanelVisibilityWrapper';
|
|
19
15
|
import { Pane } from './nodes/Pane';
|
|
20
|
-
import {
|
|
21
|
-
import { PaneLayout } from './nodes/Pane_layout';
|
|
16
|
+
import { CreativePane } from './nodes/CreativePane';
|
|
22
17
|
import { Markdown } from './nodes/Markdown';
|
|
23
|
-
import { BgPaneWrapper } from './nodes/BgPaneWrapper';
|
|
24
18
|
import { StoryFragment } from './nodes/StoryFragment';
|
|
25
|
-
import {
|
|
19
|
+
import { GridLayout } from './nodes/GridLayout';
|
|
26
20
|
import { Widget } from './nodes/Widget';
|
|
27
|
-
import {
|
|
21
|
+
import { NodeBasicTag } from './nodes/tagElements/NodeBasicTag';
|
|
22
|
+
import { NodeImg } from './nodes/tagElements/NodeImg';
|
|
28
23
|
import { NodeA } from './nodes/tagElements/NodeA';
|
|
29
|
-
import { NodeAEraser } from './nodes/tagElements/NodeA_eraser';
|
|
30
24
|
import { NodeButton } from './nodes/tagElements/NodeButton';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import { NodeBasicTag } from './nodes/tagElements/NodeBasicTag';
|
|
34
|
-
import { NodeBasicTagInsert } from './nodes/tagElements/NodeBasicTag_insert';
|
|
35
|
-
import { NodeBasicTagEraser } from './nodes/tagElements/NodeBasicTag_eraser';
|
|
36
|
-
import { NodeBasicTagSettings } from './nodes/tagElements/NodeBasicTag_settings';
|
|
37
|
-
import { Pane_DesignLibrary } from './nodes/Pane_DesignLibrary';
|
|
38
|
-
import { GridLayout } from './nodes/GridLayout';
|
|
39
|
-
import { GridLayoutEraser } from './nodes/GridLayout_eraser';
|
|
40
|
-
import { MarkdownEraser } from './nodes/Markdown_eraser';
|
|
25
|
+
import { NodeText } from './nodes/tagElements/NodeText';
|
|
26
|
+
import { BgPaneWrapper } from './nodes/BgPaneWrapper';
|
|
41
27
|
import AddPanePanel from '@/components/edit/pane/AddPanePanel';
|
|
42
28
|
import ConfigPanePanel from '@/components/edit/pane/ConfigPanePanel';
|
|
43
29
|
import StoryFragmentConfigPanel from '@/components/edit/storyfragment/StoryFragmentConfigPanel';
|
|
44
30
|
import StoryFragmentTitlePanel from '@/components/edit/storyfragment/StoryFragmentPanel_title';
|
|
45
31
|
import ContextPanePanel from '@/components/edit/context/ContextPaneConfig';
|
|
46
32
|
import ContextPaneTitlePanel from '@/components/edit/context/ContextPaneConfig_title';
|
|
47
|
-
|
|
48
|
-
import {
|
|
33
|
+
|
|
34
|
+
import type { NodeProps } from '@/types/nodeProps';
|
|
49
35
|
import type {
|
|
50
|
-
StoryFragmentNode,
|
|
51
|
-
PaneNode,
|
|
52
|
-
BaseNode,
|
|
53
36
|
FlatNode,
|
|
37
|
+
PaneNode,
|
|
38
|
+
StoryFragmentNode,
|
|
54
39
|
} from '@/types/compositorTypes';
|
|
55
|
-
import { PaneAddMode } from '@/types/compositorTypes';
|
|
56
|
-
import { handleClickEventDefault } from '@/utils/compositor/handleClickEvent';
|
|
57
|
-
import { selectionStore } from '@/stores/selection';
|
|
58
|
-
import type { NodeProps, SelectionOrigin } from '@/types/nodeProps';
|
|
59
|
-
|
|
60
|
-
const VERBOSE = false;
|
|
61
|
-
|
|
62
|
-
function parseCodeHook(node: BaseNode | FlatNode) {
|
|
63
|
-
if ('codeHookParams' in node && Array.isArray(node.codeHookParams)) {
|
|
64
|
-
const hookMatch = node.copy?.match(regexpHook);
|
|
65
|
-
|
|
66
|
-
if (!hookMatch) return null;
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
hook: hookMatch[1],
|
|
70
|
-
value1: node.codeHookParams[0] || null,
|
|
71
|
-
value2: node.codeHookParams[1] || null,
|
|
72
|
-
value3: node.codeHookParams[2] || '',
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if ('children' in node && Array.isArray(node.children)) {
|
|
77
|
-
const firstChild = node.children[0];
|
|
78
|
-
if (!firstChild?.value) return null;
|
|
79
|
-
|
|
80
|
-
const regexpValues = /((?:[^\\|]+|\\\|?)+)/g;
|
|
81
|
-
const hookMatch = firstChild.value.match(regexpHook);
|
|
82
|
-
|
|
83
|
-
if (!hookMatch) return null;
|
|
84
|
-
|
|
85
|
-
const hook = hookMatch[1];
|
|
86
|
-
const hookValuesRaw = hookMatch[2].match(regexpValues);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
hook,
|
|
90
|
-
value1: hookValuesRaw?.[0] || null,
|
|
91
|
-
value2: hookValuesRaw?.[1] || null,
|
|
92
|
-
value3: hookValuesRaw?.[2] || '',
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
40
|
|
|
99
41
|
const EmptyPageHandler = (props: NodeProps) => {
|
|
100
42
|
const ctx = getCtx(props);
|
|
@@ -113,455 +55,185 @@ const EmptyPageHandler = (props: NodeProps) => {
|
|
|
113
55
|
);
|
|
114
56
|
};
|
|
115
57
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
props
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
const hasPanes = useStore(getCtx(props).hasPanes);
|
|
123
|
-
const sharedProps = {
|
|
124
|
-
...props,
|
|
125
|
-
nodeId: node.id,
|
|
126
|
-
isSandboxMode: props.isSandboxMode,
|
|
127
|
-
};
|
|
128
|
-
const type = getType(node);
|
|
129
|
-
const toolModeVal = getCtx(props).toolModeValStore.get().value;
|
|
130
|
-
const settingsPanel = useStore(settingsPanelStore);
|
|
58
|
+
export const Node = memo((props: NodeProps) => {
|
|
59
|
+
const ctx = getCtx(props);
|
|
60
|
+
const node = ctx.allNodes.get().get(props.nodeId);
|
|
61
|
+
const viewport = useStore(viewportKeyStore).value;
|
|
62
|
+
const isPreview = ctx.rootNodeId.get() === `tmp`;
|
|
63
|
+
const hasPanes = useStore(ctx.hasPanes);
|
|
131
64
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const parentNode = node.parentId
|
|
136
|
-
? getCtx(props).allNodes.get().get(node.parentId)
|
|
137
|
-
: null;
|
|
138
|
-
if (parentNode && isGridLayoutNode(parentNode)) {
|
|
139
|
-
return <MarkdownEraser {...sharedProps} />;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return <Markdown {...sharedProps} />;
|
|
143
|
-
}
|
|
65
|
+
if (!node) return null;
|
|
66
|
+
|
|
67
|
+
let element: ReactNode = null;
|
|
144
68
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
69
|
+
// 1. Root Types (StoryFragment & Pane) - handled with specific early returns or complex wrapping
|
|
70
|
+
if (node.nodeType === 'StoryFragment') {
|
|
71
|
+
const sf = node as StoryFragmentNode;
|
|
72
|
+
if (!isPreview) ctx.hasTitle.set(!(!sf.slug || !sf.title));
|
|
148
73
|
|
|
74
|
+
if (!(sf.slug && sf.title)) {
|
|
149
75
|
return (
|
|
150
|
-
|
|
151
|
-
|
|
76
|
+
<div
|
|
77
|
+
className="fixed inset-0 overflow-y-auto bg-black bg-opacity-75"
|
|
78
|
+
style={{ zIndex: 9005 }}
|
|
79
|
+
>
|
|
80
|
+
<div className="flex min-h-screen items-center justify-center p-1.5">
|
|
152
81
|
<div
|
|
153
|
-
className="fixed inset-0
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
onClick={() => (window.location.href = '/storykeep')}
|
|
160
|
-
/>
|
|
161
|
-
|
|
162
|
-
<div className="relative w-full max-w-4xl rounded-lg bg-white shadow-xl">
|
|
163
|
-
<div className="absolute right-4 top-4 z-10">
|
|
164
|
-
<button
|
|
165
|
-
onClick={() => (window.location.href = '/storykeep')}
|
|
166
|
-
className="flex h-10 w-10 items-center justify-center rounded-full bg-white bg-opacity-90 shadow-lg transition-all duration-200 hover:bg-opacity-100"
|
|
167
|
-
title="Cancel and return to StoryKeep"
|
|
168
|
-
aria-label="Cancel and return to StoryKeep"
|
|
169
|
-
>
|
|
170
|
-
<svg
|
|
171
|
-
width="24"
|
|
172
|
-
height="24"
|
|
173
|
-
viewBox="0 0 24 24"
|
|
174
|
-
fill="none"
|
|
175
|
-
stroke="currentColor"
|
|
176
|
-
strokeWidth="2"
|
|
177
|
-
strokeLinecap="round"
|
|
178
|
-
strokeLinejoin="round"
|
|
179
|
-
>
|
|
180
|
-
<line x1="18" y1="6" x2="6" y2="18" />
|
|
181
|
-
<line x1="6" y1="6" x2="18" y2="18" />
|
|
182
|
-
</svg>
|
|
183
|
-
</button>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
<div className="p-6">
|
|
187
|
-
<StoryFragmentTitlePanel nodeId={props.nodeId} />
|
|
188
|
-
</div>
|
|
189
|
-
</div>
|
|
82
|
+
className="fixed inset-0 bg-black opacity-65"
|
|
83
|
+
onClick={() => (window.location.href = '/storykeep')}
|
|
84
|
+
/>
|
|
85
|
+
<div className="relative w-full max-w-4xl rounded-lg bg-white shadow-xl">
|
|
86
|
+
<div className="p-6">
|
|
87
|
+
<StoryFragmentTitlePanel nodeId={props.nodeId} />
|
|
190
88
|
</div>
|
|
191
89
|
</div>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
) : (
|
|
195
|
-
<>
|
|
196
|
-
<PanelVisibilityWrapper
|
|
197
|
-
nodeId={props.nodeId}
|
|
198
|
-
panelType="storyfragment"
|
|
199
|
-
ctx={getCtx(props)}
|
|
200
|
-
>
|
|
201
|
-
<StoryFragmentConfigPanel
|
|
202
|
-
nodeId={props.nodeId}
|
|
203
|
-
isSandboxMode={props.isSandboxMode || false}
|
|
204
|
-
/>
|
|
205
|
-
</PanelVisibilityWrapper>
|
|
206
|
-
<StoryFragment {...sharedProps} />
|
|
207
|
-
</>
|
|
208
|
-
)}
|
|
209
|
-
</>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
210
92
|
);
|
|
211
93
|
}
|
|
212
94
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
95
|
+
if (!hasPanes && !isPreview) {
|
|
96
|
+
return <EmptyPageHandler {...props} />;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<>
|
|
101
|
+
<StoryFragmentConfigPanel
|
|
102
|
+
nodeId={props.nodeId}
|
|
103
|
+
isSandboxMode={props.isSandboxMode || false}
|
|
104
|
+
/>
|
|
105
|
+
<StoryFragment {...props} />
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
} else if (isPaneNode(node)) {
|
|
109
|
+
const paneNode = node as PaneNode;
|
|
110
|
+
const isHtmlAstPane = !!paneNode.htmlAst;
|
|
111
|
+
const paneNodes = ctx.getChildNodeIDs(node.id);
|
|
112
|
+
|
|
113
|
+
if (paneNode.isContextPane) {
|
|
114
|
+
if (!isPreview) ctx.hasTitle.set(!(!paneNode.slug || !paneNode.title));
|
|
115
|
+
|
|
116
|
+
if (!isPreview && !(paneNode.slug && paneNode.title)) {
|
|
219
117
|
return (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
>
|
|
226
|
-
<div className="
|
|
227
|
-
<
|
|
228
|
-
<div className="p-6">
|
|
229
|
-
<ContextPaneTitlePanel nodeId={props.nodeId} />
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
118
|
+
<div
|
|
119
|
+
className="fixed inset-0 overflow-y-auto bg-black bg-opacity-75"
|
|
120
|
+
style={{ zIndex: 9005 }}
|
|
121
|
+
>
|
|
122
|
+
<div className="flex min-h-screen items-center justify-center p-1.5">
|
|
123
|
+
<div className="relative w-full max-w-4xl rounded-lg bg-white shadow-xl">
|
|
124
|
+
<div className="p-6">
|
|
125
|
+
<ContextPaneTitlePanel nodeId={props.nodeId} />
|
|
232
126
|
</div>
|
|
233
127
|
</div>
|
|
234
|
-
) : !isPreview ? (
|
|
235
|
-
<ContextPanePanel nodeId={node.id} />
|
|
236
|
-
) : null}
|
|
237
|
-
<div>
|
|
238
|
-
{toolModeVal === 'designLibrary' ? (
|
|
239
|
-
<Pane_DesignLibrary {...sharedProps} />
|
|
240
|
-
) : (
|
|
241
|
-
<Pane {...sharedProps} />
|
|
242
|
-
)}
|
|
243
|
-
{!isPreview &&
|
|
244
|
-
paneNode.slug &&
|
|
245
|
-
paneNode.title &&
|
|
246
|
-
paneNodes.length === 0 && (
|
|
247
|
-
<PanelVisibilityWrapper
|
|
248
|
-
nodeId={node.id}
|
|
249
|
-
panelType="add"
|
|
250
|
-
ctx={getCtx(props)}
|
|
251
|
-
>
|
|
252
|
-
<AddPanePanel
|
|
253
|
-
nodeId={node.id}
|
|
254
|
-
first={true}
|
|
255
|
-
ctx={getCtx(props)}
|
|
256
|
-
isContextPane={true}
|
|
257
|
-
/>
|
|
258
|
-
</PanelVisibilityWrapper>
|
|
259
|
-
)}
|
|
260
128
|
</div>
|
|
261
|
-
|
|
129
|
+
</div>
|
|
262
130
|
);
|
|
263
131
|
}
|
|
264
132
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const firstPane =
|
|
273
|
-
storyFragment?.paneIds?.length && storyFragment.paneIds[0];
|
|
274
|
-
if (isPreview) return <Pane {...sharedProps} />;
|
|
275
|
-
return (
|
|
276
|
-
<>
|
|
277
|
-
{storyFragment && firstPane === node.id && (
|
|
278
|
-
<PanelVisibilityWrapper
|
|
279
|
-
nodeId={`${node.id}-0`}
|
|
280
|
-
panelType="add"
|
|
281
|
-
ctx={getCtx(props)}
|
|
282
|
-
>
|
|
283
|
-
<AddPanePanel nodeId={node.id} first={true} ctx={getCtx(props)} />
|
|
133
|
+
if (!isPreview && !paneNodes.length) {
|
|
134
|
+
// Context Pane Empty State
|
|
135
|
+
return (
|
|
136
|
+
<>
|
|
137
|
+
<ContextPanePanel nodeId={node.id} />
|
|
138
|
+
<PanelVisibilityWrapper nodeId={node.id} panelType="add" ctx={ctx}>
|
|
139
|
+
<Pane {...props} />
|
|
284
140
|
</PanelVisibilityWrapper>
|
|
285
|
-
|
|
286
|
-
<div className="py-0.5">
|
|
287
|
-
<PanelVisibilityWrapper
|
|
141
|
+
<AddPanePanel
|
|
288
142
|
nodeId={node.id}
|
|
289
|
-
|
|
290
|
-
ctx={
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
{toolModeVal === `eraser` ? (
|
|
295
|
-
<PaneEraser {...sharedProps} />
|
|
296
|
-
) : toolModeVal === `layout` ? (
|
|
297
|
-
<PaneLayout {...sharedProps} />
|
|
298
|
-
) : toolModeVal === 'designLibrary' ? (
|
|
299
|
-
<Pane_DesignLibrary {...sharedProps} />
|
|
300
|
-
) : (
|
|
301
|
-
<Pane {...sharedProps} />
|
|
302
|
-
)}
|
|
303
|
-
</div>
|
|
304
|
-
<PanelVisibilityWrapper
|
|
305
|
-
nodeId={node.id}
|
|
306
|
-
panelType="add"
|
|
307
|
-
ctx={getCtx(props)}
|
|
308
|
-
>
|
|
309
|
-
<AddPanePanel nodeId={node.id} first={false} ctx={getCtx(props)} />
|
|
310
|
-
</PanelVisibilityWrapper>
|
|
311
|
-
</>
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
case 'BgPane':
|
|
316
|
-
return <BgPaneWrapper {...sharedProps} />;
|
|
317
|
-
case 'GridLayoutNode': {
|
|
318
|
-
if (toolModeVal === 'eraser') {
|
|
319
|
-
return <GridLayoutEraser {...sharedProps} />;
|
|
320
|
-
}
|
|
321
|
-
return <GridLayout {...sharedProps} />;
|
|
322
|
-
}
|
|
323
|
-
case 'TagElement':
|
|
324
|
-
return <TagElement {...sharedProps} />;
|
|
325
|
-
// tag elements
|
|
326
|
-
case 'h2':
|
|
327
|
-
case 'h3':
|
|
328
|
-
case 'h4':
|
|
329
|
-
case 'ol':
|
|
330
|
-
case 'ul':
|
|
331
|
-
case 'li':
|
|
332
|
-
case 'aside':
|
|
333
|
-
case 'p': {
|
|
334
|
-
if (toolModeVal === 'styles') {
|
|
335
|
-
let className = getCtx(props).getNodeClasses(
|
|
336
|
-
node.id,
|
|
337
|
-
viewportKeyStore.get().value
|
|
338
|
-
);
|
|
339
|
-
if (settingsPanel?.nodeId === node.id) {
|
|
340
|
-
className +=
|
|
341
|
-
' outline-4 outline-dotted outline-orange-400 outline-offset-2';
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const handleElementClick = (e: MouseEvent<HTMLElement>) => {
|
|
345
|
-
e.stopPropagation();
|
|
346
|
-
const { isActive } = selectionStore.get();
|
|
347
|
-
if (isActive) {
|
|
348
|
-
// A drag just finished. The user's intent was to select text.
|
|
349
|
-
// Do NOT open the panel.
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
// else
|
|
353
|
-
handleClickEventDefault(node as FlatNode, true);
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
const handleMouseDown = (e: MouseEvent<HTMLElement>) => {
|
|
357
|
-
if (VERBOSE)
|
|
358
|
-
console.log('[Node.tsx] handleMouseDown FIRED', { event: e });
|
|
359
|
-
if (!props.onDragStart) {
|
|
360
|
-
if (VERBOSE)
|
|
361
|
-
console.log(
|
|
362
|
-
'[Node.tsx] handleMouseDown ABORTED: no onDragStart prop'
|
|
363
|
-
);
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
e.preventDefault();
|
|
367
|
-
if (VERBOSE) console.log('[Node.tsx] preventDefault called');
|
|
368
|
-
|
|
369
|
-
const target = e.target as HTMLElement;
|
|
370
|
-
if (VERBOSE) console.log('[Node.tsx] mousedown target:', target);
|
|
371
|
-
const textNodeElement = target.closest('[data-parent-text-node-id]');
|
|
372
|
-
|
|
373
|
-
if (textNodeElement) {
|
|
374
|
-
const parentTextNodeId = textNodeElement.getAttribute(
|
|
375
|
-
'data-parent-text-node-id'
|
|
376
|
-
);
|
|
377
|
-
const startCharOffset = parseInt(
|
|
378
|
-
textNodeElement.getAttribute('data-start-char-offset') || '0',
|
|
379
|
-
10
|
|
380
|
-
);
|
|
381
|
-
|
|
382
|
-
if (parentTextNodeId) {
|
|
383
|
-
const origin: SelectionOrigin = {
|
|
384
|
-
blockNodeId: node.id,
|
|
385
|
-
lcaNodeId: node.id,
|
|
386
|
-
startNodeId: parentTextNodeId,
|
|
387
|
-
startCharOffset: startCharOffset,
|
|
388
|
-
endNodeId: parentTextNodeId,
|
|
389
|
-
endCharOffset: startCharOffset,
|
|
390
|
-
};
|
|
391
|
-
props.onDragStart(origin, e);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
const children = getCtx(props).getChildNodeIDs(node.id);
|
|
397
|
-
|
|
398
|
-
// Propagate props to children, but explicitly enable text selection
|
|
399
|
-
// and remove the onDragStart handler to prevent it from firing on child elements.
|
|
400
|
-
const childProps: NodeProps = {
|
|
401
|
-
...props,
|
|
402
|
-
onDragStart: undefined,
|
|
403
|
-
isSelectableText: true,
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
return createElement(
|
|
407
|
-
type,
|
|
408
|
-
{
|
|
409
|
-
className: className,
|
|
410
|
-
onMouseDown: handleMouseDown,
|
|
411
|
-
onClick: handleElementClick,
|
|
412
|
-
'data-node-id': node.id,
|
|
413
|
-
style: { userSelect: 'none' },
|
|
414
|
-
},
|
|
415
|
-
<RenderChildren children={children} nodeProps={childProps} />
|
|
143
|
+
first={true}
|
|
144
|
+
ctx={ctx}
|
|
145
|
+
isContextPane={true}
|
|
146
|
+
/>
|
|
147
|
+
</>
|
|
416
148
|
);
|
|
417
149
|
}
|
|
418
|
-
|
|
419
|
-
if (toolModeVal === `insert`)
|
|
420
|
-
return <NodeBasicTagInsert {...sharedProps} tagName={type} />;
|
|
421
|
-
else if (toolModeVal === `eraser`)
|
|
422
|
-
return <NodeBasicTagEraser {...sharedProps} tagName={type} />;
|
|
423
|
-
else if (toolModeVal === `move`)
|
|
424
|
-
return <NodeBasicTagSettings {...sharedProps} tagName={type} />;
|
|
425
|
-
return <NodeBasicTag {...sharedProps} tagName={type} />;
|
|
426
150
|
}
|
|
427
151
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
152
|
+
// Resolve Content
|
|
153
|
+
const content = isHtmlAstPane ? (
|
|
154
|
+
<CreativePane nodeId={props.nodeId} htmlAst={paneNode.htmlAst!} />
|
|
155
|
+
) : (
|
|
156
|
+
<Pane {...props} />
|
|
157
|
+
);
|
|
432
158
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return <></>;
|
|
452
|
-
default:
|
|
453
|
-
console.warn(`Node.tsx miss on ${type}`, node);
|
|
454
|
-
return <></>;
|
|
159
|
+
element = (
|
|
160
|
+
<>
|
|
161
|
+
<div className="py-0.5">
|
|
162
|
+
<ConfigPanePanel
|
|
163
|
+
nodeId={props.nodeId}
|
|
164
|
+
isHtmlAstPane={isHtmlAstPane}
|
|
165
|
+
/>
|
|
166
|
+
<PanelVisibilityWrapper
|
|
167
|
+
nodeId={props.nodeId}
|
|
168
|
+
panelType="settings"
|
|
169
|
+
ctx={ctx}
|
|
170
|
+
>
|
|
171
|
+
{content}
|
|
172
|
+
</PanelVisibilityWrapper>
|
|
173
|
+
</div>
|
|
174
|
+
<AddPanePanel nodeId={props.nodeId} first={false} ctx={ctx} />
|
|
175
|
+
</>
|
|
176
|
+
);
|
|
455
177
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
tagName
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
props.nodeId,
|
|
492
|
-
() => {}
|
|
493
|
-
);
|
|
494
|
-
return () => unsubscribe();
|
|
495
|
-
}
|
|
496
|
-
}, [props.nodeId, isEditLocked]);
|
|
497
|
-
|
|
498
|
-
const nodeTagName = node?.tagName || '';
|
|
499
|
-
const isBlockTag = ['h2', 'h3', 'h4', 'ol', 'ul', 'li', 'p'].includes(
|
|
500
|
-
nodeTagName
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
const parentNode = node?.parentId
|
|
504
|
-
? getCtx(props).allNodes.get().get(node.parentId)
|
|
505
|
-
: null;
|
|
506
|
-
const isTopLevelBlock = isBlockTag && parentNode?.nodeType === 'Markdown';
|
|
507
|
-
|
|
508
|
-
const closestMarkdownId = getCtx(props).getClosestNodeTypeFromId(
|
|
509
|
-
props.nodeId,
|
|
510
|
-
'Markdown'
|
|
511
|
-
);
|
|
512
|
-
const isEditableMode = [`text`].includes(
|
|
513
|
-
getCtx(props).toolModeValStore.get().value
|
|
514
|
-
);
|
|
515
|
-
const isStylesMode = [`styles`].includes(
|
|
516
|
-
getCtx(props).toolModeValStore.get().value
|
|
517
|
-
);
|
|
518
|
-
|
|
519
|
-
const isHighlighted =
|
|
520
|
-
isTopLevelBlock &&
|
|
521
|
-
closestMarkdownId === markdownParentId &&
|
|
522
|
-
nodeTagName === styleTagName &&
|
|
523
|
-
!isEditableMode;
|
|
524
|
-
|
|
525
|
-
const isOverride = overrideNodeId === props.nodeId;
|
|
526
|
-
|
|
527
|
-
const highlightStyle = isHighlighted
|
|
528
|
-
? {
|
|
529
|
-
outline: isOverride
|
|
530
|
-
? '3.5px dotted rgba(255, 165, 0, 0.85)'
|
|
531
|
-
: '2.5px dashed rgba(0, 0, 0, 0.3)',
|
|
178
|
+
// 2. Content Types
|
|
179
|
+
else if (node.nodeType === 'BgPane') {
|
|
180
|
+
element = <BgPaneWrapper {...props} />;
|
|
181
|
+
} else if (node.nodeType === 'Markdown') {
|
|
182
|
+
element = <Markdown {...props} />;
|
|
183
|
+
} else if (isGridLayoutNode(node)) {
|
|
184
|
+
element = <GridLayout {...props} />;
|
|
185
|
+
} else if (node.nodeType === 'TagElement') {
|
|
186
|
+
const flatNode = node as FlatNode;
|
|
187
|
+
|
|
188
|
+
switch (flatNode.tagName) {
|
|
189
|
+
case 'text':
|
|
190
|
+
element = <NodeText {...props} />;
|
|
191
|
+
break;
|
|
192
|
+
case 'img':
|
|
193
|
+
element = <NodeImg {...props} />;
|
|
194
|
+
break;
|
|
195
|
+
case 'a':
|
|
196
|
+
element = <NodeA {...props} />;
|
|
197
|
+
break;
|
|
198
|
+
case 'button':
|
|
199
|
+
element = <NodeButton {...props} />;
|
|
200
|
+
break;
|
|
201
|
+
case 'code': {
|
|
202
|
+
const hookData = parseCodeHook(node);
|
|
203
|
+
element = hookData ? (
|
|
204
|
+
<Widget
|
|
205
|
+
{...props}
|
|
206
|
+
hook={hookData.hook}
|
|
207
|
+
value1={hookData.value1}
|
|
208
|
+
value2={hookData.value2}
|
|
209
|
+
value3={hookData.value3}
|
|
210
|
+
/>
|
|
211
|
+
) : null;
|
|
212
|
+
break;
|
|
532
213
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
node?.nodeType === 'Markdown' || isGridLayoutNode(node);
|
|
544
|
-
|
|
545
|
-
if (isPanelActive && isStyleableContainer) {
|
|
546
|
-
const highlightStyle = {
|
|
547
|
-
outline: '3.5px dotted rgba(255, 165, 0, 0.85)',
|
|
548
|
-
};
|
|
549
|
-
return <div style={highlightStyle}>{element}</div>;
|
|
214
|
+
default:
|
|
215
|
+
element = (
|
|
216
|
+
<NodeBasicTag
|
|
217
|
+
{...props}
|
|
218
|
+
tagName={flatNode.tagName as keyof JSX.IntrinsicElements}
|
|
219
|
+
isSelectableText={true}
|
|
220
|
+
/>
|
|
221
|
+
);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
550
224
|
}
|
|
551
225
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
226
|
+
// 3. Apply Overlay if addressable
|
|
227
|
+
if (element && isAddressableNode(node, ctx)) {
|
|
228
|
+
const isInline = getNodeDisplayMode(node, viewport, ctx);
|
|
229
|
+
const isTopLevel = isTopLevelBlockNode(node, ctx);
|
|
555
230
|
|
|
556
|
-
if (isTopLevelBlock) {
|
|
557
231
|
return (
|
|
558
|
-
<
|
|
232
|
+
<NodeOverlay isInline={isInline} isTopLevel={isTopLevel} {...props}>
|
|
559
233
|
{element}
|
|
560
|
-
</
|
|
234
|
+
</NodeOverlay>
|
|
561
235
|
);
|
|
562
236
|
}
|
|
563
237
|
|
|
564
|
-
return element
|
|
238
|
+
return <>{element}</>;
|
|
565
239
|
});
|
|
566
|
-
|
|
567
|
-
export default Node;
|