@alpaca-editor/core 1.0.3812 → 1.0.3815
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/dist/components/ui/context-menu.d.ts +25 -0
- package/dist/components/ui/context-menu.js +51 -0
- package/dist/components/ui/context-menu.js.map +1 -0
- package/dist/config/config.js +3 -2
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +4 -2
- package/dist/editor/ComponentInfo.js +1 -1
- package/dist/editor/ComponentInfo.js.map +1 -1
- package/dist/editor/ConfirmationDialog.d.ts +1 -1
- package/dist/editor/ContextMenu.d.ts +1 -1
- package/dist/editor/ContextMenu.js +24 -9
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/ImageEditor.js +2 -2
- package/dist/editor/ImageEditor.js.map +1 -1
- package/dist/editor/ItemInfo.js +2 -2
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/MainLayout.js +3 -3
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/Titlebar.js +1 -1
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AiTerminal.js +19 -12
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/client/EditorClient.js +19 -4
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +1 -1
- package/dist/editor/client/operations.js +15 -14
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +8 -5
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +15 -13
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/componentTreeHelper.js +3 -3
- package/dist/editor/componentTreeHelper.js.map +1 -1
- package/dist/editor/control-center/ControlCenterMenu.js +3 -3
- package/dist/editor/control-center/ControlCenterMenu.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +4 -4
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +52 -14
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +5 -5
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +114 -45
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.d.ts +0 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +119 -215
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelBuilder.d.ts +3 -0
- package/dist/editor/page-viewer/pageModelBuilder.js +299 -0
- package/dist/editor/page-viewer/pageModelBuilder.js.map +1 -0
- package/dist/editor/pageModel.d.ts +5 -0
- package/dist/editor/sidebar/ComponentPalette.js +30 -30
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +7 -6
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +1 -1
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/sidebar/SidebarView.js +3 -3
- package/dist/editor/sidebar/SidebarView.js.map +1 -1
- package/dist/editor/ui/CopyToClipboardButton.js +2 -1
- package/dist/editor/ui/CopyToClipboardButton.js.map +1 -1
- package/dist/editor/ui/Icons.d.ts +0 -1
- package/dist/editor/ui/Icons.js +0 -3
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/ui/Section.js +1 -1
- package/dist/editor/ui/Section.js.map +1 -1
- package/dist/editor/ui/SimpleMenu.d.ts +1 -8
- package/dist/editor/ui/SimpleMenu.js +1 -1
- package/dist/editor/ui/SimpleMenu.js.map +1 -1
- package/dist/editor/utils.d.ts +2 -2
- package/dist/editor/utils.js +57 -9
- package/dist/editor/utils.js.map +1 -1
- package/dist/lib/safelist.js +1 -1
- package/dist/lib/safelist.js.map +1 -1
- package/dist/splash-screen/SplashScreen.js +0 -1
- package/dist/splash-screen/SplashScreen.js.map +1 -1
- package/dist/styles.css +242 -59
- package/dist/types.d.ts +2 -2
- package/package.json +3 -2
- package/src/components/ui/context-menu.tsx +250 -0
- package/src/config/config.tsx +2 -2
- package/src/config/types.ts +4 -2
- package/src/editor/ComponentInfo.tsx +3 -5
- package/src/editor/ConfirmationDialog.tsx +1 -1
- package/src/editor/ContextMenu.tsx +68 -19
- package/src/editor/ImageEditor.tsx +2 -2
- package/src/editor/ItemInfo.tsx +4 -4
- package/src/editor/MainLayout.tsx +3 -4
- package/src/editor/Titlebar.tsx +1 -1
- package/src/editor/ai/AiTerminal.tsx +31 -24
- package/src/editor/client/EditorClient.tsx +23 -6
- package/src/editor/client/editContext.ts +1 -1
- package/src/editor/client/operations.ts +16 -14
- package/src/editor/client/pageModelBuilder.ts +26 -18
- package/src/editor/commands/componentCommands.tsx +58 -39
- package/src/editor/componentTreeHelper.tsx +3 -2
- package/src/editor/control-center/ControlCenterMenu.tsx +4 -4
- package/src/editor/field-types/TreeListEditor.tsx +11 -11
- package/src/editor/page-editor-chrome/FrameMenu.tsx +81 -17
- package/src/editor/page-editor-chrome/InlineEditor.tsx +5 -5
- package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +12 -15
- package/src/editor/page-editor-chrome/PlaceholderDropZones.tsx +159 -68
- package/src/editor/page-viewer/PageViewerFrame.tsx +131 -300
- package/src/editor/page-viewer/pageModelBuilder.ts +412 -0
- package/src/editor/pageModel.ts +5 -0
- package/src/editor/sidebar/ComponentPalette.tsx +108 -106
- package/src/editor/sidebar/ComponentTree.tsx +10 -5
- package/src/editor/sidebar/MainContentTree.tsx +1 -1
- package/src/editor/sidebar/SidebarView.tsx +9 -9
- package/src/editor/ui/CopyToClipboardButton.tsx +2 -1
- package/src/editor/ui/Icons.tsx +0 -18
- package/src/editor/ui/Section.tsx +4 -4
- package/src/editor/ui/SimpleMenu.tsx +5 -13
- package/src/editor/utils.ts +74 -17
- package/src/lib/safelist.tsx +2 -0
- package/src/splash-screen/SplashScreen.tsx +0 -1
- package/src/types.ts +2 -4
- package/styles.css +58 -17
|
@@ -10,6 +10,19 @@ import {
|
|
|
10
10
|
} from "../../types";
|
|
11
11
|
|
|
12
12
|
import { Component, ItemDescriptor, Placeholder } from "../pageModel";
|
|
13
|
+
import {
|
|
14
|
+
Check,
|
|
15
|
+
Copy,
|
|
16
|
+
MessageCircleMore,
|
|
17
|
+
Palette,
|
|
18
|
+
Plus,
|
|
19
|
+
RefreshCcw,
|
|
20
|
+
Sparkles,
|
|
21
|
+
Square,
|
|
22
|
+
StopCircle,
|
|
23
|
+
Trash2,
|
|
24
|
+
TriangleAlert,
|
|
25
|
+
} from "lucide-react";
|
|
13
26
|
|
|
14
27
|
export type ComponentCommandData = CommandData & {
|
|
15
28
|
components: Component[];
|
|
@@ -37,11 +50,11 @@ export function getSelectedComponentCommands(editContext: EditContextType) {
|
|
|
37
50
|
|
|
38
51
|
const componentCommands = getComponentCommands(
|
|
39
52
|
selectedComponents,
|
|
40
|
-
editContext
|
|
53
|
+
editContext,
|
|
41
54
|
);
|
|
42
55
|
|
|
43
56
|
const componentCommandMenuItems = componentCommands.filter(
|
|
44
|
-
(x) => x.visibilityScopes.indexOf("menu") >= 0
|
|
57
|
+
(x) => x.visibilityScopes.indexOf("menu") >= 0,
|
|
45
58
|
);
|
|
46
59
|
|
|
47
60
|
return componentCommandMenuItems;
|
|
@@ -49,14 +62,14 @@ export function getSelectedComponentCommands(editContext: EditContextType) {
|
|
|
49
62
|
|
|
50
63
|
export function getComponentCommands(
|
|
51
64
|
entities: (Placeholder | Component)[],
|
|
52
|
-
editContext: EditContextType
|
|
65
|
+
editContext: EditContextType,
|
|
53
66
|
): ComponentCommand[] {
|
|
54
67
|
const components = entities.filter(
|
|
55
|
-
(x) => x && !isPlaceholder(x)
|
|
68
|
+
(x) => x && !isPlaceholder(x),
|
|
56
69
|
) as Component[];
|
|
57
70
|
|
|
58
71
|
const commands = [
|
|
59
|
-
getCreateCommentCommand(),
|
|
72
|
+
getCreateCommentCommand(components),
|
|
60
73
|
getInsertCommand(components, editContext),
|
|
61
74
|
getDeleteCommand(components, editContext),
|
|
62
75
|
getDuplicateCommand(components, editContext),
|
|
@@ -72,7 +85,7 @@ export function getComponentCommands(
|
|
|
72
85
|
|
|
73
86
|
function getInsertCommand(
|
|
74
87
|
components: Component[],
|
|
75
|
-
editContext: EditContextType
|
|
88
|
+
editContext: EditContextType,
|
|
76
89
|
): ComponentCommand | null {
|
|
77
90
|
if (components.length !== 1 || isPlaceholder(components[0])) return null;
|
|
78
91
|
const item = components[0];
|
|
@@ -80,7 +93,7 @@ function getInsertCommand(
|
|
|
80
93
|
if (!item.placeholders || item.placeholders.length === 0) return null;
|
|
81
94
|
return {
|
|
82
95
|
id: "insert",
|
|
83
|
-
icon:
|
|
96
|
+
icon: <Plus size={14} />,
|
|
84
97
|
label: "Insert component",
|
|
85
98
|
disabled: (context) => !context.editContext.page?.item.canWriteItem,
|
|
86
99
|
visibilityScopes: ["editFrame", "contextMenu"],
|
|
@@ -92,13 +105,13 @@ function getInsertCommand(
|
|
|
92
105
|
|
|
93
106
|
function getDuplicateCommand(
|
|
94
107
|
components: Component[],
|
|
95
|
-
editContext: EditContextType
|
|
108
|
+
editContext: EditContextType,
|
|
96
109
|
): ComponentCommand | null {
|
|
97
110
|
if (components.length !== 1) return null;
|
|
98
111
|
|
|
99
112
|
return {
|
|
100
113
|
id: "duplicate",
|
|
101
|
-
icon:
|
|
114
|
+
icon: <Copy size={14} />,
|
|
102
115
|
label: "Duplicate",
|
|
103
116
|
visibilityScopes: ["contextMenu", "menu"],
|
|
104
117
|
disabled: (c) => !(c.editContext.page?.item.canWriteItem || false),
|
|
@@ -118,7 +131,7 @@ function getDuplicateCommand(
|
|
|
118
131
|
function getAiCommand(editContext: EditContextType): ComponentCommand {
|
|
119
132
|
return {
|
|
120
133
|
id: "ai",
|
|
121
|
-
icon:
|
|
134
|
+
icon: <Sparkles size={14} />,
|
|
122
135
|
label: "AI",
|
|
123
136
|
disabled: () => false,
|
|
124
137
|
|
|
@@ -134,7 +147,7 @@ function getAiCommand(editContext: EditContextType): ComponentCommand {
|
|
|
134
147
|
|
|
135
148
|
function getDesignCommand(
|
|
136
149
|
components: Component[],
|
|
137
|
-
editContext: EditContextType
|
|
150
|
+
editContext: EditContextType,
|
|
138
151
|
): ComponentCommand | null {
|
|
139
152
|
if (components.length !== 1 || isPlaceholder(components[0])) return null;
|
|
140
153
|
const item = components[0];
|
|
@@ -142,21 +155,21 @@ function getDesignCommand(
|
|
|
142
155
|
if (!item.datasourceItem?.fields) return null;
|
|
143
156
|
if (
|
|
144
157
|
!Object.values(item.datasourceItem.fields).find(
|
|
145
|
-
(x) => x.section === "Design"
|
|
158
|
+
(x) => x.section === "Design",
|
|
146
159
|
)
|
|
147
160
|
)
|
|
148
161
|
return null;
|
|
149
162
|
|
|
150
163
|
return {
|
|
151
164
|
id: "design",
|
|
152
|
-
icon:
|
|
165
|
+
icon: <Palette size={14} />,
|
|
153
166
|
label: "Design",
|
|
154
167
|
disabled: () => false,
|
|
155
168
|
execute: async (context: CommandContext<any>) => {
|
|
156
169
|
editContext.showFieldEditorPopup(
|
|
157
170
|
item.datasourceItem?.fields || [],
|
|
158
171
|
["Design", "Rendering"],
|
|
159
|
-
context.event
|
|
172
|
+
context.event!,
|
|
160
173
|
);
|
|
161
174
|
},
|
|
162
175
|
visibilityScopes: ["editFrame", "contextMenu"],
|
|
@@ -165,7 +178,7 @@ function getDesignCommand(
|
|
|
165
178
|
|
|
166
179
|
function getLinkToMasterCommand(
|
|
167
180
|
components: Component[],
|
|
168
|
-
editContext: EditContextType
|
|
181
|
+
editContext: EditContextType,
|
|
169
182
|
): ComponentCommand | null {
|
|
170
183
|
if (!components.length) return null;
|
|
171
184
|
if (editContext.page?.item?.masterLanguages?.length === 0) return null;
|
|
@@ -174,7 +187,7 @@ function getLinkToMasterCommand(
|
|
|
174
187
|
components,
|
|
175
188
|
editContext,
|
|
176
189
|
"componentLinkedToMasterLanguage",
|
|
177
|
-
"Linked To Master Language"
|
|
190
|
+
"Linked To Master Language",
|
|
178
191
|
);
|
|
179
192
|
}
|
|
180
193
|
|
|
@@ -182,30 +195,34 @@ function getCheckboxCommand(
|
|
|
182
195
|
components: Component[],
|
|
183
196
|
editContext: EditContextType,
|
|
184
197
|
fieldName: string,
|
|
185
|
-
label: string
|
|
198
|
+
label: string,
|
|
186
199
|
): ComponentCommand | null {
|
|
187
200
|
const someLinked = components.find(
|
|
188
201
|
(x) =>
|
|
189
202
|
x.datasourceItem?.fields.find((x) => x.name === fieldName)?.rawValue ===
|
|
190
|
-
"1"
|
|
203
|
+
"1",
|
|
191
204
|
);
|
|
192
205
|
const allLinked = !components.find(
|
|
193
206
|
(x) =>
|
|
194
207
|
x.datasourceItem?.fields.find((x) => x.name === fieldName)?.rawValue !==
|
|
195
|
-
"1"
|
|
208
|
+
"1",
|
|
196
209
|
);
|
|
197
210
|
|
|
198
211
|
return {
|
|
199
212
|
id: fieldName,
|
|
200
|
-
icon:
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
icon: allLinked ? (
|
|
214
|
+
<Check size={14} />
|
|
215
|
+
) : someLinked ? (
|
|
216
|
+
<StopCircle size={14} />
|
|
217
|
+
) : (
|
|
218
|
+
<Square size={14} />
|
|
219
|
+
),
|
|
203
220
|
label,
|
|
204
221
|
disabled: () => false,
|
|
205
222
|
execute: async () => {
|
|
206
223
|
components.forEach((c) => {
|
|
207
224
|
const field = c.datasourceItem?.fields.find(
|
|
208
|
-
(x) => x.name === fieldName
|
|
225
|
+
(x) => x.name === fieldName,
|
|
209
226
|
);
|
|
210
227
|
if (!field) return;
|
|
211
228
|
editContext.operations.editField({
|
|
@@ -221,7 +238,7 @@ function getCheckboxCommand(
|
|
|
221
238
|
|
|
222
239
|
function getInheritChildrenFromMasterCommand(
|
|
223
240
|
components: Component[],
|
|
224
|
-
editContext: EditContextType
|
|
241
|
+
editContext: EditContextType,
|
|
225
242
|
): ComponentCommand | null {
|
|
226
243
|
if (!components.length) return null;
|
|
227
244
|
if (editContext.page?.item?.masterLanguages?.length === 0) return null;
|
|
@@ -232,7 +249,7 @@ function getInheritChildrenFromMasterCommand(
|
|
|
232
249
|
components,
|
|
233
250
|
editContext,
|
|
234
251
|
"inheritChildrenFromMasterLanguage",
|
|
235
|
-
"Inherit Children From Master"
|
|
252
|
+
"Inherit Children From Master",
|
|
236
253
|
);
|
|
237
254
|
}
|
|
238
255
|
|
|
@@ -243,7 +260,7 @@ function isLocked(c: Component, editContext: EditContextType): boolean {
|
|
|
243
260
|
x.fieldLock?.item.id === c.id &&
|
|
244
261
|
x.fieldLock.item.language == c.datasourceItem?.language &&
|
|
245
262
|
x.fieldLock.item.version === c.datasourceItem?.version &&
|
|
246
|
-
x.sessionId !== editContext.sessionId
|
|
263
|
+
x.sessionId !== editContext.sessionId,
|
|
247
264
|
) !== undefined
|
|
248
265
|
) {
|
|
249
266
|
return true;
|
|
@@ -252,21 +269,21 @@ function isLocked(c: Component, editContext: EditContextType): boolean {
|
|
|
252
269
|
c.placeholders?.find(
|
|
253
270
|
(x) =>
|
|
254
271
|
x.components.find((child) => isLocked(child, editContext)) !==
|
|
255
|
-
undefined
|
|
272
|
+
undefined,
|
|
256
273
|
) !== undefined
|
|
257
274
|
);
|
|
258
275
|
}
|
|
259
276
|
|
|
260
277
|
function getDeleteCommand(
|
|
261
278
|
components: Component[],
|
|
262
|
-
editContext: EditContextType
|
|
279
|
+
editContext: EditContextType,
|
|
263
280
|
): ComponentCommand | null {
|
|
264
281
|
const applicableComponents = components.filter(
|
|
265
282
|
(c) =>
|
|
266
283
|
((!isPlaceholder(c) && !c.layoutId) ||
|
|
267
284
|
c.layoutId === editContext.page?.item.id) &&
|
|
268
285
|
!isLocked(c, editContext) &&
|
|
269
|
-
editContext.page?.item.canWriteItem
|
|
286
|
+
editContext.page?.item.canWriteItem,
|
|
270
287
|
);
|
|
271
288
|
|
|
272
289
|
if (applicableComponents.length === 0) return null;
|
|
@@ -274,7 +291,7 @@ function getDeleteCommand(
|
|
|
274
291
|
return {
|
|
275
292
|
id: "delete",
|
|
276
293
|
label: "Delete",
|
|
277
|
-
icon:
|
|
294
|
+
icon: <Trash2 size={14} />,
|
|
278
295
|
execute: async (context: CommandContext<any>) =>
|
|
279
296
|
deleteComponents(applicableComponents, context.editContext),
|
|
280
297
|
disabled: () =>
|
|
@@ -295,7 +312,7 @@ function canSynchronize(placeholderData: Placeholder) {
|
|
|
295
312
|
|
|
296
313
|
function getSyncCommand(
|
|
297
314
|
components: (Placeholder | Component)[],
|
|
298
|
-
editContext: EditContextType
|
|
315
|
+
editContext: EditContextType,
|
|
299
316
|
): ComponentCommand {
|
|
300
317
|
const placeholders: PlaceholderToSynchronize[] = [];
|
|
301
318
|
|
|
@@ -321,13 +338,13 @@ function getSyncCommand(
|
|
|
321
338
|
placeholders.length > 0 ||
|
|
322
339
|
(components.length === 0 &&
|
|
323
340
|
editContext.page?.rootComponent.placeholders.find((x) =>
|
|
324
|
-
canSynchronize(x)
|
|
341
|
+
canSynchronize(x),
|
|
325
342
|
));
|
|
326
343
|
|
|
327
344
|
return {
|
|
328
345
|
id: "synchronize",
|
|
329
346
|
label: "Synchronize",
|
|
330
|
-
icon:
|
|
347
|
+
icon: <RefreshCcw size={14} />,
|
|
331
348
|
disabled: () => !canSync,
|
|
332
349
|
visibilityScopes: ["menu", "editFrame", "contextMenu"],
|
|
333
350
|
execute: async () => {
|
|
@@ -348,7 +365,7 @@ function getSyncCommand(
|
|
|
348
365
|
|
|
349
366
|
function deleteComponents(
|
|
350
367
|
components: Component[],
|
|
351
|
-
editContext: EditContextType
|
|
368
|
+
editContext: EditContextType,
|
|
352
369
|
) {
|
|
353
370
|
if (!components.length) return;
|
|
354
371
|
|
|
@@ -360,7 +377,7 @@ function deleteComponents(
|
|
|
360
377
|
: "Are you sure you want to remove this component? ") +
|
|
361
378
|
components.map((x) => x.name).join(", "),
|
|
362
379
|
header: components.length > 1 ? "Remove components" : "Remove component",
|
|
363
|
-
icon:
|
|
380
|
+
icon: <TriangleAlert size={14} />,
|
|
364
381
|
accept: () => {
|
|
365
382
|
if (!editContext.page?.item.descriptor) return;
|
|
366
383
|
console.log("Remove components", components);
|
|
@@ -378,13 +395,15 @@ function deleteComponents(
|
|
|
378
395
|
});
|
|
379
396
|
}
|
|
380
397
|
|
|
381
|
-
function getCreateCommentCommand(
|
|
382
|
-
|
|
398
|
+
function getCreateCommentCommand(
|
|
399
|
+
components: Component[],
|
|
400
|
+
): ComponentCommand | null {
|
|
401
|
+
if (components.length !== 1 || isPlaceholder(components[0])) return null;
|
|
383
402
|
|
|
384
403
|
return {
|
|
385
404
|
id: "addComment",
|
|
386
405
|
label: "Add Comment",
|
|
387
|
-
icon:
|
|
406
|
+
icon: <MessageCircleMore size={14} />,
|
|
388
407
|
disabled: () => false,
|
|
389
408
|
visibilityScopes: ["contextMenu"],
|
|
390
409
|
execute: async (context: CommandContext<any>) => {
|
|
@@ -396,7 +415,7 @@ function getCreateCommentCommand(): ComponentCommand | null {
|
|
|
396
415
|
|
|
397
416
|
function getItemDescriptor(
|
|
398
417
|
component: Component,
|
|
399
|
-
editContext: EditContextType
|
|
418
|
+
editContext: EditContextType,
|
|
400
419
|
): ItemDescriptor | null {
|
|
401
420
|
return {
|
|
402
421
|
id: component.id,
|
|
@@ -104,11 +104,12 @@ export const isValidPlaceholder = (
|
|
|
104
104
|
(y) =>
|
|
105
105
|
y.typeId === dragObject.typeId ||
|
|
106
106
|
y.typeId === dragObject?.templateId ||
|
|
107
|
-
y.
|
|
107
|
+
y.compatibleTypeIds?.find((z) => z == dragObject.typeId) !==
|
|
108
108
|
undefined ||
|
|
109
109
|
y.typeId === dragObject.templateId ||
|
|
110
|
-
y.
|
|
110
|
+
y.compatibleTypeIds?.find((z) => z == dragObject.templateId) !==
|
|
111
111
|
undefined,
|
|
112
|
+
undefined,
|
|
112
113
|
) !== undefined
|
|
113
114
|
);
|
|
114
115
|
};
|
|
@@ -9,7 +9,7 @@ export function ControlCenterMenu() {
|
|
|
9
9
|
const searchParams = useSearchParams();
|
|
10
10
|
const urlActiveItemKey = searchParams.get("ccpanel");
|
|
11
11
|
const [activeItemKey, setActiveItemKey] = useState<string | null>(
|
|
12
|
-
urlActiveItemKey
|
|
12
|
+
urlActiveItemKey,
|
|
13
13
|
);
|
|
14
14
|
|
|
15
15
|
const router = useRouter();
|
|
@@ -34,12 +34,12 @@ export function ControlCenterMenu() {
|
|
|
34
34
|
|
|
35
35
|
const items = config?.controlCenter.groups.map((group) => {
|
|
36
36
|
return {
|
|
37
|
-
|
|
37
|
+
id: group.title,
|
|
38
38
|
label: group.title,
|
|
39
39
|
icon: group.icon,
|
|
40
40
|
items:
|
|
41
41
|
group.panels.map((panel) => ({
|
|
42
|
-
|
|
42
|
+
id: panel.id,
|
|
43
43
|
label: panel.title,
|
|
44
44
|
})) || [],
|
|
45
45
|
};
|
|
@@ -64,7 +64,7 @@ export function ControlCenterMenu() {
|
|
|
64
64
|
items={items}
|
|
65
65
|
activeItemKey={activeItemKey}
|
|
66
66
|
onItemClick={(item) => {
|
|
67
|
-
setActiveItemKey(item.
|
|
67
|
+
setActiveItemKey(item.id);
|
|
68
68
|
}}
|
|
69
69
|
/>
|
|
70
70
|
);
|
|
@@ -33,7 +33,7 @@ export default function TreeListEditor({
|
|
|
33
33
|
ItemData[]
|
|
34
34
|
>([]);
|
|
35
35
|
const [selectedFromList, setSelectedFromList] = useState<ReferencedItem[]>(
|
|
36
|
-
[]
|
|
36
|
+
[],
|
|
37
37
|
);
|
|
38
38
|
const overlayPanelRef = useRef<OverlayPanel>(null);
|
|
39
39
|
const [currentItemId, setCurrentItemId] = useState<string>("");
|
|
@@ -109,7 +109,7 @@ export default function TreeListEditor({
|
|
|
109
109
|
idPath?: string;
|
|
110
110
|
name: string;
|
|
111
111
|
icon?: string;
|
|
112
|
-
}[]
|
|
112
|
+
}[],
|
|
113
113
|
) {
|
|
114
114
|
setSelectedItemNodesInTree([]);
|
|
115
115
|
|
|
@@ -138,8 +138,8 @@ export default function TreeListEditor({
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
return (
|
|
141
|
-
<div className="
|
|
142
|
-
<div className="
|
|
141
|
+
<div className="focus-shadow border border-gray-200">
|
|
142
|
+
<div className="mb-1 border-b border-gray-200 bg-white p-2">
|
|
143
143
|
<ItemSearch
|
|
144
144
|
rootItemIds={rootItemIds.map((x) => normalizeGuid(x))}
|
|
145
145
|
itemSelected={async (item) => {
|
|
@@ -181,9 +181,9 @@ export default function TreeListEditor({
|
|
|
181
181
|
</div>
|
|
182
182
|
</SplitterPanel>
|
|
183
183
|
<SplitterPanel>
|
|
184
|
-
<div className="h-full w-full
|
|
184
|
+
<div className="relative h-full w-full">
|
|
185
185
|
<div className="absolute inset-0 flex">
|
|
186
|
-
<div className="
|
|
186
|
+
<div className="flex flex-col justify-center gap-1 bg-gray-100 p-1">
|
|
187
187
|
<SimpleIconButton
|
|
188
188
|
label="Add"
|
|
189
189
|
icon="pi pi-angle-right"
|
|
@@ -197,7 +197,7 @@ export default function TreeListEditor({
|
|
|
197
197
|
disabled={readOnly}
|
|
198
198
|
/>
|
|
199
199
|
</div>
|
|
200
|
-
<div className="
|
|
200
|
+
<div className="relative h-full flex-1">
|
|
201
201
|
<ListBox
|
|
202
202
|
className="absolute inset-0 overflow-auto text-xs"
|
|
203
203
|
options={values}
|
|
@@ -209,7 +209,7 @@ export default function TreeListEditor({
|
|
|
209
209
|
onChange={(e) => setSelectedFromList(e.value)}
|
|
210
210
|
itemTemplate={(option) => (
|
|
211
211
|
<div
|
|
212
|
-
className="
|
|
212
|
+
className="group relative flex items-center gap-1.5 select-none hover:bg-gray-50"
|
|
213
213
|
onMouseEnter={async () => {
|
|
214
214
|
setHoveredItemId(option.id);
|
|
215
215
|
// setExpandIdPath(option.idPath || "");
|
|
@@ -219,10 +219,10 @@ export default function TreeListEditor({
|
|
|
219
219
|
if (!readOnly) removeFromList([option]);
|
|
220
220
|
}}
|
|
221
221
|
>
|
|
222
|
-
<img src={option.icon} className="
|
|
222
|
+
<img src={option.icon} className="h-4 w-4" />
|
|
223
223
|
{trimPath(option.path)}{" "}
|
|
224
224
|
<button
|
|
225
|
-
className="opacity-0 group-hover:opacity-100
|
|
225
|
+
className="opacity-0 transition-opacity group-hover:opacity-100"
|
|
226
226
|
onClick={(e) => {
|
|
227
227
|
e.stopPropagation();
|
|
228
228
|
setCurrentItemId(option.id);
|
|
@@ -245,7 +245,7 @@ export default function TreeListEditor({
|
|
|
245
245
|
<div className="p-3">
|
|
246
246
|
<div className="flex justify-end gap-2">
|
|
247
247
|
<Button
|
|
248
|
-
className="px-3 py-1
|
|
248
|
+
className="rounded bg-blue-500 px-3 py-1 text-sm text-white"
|
|
249
249
|
onClick={() => {
|
|
250
250
|
editContext.loadItem(currentItemId);
|
|
251
251
|
overlayPanelRef.current?.hide();
|
|
@@ -5,7 +5,8 @@ import { Rect, findComponentRect } from "../utils";
|
|
|
5
5
|
import { useThrottledCallback } from "use-debounce";
|
|
6
6
|
import { Component } from "../pageModel";
|
|
7
7
|
import { PageViewContext } from "../page-viewer/pageViewContext";
|
|
8
|
-
|
|
8
|
+
import { ArrowUpFromDot } from "lucide-react";
|
|
9
|
+
import { cn } from "../../lib/utils";
|
|
9
10
|
export function FrameMenu({
|
|
10
11
|
component,
|
|
11
12
|
mode,
|
|
@@ -18,8 +19,12 @@ export function FrameMenu({
|
|
|
18
19
|
const editContext = useEditContext();
|
|
19
20
|
const resizeObserverRef = useRef<ResizeObserver | null>(null);
|
|
20
21
|
const mutationObserverRef = useRef<MutationObserver | null>(null);
|
|
22
|
+
const headerRef = useRef<HTMLDivElement>(null);
|
|
21
23
|
|
|
22
24
|
const [componentRect, setComponentRect] = useState<Rect>();
|
|
25
|
+
const [isHeaderWiderThanComponent, setIsHeaderWiderThanComponent] =
|
|
26
|
+
useState(false);
|
|
27
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
23
28
|
|
|
24
29
|
const updatePosition = () => {
|
|
25
30
|
if (!component || !editContext || !pageViewContext) return;
|
|
@@ -32,7 +37,7 @@ export function FrameMenu({
|
|
|
32
37
|
setComponentRect(undefined);
|
|
33
38
|
};
|
|
34
39
|
|
|
35
|
-
const componentRect = findComponentRect(iframe, component
|
|
40
|
+
const componentRect = findComponentRect(iframe, component)?.rect;
|
|
36
41
|
|
|
37
42
|
if (!componentRect) {
|
|
38
43
|
resetSelection();
|
|
@@ -74,7 +79,7 @@ export function FrameMenu({
|
|
|
74
79
|
scrollContainer?.addEventListener("scroll", updatePositionThrottled);
|
|
75
80
|
iframe.contentWindow?.addEventListener("scroll", updatePositionThrottled);
|
|
76
81
|
|
|
77
|
-
const componentRect = findComponentRect(iframe, component
|
|
82
|
+
const componentRect = findComponentRect(iframe, component);
|
|
78
83
|
|
|
79
84
|
if (!componentRect) {
|
|
80
85
|
updatePosition();
|
|
@@ -98,6 +103,24 @@ export function FrameMenu({
|
|
|
98
103
|
};
|
|
99
104
|
}, [component]);
|
|
100
105
|
|
|
106
|
+
// Effect to measure header width and compare with componentRect
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!headerRef.current || !componentRect) return;
|
|
109
|
+
|
|
110
|
+
const headerResizeObserver = new ResizeObserver((entries) => {
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
const headerWidth = entry.contentRect.width;
|
|
113
|
+
setIsHeaderWiderThanComponent(headerWidth > componentRect.width);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
headerResizeObserver.observe(headerRef.current);
|
|
118
|
+
|
|
119
|
+
return () => {
|
|
120
|
+
headerResizeObserver.disconnect();
|
|
121
|
+
};
|
|
122
|
+
}, [componentRect]);
|
|
123
|
+
|
|
101
124
|
useEffect(() => {
|
|
102
125
|
setTimeout(() => {
|
|
103
126
|
updatePosition();
|
|
@@ -114,6 +137,7 @@ export function FrameMenu({
|
|
|
114
137
|
|
|
115
138
|
const commands = editContext.getComponentCommands([component]);
|
|
116
139
|
const isDraggable =
|
|
140
|
+
component.canBeMoved &&
|
|
117
141
|
mode === "edit" &&
|
|
118
142
|
!component.layoutId &&
|
|
119
143
|
pageViewContext.page?.item.canWriteItem;
|
|
@@ -140,9 +164,8 @@ export function FrameMenu({
|
|
|
140
164
|
}));
|
|
141
165
|
|
|
142
166
|
const customButtons: EditButton[] = []; // TODO
|
|
143
|
-
let buttons = [...customButtons];
|
|
144
167
|
|
|
145
|
-
buttons = [...
|
|
168
|
+
const buttons = [...customButtons, ...commandButtons];
|
|
146
169
|
|
|
147
170
|
function handleDragStart(event: React.DragEvent<HTMLDivElement>): void {
|
|
148
171
|
if (!component?.datasourceItem) return;
|
|
@@ -169,7 +192,7 @@ export function FrameMenu({
|
|
|
169
192
|
editContext!.dragEnd();
|
|
170
193
|
}
|
|
171
194
|
|
|
172
|
-
const isShared = component.
|
|
195
|
+
const isShared = component.isShared;
|
|
173
196
|
const isReadonly = mode === "compare" || mode === "view";
|
|
174
197
|
const isLayout = component.layoutId;
|
|
175
198
|
|
|
@@ -179,29 +202,50 @@ export function FrameMenu({
|
|
|
179
202
|
? "shared"
|
|
180
203
|
: isLayout
|
|
181
204
|
? "layout"
|
|
182
|
-
:
|
|
205
|
+
: component.canBeMoved
|
|
206
|
+
? "default"
|
|
207
|
+
: "nonMovable";
|
|
183
208
|
|
|
184
209
|
const colorVariants = {
|
|
185
210
|
shared: "border-orange-400",
|
|
186
|
-
readonly: "border-
|
|
211
|
+
readonly: "border-gray-400",
|
|
187
212
|
layout: "border-purple-400",
|
|
188
213
|
default: "border-sky-400",
|
|
214
|
+
nonMovable: "border-red-400",
|
|
189
215
|
};
|
|
190
216
|
|
|
191
217
|
const bgColorVariants = {
|
|
192
218
|
shared: "bg-orange-400",
|
|
193
|
-
readonly: "bg-
|
|
219
|
+
readonly: "bg-gray-400",
|
|
194
220
|
layout: "bg-purple-400",
|
|
195
221
|
default: "bg-sky-400",
|
|
222
|
+
nonMovable: "bg-red-400",
|
|
196
223
|
};
|
|
197
|
-
|
|
224
|
+
|
|
225
|
+
// Calculate initial estimation for the header width
|
|
226
|
+
const estimatedHeaderWidth = buttons.length * 30 + component.name.length * 8; // Approximate width calculation
|
|
227
|
+
const initialIsHeaderWiderThanComponent =
|
|
228
|
+
estimatedHeaderWidth > (componentRect?.width || 0);
|
|
229
|
+
|
|
230
|
+
useEffect(() => {
|
|
231
|
+
setIsHeaderWiderThanComponent(initialIsHeaderWiderThanComponent);
|
|
232
|
+
}, [initialIsHeaderWiderThanComponent]);
|
|
198
233
|
|
|
199
234
|
const isMultiSelected = editContext.selection.length > 1;
|
|
235
|
+
if (!componentRect) return null;
|
|
200
236
|
|
|
201
237
|
return (
|
|
202
238
|
<>
|
|
203
239
|
<div
|
|
204
|
-
className={
|
|
240
|
+
className={cn(
|
|
241
|
+
"pointer-events-none absolute inset-0 rounded-b-sm border-2",
|
|
242
|
+
colorVariants[color],
|
|
243
|
+
"tour-frame-menu opacity-50 hover:opacity-100",
|
|
244
|
+
isHovered && "opacity-100",
|
|
245
|
+
!isMultiSelected && isHeaderWiderThanComponent && "border-t-0",
|
|
246
|
+
!isMultiSelected && !isHeaderWiderThanComponent && "rounded-tl-sm",
|
|
247
|
+
isMultiSelected && "rounded-t-sm",
|
|
248
|
+
)}
|
|
205
249
|
style={{
|
|
206
250
|
left: componentRect.x,
|
|
207
251
|
top: componentRect.y,
|
|
@@ -213,9 +257,11 @@ export function FrameMenu({
|
|
|
213
257
|
>
|
|
214
258
|
{!isMultiSelected && (
|
|
215
259
|
<div
|
|
260
|
+
ref={headerRef}
|
|
216
261
|
className={
|
|
217
262
|
`editframe-menu pointer-events-auto absolute z-1000 flex items-center pr-4 text-base text-white ${bgColorVariants[color]} ` +
|
|
218
|
-
(componentRect.y - 36 < 0 ? "rounded-bl-lg" : "rounded-t-lg")
|
|
263
|
+
(componentRect.y - 36 < 0 ? "rounded-bl-lg" : "rounded-t-lg") +
|
|
264
|
+
(isHeaderWiderThanComponent ? " rounded-bl-lg" : "")
|
|
219
265
|
}
|
|
220
266
|
style={{
|
|
221
267
|
right: "-2px",
|
|
@@ -232,20 +278,38 @@ export function FrameMenu({
|
|
|
232
278
|
draggable={isDraggable}
|
|
233
279
|
onDragStart={handleDragStart}
|
|
234
280
|
onDragEnd={handleDragEnd}
|
|
235
|
-
className={`
|
|
281
|
+
className={`group flex items-center gap-1 pr-2 pl-3 text-sm text-nowrap ${
|
|
236
282
|
isDraggable ? "cursor-move" : "cursor-default"
|
|
237
283
|
} `}
|
|
238
284
|
>
|
|
239
285
|
{component.name}
|
|
286
|
+
{component.parentPlaceholder?.parentComponent && (
|
|
287
|
+
<span
|
|
288
|
+
className="cursor-pointer opacity-0 transition-opacity group-hover:opacity-100"
|
|
289
|
+
onClick={() => {
|
|
290
|
+
editContext.select([
|
|
291
|
+
component.parentPlaceholder?.parentComponent.id || "",
|
|
292
|
+
]);
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
<ArrowUpFromDot height={14} width={14} />
|
|
296
|
+
</span>
|
|
297
|
+
)}
|
|
240
298
|
</div>
|
|
241
299
|
{mode === "edit" && (
|
|
242
|
-
<div className="flex items-center gap-2">
|
|
300
|
+
<div className="flex items-center gap-2 text-sm">
|
|
243
301
|
{buttons.map((b, i) => (
|
|
244
|
-
<div
|
|
302
|
+
<div
|
|
303
|
+
className="cursor-pointer hover:text-gray-200"
|
|
304
|
+
key={i}
|
|
305
|
+
onClick={(ev) => {
|
|
306
|
+
ev.stopPropagation();
|
|
307
|
+
b.onClick(ev);
|
|
308
|
+
}}
|
|
309
|
+
>
|
|
245
310
|
{typeof b.icon === "string" ? (
|
|
246
311
|
<i
|
|
247
|
-
className={b.icon + " cursor-pointer"}
|
|
248
|
-
onClick={b.onClick}
|
|
312
|
+
className={b.icon + " cursor-pointer text-sm"}
|
|
249
313
|
title={b.label}
|
|
250
314
|
/>
|
|
251
315
|
) : (
|
|
@@ -28,7 +28,7 @@ export function InlineEditor({
|
|
|
28
28
|
x.fieldId === fieldId &&
|
|
29
29
|
x.item.id === itemId &&
|
|
30
30
|
x.item.language === language &&
|
|
31
|
-
x.item.version === version
|
|
31
|
+
x.item.version === version,
|
|
32
32
|
)?.value;
|
|
33
33
|
|
|
34
34
|
if (modifiedFieldValue === value) return;
|
|
@@ -47,7 +47,7 @@ export function InlineEditor({
|
|
|
47
47
|
value: value,
|
|
48
48
|
});
|
|
49
49
|
},
|
|
50
|
-
context.configuration.debounceFieldEditsInterval
|
|
50
|
+
context.configuration.debounceFieldEditsInterval,
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
useEffect(() => {
|
|
@@ -56,7 +56,7 @@ export function InlineEditor({
|
|
|
56
56
|
|
|
57
57
|
const editableElements =
|
|
58
58
|
pageViewContext.editorIframeRef.current?.contentWindow?.document.querySelectorAll(
|
|
59
|
-
'[contenteditable="true"]'
|
|
59
|
+
'[contenteditable="true"]',
|
|
60
60
|
);
|
|
61
61
|
|
|
62
62
|
editableElements?.forEach((element) => {
|
|
@@ -90,7 +90,7 @@ export function InlineEditor({
|
|
|
90
90
|
fieldName,
|
|
91
91
|
itemId,
|
|
92
92
|
language,
|
|
93
|
-
version
|
|
93
|
+
version,
|
|
94
94
|
);
|
|
95
95
|
});
|
|
96
96
|
|
|
@@ -116,7 +116,7 @@ export function InlineEditor({
|
|
|
116
116
|
modifiedFieldsContext?.modifiedFields.forEach((field) => {
|
|
117
117
|
const elements =
|
|
118
118
|
pageViewContext.editorIframeRef.current!.contentWindow?.document.querySelectorAll(
|
|
119
|
-
`[data-fieldid="${field.fieldId}"][data-itemid="${field.item.id}"][data-language="${field.item.language}"][data-version="${field.item.version}"
|
|
119
|
+
`[data-fieldid="${field.fieldId}"][data-itemid="${field.item.id}"][data-language="${field.item.language}"][data-version="${field.item.version}"`,
|
|
120
120
|
);
|
|
121
121
|
|
|
122
122
|
elements?.forEach(async (element) => {
|