@alpaca-editor/core 1.0.3813 → 1.0.3817

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 (207) hide show
  1. package/dist/components/ui/context-menu.d.ts +25 -0
  2. package/dist/components/ui/context-menu.js +51 -0
  3. package/dist/components/ui/context-menu.js.map +1 -0
  4. package/dist/config/config.js +4 -3
  5. package/dist/config/config.js.map +1 -1
  6. package/dist/config/types.d.ts +4 -2
  7. package/dist/editor/ComponentInfo.js +1 -1
  8. package/dist/editor/ComponentInfo.js.map +1 -1
  9. package/dist/editor/ConfirmationDialog.d.ts +1 -1
  10. package/dist/editor/ContextMenu.d.ts +1 -1
  11. package/dist/editor/ContextMenu.js +24 -9
  12. package/dist/editor/ContextMenu.js.map +1 -1
  13. package/dist/editor/EditorWarnings.js +1 -1
  14. package/dist/editor/EditorWarnings.js.map +1 -1
  15. package/dist/editor/FieldList.js +1 -1
  16. package/dist/editor/FieldList.js.map +1 -1
  17. package/dist/editor/FieldListFieldWithFallbacks.js +3 -3
  18. package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
  19. package/dist/editor/ImageEditor.js +2 -2
  20. package/dist/editor/ImageEditor.js.map +1 -1
  21. package/dist/editor/ItemInfo.js +2 -2
  22. package/dist/editor/ItemInfo.js.map +1 -1
  23. package/dist/editor/MainLayout.js +3 -3
  24. package/dist/editor/MainLayout.js.map +1 -1
  25. package/dist/editor/Titlebar.js +1 -1
  26. package/dist/editor/Titlebar.js.map +1 -1
  27. package/dist/editor/ai/AiTerminal.js +19 -12
  28. package/dist/editor/ai/AiTerminal.js.map +1 -1
  29. package/dist/editor/client/EditorClient.js +90 -35
  30. package/dist/editor/client/EditorClient.js.map +1 -1
  31. package/dist/editor/client/editContext.d.ts +10 -4
  32. package/dist/editor/client/editContext.js.map +1 -1
  33. package/dist/editor/client/operations.d.ts +5 -1
  34. package/dist/editor/client/operations.js +112 -17
  35. package/dist/editor/client/operations.js.map +1 -1
  36. package/dist/editor/client/pageModelBuilder.js +8 -5
  37. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  38. package/dist/editor/commands/componentCommands.js +15 -13
  39. package/dist/editor/commands/componentCommands.js.map +1 -1
  40. package/dist/editor/component-designer/ComponentDesigner.js +1 -1
  41. package/dist/editor/component-designer/ComponentDesigner.js.map +1 -1
  42. package/dist/editor/componentTreeHelper.js +3 -3
  43. package/dist/editor/componentTreeHelper.js.map +1 -1
  44. package/dist/editor/control-center/ControlCenterMenu.js +3 -3
  45. package/dist/editor/control-center/ControlCenterMenu.js.map +1 -1
  46. package/dist/editor/field-types/TreeListEditor.js +4 -4
  47. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  48. package/dist/editor/menubar/LanguageSelector.js +3 -3
  49. package/dist/editor/menubar/LanguageSelector.js.map +1 -1
  50. package/dist/editor/menubar/PageSelector.js +1 -1
  51. package/dist/editor/menubar/PageSelector.js.map +1 -1
  52. package/dist/editor/menubar/PageViewerControls.js +12 -7
  53. package/dist/editor/menubar/PageViewerControls.js.map +1 -1
  54. package/dist/editor/menubar/Separator.js +1 -1
  55. package/dist/editor/menubar/VersionSelector.js +1 -1
  56. package/dist/editor/menubar/VersionSelector.js.map +1 -1
  57. package/dist/editor/page-editor-chrome/FrameMenu.d.ts +2 -2
  58. package/dist/editor/page-editor-chrome/FrameMenu.js +66 -22
  59. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  60. package/dist/editor/page-editor-chrome/FrameMenus.d.ts +2 -2
  61. package/dist/editor/page-editor-chrome/FrameMenus.js +2 -2
  62. package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
  63. package/dist/editor/page-editor-chrome/InlineEditor.d.ts +2 -2
  64. package/dist/editor/page-editor-chrome/InlineEditor.js +175 -17
  65. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  66. package/dist/editor/page-editor-chrome/PageEditorChrome.d.ts +2 -2
  67. package/dist/editor/page-editor-chrome/PageEditorChrome.js +2 -2
  68. package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
  69. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +5 -5
  70. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  71. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +114 -45
  72. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  73. package/dist/editor/page-viewer/EditorForm.d.ts +2 -1
  74. package/dist/editor/page-viewer/EditorForm.js +9 -8
  75. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  76. package/dist/editor/page-viewer/MiniMap.d.ts +2 -2
  77. package/dist/editor/page-viewer/MiniMap.js +2 -2
  78. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  79. package/dist/editor/page-viewer/PageViewer.d.ts +2 -2
  80. package/dist/editor/page-viewer/PageViewer.js +3 -3
  81. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  82. package/dist/editor/page-viewer/PageViewerFrame.d.ts +2 -3
  83. package/dist/editor/page-viewer/PageViewerFrame.js +127 -223
  84. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  85. package/dist/editor/page-viewer/pageModelBuilder.d.ts +3 -0
  86. package/dist/editor/page-viewer/pageModelBuilder.js +299 -0
  87. package/dist/editor/page-viewer/pageModelBuilder.js.map +1 -0
  88. package/dist/editor/pageModel.d.ts +5 -0
  89. package/dist/editor/reviews/Comments.d.ts +2 -0
  90. package/dist/editor/reviews/Comments.js +26 -9
  91. package/dist/editor/reviews/Comments.js.map +1 -1
  92. package/dist/editor/reviews/DiffView.d.ts +17 -0
  93. package/dist/editor/reviews/DiffView.js +57 -0
  94. package/dist/editor/reviews/DiffView.js.map +1 -0
  95. package/dist/editor/reviews/SuggestedEdit.d.ts +4 -0
  96. package/dist/editor/reviews/SuggestedEdit.js +180 -0
  97. package/dist/editor/reviews/SuggestedEdit.js.map +1 -0
  98. package/dist/editor/services/suggestedEditsService.d.ts +17 -0
  99. package/dist/editor/services/suggestedEditsService.js +26 -0
  100. package/dist/editor/services/suggestedEditsService.js.map +1 -0
  101. package/dist/editor/sidebar/ComponentPalette.js +30 -30
  102. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  103. package/dist/editor/sidebar/ComponentTree.js +7 -6
  104. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  105. package/dist/editor/sidebar/MainContentTree.js +1 -1
  106. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  107. package/dist/editor/sidebar/SidebarView.js +3 -3
  108. package/dist/editor/sidebar/SidebarView.js.map +1 -1
  109. package/dist/editor/ui/CopyToClipboardButton.js +2 -1
  110. package/dist/editor/ui/CopyToClipboardButton.js.map +1 -1
  111. package/dist/editor/ui/Icons.d.ts +0 -1
  112. package/dist/editor/ui/Icons.js +0 -3
  113. package/dist/editor/ui/Icons.js.map +1 -1
  114. package/dist/editor/ui/PerfectTree.js +3 -3
  115. package/dist/editor/ui/PerfectTree.js.map +1 -1
  116. package/dist/editor/ui/Section.js +1 -1
  117. package/dist/editor/ui/Section.js.map +1 -1
  118. package/dist/editor/ui/SimpleIconButton.js +3 -1
  119. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  120. package/dist/editor/ui/SimpleMenu.d.ts +1 -8
  121. package/dist/editor/ui/SimpleMenu.js +1 -1
  122. package/dist/editor/ui/SimpleMenu.js.map +1 -1
  123. package/dist/editor/utils.d.ts +2 -2
  124. package/dist/editor/utils.js +57 -9
  125. package/dist/editor/utils.js.map +1 -1
  126. package/dist/editor/views/CompareView.js +4 -13
  127. package/dist/editor/views/CompareView.js.map +1 -1
  128. package/dist/editor/views/EditView.js +2 -2
  129. package/dist/editor/views/EditView.js.map +1 -1
  130. package/dist/editor/views/SingleEditView.d.ts +2 -2
  131. package/dist/editor/views/SingleEditView.js +2 -2
  132. package/dist/editor/views/SingleEditView.js.map +1 -1
  133. package/dist/lib/safelist.js +1 -1
  134. package/dist/lib/safelist.js.map +1 -1
  135. package/dist/page-wizard/steps/BuildPageStep.js +2 -2
  136. package/dist/page-wizard/steps/BuildPageStep.js.map +1 -1
  137. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +2 -2
  138. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js.map +1 -1
  139. package/dist/splash-screen/SplashScreen.js +0 -1
  140. package/dist/splash-screen/SplashScreen.js.map +1 -1
  141. package/dist/styles.css +275 -58
  142. package/dist/types.d.ts +20 -2
  143. package/package.json +6 -2
  144. package/src/components/ui/context-menu.tsx +250 -0
  145. package/src/config/config.tsx +4 -4
  146. package/src/config/types.ts +4 -2
  147. package/src/editor/ComponentInfo.tsx +3 -5
  148. package/src/editor/ConfirmationDialog.tsx +1 -1
  149. package/src/editor/ContextMenu.tsx +68 -19
  150. package/src/editor/EditorWarnings.tsx +2 -2
  151. package/src/editor/FieldList.tsx +6 -6
  152. package/src/editor/FieldListFieldWithFallbacks.tsx +9 -9
  153. package/src/editor/ImageEditor.tsx +2 -2
  154. package/src/editor/ItemInfo.tsx +4 -4
  155. package/src/editor/MainLayout.tsx +3 -4
  156. package/src/editor/Titlebar.tsx +4 -4
  157. package/src/editor/ai/AiTerminal.tsx +31 -24
  158. package/src/editor/client/EditorClient.tsx +106 -57
  159. package/src/editor/client/editContext.ts +13 -4
  160. package/src/editor/client/operations.ts +162 -23
  161. package/src/editor/client/pageModelBuilder.ts +26 -18
  162. package/src/editor/commands/componentCommands.tsx +58 -39
  163. package/src/editor/component-designer/ComponentDesigner.tsx +1 -1
  164. package/src/editor/componentTreeHelper.tsx +3 -2
  165. package/src/editor/control-center/ControlCenterMenu.tsx +4 -4
  166. package/src/editor/field-types/TreeListEditor.tsx +11 -11
  167. package/src/editor/menubar/LanguageSelector.tsx +6 -6
  168. package/src/editor/menubar/PageSelector.tsx +11 -11
  169. package/src/editor/menubar/PageViewerControls.tsx +49 -23
  170. package/src/editor/menubar/Separator.tsx +2 -2
  171. package/src/editor/menubar/VersionSelector.tsx +1 -1
  172. package/src/editor/page-editor-chrome/FrameMenu.tsx +94 -29
  173. package/src/editor/page-editor-chrome/FrameMenus.tsx +6 -6
  174. package/src/editor/page-editor-chrome/InlineEditor.tsx +237 -26
  175. package/src/editor/page-editor-chrome/PageEditorChrome.tsx +11 -14
  176. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +12 -15
  177. package/src/editor/page-editor-chrome/PlaceholderDropZones.tsx +159 -68
  178. package/src/editor/page-viewer/EditorForm.tsx +15 -9
  179. package/src/editor/page-viewer/MiniMap.tsx +4 -4
  180. package/src/editor/page-viewer/PageViewer.tsx +6 -6
  181. package/src/editor/page-viewer/PageViewerFrame.tsx +146 -309
  182. package/src/editor/page-viewer/pageModelBuilder.ts +412 -0
  183. package/src/editor/pageModel.ts +5 -0
  184. package/src/editor/reviews/Comments.tsx +56 -15
  185. package/src/editor/reviews/DiffView.tsx +109 -0
  186. package/src/editor/reviews/SuggestedEdit.tsx +316 -0
  187. package/src/editor/services/suggestedEditsService.ts +39 -0
  188. package/src/editor/sidebar/ComponentPalette.tsx +108 -106
  189. package/src/editor/sidebar/ComponentTree.tsx +10 -5
  190. package/src/editor/sidebar/MainContentTree.tsx +1 -1
  191. package/src/editor/sidebar/SidebarView.tsx +9 -9
  192. package/src/editor/ui/CopyToClipboardButton.tsx +2 -1
  193. package/src/editor/ui/Icons.tsx +0 -18
  194. package/src/editor/ui/PerfectTree.tsx +5 -5
  195. package/src/editor/ui/Section.tsx +4 -4
  196. package/src/editor/ui/SimpleIconButton.tsx +5 -3
  197. package/src/editor/ui/SimpleMenu.tsx +5 -13
  198. package/src/editor/utils.ts +74 -17
  199. package/src/editor/views/CompareView.tsx +13 -24
  200. package/src/editor/views/EditView.tsx +2 -2
  201. package/src/editor/views/SingleEditView.tsx +3 -3
  202. package/src/lib/safelist.tsx +4 -0
  203. package/src/page-wizard/steps/BuildPageStep.tsx +18 -25
  204. package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +16 -18
  205. package/src/splash-screen/SplashScreen.tsx +0 -1
  206. package/src/types.ts +20 -3
  207. 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: "pi pi-plus",
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: "pi pi-copy",
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: "pi pi-sparkles",
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: "pi pi-palette",
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
- "pi pi-" +
202
- (allLinked ? "check-square" : someLinked ? "stop-circle" : "stop"),
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: "pi pi-fw pi-trash",
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: "pi pi-fw pi-sync",
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: "pi pi-exclamation-triangle",
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(): ComponentCommand | null {
382
- // if (components.length !== 1 || isPlaceholder(components[0])) return null;
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: "pi pi-comment",
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,
@@ -63,7 +63,7 @@ export function ComponentDesigner() {
63
63
  <StackedPanels panels={mainPanels} />
64
64
  </SplitterPanel>
65
65
  <SplitterPanel>
66
- <PageViewerFrame mode="view" />
66
+ <PageViewerFrame compareView={false} />
67
67
  </SplitterPanel>
68
68
  </Splitter>
69
69
  );
@@ -104,11 +104,12 @@ export const isValidPlaceholder = (
104
104
  (y) =>
105
105
  y.typeId === dragObject.typeId ||
106
106
  y.typeId === dragObject?.templateId ||
107
- y.compatibleTemplates?.find((z) => z == dragObject.typeId) !==
107
+ y.compatibleTypeIds?.find((z) => z == dragObject.typeId) !==
108
108
  undefined ||
109
109
  y.typeId === dragObject.templateId ||
110
- y.compatibleTemplates?.find((z) => z == dragObject.templateId) !==
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
- key: group.title,
37
+ id: group.title,
38
38
  label: group.title,
39
39
  icon: group.icon,
40
40
  items:
41
41
  group.panels.map((panel) => ({
42
- key: panel.id,
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.key);
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="border focus-shadow border-gray-200">
142
- <div className="bg-white mb-1 p-2 border-b border-gray-200">
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 relative">
184
+ <div className="relative h-full w-full">
185
185
  <div className="absolute inset-0 flex">
186
- <div className="bg-gray-100 flex flex-col justify-center gap-1 p-1">
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="flex-1 h-full relative">
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="select-none hover:bg-gray-50 relative group flex items-center gap-1"
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="w-4 h-4 mr-2" />
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 transition-opacity"
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 bg-blue-500 text-white rounded text-sm"
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();
@@ -31,7 +31,7 @@ export function LanguageSelector({
31
31
  const allLanguages = editContext?.itemLanguages || [];
32
32
 
33
33
  const currentLanguage = allLanguages.find(
34
- (x) => x.languageCode === selectedLanguage
34
+ (x) => x.languageCode === selectedLanguage,
35
35
  );
36
36
 
37
37
  const languages = showAllLanguagesInternal
@@ -49,11 +49,11 @@ export function LanguageSelector({
49
49
  return (
50
50
  <>
51
51
  <div
52
- className={`p-[7px] text-sm cursor-pointer flex items-center gap-3 ${
52
+ className={`flex cursor-pointer items-center gap-3 p-[7px] py-[5px] text-sm ${
53
53
  darkMode
54
54
  ? "text-gray-500 hover:bg-gray-300"
55
55
  : "text-gray-200 hover:bg-gray-500"
56
- } rounded-md ${disabled ? "opacity-50" : ""}`}
56
+ } rounded-md ${disabled ? "opacity-50" : ""}`}
57
57
  onClick={(ev) => {
58
58
  if (disabled) return;
59
59
  overlaypanel.current?.toggle(ev, ev.currentTarget);
@@ -82,9 +82,9 @@ export function LanguageSelector({
82
82
  </div>
83
83
  </div>
84
84
  <OverlayPanel dismissable={true} ref={overlaypanel} closeOnEscape>
85
- <div className="max-h-[50vh] min-w-64 flex flex-col">
85
+ <div className="flex max-h-[50vh] min-w-64 flex-col">
86
86
  {showAllLanguagesSwitch && (
87
- <div className="text-xs p-2 flex items-center gap-2 justify-center">
87
+ <div className="flex items-center justify-center gap-2 p-2 text-xs">
88
88
  <span
89
89
  className="cursor-pointer"
90
90
  onClick={() => setShowAllLanguagesInternal(false)}
@@ -108,7 +108,7 @@ export function LanguageSelector({
108
108
  {languages.map((x) => (
109
109
  <div
110
110
  key={x.languageCode}
111
- className="cursor-pointer hover:bg-gray-200 flex gap-2 p-2"
111
+ className="flex cursor-pointer gap-2 p-2 hover:bg-gray-200"
112
112
  onClick={() => selectLanguage(x)}
113
113
  >
114
114
  <img src={x.icon} className="h-5" /> {x.name} ({x.versions})
@@ -49,7 +49,7 @@ export function PageSelector({
49
49
  <>
50
50
  <div
51
51
  id="page-selector-button"
52
- className="p-[7px] text-sm cursor-pointer flex items-center gap-3 text-gray-200 hover:bg-gray-500 rounded-md"
52
+ className="flex cursor-pointer items-center gap-3 rounded-md p-[7px] py-[5px] text-sm text-gray-200 hover:bg-gray-500"
53
53
  onClick={(ev) => overlaypanel.current?.toggle(ev, ev.currentTarget)}
54
54
  data-testid="page-selector-button"
55
55
  >
@@ -66,10 +66,10 @@ export function PageSelector({
66
66
  </div>
67
67
  </div>
68
68
  <OverlayPanel dismissable={true} ref={overlaypanel} closeOnEscape>
69
- <div className="h-[75vh] min-w-48 flex flex-col overflow-hidden">
70
- <div className="flex-1 flex flex-col gap-1">
71
- <div className="p-2 flex flex-col">
72
- <div className="text-xs text-gray-500 mb-2 flex items-center gap-1">
69
+ <div className="flex h-[75vh] min-w-48 flex-col overflow-hidden">
70
+ <div className="flex flex-1 flex-col gap-1">
71
+ <div className="flex flex-col p-2">
72
+ <div className="mb-2 flex items-center gap-1 text-xs text-gray-500">
73
73
  <ArrowDownIcon /> Search
74
74
  </div>
75
75
  <ItemSearch
@@ -78,8 +78,8 @@ export function PageSelector({
78
78
  itemSelected={(item) => loadItem(item)}
79
79
  />
80
80
  </div>
81
- <div className="flex-1 flex flex-col">
82
- <div className="border-t p-2 pb-1 text-xs text-gray-500 flex items-center gap-1">
81
+ <div className="flex flex-1 flex-col">
82
+ <div className="flex items-center gap-1 border-t p-2 pb-1 text-xs text-gray-500">
83
83
  <ArrowDownIcon /> Select
84
84
  </div>
85
85
  <div className="relative flex-1">
@@ -91,8 +91,8 @@ export function PageSelector({
91
91
  </div>
92
92
  </div>
93
93
  </div>
94
- <div className="border-t p-2 flex flex-col">
95
- <div className="text-xs text-gray-500 mb-2 flex items-center gap-1">
94
+ <div className="flex flex-col border-t p-2">
95
+ <div className="mb-2 flex items-center gap-1 text-xs text-gray-500">
96
96
  <ArrowDownIcon /> Last visited
97
97
  </div>
98
98
  <BrowseHistory
@@ -101,8 +101,8 @@ export function PageSelector({
101
101
  />
102
102
  </div>
103
103
  </div>
104
- <div className="border-t p-2 flex flex-col">
105
- <div className="text-xs text-gray-500 mb-2 flex items-center gap-1">
104
+ <div className="flex flex-col border-t p-2">
105
+ <div className="mb-2 flex items-center gap-1 text-xs text-gray-500">
106
106
  <ArrowDownIcon /> Actions
107
107
  </div>
108
108
  <div className="flex gap-2">
@@ -3,6 +3,7 @@ import { useEditContext } from "../client/editContext";
3
3
  import { Separator } from "./Separator";
4
4
  import { CompareIcon, FormEditIcon } from "../ui/Icons";
5
5
  import { SimpleIconButton } from "../ui/SimpleIconButton";
6
+ import { Route, SquarePen, UserRoundPen, EyeIcon, Pencil } from "lucide-react";
6
7
 
7
8
  export function PageViewerControls() {
8
9
  const editContext = useEditContext();
@@ -17,16 +18,54 @@ export function PageViewerControls() {
17
18
  const setDevice = pageViewContext.setDevice;
18
19
 
19
20
  return (
20
- <div className="flex gap-2 items-center">
21
+ <div className="flex items-center gap-2">
21
22
  {hasLayout && (
22
23
  <>
23
- {" "}
24
+ {!editContext.user?.isLimitedPreviewUser && (
25
+ <SimpleIconButton
26
+ icon={<Pencil className="h-6 w-6 p-1" />}
27
+ label="Edit"
28
+ size="large"
29
+ className={classNames(
30
+ editContext.mode === "edit"
31
+ ? "bg-gray-200"
32
+ : "hover:bg-gray-200 hover:text-gray-800",
33
+ )}
34
+ onClick={() => editContext.setMode("edit")}
35
+ />
36
+ )}
37
+
38
+ <SimpleIconButton
39
+ icon={<EyeIcon className="h-6 w-6 p-1" />}
40
+ label="Preview"
41
+ size="large"
42
+ className={classNames(
43
+ editContext.mode === "preview"
44
+ ? "bg-gray-200"
45
+ : "hover:bg-gray-200 hover:text-gray-800",
46
+ )}
47
+ onClick={() => editContext.setMode("preview")}
48
+ />
49
+
50
+ <SimpleIconButton
51
+ selected={editContext?.mode === "suggestions"}
52
+ icon={<UserRoundPen size={24} className="p-0.5" />}
53
+ label="Suggestions"
54
+ size="large"
55
+ className={classNames(
56
+ editContext?.mode === "suggestions"
57
+ ? "text-gray-600"
58
+ : "hover:text-gray-600",
59
+ )}
60
+ onClick={() => editContext?.setMode("suggestions")}
61
+ />
62
+ <Separator size="large" />
24
63
  <i
25
64
  className={classNames(
26
65
  device === "desktop"
27
66
  ? "bg-gray-200"
28
- : " hover:bg-gray-200 text-gray-100 hover:text-gray-800",
29
- "pi pi-desktop cursor-pointer p-2 rounded-full"
67
+ : "text-gray-400 hover:bg-gray-200 hover:text-gray-800",
68
+ "pi pi-desktop cursor-pointer rounded-full p-2",
30
69
  )}
31
70
  title="Desktop"
32
71
  onClick={() => {
@@ -37,8 +76,8 @@ export function PageViewerControls() {
37
76
  className={classNames(
38
77
  device && device !== "desktop"
39
78
  ? "bg-gray-200"
40
- : " hover:bg-gray-200 text-gray-100 hover:text-gray-800",
41
- "pi pi-mobile cursor-pointer p-2 rounded-full"
79
+ : "text-gray-400 hover:bg-gray-200 hover:text-gray-800",
80
+ "pi pi-mobile cursor-pointer rounded-full p-2",
42
81
  )}
43
82
  title="Mobile"
44
83
  onClick={() => {
@@ -51,8 +90,8 @@ export function PageViewerControls() {
51
90
  className={classNames(
52
91
  !device
53
92
  ? "bg-gray-200"
54
- : " hover:bg-gray-200 text-gray-100 hover:text-gray-800",
55
- "w-8 h-8 cursor-pointer p-1 rounded-full"
93
+ : "text-gray-400 hover:bg-gray-200 hover:text-gray-800",
94
+ "h-8 w-8 cursor-pointer rounded-full p-1",
56
95
  )}
57
96
  title="Form"
58
97
  onClick={() => {
@@ -63,27 +102,14 @@ export function PageViewerControls() {
63
102
  </i>
64
103
  <Separator size="large" />
65
104
  <i
66
- className="pi pi-external-link cursor-pointer hover:bg-gray-200 p-2 rounded-full text-gray-100 hover:text-gray-800"
105
+ className="pi pi-external-link cursor-pointer rounded-full p-2 text-gray-400 hover:bg-gray-200 hover:text-gray-800"
67
106
  title="Fullscreen"
68
107
  onClick={() => pageViewContext.setFullscreen(true)}
69
108
  />
70
- {!editContext.user?.isLimitedPreviewUser && (
71
- <i
72
- className={classNames(
73
- editContext.previewMode
74
- ? "bg-gray-200"
75
- : " hover:bg-gray-200 text-gray-100 hover:text-gray-800",
76
- "pi pi-eye cursor-pointer p-2 rounded-full"
77
- )}
78
- title="Preview"
79
- onClick={() => editContext.setPreviewMode((x) => !x)}
80
- />
81
- )}
82
- <Separator size="large" />
83
109
  </>
84
110
  )}
85
111
  <SimpleIconButton
86
- icon={<CompareIcon className="w-6 h-6 p-1" />}
112
+ icon={<CompareIcon className="h-6 w-6 p-1" />}
87
113
  label="Compare"
88
114
  size="large"
89
115
  className={