@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.
- 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 +4 -3
- 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/EditorWarnings.js +1 -1
- package/dist/editor/EditorWarnings.js.map +1 -1
- package/dist/editor/FieldList.js +1 -1
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/FieldListFieldWithFallbacks.js +3 -3
- package/dist/editor/FieldListFieldWithFallbacks.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 +90 -35
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +10 -4
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/operations.d.ts +5 -1
- package/dist/editor/client/operations.js +112 -17
- 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/component-designer/ComponentDesigner.js +1 -1
- package/dist/editor/component-designer/ComponentDesigner.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/menubar/LanguageSelector.js +3 -3
- package/dist/editor/menubar/LanguageSelector.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +1 -1
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/menubar/PageViewerControls.js +12 -7
- package/dist/editor/menubar/PageViewerControls.js.map +1 -1
- package/dist/editor/menubar/Separator.js +1 -1
- package/dist/editor/menubar/VersionSelector.js +1 -1
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.d.ts +2 -2
- package/dist/editor/page-editor-chrome/FrameMenu.js +66 -22
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenus.d.ts +2 -2
- package/dist/editor/page-editor-chrome/FrameMenus.js +2 -2
- package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineEditor.d.ts +2 -2
- package/dist/editor/page-editor-chrome/InlineEditor.js +175 -17
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/PageEditorChrome.d.ts +2 -2
- package/dist/editor/page-editor-chrome/PageEditorChrome.js +2 -2
- package/dist/editor/page-editor-chrome/PageEditorChrome.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/EditorForm.d.ts +2 -1
- package/dist/editor/page-viewer/EditorForm.js +9 -8
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/MiniMap.d.ts +2 -2
- package/dist/editor/page-viewer/MiniMap.js +2 -2
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.d.ts +2 -2
- package/dist/editor/page-viewer/PageViewer.js +3 -3
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.d.ts +2 -3
- package/dist/editor/page-viewer/PageViewerFrame.js +127 -223
- 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/reviews/Comments.d.ts +2 -0
- package/dist/editor/reviews/Comments.js +26 -9
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/DiffView.d.ts +17 -0
- package/dist/editor/reviews/DiffView.js +57 -0
- package/dist/editor/reviews/DiffView.js.map +1 -0
- package/dist/editor/reviews/SuggestedEdit.d.ts +4 -0
- package/dist/editor/reviews/SuggestedEdit.js +180 -0
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -0
- package/dist/editor/services/suggestedEditsService.d.ts +17 -0
- package/dist/editor/services/suggestedEditsService.js +26 -0
- package/dist/editor/services/suggestedEditsService.js.map +1 -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/PerfectTree.js +3 -3
- package/dist/editor/ui/PerfectTree.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/SimpleIconButton.js +3 -1
- package/dist/editor/ui/SimpleIconButton.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/editor/views/CompareView.js +4 -13
- package/dist/editor/views/CompareView.js.map +1 -1
- package/dist/editor/views/EditView.js +2 -2
- package/dist/editor/views/EditView.js.map +1 -1
- package/dist/editor/views/SingleEditView.d.ts +2 -2
- package/dist/editor/views/SingleEditView.js +2 -2
- package/dist/editor/views/SingleEditView.js.map +1 -1
- package/dist/lib/safelist.js +1 -1
- package/dist/lib/safelist.js.map +1 -1
- package/dist/page-wizard/steps/BuildPageStep.js +2 -2
- package/dist/page-wizard/steps/BuildPageStep.js.map +1 -1
- package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +2 -2
- package/dist/page-wizard/steps/CreatePageAndLayoutStep.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 +275 -58
- package/dist/types.d.ts +20 -2
- package/package.json +6 -2
- package/src/components/ui/context-menu.tsx +250 -0
- package/src/config/config.tsx +4 -4
- 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/EditorWarnings.tsx +2 -2
- package/src/editor/FieldList.tsx +6 -6
- package/src/editor/FieldListFieldWithFallbacks.tsx +9 -9
- 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 +4 -4
- package/src/editor/ai/AiTerminal.tsx +31 -24
- package/src/editor/client/EditorClient.tsx +106 -57
- package/src/editor/client/editContext.ts +13 -4
- package/src/editor/client/operations.ts +162 -23
- package/src/editor/client/pageModelBuilder.ts +26 -18
- package/src/editor/commands/componentCommands.tsx +58 -39
- package/src/editor/component-designer/ComponentDesigner.tsx +1 -1
- 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/menubar/LanguageSelector.tsx +6 -6
- package/src/editor/menubar/PageSelector.tsx +11 -11
- package/src/editor/menubar/PageViewerControls.tsx +49 -23
- package/src/editor/menubar/Separator.tsx +2 -2
- package/src/editor/menubar/VersionSelector.tsx +1 -1
- package/src/editor/page-editor-chrome/FrameMenu.tsx +94 -29
- package/src/editor/page-editor-chrome/FrameMenus.tsx +6 -6
- package/src/editor/page-editor-chrome/InlineEditor.tsx +237 -26
- package/src/editor/page-editor-chrome/PageEditorChrome.tsx +11 -14
- 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/EditorForm.tsx +15 -9
- package/src/editor/page-viewer/MiniMap.tsx +4 -4
- package/src/editor/page-viewer/PageViewer.tsx +6 -6
- package/src/editor/page-viewer/PageViewerFrame.tsx +146 -309
- package/src/editor/page-viewer/pageModelBuilder.ts +412 -0
- package/src/editor/pageModel.ts +5 -0
- package/src/editor/reviews/Comments.tsx +56 -15
- package/src/editor/reviews/DiffView.tsx +109 -0
- package/src/editor/reviews/SuggestedEdit.tsx +316 -0
- package/src/editor/services/suggestedEditsService.ts +39 -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/PerfectTree.tsx +5 -5
- package/src/editor/ui/Section.tsx +4 -4
- package/src/editor/ui/SimpleIconButton.tsx +5 -3
- package/src/editor/ui/SimpleMenu.tsx +5 -13
- package/src/editor/utils.ts +74 -17
- package/src/editor/views/CompareView.tsx +13 -24
- package/src/editor/views/EditView.tsx +2 -2
- package/src/editor/views/SingleEditView.tsx +3 -3
- package/src/lib/safelist.tsx +4 -0
- package/src/page-wizard/steps/BuildPageStep.tsx +18 -25
- package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +16 -18
- package/src/splash-screen/SplashScreen.tsx +0 -1
- package/src/types.ts +20 -3
- 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();
|
|
@@ -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={`
|
|
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
|
-
}
|
|
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
|
|
85
|
+
<div className="flex max-h-[50vh] min-w-64 flex-col">
|
|
86
86
|
{showAllLanguagesSwitch && (
|
|
87
|
-
<div className="
|
|
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
|
|
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="
|
|
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
|
|
70
|
-
<div className="flex-1 flex
|
|
71
|
-
<div className="
|
|
72
|
-
<div className="
|
|
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
|
|
82
|
-
<div className="border-t p-2 pb-1 text-xs text-gray-500
|
|
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
|
|
95
|
-
<div className="
|
|
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
|
|
105
|
-
<div className="
|
|
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
|
|
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
|
|
29
|
-
"pi pi-desktop cursor-pointer p-2
|
|
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
|
|
41
|
-
"pi pi-mobile cursor-pointer p-2
|
|
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
|
|
55
|
-
"
|
|
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
|
|
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="
|
|
112
|
+
icon={<CompareIcon className="h-6 w-6 p-1" />}
|
|
87
113
|
label="Compare"
|
|
88
114
|
size="large"
|
|
89
115
|
className={
|