@alpaca-editor/core 1.0.3962 → 1.0.3964

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 (116) hide show
  1. package/dist/config/config.js +11 -10
  2. package/dist/config/config.js.map +1 -1
  3. package/dist/config/types.d.ts +2 -1
  4. package/dist/editor/ContentTree.js +3 -2
  5. package/dist/editor/ContentTree.js.map +1 -1
  6. package/dist/editor/FieldListField.js +13 -4
  7. package/dist/editor/FieldListField.js.map +1 -1
  8. package/dist/editor/ImageEditButton.js +1 -1
  9. package/dist/editor/ImageEditButton.js.map +1 -1
  10. package/dist/editor/MainLayout.js +2 -1
  11. package/dist/editor/MainLayout.js.map +1 -1
  12. package/dist/editor/menubar/ApproveAndPublish.d.ts +1 -1
  13. package/dist/editor/menubar/ApproveAndPublish.js +4 -1
  14. package/dist/editor/menubar/ApproveAndPublish.js.map +1 -1
  15. package/dist/editor/menubar/GenericToolbar.d.ts +11 -0
  16. package/dist/editor/menubar/GenericToolbar.js +10 -0
  17. package/dist/editor/menubar/GenericToolbar.js.map +1 -0
  18. package/dist/editor/menubar/ItemToolbar.d.ts +1 -0
  19. package/dist/editor/menubar/ItemToolbar.js +11 -0
  20. package/dist/editor/menubar/ItemToolbar.js.map +1 -0
  21. package/dist/editor/menubar/PageToolbar.d.ts +1 -0
  22. package/dist/editor/menubar/PageToolbar.js +33 -0
  23. package/dist/editor/menubar/PageToolbar.js.map +1 -0
  24. package/dist/editor/menubar/PageViewerControls.js +2 -28
  25. package/dist/editor/menubar/PageViewerControls.js.map +1 -1
  26. package/dist/editor/menubar/ToolbarFactory.d.ts +2 -0
  27. package/dist/editor/menubar/ToolbarFactory.js +52 -0
  28. package/dist/editor/menubar/ToolbarFactory.js.map +1 -0
  29. package/dist/editor/menubar/WorkflowButton.js +2 -0
  30. package/dist/editor/menubar/WorkflowButton.js.map +1 -1
  31. package/dist/editor/menubar/toolbar-sections/CompareControls.d.ts +1 -0
  32. package/dist/editor/menubar/toolbar-sections/CompareControls.js +11 -0
  33. package/dist/editor/menubar/toolbar-sections/CompareControls.js.map +1 -0
  34. package/dist/editor/menubar/toolbar-sections/EditControls.d.ts +1 -0
  35. package/dist/editor/menubar/toolbar-sections/EditControls.js +16 -0
  36. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -0
  37. package/dist/editor/menubar/toolbar-sections/InsertControls.d.ts +1 -0
  38. package/dist/editor/menubar/toolbar-sections/InsertControls.js +15 -0
  39. package/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -0
  40. package/dist/editor/menubar/toolbar-sections/ReviewCommands.d.ts +1 -0
  41. package/dist/editor/menubar/toolbar-sections/ReviewCommands.js +41 -0
  42. package/dist/editor/menubar/toolbar-sections/ReviewCommands.js.map +1 -0
  43. package/dist/editor/menubar/toolbar-sections/UtilityControls.d.ts +1 -0
  44. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +13 -0
  45. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -0
  46. package/dist/editor/menubar/toolbar-sections/ViewportControls.d.ts +1 -0
  47. package/dist/editor/menubar/toolbar-sections/ViewportControls.js +20 -0
  48. package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -0
  49. package/dist/editor/menubar/toolbar-sections/index.d.ts +6 -0
  50. package/dist/editor/menubar/toolbar-sections/index.js +7 -0
  51. package/dist/editor/menubar/toolbar-sections/index.js.map +1 -0
  52. package/dist/editor/page-viewer/EditorForm.js +10 -7
  53. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  54. package/dist/editor/reviews/reviewCommands.js +3 -2
  55. package/dist/editor/reviews/reviewCommands.js.map +1 -1
  56. package/dist/editor/sidebar/ComponentPalette.js +1 -1
  57. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  58. package/dist/editor/sidebar/ComponentTree.js +1 -1
  59. package/dist/editor/sidebar/SidebarView.js +2 -2
  60. package/dist/editor/sidebar/SidebarView.js.map +1 -1
  61. package/dist/editor/sidebar/Translations.js +8 -6
  62. package/dist/editor/sidebar/Translations.js.map +1 -1
  63. package/dist/editor/ui/Icons.js +2 -2
  64. package/dist/editor/ui/Icons.js.map +1 -1
  65. package/dist/editor/ui/Section.js +1 -1
  66. package/dist/editor/ui/Section.js.map +1 -1
  67. package/dist/editor/ui/SimpleIconButton.js +3 -5
  68. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  69. package/dist/editor/views/CompareView.js +2 -2
  70. package/dist/editor/views/CompareView.js.map +1 -1
  71. package/dist/editor/views/ItemEditor.js +1 -1
  72. package/dist/editor/views/ItemEditor.js.map +1 -1
  73. package/dist/revision.d.ts +2 -2
  74. package/dist/revision.js +2 -2
  75. package/dist/splash-screen/RecentPages.js +1 -1
  76. package/dist/splash-screen/RecentPages.js.map +1 -1
  77. package/dist/styles.css +23 -28
  78. package/package.json +1 -1
  79. package/src/config/config.tsx +17 -14
  80. package/src/config/types.ts +3 -1
  81. package/src/editor/ContentTree.tsx +10 -4
  82. package/src/editor/FieldListField.tsx +31 -3
  83. package/src/editor/ImageEditButton.tsx +1 -1
  84. package/src/editor/MainLayout.tsx +2 -1
  85. package/src/editor/menubar/ApproveAndPublish.tsx +4 -2
  86. package/src/editor/menubar/GenericToolbar.tsx +43 -0
  87. package/src/editor/menubar/ItemToolbar.tsx +24 -0
  88. package/src/editor/menubar/PageToolbar.tsx +154 -0
  89. package/src/editor/menubar/PageViewerControls.tsx +2 -160
  90. package/src/editor/menubar/ToolbarFactory.tsx +68 -0
  91. package/src/editor/menubar/WorkflowButton.tsx +1 -0
  92. package/src/editor/menubar/toolbar-sections/CompareControls.tsx +22 -0
  93. package/src/editor/menubar/toolbar-sections/EditControls.tsx +54 -0
  94. package/src/editor/menubar/toolbar-sections/InsertControls.tsx +28 -0
  95. package/src/editor/menubar/toolbar-sections/ReviewCommands.tsx +60 -0
  96. package/src/editor/menubar/toolbar-sections/UtilityControls.tsx +33 -0
  97. package/src/editor/menubar/toolbar-sections/ViewportControls.tsx +58 -0
  98. package/src/editor/menubar/toolbar-sections/index.ts +6 -0
  99. package/src/editor/page-viewer/EditorForm.tsx +19 -8
  100. package/src/editor/reviews/reviewCommands.tsx +3 -2
  101. package/src/editor/sidebar/ComponentPalette.tsx +1 -1
  102. package/src/editor/sidebar/ComponentTree.tsx +1 -1
  103. package/src/editor/sidebar/SidebarView.tsx +4 -2
  104. package/src/editor/sidebar/Translations.tsx +17 -15
  105. package/src/editor/ui/Icons.tsx +4 -4
  106. package/src/editor/ui/Section.tsx +1 -1
  107. package/src/editor/ui/SimpleIconButton.tsx +6 -7
  108. package/src/editor/views/CompareView.tsx +2 -2
  109. package/src/editor/views/ItemEditor.tsx +1 -1
  110. package/src/revision.ts +2 -2
  111. package/src/splash-screen/RecentPages.tsx +1 -1
  112. package/styles.css +15 -8
  113. package/dist/editor/menubar/Menu.d.ts +0 -1
  114. package/dist/editor/menubar/Menu.js +0 -63
  115. package/dist/editor/menubar/Menu.js.map +0 -1
  116. package/src/editor/menubar/Menu.tsx +0 -83
@@ -19,6 +19,7 @@ import {
19
19
  import { useThrottledCallback } from "use-debounce";
20
20
  import { SimpleIconButton } from "./ui/SimpleIconButton";
21
21
  import { FieldHistory } from "./FieldHistory";
22
+ import { Copy } from "lucide-react";
22
23
 
23
24
  export default function FieldListField({
24
25
  field,
@@ -53,6 +54,7 @@ export default function FieldListField({
53
54
  const [isModified, setIsModified] = useState(false);
54
55
  const [isSaved, setIsSaved] = useState(false);
55
56
  const [historyEntry, setHistoryEntry] = useState<FieldHistoryItem>();
57
+ const [showCopiedHint, setShowCopiedHint] = useState(false);
56
58
  async function handleActionClick(action: FieldButton): Promise<void> {
57
59
  editContext?.triggerFieldAction(field.descriptor, action);
58
60
  }
@@ -247,7 +249,7 @@ export default function FieldListField({
247
249
  !simplified) && <span className="text-xs">·</span>}
248
250
  {!field.isFallback && field.rawValue !== null ? (
249
251
  <button
250
- className="p-0 text-xs"
252
+ className="text-gray-1 p-0 text-xs"
251
253
  onClick={() => {
252
254
  editContext?.operations.editField({
253
255
  field: field.descriptor,
@@ -260,11 +262,12 @@ export default function FieldListField({
260
262
  ) : (
261
263
  showFallbackButton
262
264
  )}
265
+
263
266
  {config?.buttons?.map((x) => {
264
267
  return (
265
268
  <button
266
269
  key={x.id}
267
- className="p-0 text-xs"
270
+ className="text-gray-1 p-0 text-xs"
268
271
  onClick={() =>
269
272
  editContext.triggerFieldAction(field.descriptor, x)
270
273
  }
@@ -275,7 +278,7 @@ export default function FieldListField({
275
278
  })}
276
279
  {!simplified && (
277
280
  <button
278
- className="p-0 text-xs"
281
+ className="text-gray-1 p-0 text-xs"
279
282
  onClick={() => {
280
283
  setShowRawValue(!showRawValue);
281
284
  }}
@@ -289,6 +292,31 @@ export default function FieldListField({
289
292
  Raw
290
293
  </button>
291
294
  )}
295
+ {field.rawValue && (
296
+ <div className="relative">
297
+ <button
298
+ className="text-gray-1 flex items-center gap-1 p-0 text-xs"
299
+ onClick={() => {
300
+ navigator.clipboard.writeText(field.rawValue!);
301
+ setShowCopiedHint(true);
302
+ setTimeout(() => setShowCopiedHint(false), 2000);
303
+ }}
304
+ >
305
+ <Copy strokeWidth={1} className="h-3 w-3" /> Copy
306
+ </button>
307
+ {showCopiedHint && (
308
+ <div
309
+ className="absolute -top-8 left-1/2 animate-pulse rounded bg-gray-800 px-2 py-1 text-xs whitespace-nowrap text-white shadow-lg"
310
+ style={{
311
+ animation: "fadeOut 2s ease-out forwards",
312
+ transform: "translateX(calc(-50% + 15px))",
313
+ }}
314
+ >
315
+ Copied!
316
+ </div>
317
+ )}
318
+ </div>
319
+ )}
292
320
  <div className="ml-auto flex items-center gap-1">
293
321
  <SimpleIconButton
294
322
  icon="pi pi-comment"
@@ -45,7 +45,7 @@ export function ImageEditButton({
45
45
 
46
46
  const defaultTriggerButton = (
47
47
  <button
48
- className={`text-dark border-gray-3 hover:bg-gray-5 absolute right-2 bottom-2 flex items-center justify-center gap-2 border bg-white p-2 opacity-70 shadow-lg transition-opacity hover:opacity-85 ${buttonClassName || ""}`}
48
+ className={`text-dark border-gray-3 hover:bg-gray-5 absolute right-2 bottom-2 flex items-center justify-center gap-2 rounded border bg-white p-1.5 text-xs font-medium opacity-70 shadow-lg transition-opacity hover:opacity-85 ${buttonClassName || ""}`}
49
49
  onClick={(e) => {
50
50
  e.stopPropagation();
51
51
  }}
@@ -78,7 +78,8 @@ export default function MainLayout(props: MainLayoutProps) {
78
78
  {!props.view.hideViewSelector && <LeftToolbar />}
79
79
  <div className="flex flex-1 flex-col">
80
80
  {editContext?.view?.titlebar}
81
- {editContext?.view?.toolbar}
81
+ {editContext?.view?.toolbarFactory &&
82
+ editContext?.view?.toolbarFactory(editContext)}
82
83
  <div className="bg-gray-4 flex-1">
83
84
  <Splitter
84
85
  splitterClassName="bg-transparent -mr-2 md:w-[8px]"
@@ -2,12 +2,14 @@ import { useEditContext } from "../client/editContext";
2
2
 
3
3
  export function ApproveAndPublishButton() {
4
4
  const editContext = useEditContext();
5
+ console.log("USER", editContext?.user);
6
+ if (editContext?.user?.isLimitedPreviewUser) return null;
5
7
  return (
6
8
  <div
7
- className="bg-alpaca-blue hover:bg-alpaca-blue-light text-white p-4 cursor-pointer text-sm rounded-l-full"
9
+ className="bg-alpaca-blue hover:bg-alpaca-blue-light cursor-pointer rounded-l-full p-4 text-sm text-white"
8
10
  onClick={() => {
9
11
  const workboxView = editContext?.configuration.editor.views.find(
10
- (x) => x.name == "workbox"
12
+ (x) => x.name == "workbox",
11
13
  );
12
14
  if (workboxView) editContext?.switchView(workboxView.name);
13
15
  }}
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { Separator } from "./Separator";
3
+
4
+ export interface ToolbarSection {
5
+ key: string;
6
+ component: React.ReactNode;
7
+ }
8
+
9
+ export interface GenericToolbarProps {
10
+ left?: ToolbarSection[];
11
+ center?: ToolbarSection[];
12
+ right?: ToolbarSection[];
13
+ }
14
+
15
+ export function GenericToolbar({
16
+ left = [],
17
+ center = [],
18
+ right = [],
19
+ }: GenericToolbarProps) {
20
+ const renderSections = (sections: ToolbarSection[]) => {
21
+ return sections.map((section, index) => (
22
+ <React.Fragment key={section.key}>
23
+ {index > 0 && <Separator size="large" />}
24
+ {section.component}
25
+ </React.Fragment>
26
+ ));
27
+ };
28
+
29
+ return (
30
+ <div className="flex items-center justify-between gap-2 border-b px-4 py-2">
31
+ {/* Left section */}
32
+ <div className="flex items-center gap-2">{renderSections(left)}</div>
33
+
34
+ {/* Center section */}
35
+ {center.length > 0 && (
36
+ <div className="flex items-center gap-2">{renderSections(center)}</div>
37
+ )}
38
+
39
+ {/* Right section */}
40
+ <div className="flex items-center gap-2">{renderSections(right)}</div>
41
+ </div>
42
+ );
43
+ }
@@ -0,0 +1,24 @@
1
+ import { useEditContext } from "../client/editContext";
2
+ import { CompareIcon } from "../ui/Icons";
3
+ import { SimpleIconButton } from "../ui/SimpleIconButton";
4
+
5
+ export function ItemToolbar() {
6
+ const editContext = useEditContext();
7
+
8
+ if (!editContext) return null;
9
+
10
+ return (
11
+ <div className="flex items-center justify-center gap-2 border-b px-4 py-2">
12
+ <SimpleIconButton
13
+ icon={<CompareIcon className="h-6 w-6 p-1" />}
14
+ label="Compare"
15
+ size="large"
16
+ className={
17
+ editContext.compareMode ? "text-gray-600" : "hover:text-gray-600"
18
+ }
19
+ selected={editContext.compareMode}
20
+ onClick={() => editContext.setCompareMode(!editContext.compareMode)}
21
+ />
22
+ </div>
23
+ );
24
+ }
@@ -0,0 +1,154 @@
1
+ import { useEditContext } from "../client/editContext";
2
+ import { Separator } from "./Separator";
3
+ import { CompareIcon } from "../ui/Icons";
4
+ import { SimpleIconButton } from "../ui/SimpleIconButton";
5
+ import {
6
+ EyeIcon,
7
+ MessagesSquare,
8
+ Pencil,
9
+ Monitor,
10
+ Smartphone,
11
+ Table,
12
+ Plus,
13
+ Layers,
14
+ } from "lucide-react";
15
+ import { EnterFullScreenIcon } from "@radix-ui/react-icons";
16
+
17
+ export function PageToolbar() {
18
+ const editContext = useEditContext();
19
+
20
+ if (!editContext) return null;
21
+
22
+ const pageViewContext = editContext.pageView;
23
+
24
+ const device = pageViewContext.device;
25
+ const setDevice = pageViewContext.setDevice;
26
+
27
+ // Insert mode logic
28
+ const insertMode = editContext.insertMode;
29
+
30
+ const toggleInsertMode = () => {
31
+ editContext.setInsertMode(true);
32
+ };
33
+
34
+ // Calculate total count of comments and suggestions
35
+ const commentsCount =
36
+ editContext.comments?.filter((x) => !x.isResolved).length || 0;
37
+ const suggestionsCount =
38
+ editContext.suggestedEdits?.filter((x) => x.status === "pending").length ||
39
+ 0;
40
+ const totalCount = commentsCount + suggestionsCount;
41
+
42
+ return (
43
+ <div className="flex items-center justify-between gap-2 border-b px-4 py-2">
44
+ <div className="flex items-center gap-2">
45
+ {!editContext.user?.isLimitedPreviewUser && (
46
+ <SimpleIconButton
47
+ icon={<Pencil className="h-6 w-6 p-1" strokeWidth={1} />}
48
+ label="Edit"
49
+ size="large"
50
+ selected={editContext.mode === "edit"}
51
+ onClick={() => editContext.setMode("edit")}
52
+ />
53
+ )}
54
+
55
+ <SimpleIconButton
56
+ icon={<EyeIcon className="h-6 w-6 p-1" strokeWidth={1} />}
57
+ label="Preview"
58
+ size="large"
59
+ selected={editContext.mode === "preview"}
60
+ onClick={() => editContext.setMode("preview")}
61
+ />
62
+
63
+ <div className="relative">
64
+ <SimpleIconButton
65
+ selected={editContext?.mode === "suggestions"}
66
+ icon={<MessagesSquare strokeWidth={1} className="h-6 w-6 p-1" />}
67
+ label="Write suggestions"
68
+ size="large"
69
+ onClick={() => editContext?.setMode("suggestions")}
70
+ />
71
+ {totalCount > 0 && (
72
+ <div className="bg-theme-secondary text-3xs absolute -top-1 -right-1 flex h-[16px] min-w-[16px] items-center justify-center rounded-full px-1 text-white">
73
+ {totalCount > 99 ? "99+" : totalCount}
74
+ </div>
75
+ )}
76
+ </div>
77
+ <Separator size="large" />
78
+ <SimpleIconButton
79
+ icon={<Plus className="h-6 w-6 p-1" strokeWidth={1} />}
80
+ label="Add Component"
81
+ size="large"
82
+ selected={insertMode}
83
+ onClick={toggleInsertMode}
84
+ disabled={
85
+ !editContext.page?.item.canWriteItem || editContext.mode !== "edit"
86
+ }
87
+ />
88
+ </div>
89
+ {!editContext.isMobile && (
90
+ <div className="flex items-center gap-2">
91
+ <SimpleIconButton
92
+ icon={<Monitor className="h-6 w-6 p-1" strokeWidth={1} />}
93
+ label="Desktop"
94
+ size="large"
95
+ selected={device === "desktop"}
96
+ onClick={() => setDevice("desktop")}
97
+ />
98
+ <SimpleIconButton
99
+ icon={<Smartphone className="h-6 w-6 p-1" strokeWidth={1} />}
100
+ label="Mobile"
101
+ size="large"
102
+ selected={Boolean(device && device !== "desktop")}
103
+ onClick={() => {
104
+ if (editContext.configuration.devices[0]) {
105
+ setDevice(editContext.configuration.devices[0].name);
106
+ }
107
+ }}
108
+ />
109
+ <SimpleIconButton
110
+ icon={<Table className="h-6 w-6 p-1" strokeWidth={1} />}
111
+ label="Form"
112
+ size="large"
113
+ selected={!device}
114
+ onClick={() => setDevice("")}
115
+ />
116
+ <Separator size="large" />
117
+ {!editContext.isMobile && (
118
+ <SimpleIconButton
119
+ icon={<CompareIcon className="h-6 w-6 p-1" />}
120
+ label="Compare"
121
+ size="large"
122
+ className={
123
+ editContext.compareMode
124
+ ? "text-gray-600"
125
+ : "hover:text-gray-600"
126
+ }
127
+ selected={editContext.compareMode}
128
+ onClick={() =>
129
+ editContext.setCompareMode(!editContext.compareMode)
130
+ }
131
+ />
132
+ )}
133
+ </div>
134
+ )}
135
+ <div className="flex items-center gap-2">
136
+ <SimpleIconButton
137
+ icon={<EnterFullScreenIcon className="h-6 w-6 p-1" />}
138
+ label="Fullscreen"
139
+ size="large"
140
+ onClick={() => pageViewContext.setFullscreen(true)}
141
+ />
142
+ <SimpleIconButton
143
+ icon={<Layers className="h-6 w-6 p-1" strokeWidth={1} />}
144
+ label="Component Navigator"
145
+ size="large"
146
+ selected={editContext.showRightSidebar}
147
+ onClick={() =>
148
+ editContext.setShowRightSidebar(!editContext.showRightSidebar)
149
+ }
150
+ />
151
+ </div>
152
+ </div>
153
+ );
154
+ }
@@ -1,168 +1,10 @@
1
1
  import { useEditContext } from "../client/editContext";
2
- import { Separator } from "./Separator";
3
- import { CompareIcon, FormEditIcon } from "../ui/Icons";
4
- import { SimpleIconButton } from "../ui/SimpleIconButton";
5
- import {
6
- EyeIcon,
7
- MessagesSquare,
8
- Pencil,
9
- Monitor,
10
- Smartphone,
11
- Table,
12
- Plus,
13
- Layers,
14
- } from "lucide-react";
15
- import { EnterFullScreenIcon } from "@radix-ui/react-icons";
2
+ import { createEditToolbar } from "./ToolbarFactory";
16
3
 
17
4
  export function PageViewerControls() {
18
5
  const editContext = useEditContext();
19
6
 
20
7
  if (!editContext) return null;
21
8
 
22
- const hasLayout = editContext.contentEditorItem?.hasLayout;
23
-
24
- const pageViewContext = editContext.pageView;
25
-
26
- const device = pageViewContext.device;
27
- const setDevice = pageViewContext.setDevice;
28
-
29
- // Insert mode logic
30
- const insertMode = editContext.insertMode;
31
-
32
- const toggleInsertMode = () => {
33
- editContext.setInsertMode(true);
34
- };
35
-
36
- // Calculate total count of comments and suggestions
37
- const commentsCount =
38
- editContext.comments?.filter((x) => !x.isResolved).length || 0;
39
- const suggestionsCount =
40
- editContext.suggestedEdits?.filter((x) => x.status === "pending").length ||
41
- 0;
42
- const totalCount = commentsCount + suggestionsCount;
43
-
44
- return (
45
- <div className="flex items-center justify-between gap-2 border-b px-4 py-2">
46
- {hasLayout && (
47
- <>
48
- <div className="flex items-center gap-2">
49
- {!editContext.user?.isLimitedPreviewUser && (
50
- <SimpleIconButton
51
- icon={<Pencil className="h-6 w-6 p-1" strokeWidth={1} />}
52
- label="Edit"
53
- size="large"
54
- selected={editContext.mode === "edit"}
55
- onClick={() => editContext.setMode("edit")}
56
- />
57
- )}
58
-
59
- <SimpleIconButton
60
- icon={<EyeIcon className="h-6 w-6 p-1" strokeWidth={1} />}
61
- label="Preview"
62
- size="large"
63
- selected={editContext.mode === "preview"}
64
- onClick={() => editContext.setMode("preview")}
65
- />
66
-
67
- <div className="relative">
68
- <SimpleIconButton
69
- selected={editContext?.mode === "suggestions"}
70
- icon={
71
- <MessagesSquare strokeWidth={1} className="h-6 w-6 p-1" />
72
- }
73
- label="Write suggestions"
74
- size="large"
75
- onClick={() => editContext?.setMode("suggestions")}
76
- />
77
- {totalCount > 0 && (
78
- <div className="bg-theme-secondary text-3xs absolute -top-1 -right-1 flex h-[16px] min-w-[16px] items-center justify-center rounded-full px-1 text-white">
79
- {totalCount > 99 ? "99+" : totalCount}
80
- </div>
81
- )}
82
- </div>
83
- <Separator size="large" />
84
- <SimpleIconButton
85
- icon={<Plus className="h-6 w-6 p-1" strokeWidth={1} />}
86
- label="Add Component"
87
- size="large"
88
- selected={insertMode}
89
- onClick={toggleInsertMode}
90
- disabled={
91
- !editContext.page?.item.canWriteItem ||
92
- editContext.mode !== "edit"
93
- }
94
- />
95
- </div>
96
- {!editContext.isMobile && (
97
- <div className="flex items-center gap-2">
98
- <SimpleIconButton
99
- icon={<Monitor className="h-6 w-6 p-1" strokeWidth={1} />}
100
- label="Desktop"
101
- size="large"
102
- selected={device === "desktop"}
103
- onClick={() => setDevice("desktop")}
104
- />
105
- <SimpleIconButton
106
- icon={<Smartphone className="h-6 w-6 p-1" strokeWidth={1} />}
107
- label="Mobile"
108
- size="large"
109
- selected={Boolean(device && device !== "desktop")}
110
- onClick={() => {
111
- if (editContext.configuration.devices[0]) {
112
- setDevice(editContext.configuration.devices[0].name);
113
- }
114
- }}
115
- />
116
- <SimpleIconButton
117
- icon={<Table className="h-6 w-6 p-1" strokeWidth={1} />}
118
- label="Form"
119
- size="large"
120
- selected={!device}
121
- onClick={() => setDevice("")}
122
- />
123
- <Separator size="large" />
124
- {!editContext.isMobile && (
125
- <SimpleIconButton
126
- icon={<CompareIcon className="h-6 w-6 p-1" />}
127
- label="Compare"
128
- size="large"
129
- className={
130
- editContext.compareMode
131
- ? "text-gray-600"
132
- : "hover:text-gray-600"
133
- }
134
- selected={editContext.compareMode}
135
- onClick={() =>
136
- editContext.setCompareMode(!editContext.compareMode)
137
- }
138
- />
139
- )}
140
- </div>
141
- )}
142
- {/* <i
143
- className="pi pi-external-link cursor-pointer rounded-full p-2 text-gray-400 hover:bg-gray-200 hover:text-gray-800"
144
- title="Fullscreen"
145
- onClick={() => pageViewContext.setFullscreen(true)}
146
- /> */}
147
- <div className="flex items-center gap-2">
148
- <SimpleIconButton
149
- icon={<EnterFullScreenIcon className="h-6 w-6 p-1" />}
150
- label="Fullscreen"
151
- size="large"
152
- onClick={() => pageViewContext.setFullscreen(true)}
153
- />
154
- <SimpleIconButton
155
- icon={<Layers className="h-6 w-6 p-1" strokeWidth={1} />}
156
- label="Component Navigator"
157
- size="large"
158
- selected={editContext.showRightSidebar}
159
- onClick={() =>
160
- editContext.setShowRightSidebar(!editContext.showRightSidebar)
161
- }
162
- />
163
- </div>
164
- </>
165
- )}
166
- </div>
167
- );
9
+ return createEditToolbar(editContext);
168
10
  }
@@ -0,0 +1,68 @@
1
+ import { EditContextType } from "../client/editContext";
2
+ import { GenericToolbar, ToolbarSection } from "./GenericToolbar";
3
+ import {
4
+ ReviewCommands,
5
+ EditControls,
6
+ InsertControls,
7
+ ViewportControls,
8
+ UtilityControls,
9
+ CompareControls,
10
+ } from "./toolbar-sections";
11
+
12
+ export function createEditToolbar(editContext: EditContextType) {
13
+ if (!editContext) return null;
14
+
15
+ const hasLayout = editContext.contentEditorItem?.hasLayout;
16
+ const isReviewsView = editContext.viewName === "reviews";
17
+
18
+ // For items without layout (simple content editor)
19
+ if (!hasLayout) {
20
+ const left: ToolbarSection[] = [
21
+ {
22
+ key: "compare",
23
+ component: <CompareControls />,
24
+ },
25
+ ];
26
+
27
+ return <GenericToolbar left={left} />;
28
+ }
29
+
30
+ // For pages with layout
31
+ const left: ToolbarSection[] = [];
32
+ const right: ToolbarSection[] = [];
33
+ const center: ToolbarSection[] = [];
34
+
35
+ // Add review commands if in reviews view
36
+
37
+ // Standard edit controls
38
+ left.push({
39
+ key: "edit-controls",
40
+ component: <EditControls />,
41
+ });
42
+ if (isReviewsView) {
43
+ left.push({
44
+ key: "review-commands",
45
+ component: <ReviewCommands />,
46
+ });
47
+ }
48
+
49
+ // Insert controls
50
+ left.push({
51
+ key: "insert-controls",
52
+ component: <InsertControls />,
53
+ });
54
+
55
+ // Viewport controls (desktop/mobile/form)
56
+ center.push({
57
+ key: "viewport-controls",
58
+ component: <ViewportControls />,
59
+ });
60
+
61
+ // Utility controls (compare, fullscreen, sidebar)
62
+ right.push({
63
+ key: "utility-controls",
64
+ component: <UtilityControls />,
65
+ });
66
+
67
+ return <GenericToolbar left={left} right={right} center={center} />;
68
+ }
@@ -11,6 +11,7 @@ export function WorkflowButton() {
11
11
  const editContext = useEditContext();
12
12
 
13
13
  if (!editContext?.currentItemDescriptor) return null;
14
+ if (editContext?.user?.isLimitedPreviewUser) return null;
14
15
 
15
16
  // Find the current item in workboxItems to get its workflow commands
16
17
  const currentWorkboxItem = editContext.workboxItems?.find(
@@ -0,0 +1,22 @@
1
+ import { useEditContext } from "../../client/editContext";
2
+ import { SimpleIconButton } from "../../ui/SimpleIconButton";
3
+ import { CompareIcon } from "../../ui/Icons";
4
+
5
+ export function CompareControls() {
6
+ const editContext = useEditContext();
7
+
8
+ if (!editContext) return null;
9
+
10
+ return (
11
+ <SimpleIconButton
12
+ icon={<CompareIcon className="h-6 w-6 p-1" />}
13
+ label="Compare"
14
+ size="large"
15
+ className={
16
+ editContext.compareMode ? "text-gray-600" : "hover:text-gray-600"
17
+ }
18
+ selected={editContext.compareMode}
19
+ onClick={() => editContext.setCompareMode(!editContext.compareMode)}
20
+ />
21
+ );
22
+ }
@@ -0,0 +1,54 @@
1
+ import { useEditContext } from "../../client/editContext";
2
+ import { SimpleIconButton } from "../../ui/SimpleIconButton";
3
+ import { EyeIcon, MessagesSquare, Pencil } from "lucide-react";
4
+
5
+ export function EditControls() {
6
+ const editContext = useEditContext();
7
+
8
+ if (!editContext) return null;
9
+
10
+ // Calculate total count of comments and suggestions
11
+ const commentsCount =
12
+ editContext.comments?.filter((x) => !x.isResolved).length || 0;
13
+ const suggestionsCount =
14
+ editContext.suggestedEdits?.filter((x) => x.status === "pending").length ||
15
+ 0;
16
+ const totalCount = commentsCount + suggestionsCount;
17
+
18
+ return (
19
+ <>
20
+ {!editContext.user?.isLimitedPreviewUser && (
21
+ <SimpleIconButton
22
+ icon={<Pencil className="h-6 w-6 p-1" strokeWidth={1} />}
23
+ label="Edit"
24
+ size="large"
25
+ selected={editContext.mode === "edit"}
26
+ onClick={() => editContext.setMode("edit")}
27
+ />
28
+ )}
29
+
30
+ <SimpleIconButton
31
+ icon={<EyeIcon className="h-6 w-6 p-1" strokeWidth={1} />}
32
+ label="Preview"
33
+ size="large"
34
+ selected={editContext.mode === "preview"}
35
+ onClick={() => editContext.setMode("preview")}
36
+ />
37
+
38
+ <div className="relative">
39
+ <SimpleIconButton
40
+ selected={editContext?.mode === "suggestions"}
41
+ icon={<MessagesSquare strokeWidth={1} className="h-6 w-6 p-1" />}
42
+ label="Write suggestions"
43
+ size="large"
44
+ onClick={() => editContext?.setMode("suggestions")}
45
+ />
46
+ {totalCount > 0 && (
47
+ <div className="bg-theme-secondary text-3xs absolute -top-1 -right-1 flex h-[16px] min-w-[16px] items-center justify-center rounded-full px-1 text-white">
48
+ {totalCount > 99 ? "99+" : totalCount}
49
+ </div>
50
+ )}
51
+ </div>
52
+ </>
53
+ );
54
+ }