astro-tractstack 2.1.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +54 -266
  2. package/bin/create-tractstack.js +9 -6
  3. package/dist/index.js +109 -71
  4. package/package.json +4 -2
  5. package/templates/css/custom.css +5 -0
  6. package/templates/custom/minimal/CodeHook.astro +1 -0
  7. package/templates/custom/with-examples/CodeHook.astro +1 -0
  8. package/templates/icons/code.svg +18 -0
  9. package/templates/icons/li.svg +4 -0
  10. package/templates/icons/link.svg +22 -0
  11. package/templates/icons/p.svg +3 -0
  12. package/templates/src/client/app.js +80 -1
  13. package/templates/src/components/Footer.astro +1 -1
  14. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +6 -6
  15. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +3 -3
  16. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +1 -1
  17. package/templates/src/components/codehooks/ListContentSetup.tsx +2 -2
  18. package/templates/src/components/codehooks/ProductCardSetup.tsx +1 -1
  19. package/templates/src/components/codehooks/ProductGridSetup.tsx +2 -2
  20. package/templates/src/components/codehooks/SandboxRegisterForm.tsx +3 -3
  21. package/templates/src/components/compositor/Compositor.tsx +25 -9
  22. package/templates/src/components/compositor/Node.tsx +168 -496
  23. package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +1 -0
  24. package/templates/src/components/compositor/elements/SignUp.tsx +1 -1
  25. package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +2 -0
  26. package/templates/src/components/compositor/nodes/CreativePane.tsx +262 -0
  27. package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +4 -6
  28. package/templates/src/components/compositor/nodes/GridLayout.tsx +4 -2
  29. package/templates/src/components/compositor/nodes/Markdown.tsx +18 -3
  30. package/templates/src/components/compositor/nodes/Pane.tsx +11 -5
  31. package/templates/src/components/compositor/nodes/RenderChildren.tsx +1 -1
  32. package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +5 -5
  33. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +90 -42
  34. package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +2 -0
  35. package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +27 -1
  36. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +10 -8
  37. package/templates/src/components/compositor/tools/NodeOverlay.tsx +224 -0
  38. package/templates/src/components/compositor/tools/PaneOverlay.tsx +122 -0
  39. package/templates/src/components/edit/Header.tsx +68 -9
  40. package/templates/src/components/edit/PanelSwitch.tsx +42 -4
  41. package/templates/src/components/edit/SettingsPanel.tsx +2 -3
  42. package/templates/src/components/edit/ToolMode.tsx +1 -31
  43. package/templates/src/components/edit/pane/AddPanePanel_break.tsx +2 -2
  44. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +1 -1
  45. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +193 -659
  46. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +15 -82
  47. package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +95 -45
  48. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +137 -49
  49. package/templates/src/components/edit/pane/RestylePaneModal.tsx +1 -1
  50. package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +375 -0
  51. package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +1 -23
  52. package/templates/src/components/edit/pane/steps/AiLibraryCopyStep.tsx +327 -0
  53. package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +267 -0
  54. package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +371 -0
  55. package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +201 -76
  56. package/templates/src/components/edit/pane/steps/CreativeInjectStep.tsx +141 -0
  57. package/templates/src/components/edit/panels/CreativeImagePanel.tsx +435 -0
  58. package/templates/src/components/edit/panels/CreativeLinkPanel.tsx +110 -0
  59. package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +1 -1
  60. package/templates/src/components/edit/panels/StyleParentPanel.tsx +118 -126
  61. package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +3 -2
  62. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +1 -0
  63. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +3 -1
  64. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +3 -1
  65. package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +1 -1
  66. package/templates/src/components/edit/state/SaveModal.tsx +19 -787
  67. package/templates/src/components/edit/state/SaveToLibraryModal.tsx +2 -2
  68. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +1 -1
  69. package/templates/src/components/edit/widgets/BunnyWidget.tsx +5 -5
  70. package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +1 -1
  71. package/templates/src/components/edit/widgets/SignupWidget.tsx +1 -1
  72. package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +1 -1
  73. package/templates/src/components/fields/ArtpackImage.tsx +11 -3
  74. package/templates/src/components/fields/BackgroundImage.tsx +8 -0
  75. package/templates/src/components/fields/BackgroundImageWrapper.tsx +15 -9
  76. package/templates/src/components/fields/ImageUpload.tsx +6 -0
  77. package/templates/src/components/form/ActionBuilderField.tsx +15 -5
  78. package/templates/src/components/form/ActionBuilderSlugSelector.tsx +1 -1
  79. package/templates/src/components/form/ColorPicker.tsx +1 -1
  80. package/templates/src/components/form/EnumSelect.tsx +1 -1
  81. package/templates/src/components/form/NumberInput.tsx +1 -1
  82. package/templates/src/components/form/StringArrayInput.tsx +1 -1
  83. package/templates/src/components/form/StringInput.tsx +1 -1
  84. package/templates/src/components/form/UnsavedChangesBar.tsx +1 -1
  85. package/templates/src/components/form/advanced/APIConfigSection.tsx +2 -2
  86. package/templates/src/components/form/advanced/AuthConfigSection.tsx +2 -2
  87. package/templates/src/components/profile/ProfileCreate.tsx +1 -1
  88. package/templates/src/components/profile/ProfileEdit.tsx +1 -1
  89. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +2 -2
  90. package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +1 -1
  91. package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +2 -2
  92. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +1 -1
  93. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +6 -6
  94. package/templates/src/components/storykeep/controls/content/MenuForm.tsx +1 -1
  95. package/templates/src/components/storykeep/controls/content/PaneTable.tsx +358 -0
  96. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +1 -1
  97. package/templates/src/constants/prompts.json +18 -10
  98. package/templates/src/constants.ts +3 -0
  99. package/templates/src/hooks/usePaneFragments.ts +60 -0
  100. package/templates/src/lib/session.ts +71 -16
  101. package/templates/src/pages/[...slug].astro +5 -46
  102. package/templates/src/pages/api/css.ts +149 -0
  103. package/templates/src/pages/context/[...contextSlug].astro +1 -0
  104. package/templates/src/pages/maint.astro +1 -1
  105. package/templates/src/pages/storykeep/login.astro +2 -2
  106. package/templates/src/stores/nodes.ts +162 -49
  107. package/templates/src/stores/orphanAnalysis.ts +6 -30
  108. package/templates/src/stores/previews.ts +7 -0
  109. package/templates/src/stores/storykeep.ts +0 -8
  110. package/templates/src/types/compositorTypes.ts +53 -10
  111. package/templates/src/utils/compositor/aiGeneration.ts +93 -0
  112. package/templates/src/utils/compositor/allowInsert.ts +2 -0
  113. package/templates/src/utils/compositor/htmlAst.ts +704 -0
  114. package/templates/src/utils/compositor/nodesHelper.ts +281 -102
  115. package/templates/src/utils/compositor/savePipeline.ts +893 -0
  116. package/templates/src/utils/etl/index.ts +3 -0
  117. package/templates/src/utils/etl/transformer.ts +10 -0
  118. package/templates/src/utils/helpers.ts +101 -0
  119. package/utils/inject-files.ts +100 -62
  120. package/templates/icons/text.svg +0 -6
  121. package/templates/src/components/compositor/NodeWithGuid.tsx +0 -69
  122. package/templates/src/components/compositor/nodes/GridLayout_eraser.tsx +0 -33
  123. package/templates/src/components/compositor/nodes/Markdown_eraser.tsx +0 -56
  124. package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +0 -269
  125. package/templates/src/components/compositor/nodes/Pane_eraser.tsx +0 -186
  126. package/templates/src/components/compositor/nodes/Pane_layout.tsx +0 -79
  127. package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +0 -26
  128. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +0 -61
  129. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +0 -120
  130. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +0 -62
  131. package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +0 -26
@@ -1,269 +0,0 @@
1
- import { type CSSProperties, useEffect, useState } from 'react';
2
- import { useStore } from '@nanostores/react';
3
- import ArchiveBoxArrowDownIcon from '@heroicons/react/24/outline/ArchiveBoxArrowDownIcon';
4
- import ArrowPathRoundedSquareIcon from '@heroicons/react/24/outline/ArrowPathRoundedSquareIcon';
5
- import ArrowDownTrayIcon from '@heroicons/react/24/outline/ArrowDownTrayIcon';
6
- import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
7
- import SparklesIcon from '@heroicons/react/24/solid/SparklesIcon';
8
- import { viewportKeyStore } from '@/stores/storykeep';
9
- import { getCtx } from '@/stores/nodes';
10
- import { RenderChildren } from './RenderChildren';
11
- import { CodeHookContainer } from './Pane';
12
- import type { NodeProps } from '@/types/nodeProps';
13
- import type { BgImageNode, ArtpackImageNode } from '@/types/compositorTypes';
14
- import { SaveToLibraryModal } from '@/components/edit/state/SaveToLibraryModal';
15
- import { RestylePaneModal } from '@/components/edit/pane/RestylePaneModal';
16
- import { AiRestylePaneModal } from '@/components/edit/pane/AiRestylePaneModal';
17
- import { selectionStore } from '@/stores/selection';
18
- import { copyPaneToClipboard } from '@/utils/compositor/designLibraryHelper';
19
-
20
- function getSizeClasses(
21
- size: string,
22
- side: 'image' | 'content',
23
- viewport: string
24
- ): string {
25
- if (viewport === 'mobile') {
26
- return 'w-full';
27
- }
28
- switch (size) {
29
- case 'narrow':
30
- return side === 'image' ? 'w-1/3' : 'w-2/3';
31
- case 'wide':
32
- return side === 'image' ? 'w-2/3' : 'w-1/3';
33
- default:
34
- return 'w-1/2';
35
- }
36
- }
37
-
38
- export const Pane_DesignLibrary = (props: NodeProps) => {
39
- const ctx = getCtx(props);
40
- const { isRestyleModalOpen, isAiRestyleModalOpen } = useStore(
41
- selectionStore,
42
- {
43
- keys: ['isRestyleModalOpen', 'isAiRestyleModalOpen'],
44
- }
45
- );
46
- const [currentViewport, setCurrentViewport] = useState(
47
- viewportKeyStore.get().value
48
- );
49
-
50
- useEffect(() => {
51
- const unsubscribeViewport = viewportKeyStore.subscribe((newViewport) => {
52
- setCurrentViewport(newViewport.value);
53
- });
54
- return () => unsubscribeViewport();
55
- }, []);
56
-
57
- const wrapperClasses = `grid ${ctx.getNodeClasses(props.nodeId, currentViewport)}`;
58
- const contentClasses = 'relative w-full h-auto justify-self-start';
59
- const contentStyles: CSSProperties = {
60
- ...ctx.getNodeCSSPropertiesStyles(props.nodeId),
61
- gridArea: '1/1/1/1',
62
- position: 'relative',
63
- zIndex: 1,
64
- };
65
- const codeHookPayload = ctx.getNodeCodeHookPayload(props.nodeId);
66
- const [children, setChildren] = useState<string[]>([
67
- ...ctx.getChildNodeIDs(props.nodeId),
68
- ]);
69
- const [isSaveModalOpen, setIsSaveModalOpen] = useState(false);
70
- const [wasCopied, setWasCopied] = useState(false);
71
- const [renderCount, setRenderCount] = useState(0);
72
-
73
- const getPaneId = (): string => `pane-${props.nodeId}`;
74
-
75
- useEffect(() => {
76
- const unsubscribe = ctx.notifications.subscribe(props.nodeId, () => {
77
- setChildren([...ctx.getChildNodeIDs(props.nodeId)]);
78
- setRenderCount((prev) => prev + 1);
79
- });
80
- return unsubscribe;
81
- }, [props.nodeId, ctx.notifications]);
82
-
83
- const handleRestyleClick = (e: React.MouseEvent) => {
84
- e.stopPropagation();
85
- selectionStore.setKey('paneToRestyleId', props.nodeId);
86
- selectionStore.setKey('isRestyleModalOpen', true);
87
- };
88
-
89
- const handleAiRestyleClick = (e: React.MouseEvent) => {
90
- e.stopPropagation();
91
- selectionStore.setKey('paneToRestyleId', props.nodeId);
92
- selectionStore.setKey('isAiRestyleModalOpen', true);
93
- };
94
-
95
- const handleSaveClick = (e: React.MouseEvent) => {
96
- e.stopPropagation();
97
- setIsSaveModalOpen(true);
98
- };
99
-
100
- const handleCopyToClipboard = async (e: React.MouseEvent) => {
101
- e.stopPropagation();
102
- const success = await copyPaneToClipboard(props.nodeId);
103
- if (success) {
104
- setWasCopied(true);
105
- setTimeout(() => setWasCopied(false), 2000);
106
- }
107
- };
108
-
109
- const Buttons = () => (
110
- <div className="absolute left-2 top-2 z-10 flex flex-row gap-x-2">
111
- {!props.isSandboxMode && (
112
- <button
113
- title="Save Pane to Design Library"
114
- onClick={handleSaveClick}
115
- className="flex h-10 w-10 items-center justify-center rounded-full bg-cyan-600 p-1.5 shadow-lg hover:bg-cyan-700"
116
- >
117
- <ArchiveBoxArrowDownIcon className="h-7 w-7 text-white" />
118
- </button>
119
- )}
120
- <button
121
- title="Re-Color"
122
- onClick={handleAiRestyleClick}
123
- className="flex h-10 w-10 items-center justify-center rounded-full bg-purple-600 p-1.5 shadow-lg hover:bg-purple-700"
124
- >
125
- <SparklesIcon className="h-5 w-5 text-white" />
126
- </button>
127
- <button
128
- title="Restyle Pane from Design Library"
129
- onClick={handleRestyleClick}
130
- className="flex h-10 w-10 items-center justify-center rounded-full bg-blue-600 p-1.5 shadow-lg hover:bg-blue-700"
131
- >
132
- <ArrowPathRoundedSquareIcon className="h-7 w-7 text-white" />
133
- </button>
134
- <button
135
- title="Copy Pane Design to Clipboard"
136
- onClick={handleCopyToClipboard}
137
- className={`flex h-10 w-10 items-center justify-center rounded-full p-1.5 shadow-lg transition-colors ${
138
- wasCopied ? 'bg-green-500' : 'bg-gray-600 hover:bg-gray-700'
139
- }`}
140
- >
141
- {wasCopied ? (
142
- <CheckIcon className="h-7 w-7 text-white" />
143
- ) : (
144
- <ArrowDownTrayIcon className="h-7 w-7 text-white" />
145
- )}
146
- </button>
147
- </div>
148
- );
149
-
150
- const allNodes = ctx.allNodes.get();
151
- const bgNode = children
152
- .map((id) => allNodes.get(id))
153
- .find(
154
- (node) =>
155
- node?.nodeType === 'BgPane' &&
156
- 'type' in node &&
157
- (node.type === 'background-image' || node.type === 'artpack-image')
158
- ) as (BgImageNode | ArtpackImageNode) | undefined;
159
-
160
- const useFlexLayout =
161
- bgNode &&
162
- (bgNode.position === 'leftBleed' || bgNode.position === 'rightBleed');
163
- const deferFlexLayout =
164
- bgNode && (bgNode.position === 'left' || bgNode.position === 'right');
165
-
166
- const flexDirection =
167
- currentViewport === 'mobile'
168
- ? 'flex-col'
169
- : bgNode?.position === 'rightBleed'
170
- ? 'flex-row-reverse'
171
- : 'flex-row';
172
-
173
- return (
174
- <div id={getPaneId()} className="pane min-h-16">
175
- <div
176
- id={ctx.getNodeSlug(props.nodeId)}
177
- className={useFlexLayout ? '' : wrapperClasses}
178
- >
179
- {codeHookPayload ? (
180
- <div className={contentClasses} style={contentStyles}>
181
- <Buttons />
182
- <CodeHookContainer payload={codeHookPayload} />
183
- </div>
184
- ) : useFlexLayout ? (
185
- <div
186
- className={`flex flex-nowrap ${flexDirection} ${ctx.getNodeClasses(props.nodeId, currentViewport)}`}
187
- >
188
- <div
189
- className={`relative overflow-hidden ${getSizeClasses(bgNode.size || 'equal', 'image', currentViewport)}`}
190
- >
191
- <RenderChildren
192
- children={children.filter((id) => {
193
- const node = allNodes.get(id);
194
- return node?.nodeType === 'BgPane';
195
- })}
196
- nodeProps={props}
197
- key={`bg-children-${props.nodeId}-${renderCount}`}
198
- />
199
- </div>
200
- <div
201
- className={`${contentClasses} ${getSizeClasses(bgNode.size || 'equal', 'content', currentViewport)}`}
202
- style={ctx.getNodeCSSPropertiesStyles(props.nodeId)}
203
- onClick={(e) => {
204
- ctx.setClickedNodeId(props.nodeId);
205
- e.stopPropagation();
206
- }}
207
- >
208
- <Buttons />
209
- <RenderChildren
210
- children={children.filter((id) => {
211
- const node = allNodes.get(id);
212
- return node?.nodeType !== 'BgPane';
213
- })}
214
- nodeProps={props}
215
- key={`content-children-${props.nodeId}-${renderCount}`}
216
- />
217
- </div>
218
- </div>
219
- ) : deferFlexLayout ? (
220
- <div
221
- className={contentClasses}
222
- style={contentStyles}
223
- onClick={(e) => {
224
- ctx.setClickedNodeId(props.nodeId);
225
- e.stopPropagation();
226
- }}
227
- >
228
- <Buttons />
229
- <RenderChildren
230
- children={children.filter((id) => {
231
- const node = allNodes.get(id);
232
- return node?.nodeType !== 'BgPane';
233
- })}
234
- nodeProps={props}
235
- key={`content-children-${props.nodeId}-${renderCount}`}
236
- />
237
- </div>
238
- ) : (
239
- <div
240
- className={contentClasses}
241
- style={contentStyles}
242
- onClick={(e) => {
243
- ctx.setClickedNodeId(props.nodeId);
244
- e.stopPropagation();
245
- }}
246
- >
247
- <Buttons />
248
- <RenderChildren
249
- children={children}
250
- nodeProps={props}
251
- key={`render-children-${props.nodeId}-${renderCount}`}
252
- />
253
- </div>
254
- )}
255
- </div>
256
- {isSaveModalOpen && (
257
- <SaveToLibraryModal
258
- paneId={props.nodeId}
259
- onClose={() => setIsSaveModalOpen(false)}
260
- />
261
- )}
262
-
263
- {isRestyleModalOpen && <RestylePaneModal />}
264
- {isAiRestyleModalOpen && (
265
- <AiRestylePaneModal isSandboxMode={props.isSandboxMode} />
266
- )}
267
- </div>
268
- );
269
- };
@@ -1,186 +0,0 @@
1
- import { type CSSProperties, useEffect, useState } from 'react';
2
- import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
3
- import { viewportKeyStore } from '@/stores/storykeep';
4
- import { getCtx } from '@/stores/nodes';
5
- import { RenderChildren } from './RenderChildren';
6
- import { CodeHookContainer } from './Pane';
7
- import type { NodeProps } from '@/types/nodeProps';
8
- import type { BgImageNode, ArtpackImageNode } from '@/types/compositorTypes';
9
-
10
- function getSizeClasses(
11
- size: string,
12
- side: 'image' | 'content',
13
- viewport: string
14
- ): string {
15
- if (viewport === 'mobile') {
16
- return 'w-full';
17
- }
18
- switch (size) {
19
- case 'narrow':
20
- return side === 'image' ? 'w-1/3' : 'w-2/3';
21
- case 'wide':
22
- return side === 'image' ? 'w-2/3' : 'w-1/3';
23
- default:
24
- return 'w-1/2';
25
- }
26
- }
27
-
28
- export const PaneEraser = (props: NodeProps) => {
29
- const ctx = getCtx(props);
30
- const [currentViewport, setCurrentViewport] = useState(
31
- viewportKeyStore.get().value
32
- );
33
-
34
- useEffect(() => {
35
- const unsubscribeViewport = viewportKeyStore.subscribe((newViewport) => {
36
- setCurrentViewport(newViewport.value);
37
- });
38
- return () => unsubscribeViewport();
39
- }, []);
40
-
41
- const wrapperClasses = `grid ${ctx.getNodeClasses(props.nodeId, currentViewport)}`;
42
- const contentClasses = 'relative w-full h-auto justify-self-start';
43
- const contentStyles: CSSProperties = {
44
- ...ctx.getNodeCSSPropertiesStyles(props.nodeId),
45
- gridArea: '1/1/1/1',
46
- position: 'relative',
47
- zIndex: 1,
48
- };
49
- const codeHookPayload = ctx.getNodeCodeHookPayload(props.nodeId);
50
- const [children, setChildren] = useState<string[]>([
51
- ...ctx.getChildNodeIDs(props.nodeId),
52
- ]);
53
- const [renderCount, setRenderCount] = useState(0);
54
-
55
- const getPaneId = (): string => `pane-${props.nodeId}`;
56
-
57
- useEffect(() => {
58
- const unsubscribe = ctx.notifications.subscribe(props.nodeId, () => {
59
- setChildren([...ctx.getChildNodeIDs(props.nodeId)]);
60
- setRenderCount((prev) => prev + 1);
61
- });
62
- return unsubscribe;
63
- }, [props.nodeId, ctx.notifications]);
64
-
65
- const DeleteButton = () => (
66
- <button
67
- title="Delete Pane"
68
- onClick={(e) => {
69
- ctx.setClickedNodeId(props.nodeId);
70
- e.stopPropagation();
71
- }}
72
- className="absolute right-2 top-2 z-10 rounded-full bg-red-700 p-1.5 hover:bg-black"
73
- >
74
- <TrashIcon className="h-10 w-10 text-white" />
75
- </button>
76
- );
77
-
78
- const allNodes = ctx.allNodes.get();
79
- const bgNode = children
80
- .map((id) => allNodes.get(id))
81
- .find(
82
- (node) =>
83
- node?.nodeType === 'BgPane' &&
84
- 'type' in node &&
85
- (node.type === 'background-image' || node.type === 'artpack-image')
86
- ) as (BgImageNode | ArtpackImageNode) | undefined;
87
-
88
- const useFlexLayout =
89
- bgNode &&
90
- (bgNode.position === 'leftBleed' || bgNode.position === 'rightBleed');
91
- const deferFlexLayout =
92
- bgNode && (bgNode.position === 'left' || bgNode.position === 'right');
93
-
94
- const flexDirection =
95
- currentViewport === 'mobile'
96
- ? 'flex-col'
97
- : bgNode?.position === 'rightBleed'
98
- ? 'flex-row-reverse'
99
- : 'flex-row';
100
-
101
- return (
102
- <div id={getPaneId()} className="pane min-h-16">
103
- <div
104
- id={ctx.getNodeSlug(props.nodeId)}
105
- className={useFlexLayout ? '' : wrapperClasses}
106
- >
107
- {codeHookPayload ? (
108
- <div className={contentClasses} style={contentStyles}>
109
- <DeleteButton />
110
- <CodeHookContainer payload={codeHookPayload} />
111
- </div>
112
- ) : useFlexLayout ? (
113
- <div
114
- className={`flex flex-nowrap ${flexDirection} ${ctx.getNodeClasses(props.nodeId, currentViewport)}`}
115
- >
116
- <div
117
- className={`relative overflow-hidden ${getSizeClasses(bgNode.size || 'equal', 'image', currentViewport)}`}
118
- >
119
- <RenderChildren
120
- children={children.filter((id) => {
121
- const node = allNodes.get(id);
122
- return node?.nodeType === 'BgPane';
123
- })}
124
- nodeProps={props}
125
- key={`bg-children-${props.nodeId}-${renderCount}`}
126
- />
127
- </div>
128
- <div
129
- className={`${contentClasses} ${getSizeClasses(bgNode.size || 'equal', 'content', currentViewport)}`}
130
- style={ctx.getNodeCSSPropertiesStyles(props.nodeId)}
131
- onClick={(e) => {
132
- ctx.setClickedNodeId(props.nodeId);
133
- e.stopPropagation();
134
- }}
135
- >
136
- <DeleteButton />
137
- <RenderChildren
138
- children={children.filter((id) => {
139
- const node = allNodes.get(id);
140
- return node?.nodeType !== 'BgPane';
141
- })}
142
- nodeProps={props}
143
- key={`content-children-${props.nodeId}-${renderCount}`}
144
- />
145
- </div>
146
- </div>
147
- ) : deferFlexLayout ? (
148
- <div
149
- className={contentClasses}
150
- style={contentStyles}
151
- onClick={(e) => {
152
- ctx.setClickedNodeId(props.nodeId);
153
- e.stopPropagation();
154
- }}
155
- >
156
- <DeleteButton />
157
- <RenderChildren
158
- children={children.filter((id) => {
159
- const node = allNodes.get(id);
160
- return node?.nodeType !== 'BgPane';
161
- })}
162
- nodeProps={props}
163
- key={`content-children-${props.nodeId}-${renderCount}`}
164
- />
165
- </div>
166
- ) : (
167
- <div
168
- className={contentClasses}
169
- style={contentStyles}
170
- onClick={(e) => {
171
- ctx.setClickedNodeId(props.nodeId);
172
- e.stopPropagation();
173
- }}
174
- >
175
- <DeleteButton />
176
- <RenderChildren
177
- children={children}
178
- nodeProps={props}
179
- key={`render-children-${props.nodeId}-${renderCount}`}
180
- />
181
- </div>
182
- )}
183
- </div>
184
- </div>
185
- );
186
- };
@@ -1,79 +0,0 @@
1
- import { type CSSProperties, useEffect, useState } from 'react';
2
- import PuzzlePieceIcon from '@heroicons/react/24/outline/PuzzlePieceIcon';
3
- import { viewportKeyStore } from '@/stores/storykeep';
4
- import { getCtx } from '@/stores/nodes';
5
- import { RenderChildren } from './RenderChildren';
6
- import { CodeHookContainer } from './Pane';
7
- import { type NodeProps } from '@/types/nodeProps';
8
-
9
- export const PaneLayout = (props: NodeProps) => {
10
- const wrapperClasses = `grid ${getCtx(props).getNodeClasses(props.nodeId, viewportKeyStore.get().value)}`;
11
- const contentClasses = 'relative w-full h-auto justify-self-start';
12
- const contentStyles: CSSProperties = {
13
- ...getCtx(props).getNodeCSSPropertiesStyles(props.nodeId),
14
- gridArea: '1/1/1/1',
15
- };
16
- const codeHookPayload = getCtx(props).getNodeCodeHookPayload(props.nodeId);
17
- const [children, setChildren] = useState<string[]>([
18
- ...getCtx(props).getChildNodeIDs(props.nodeId),
19
- ]);
20
-
21
- const getPaneId = (): string => `pane-${props.nodeId}`;
22
-
23
- useEffect(() => {
24
- const unsubscribe = getCtx(props).notifications.subscribe(
25
- props.nodeId,
26
- () => {
27
- console.log(
28
- 'notification received data update for page node: ' + props.nodeId
29
- );
30
- setChildren([...getCtx(props).getChildNodeIDs(props.nodeId)]);
31
- }
32
- );
33
- return unsubscribe;
34
- }, []);
35
-
36
- return (
37
- <div id={getPaneId()} className="pane min-h-16">
38
- <div
39
- id={getCtx(props).getNodeSlug(props.nodeId)}
40
- className={wrapperClasses}
41
- >
42
- <div
43
- className={contentClasses}
44
- style={contentStyles}
45
- onClick={(e) => {
46
- getCtx(props).setClickedNodeId(props.nodeId);
47
- e.stopPropagation();
48
- }}
49
- onDoubleClick={(e) => {
50
- getCtx(props).setClickedNodeId(props.nodeId, true);
51
- e.stopPropagation();
52
- }}
53
- >
54
- {!props.isSandboxMode && (
55
- <button
56
- title="Apply New Layout"
57
- onClick={(e) => {
58
- getCtx(props).setClickedNodeId(props.nodeId);
59
- e.stopPropagation();
60
- }}
61
- onDoubleClick={(e) => {
62
- getCtx(props).setClickedNodeId(props.nodeId, true);
63
- e.stopPropagation();
64
- }}
65
- className="absolute right-2 top-2 z-10 rounded-full bg-cyan-700 p-1.5 hover:bg-black"
66
- >
67
- <PuzzlePieceIcon className="h-10 w-10 text-white" />
68
- </button>
69
- )}
70
- {codeHookPayload ? (
71
- <CodeHookContainer payload={codeHookPayload} />
72
- ) : (
73
- <RenderChildren children={children} nodeProps={props} />
74
- )}
75
- </div>
76
- </div>
77
- </div>
78
- );
79
- };
@@ -1,26 +0,0 @@
1
- import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
2
- import { getCtx } from '@/stores/nodes';
3
- import { viewportKeyStore } from '@/stores/storykeep';
4
- import { RenderChildren } from '../RenderChildren';
5
- import type { NodeProps } from '@/types/nodeProps';
6
-
7
- export const NodeAEraser = (props: NodeProps) => {
8
- return (
9
- <button
10
- className={` ${getCtx(props).getNodeClasses(props.nodeId, viewportKeyStore.get().value)} eraser-child group relative transition-all before:pointer-events-none before:absolute before:inset-0 before:opacity-50 before:outline-dashed before:outline-4 before:outline-red-700 hover:before:bg-red-600/50 hover:before:opacity-100 focus:before:bg-red-600/50 focus:before:opacity-100`}
11
- title="Delete Link"
12
- onClick={(e) => {
13
- getCtx(props).setClickedNodeId(props.nodeId);
14
- e.stopPropagation();
15
- }}
16
- >
17
- <div className="absolute right-2 top-2 rounded-full bg-red-700 p-0.5">
18
- <TrashIcon className="h-5 w-5 text-white" />
19
- </div>
20
- <RenderChildren
21
- children={getCtx(props).getChildNodeIDs(props.nodeId)}
22
- nodeProps={props}
23
- />
24
- </button>
25
- );
26
- };
@@ -1,61 +0,0 @@
1
- import { type JSX, type MouseEvent, type KeyboardEvent } from 'react';
2
- import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
3
- import { getCtx } from '@/stores/nodes';
4
- import { viewportKeyStore } from '@/stores/storykeep';
5
- import { RenderChildren } from '../RenderChildren';
6
- import { tagTitles } from '@/types/compositorTypes';
7
- import type { NodeProps } from '@/types/nodeProps';
8
-
9
- type NodeTagProps = NodeProps & { tagName: keyof JSX.IntrinsicElements };
10
-
11
- export const NodeBasicTagEraser = (props: NodeTagProps) => {
12
- const nodeId = props.nodeId;
13
- const children = getCtx(props).getChildNodeIDs(props.nodeId);
14
-
15
- const Tag = props.tagName;
16
- const tagTitle =
17
- tagTitles[props.tagName as keyof typeof tagTitles] || props.tagName;
18
-
19
- const handleClick = (e: MouseEvent) => {
20
- e.stopPropagation();
21
- getCtx(props).setClickedNodeId(nodeId);
22
- };
23
-
24
- const EraserUI = () => (
25
- <div
26
- className={`pointer-events-none absolute left-2 top-2 z-50 flex items-center gap-2 transition-opacity`}
27
- >
28
- <div className="rounded-full bg-gray-200 px-2 py-1 text-sm text-gray-800">
29
- {tagTitle}
30
- </div>
31
- <div className="flex items-center gap-1 rounded bg-white px-2 py-1 text-sm text-red-700 shadow-sm transition-colors group-focus-within:bg-red-700 group-focus-within:text-white group-hover:bg-red-700 group-hover:text-white">
32
- <TrashIcon className="h-4 w-4" />
33
- </div>
34
- </div>
35
- );
36
-
37
- return (
38
- <div
39
- className="group relative cursor-pointer"
40
- onClick={handleClick}
41
- role="button"
42
- tabIndex={0}
43
- onKeyDown={(e: KeyboardEvent) => {
44
- if (e.key === 'Enter' || e.key === ' ') {
45
- e.preventDefault();
46
- handleClick(e as unknown as MouseEvent);
47
- }
48
- }}
49
- >
50
- <div className="absolute inset-0">
51
- <div className="h-full w-full opacity-50 mix-blend-difference outline-dashed outline-4 outline-red-700 group-focus-within:opacity-100 group-hover:opacity-100" />
52
- </div>
53
- <EraserUI />
54
- <Tag
55
- className={`${getCtx(props).getNodeClasses(nodeId, viewportKeyStore.get().value)} pt-12`}
56
- >
57
- <RenderChildren children={children} nodeProps={props} />
58
- </Tag>
59
- </div>
60
- );
61
- };