@alpaca-editor/core 1.0.3815 → 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 (119) hide show
  1. package/dist/config/config.js +1 -1
  2. package/dist/config/config.js.map +1 -1
  3. package/dist/editor/EditorWarnings.js +1 -1
  4. package/dist/editor/EditorWarnings.js.map +1 -1
  5. package/dist/editor/FieldList.js +1 -1
  6. package/dist/editor/FieldList.js.map +1 -1
  7. package/dist/editor/FieldListFieldWithFallbacks.js +3 -3
  8. package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
  9. package/dist/editor/Titlebar.js +1 -1
  10. package/dist/editor/Titlebar.js.map +1 -1
  11. package/dist/editor/client/EditorClient.js +71 -31
  12. package/dist/editor/client/EditorClient.js.map +1 -1
  13. package/dist/editor/client/editContext.d.ts +9 -3
  14. package/dist/editor/client/editContext.js.map +1 -1
  15. package/dist/editor/client/operations.d.ts +5 -1
  16. package/dist/editor/client/operations.js +97 -3
  17. package/dist/editor/client/operations.js.map +1 -1
  18. package/dist/editor/component-designer/ComponentDesigner.js +1 -1
  19. package/dist/editor/component-designer/ComponentDesigner.js.map +1 -1
  20. package/dist/editor/menubar/LanguageSelector.js +3 -3
  21. package/dist/editor/menubar/LanguageSelector.js.map +1 -1
  22. package/dist/editor/menubar/PageSelector.js +1 -1
  23. package/dist/editor/menubar/PageSelector.js.map +1 -1
  24. package/dist/editor/menubar/PageViewerControls.js +12 -7
  25. package/dist/editor/menubar/PageViewerControls.js.map +1 -1
  26. package/dist/editor/menubar/Separator.js +1 -1
  27. package/dist/editor/menubar/VersionSelector.js +1 -1
  28. package/dist/editor/menubar/VersionSelector.js.map +1 -1
  29. package/dist/editor/page-editor-chrome/FrameMenu.d.ts +2 -2
  30. package/dist/editor/page-editor-chrome/FrameMenu.js +21 -15
  31. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  32. package/dist/editor/page-editor-chrome/FrameMenus.d.ts +2 -2
  33. package/dist/editor/page-editor-chrome/FrameMenus.js +2 -2
  34. package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
  35. package/dist/editor/page-editor-chrome/InlineEditor.d.ts +2 -2
  36. package/dist/editor/page-editor-chrome/InlineEditor.js +175 -17
  37. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  38. package/dist/editor/page-editor-chrome/PageEditorChrome.d.ts +2 -2
  39. package/dist/editor/page-editor-chrome/PageEditorChrome.js +2 -2
  40. package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
  41. package/dist/editor/page-viewer/EditorForm.d.ts +2 -1
  42. package/dist/editor/page-viewer/EditorForm.js +9 -8
  43. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  44. package/dist/editor/page-viewer/MiniMap.d.ts +2 -2
  45. package/dist/editor/page-viewer/MiniMap.js +2 -2
  46. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  47. package/dist/editor/page-viewer/PageViewer.d.ts +2 -2
  48. package/dist/editor/page-viewer/PageViewer.js +3 -3
  49. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  50. package/dist/editor/page-viewer/PageViewerFrame.d.ts +2 -2
  51. package/dist/editor/page-viewer/PageViewerFrame.js +12 -12
  52. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  53. package/dist/editor/reviews/Comments.d.ts +2 -0
  54. package/dist/editor/reviews/Comments.js +26 -9
  55. package/dist/editor/reviews/Comments.js.map +1 -1
  56. package/dist/editor/reviews/DiffView.d.ts +17 -0
  57. package/dist/editor/reviews/DiffView.js +57 -0
  58. package/dist/editor/reviews/DiffView.js.map +1 -0
  59. package/dist/editor/reviews/SuggestedEdit.d.ts +4 -0
  60. package/dist/editor/reviews/SuggestedEdit.js +180 -0
  61. package/dist/editor/reviews/SuggestedEdit.js.map +1 -0
  62. package/dist/editor/services/suggestedEditsService.d.ts +17 -0
  63. package/dist/editor/services/suggestedEditsService.js +26 -0
  64. package/dist/editor/services/suggestedEditsService.js.map +1 -0
  65. package/dist/editor/ui/PerfectTree.js +3 -3
  66. package/dist/editor/ui/PerfectTree.js.map +1 -1
  67. package/dist/editor/ui/SimpleIconButton.js +3 -1
  68. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  69. package/dist/editor/views/CompareView.js +4 -13
  70. package/dist/editor/views/CompareView.js.map +1 -1
  71. package/dist/editor/views/EditView.js +2 -2
  72. package/dist/editor/views/EditView.js.map +1 -1
  73. package/dist/editor/views/SingleEditView.d.ts +2 -2
  74. package/dist/editor/views/SingleEditView.js +2 -2
  75. package/dist/editor/views/SingleEditView.js.map +1 -1
  76. package/dist/lib/safelist.js +1 -1
  77. package/dist/lib/safelist.js.map +1 -1
  78. package/dist/page-wizard/steps/BuildPageStep.js +2 -2
  79. package/dist/page-wizard/steps/BuildPageStep.js.map +1 -1
  80. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +2 -2
  81. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js.map +1 -1
  82. package/dist/styles.css +36 -2
  83. package/dist/types.d.ts +18 -0
  84. package/package.json +4 -1
  85. package/src/config/config.tsx +2 -2
  86. package/src/editor/EditorWarnings.tsx +2 -2
  87. package/src/editor/FieldList.tsx +6 -6
  88. package/src/editor/FieldListFieldWithFallbacks.tsx +9 -9
  89. package/src/editor/Titlebar.tsx +4 -4
  90. package/src/editor/client/EditorClient.tsx +83 -51
  91. package/src/editor/client/editContext.ts +12 -3
  92. package/src/editor/client/operations.ts +146 -9
  93. package/src/editor/component-designer/ComponentDesigner.tsx +1 -1
  94. package/src/editor/menubar/LanguageSelector.tsx +6 -6
  95. package/src/editor/menubar/PageSelector.tsx +11 -11
  96. package/src/editor/menubar/PageViewerControls.tsx +49 -23
  97. package/src/editor/menubar/Separator.tsx +2 -2
  98. package/src/editor/menubar/VersionSelector.tsx +1 -1
  99. package/src/editor/page-editor-chrome/FrameMenu.tsx +18 -17
  100. package/src/editor/page-editor-chrome/FrameMenus.tsx +6 -6
  101. package/src/editor/page-editor-chrome/InlineEditor.tsx +233 -22
  102. package/src/editor/page-editor-chrome/PageEditorChrome.tsx +11 -14
  103. package/src/editor/page-viewer/EditorForm.tsx +15 -9
  104. package/src/editor/page-viewer/MiniMap.tsx +4 -4
  105. package/src/editor/page-viewer/PageViewer.tsx +6 -6
  106. package/src/editor/page-viewer/PageViewerFrame.tsx +19 -13
  107. package/src/editor/reviews/Comments.tsx +56 -15
  108. package/src/editor/reviews/DiffView.tsx +109 -0
  109. package/src/editor/reviews/SuggestedEdit.tsx +316 -0
  110. package/src/editor/services/suggestedEditsService.ts +39 -0
  111. package/src/editor/ui/PerfectTree.tsx +5 -5
  112. package/src/editor/ui/SimpleIconButton.tsx +5 -3
  113. package/src/editor/views/CompareView.tsx +13 -24
  114. package/src/editor/views/EditView.tsx +2 -2
  115. package/src/editor/views/SingleEditView.tsx +3 -3
  116. package/src/lib/safelist.tsx +2 -0
  117. package/src/page-wizard/steps/BuildPageStep.tsx +18 -25
  118. package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +16 -18
  119. package/src/types.ts +19 -0
@@ -0,0 +1,316 @@
1
+ import { SuggestedEdit as SuggestedEditType } from "../../types";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { useEditContext } from "../client/editContext";
4
+ import {
5
+ deleteSuggestedEdit,
6
+ createOrUpdateSuggestedEdit,
7
+ } from "../services/suggestedEditsService";
8
+ import { Button } from "../../components/ui/button";
9
+ import { formatDate } from "../utils";
10
+ import { SimpleIconButton } from "../ui/SimpleIconButton";
11
+ import { OverlayPanel } from "primereact/overlaypanel";
12
+ import { DiffView } from "./DiffView";
13
+ // Import lucide icons (adjust names as needed)
14
+ import { Trash2, GalleryVertical, Check, Brush, XCircle } from "lucide-react";
15
+ // Import patch functions from the diff library.
16
+ import { createPatch, applyPatch } from "diff";
17
+ import { cn } from "../../lib/utils";
18
+
19
+ export function SuggestedEditComponent({ edit }: { edit: SuggestedEditType }) {
20
+ const editContext = useEditContext();
21
+ const ref = useRef<HTMLDivElement>(null);
22
+ const overlayPanelRef = useRef<OverlayPanel>(null);
23
+ const [item, setItem] = useState<any>(null);
24
+ const [patchPossible, setPatchPossible] = useState<boolean>(true);
25
+
26
+ const [patchWarning, setPatchWarning] = useState<string>("");
27
+ const [applied, setApplied] = useState<boolean>(false);
28
+
29
+ const [ignoreFormatting, setIgnoreFormatting] = useState(true);
30
+ const [clipUnchanged, setClipUnchanged] = useState(true);
31
+
32
+ const canApply = editContext?.mode === "edit" && edit.status !== "Applied";
33
+
34
+ // Load the full item from the repository.
35
+ useEffect(() => {
36
+ if (
37
+ editContext?.itemsRepository &&
38
+ edit.itemId &&
39
+ edit.mainItemLanguage &&
40
+ edit.mainItemVersion !== undefined
41
+ ) {
42
+ editContext.itemsRepository
43
+ .getItem({
44
+ id: edit.itemId,
45
+ language: edit.mainItemLanguage,
46
+ version: edit.mainItemVersion,
47
+ })
48
+ .then((loadedItem) => {
49
+ setItem(loadedItem);
50
+ // When the item loads, check if the patch is applicable.
51
+ checkAndComputePatch(loadedItem);
52
+ })
53
+ .catch((err) => {
54
+ console.error("Error loading item:", err);
55
+ });
56
+ }
57
+ }, [
58
+ edit.itemId,
59
+ edit.mainItemLanguage,
60
+ edit.mainItemVersion,
61
+ editContext?.itemsRepository,
62
+ ]);
63
+
64
+ // Determine if this suggested edit is selected based on the focused field.
65
+ const isSelected =
66
+ editContext?.focusedField &&
67
+ editContext.focusedField.fieldId === edit.fieldId &&
68
+ editContext.focusedField.item.id === edit.itemId;
69
+
70
+ useEffect(() => {
71
+ if (isSelected && ref.current) {
72
+ ref.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
73
+ }
74
+ }, [isSelected]);
75
+
76
+ // When a suggested edit is clicked, update the focused field and select the item.
77
+ function handleSelectSuggestedEdit() {
78
+ if (edit.fieldId) {
79
+ editContext?.setFocusedField(
80
+ {
81
+ fieldId: edit.fieldId,
82
+ item: {
83
+ id: edit.itemId,
84
+ language: edit.mainItemLanguage,
85
+ version: edit.mainItemVersion,
86
+ },
87
+ },
88
+ false,
89
+ );
90
+ // Also select the item.
91
+ editContext?.select?.([edit.itemId]);
92
+ }
93
+ }
94
+
95
+ // Render contextual info by retrieving item and field names from the loaded item.
96
+ const renderContextInfo = () => {
97
+ const itemName = item ? item.name : null;
98
+ const fieldName =
99
+ item && item.fields
100
+ ? item.fields.find(
101
+ (f: { id: string; name?: string }) => f.id === edit.fieldId,
102
+ )?.name
103
+ : null;
104
+ if (!itemName && !fieldName) return null;
105
+ return (
106
+ <div className="mt-3 flex items-center border-t pt-3 text-xs">
107
+ {itemName && <div className="text-2xs text-gray-500">{itemName}</div>}
108
+ {fieldName && itemName && (
109
+ <div className="text-2xs mx-2 text-gray-500">&gt;</div>
110
+ )}
111
+ {fieldName && <div className="text-2xs text-gray-500">{fieldName}</div>}
112
+ </div>
113
+ );
114
+ };
115
+
116
+ // Allow deletion only if the current user is the author.
117
+ const canDelete = edit.author === editContext?.user?.name;
118
+
119
+ // Render the header with author info, creation date, and control buttons.
120
+ const renderHeader = () => {
121
+ return (
122
+ <div className="mb-3 flex items-start justify-between">
123
+ <div>
124
+ <div className="text-xs font-bold text-gray-900" title={edit.author}>
125
+ {edit.authorDisplayName || edit.author}
126
+ </div>
127
+ <div className="text-xs text-gray-500">
128
+ {edit.created ? formatDate(new Date(edit.created)) : ""}
129
+ </div>
130
+ </div>
131
+ <div className="flex items-center gap-1">
132
+ {/* Show apply patch control if not yet applied */}
133
+ {canApply && !applied && patchPossible && (
134
+ <SimpleIconButton
135
+ className="text-gray-500"
136
+ icon={<Check size={14} />}
137
+ label="Apply"
138
+ onClick={handleApplyPatch}
139
+ />
140
+ )}
141
+ {applied && (
142
+ <i
143
+ className="pi pi-check text-bold px-1 text-xs text-green-500"
144
+ title={
145
+ "Applied by " +
146
+ edit.updatedBy +
147
+ " (" +
148
+ formatDate(new Date(edit.updated!)) +
149
+ ")"
150
+ }
151
+ ></i>
152
+ )}
153
+ {canDelete && (
154
+ <SimpleIconButton
155
+ className="text-gray-500"
156
+ icon={<Trash2 size={14} />}
157
+ label="Delete"
158
+ onClick={(e: any) => overlayPanelRef.current?.toggle(e)}
159
+ />
160
+ )}
161
+ <OverlayPanel ref={overlayPanelRef}>
162
+ <Button
163
+ className="m-2"
164
+ variant="outline"
165
+ onClick={async () => {
166
+ await deleteSuggestedEdit(edit);
167
+ }}
168
+ >
169
+ Delete
170
+ </Button>
171
+ </OverlayPanel>
172
+ </div>
173
+ </div>
174
+ );
175
+ };
176
+
177
+ // Render toggle buttons using SimpleIconButtons.
178
+ const renderDiffToggleButtons = () => {
179
+ return (
180
+ <div className="mb-2 flex gap-2">
181
+ <SimpleIconButton
182
+ icon={<Brush size={14} className="p-0.5" />}
183
+ label="Ignore Formatting"
184
+ onClick={() => setIgnoreFormatting((prev) => !prev)}
185
+ className={cn("text-gray-500", ignoreFormatting ? "bg-gray-200" : "")}
186
+ />
187
+ <SimpleIconButton
188
+ icon={<GalleryVertical size={14} className="p-0.5" />}
189
+ label="Clip"
190
+ onClick={() => setClipUnchanged((prev) => !prev)}
191
+ className={cn("text-gray-500", clipUnchanged ? "bg-gray-200" : "")}
192
+ />
193
+ </div>
194
+ );
195
+ };
196
+
197
+ // Helper: Check if the patch is applicable to the current field value.
198
+ async function checkAndComputePatch(loadedItem: any) {
199
+ const field = loadedItem?.fields?.find(
200
+ (f: { id: string }) => f.id === edit.fieldId,
201
+ );
202
+ if (!field) return;
203
+ const currentValue: string = field.rawValue || "";
204
+ const patch = createPatch("field", edit.oldValue, edit.newValue);
205
+ const patchedCandidate = applyPatch(currentValue, patch);
206
+ if (patchedCandidate === false || typeof patchedCandidate !== "string") {
207
+ setPatchPossible(false);
208
+ setPatchWarning("Patch cannot be applied cleanly.");
209
+ } else {
210
+ setPatchPossible(true);
211
+ setPatchWarning("");
212
+ }
213
+ }
214
+
215
+ // Handler for applying the patch using editContext.operations.editField.
216
+ async function handleApplyPatch() {
217
+ if (!patchPossible) return;
218
+ if (!editContext) return;
219
+
220
+ // Recalculate the patch immediately before applying
221
+ const field = item?.fields?.find(
222
+ (f: { id: string }) => f.id === edit.fieldId,
223
+ );
224
+ if (!field) return;
225
+ const currentValue: string = field.rawValue || "";
226
+ const patch = createPatch("field", edit.oldValue, edit.newValue);
227
+ const patchedCandidate = applyPatch(currentValue, patch);
228
+
229
+ if (patchedCandidate === false || typeof patchedCandidate !== "string") {
230
+ setPatchWarning(
231
+ "Patch cannot be applied cleanly to current field value.",
232
+ );
233
+ return;
234
+ }
235
+
236
+ await editContext.operations.editField({
237
+ field: {
238
+ fieldId: edit.fieldId,
239
+ item: {
240
+ id: edit.itemId,
241
+ language: edit.mainItemLanguage,
242
+ version: edit.mainItemVersion,
243
+ },
244
+ },
245
+ value: patchedCandidate,
246
+ rawValue: patchedCandidate,
247
+ refresh: "immediate",
248
+ });
249
+ // Update the suggestion status to "Applied" and persist the update.
250
+ edit.status = "Applied";
251
+ await createOrUpdateSuggestedEdit(edit);
252
+ setApplied(true);
253
+ setPatchWarning("");
254
+ }
255
+
256
+ // Handler for replacing the field content completely using editContext.operations.editField.
257
+ async function handleReplaceCompletely() {
258
+ if (!editContext) return;
259
+ await editContext.operations.editField({
260
+ field: {
261
+ fieldId: edit.fieldId,
262
+ item: {
263
+ id: edit.itemId,
264
+ language: edit.mainItemLanguage,
265
+ version: edit.mainItemVersion,
266
+ },
267
+ },
268
+ value: edit.newValue,
269
+ rawValue: edit.newValue,
270
+ refresh: "immediate",
271
+ });
272
+ edit.status = "Applied";
273
+ await createOrUpdateSuggestedEdit(edit);
274
+ setApplied(true);
275
+ setPatchWarning("");
276
+ }
277
+
278
+ return (
279
+ <div
280
+ ref={ref}
281
+ key={edit.id}
282
+ data-testid="suggested-edit"
283
+ className={`mb-3 cursor-pointer rounded-lg border-2 bg-white p-3 shadow-sm hover:bg-gray-50 ${
284
+ isSelected ? "border-blue-500" : "border-transparent"
285
+ }`}
286
+ onClick={handleSelectSuggestedEdit}
287
+ >
288
+ {renderHeader()}
289
+ {renderDiffToggleButtons()}
290
+
291
+ <div className="text-sm whitespace-pre-wrap text-gray-700">
292
+ <DiffView
293
+ oldText={edit.oldValue}
294
+ newText={edit.newValue}
295
+ ignoreFormatting={ignoreFormatting}
296
+ clipUnchanged={clipUnchanged}
297
+ clipThreshold={50}
298
+ clipContext={10}
299
+ />
300
+ {canApply && patchWarning && (
301
+ <div className="mt-1 text-xs text-red-500">
302
+ {patchWarning}
303
+ <a
304
+ className="ml-2 cursor-pointer underline"
305
+ onClick={handleReplaceCompletely}
306
+ >
307
+ Click here to replace the field content.
308
+ </a>
309
+ </div>
310
+ )}
311
+ </div>
312
+
313
+ {renderContextInfo()}
314
+ </div>
315
+ );
316
+ }
@@ -0,0 +1,39 @@
1
+ import { get, post } from "./serviceHelper";
2
+ import { SuggestedEdit } from "../../types";
3
+
4
+ /**
5
+ * Creates or updates a suggested edit.
6
+ */
7
+ export function createOrUpdateSuggestedEdit(suggestedEdit: SuggestedEdit) {
8
+ return post("/alpaca/editor/suggested-edits/add", suggestedEdit);
9
+ }
10
+
11
+ /**
12
+ * Retrieves all suggested edits for a given main item based on its ID, language, and version.
13
+ */
14
+ export function getSuggestedEdits(
15
+ mainItemId: string,
16
+ mainItemLanguage: string,
17
+ mainItemVersion: number,
18
+ ) {
19
+ return get<SuggestedEdit[]>(
20
+ `/alpaca/editor/suggested-edits/index?mainItemId=${mainItemId}&mainItemLanguage=${mainItemLanguage}&mainItemVersion=${mainItemVersion}`,
21
+ );
22
+ }
23
+
24
+ /**
25
+ * Retrieves a single suggested edit by its unique identifier.
26
+ */
27
+ export function getSuggestedEditById(id: string) {
28
+ return get<SuggestedEdit>(`/alpaca/editor/suggested-edits/get?id=${id}`);
29
+ }
30
+
31
+ /**
32
+ * Deletes the given suggested edit.
33
+ */
34
+ export function deleteSuggestedEdit(suggestedEdit: SuggestedEdit) {
35
+ return post(
36
+ `/alpaca/editor/suggested-edits/delete?id=${suggestedEdit.id}`,
37
+ {},
38
+ );
39
+ }
@@ -313,8 +313,8 @@ const NodeContent = memo(
313
313
  if (node.hasChildren && node.children === null) {
314
314
  return (
315
315
  <ProgressSpinner
316
- style={{ width: "14px", height: "14px", margin: "0 2px" }}
317
- className="text-gray-500"
316
+ style={{ width: "16px", height: "16px" }}
317
+ className="m-0 text-gray-500"
318
318
  />
319
319
  );
320
320
  }
@@ -322,7 +322,7 @@ const NodeContent = memo(
322
322
  return (
323
323
  <span
324
324
  onClick={handleToggle}
325
- className={`mr-1 inline-block transform cursor-pointer text-gray-500 transition duration-150 select-none ${
325
+ className={`mr-0.5 inline-block transform cursor-pointer text-gray-500 transition duration-150 select-none ${
326
326
  isExpanded ? "rotate-90" : "rotate-0"
327
327
  }`}
328
328
  >
@@ -371,10 +371,10 @@ const NodeContent = memo(
371
371
  {node.hasChildren || node.children?.length ? (
372
372
  renderToggle()
373
373
  ) : (
374
- <div className="w-[18px]" />
374
+ <div className="w-[14px]" />
375
375
  )}
376
376
  <div
377
- className={`rounded-md border border-transparent p-0.5 hover:border-gray-300 ${
377
+ className={`rounded-md border border-transparent p-0.5 pr-1.5 hover:border-gray-300 ${
378
378
  isDragOver ? "bg-sky-200" : isSelected ? "bg-blue-100" : ""
379
379
  }`}
380
380
  onClick={handleSelect}
@@ -26,11 +26,13 @@ export function SimpleIconButton({
26
26
  disabled={disabled}
27
27
  className={classNames(
28
28
  typeof icon === "string" ? icon + " p-[6px]" : "p-[4px]",
29
- " rounded-full",
30
- disabled ? "text-gray-300" : " hover:bg-gray-200 cursor-pointer",
29
+ "rounded-full text-gray-400",
30
+ disabled
31
+ ? "cursor-none text-gray-300"
32
+ : "cursor-pointer hover:bg-gray-200",
31
33
  className,
32
34
  size === "large" ? "text-lg" : "text-xs",
33
- selected ? "bg-gray-200" : ""
35
+ selected ? "bg-gray-200" : "",
34
36
  )}
35
37
  onClick={(ev) => {
36
38
  if (!disabled) onClick(ev);
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from "react";
2
- import { useEditContext } from "../client/editContext";
2
+ import { EditorMode, useEditContext } from "../client/editContext";
3
3
  import { LanguageSelector } from "../menubar/LanguageSelector";
4
4
  import { VersionSelector } from "../menubar/VersionSelector";
5
5
  import { FullItem, ItemDescriptor, Version } from "../pageModel";
@@ -57,7 +57,7 @@ export function CompareView() {
57
57
  editContext.currentItemDescriptor?.version;
58
58
 
59
59
  const language = editContext.itemLanguages.find(
60
- (x) => x.languageCode === urlLanguage
60
+ (x) => x.languageCode === urlLanguage,
61
61
  );
62
62
 
63
63
  if (!language || !language.versions) {
@@ -108,14 +108,14 @@ export function CompareView() {
108
108
  newParams.set("compareLanguage", compareToItemDescriptor.language);
109
109
  newParams.set(
110
110
  "compareVersion",
111
- compareToItemDescriptor.version.toString()
111
+ compareToItemDescriptor.version.toString(),
112
112
  );
113
113
  router.push(`?${newParams.toString()}`);
114
114
  }
115
115
  }
116
116
 
117
117
  const originalSelector = (
118
- <div className="flex-1 bg-gray-100 border-b flex items-center justify-center flex-shrink-0 text-sm text-gray-600 p-1">
118
+ <div className="flex flex-1 flex-shrink-0 items-center justify-center border-b bg-gray-100 p-1 text-sm text-gray-600">
119
119
  <LanguageSelector
120
120
  selectedLanguage={editContext.contentEditorItem?.descriptor?.language}
121
121
  showAllLanguagesSwitch={false}
@@ -150,7 +150,7 @@ export function CompareView() {
150
150
  );
151
151
 
152
152
  const compareToSelector = (
153
- <div className="flex-1 bg-gray-100 border-b flex items-center justify-center flex-shrink-0 text-sm text-gray-600 p-1">
153
+ <div className="flex flex-1 flex-shrink-0 items-center justify-center border-b bg-gray-100 p-1 text-sm text-gray-600">
154
154
  <LanguageSelector
155
155
  selectedLanguage={compareTo?.language}
156
156
  showAllLanguagesSwitch={false}
@@ -189,13 +189,13 @@ export function CompareView() {
189
189
  comparePageViewContext.device === ""
190
190
  )
191
191
  return (
192
- <div className="flex flex-col h-full w-full items-stretch">
192
+ <div className="flex h-full w-full flex-col items-stretch">
193
193
  <div className="flex w-full">
194
194
  {originalSelector}
195
195
  {compareToSelector}
196
196
  </div>
197
- <div className="flex-1 relative">
198
- <div className="absolute w-full h-full">
197
+ <div className="relative flex-1">
198
+ <div className="absolute h-full w-full">
199
199
  <ItemEditor
200
200
  pageViewContext={editContext.pageView}
201
201
  compareToItem={compareToItem}
@@ -208,42 +208,31 @@ export function CompareView() {
208
208
  return (
209
209
  <Allotment className="flex h-full w-full">
210
210
  <Allotment.Pane>
211
- <div className="flex flex-col h-full w-full items-stretch">
211
+ <div className="flex h-full w-full flex-col items-stretch">
212
212
  {originalSelector}
213
213
  <SingleEditView
214
214
  key="original"
215
215
  name="original"
216
- mode={editContext?.previewMode ? "view" : "edit"}
216
+ compareView={false}
217
217
  pageViewContext={editContext.pageView}
218
218
  itemDescriptor={editContext.contentEditorItem?.descriptor}
219
219
  />
220
220
  </div>
221
221
  </Allotment.Pane>
222
222
  <Allotment.Pane>
223
- <div className="flex flex-col h-full w-full items-stretch">
223
+ <div className="flex h-full w-full flex-col items-stretch">
224
224
  {compareToSelector}
225
225
  {compareTo?.language && (
226
226
  <SingleEditView
227
227
  key="compareTo"
228
228
  name="compareTo"
229
- mode={
230
- compareToItem?.id ===
231
- editContext.contentEditorItem?.descriptor.id &&
232
- compareToItem?.language ===
233
- editContext.contentEditorItem?.descriptor.language &&
234
- compareToItem?.version ===
235
- editContext.contentEditorItem?.descriptor.version
236
- ? editContext?.previewMode
237
- ? "view"
238
- : "edit"
239
- : "compare"
240
- }
229
+ compareView={true}
241
230
  pageViewContext={comparePageViewContext}
242
231
  itemDescriptor={compareTo}
243
232
  />
244
233
  )}
245
234
  {!compareTo?.language && (
246
- <div className="flex flex-col h-full w-full items-center justify-center">
235
+ <div className="flex h-full w-full flex-col items-center justify-center">
247
236
  <div className="text-gray-400">
248
237
  Select a language and version to compare
249
238
  </div>
@@ -8,7 +8,7 @@ export function EditView() {
8
8
 
9
9
  if (!editContext.contentEditorItem?.descriptor)
10
10
  return (
11
- <div className="grid items-center justify-center h-full w-full">
11
+ <div className="grid h-full w-full items-center justify-center">
12
12
  <div className="text-sm text-gray-500">Not item selected</div>
13
13
  </div>
14
14
  );
@@ -19,7 +19,7 @@ export function EditView() {
19
19
  <SingleEditView
20
20
  key="single"
21
21
  name="single"
22
- mode={editContext?.previewMode ? "view" : "edit"}
22
+ compareView={false}
23
23
  pageViewContext={editContext.pageView}
24
24
  itemDescriptor={editContext.contentEditorItem?.descriptor}
25
25
  />
@@ -9,12 +9,12 @@ import { ItemEditor } from "./ItemEditor";
9
9
  export function SingleEditView({
10
10
  pageViewContext,
11
11
  itemDescriptor,
12
- mode,
12
+ compareView,
13
13
  name,
14
14
  }: {
15
15
  pageViewContext: PageViewContext;
16
16
  itemDescriptor?: ItemDescriptor;
17
- mode: "edit" | "compare" | "view";
17
+ compareView: boolean;
18
18
  name: string;
19
19
  }) {
20
20
  const editContext = useEditContext();
@@ -34,9 +34,9 @@ export function SingleEditView({
34
34
 
35
35
  return (
36
36
  <PageViewer
37
- mode={mode}
38
37
  pageViewContext={pageViewContext}
39
38
  showFormEditor={true}
39
+ compareView={compareView}
40
40
  name={name}
41
41
  followEditsDefault={true}
42
42
  />
@@ -5,10 +5,12 @@ export function Safelist() {
5
5
  <div className="bg-purple-400"></div>
6
6
  <div className="bg-sky-400"></div>
7
7
  <div className="bg-red-400"></div>
8
+ <div className="bg-teal-400"></div>
8
9
  <div className="border-orange-400"></div>
9
10
  <div className="border-purple-400"></div>
10
11
  <div className="border-sky-400"></div>
11
12
  <div className="border-red-400"></div>
13
+ <div className="border-teal-400"></div>
12
14
  </>
13
15
  );
14
16
  }