@alpaca-editor/core 1.0.3955 → 1.0.3959

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 (247) hide show
  1. package/build.css +1 -1
  2. package/dist/components/ui/badge.d.ts +9 -0
  3. package/dist/components/ui/badge.js +23 -0
  4. package/dist/components/ui/badge.js.map +1 -0
  5. package/dist/components/ui/button.js +3 -3
  6. package/dist/components/ui/button.js.map +1 -1
  7. package/dist/components/ui/command.d.ts +18 -0
  8. package/dist/components/ui/command.js +35 -0
  9. package/dist/components/ui/command.js.map +1 -0
  10. package/dist/components/ui/dialog.d.ts +15 -0
  11. package/dist/components/ui/dialog.js +37 -0
  12. package/dist/components/ui/dialog.js.map +1 -0
  13. package/dist/components/ui/dropdown-menu.d.ts +25 -0
  14. package/dist/components/ui/dropdown-menu.js +52 -0
  15. package/dist/components/ui/dropdown-menu.js.map +1 -0
  16. package/dist/components/ui/input.d.ts +3 -0
  17. package/dist/components/ui/input.js +7 -0
  18. package/dist/components/ui/input.js.map +1 -0
  19. package/dist/components/ui/menubar.d.ts +26 -0
  20. package/dist/components/ui/menubar.js +55 -0
  21. package/dist/components/ui/menubar.js.map +1 -0
  22. package/dist/components/ui/popover.d.ts +9 -0
  23. package/dist/components/ui/popover.js +63 -0
  24. package/dist/components/ui/popover.js.map +1 -0
  25. package/dist/components/ui/switch.d.ts +4 -0
  26. package/dist/components/ui/switch.js +9 -0
  27. package/dist/components/ui/switch.js.map +1 -0
  28. package/dist/components/ui/tooltip.d.ts +7 -0
  29. package/dist/components/ui/tooltip.js +18 -0
  30. package/dist/components/ui/tooltip.js.map +1 -0
  31. package/dist/config/config.js +79 -63
  32. package/dist/config/config.js.map +1 -1
  33. package/dist/config/types.d.ts +3 -3
  34. package/dist/editor/ContentTree.js +1 -1
  35. package/dist/editor/ContentTree.js.map +1 -1
  36. package/dist/editor/Editor.js +6 -2
  37. package/dist/editor/Editor.js.map +1 -1
  38. package/dist/editor/FieldList.js +1 -1
  39. package/dist/editor/FieldList.js.map +1 -1
  40. package/dist/editor/FieldListField.js +1 -1
  41. package/dist/editor/FieldListField.js.map +1 -1
  42. package/dist/editor/ImageEditor.js +16 -6
  43. package/dist/editor/ImageEditor.js.map +1 -1
  44. package/dist/editor/MainLayout.js +4 -4
  45. package/dist/editor/MainLayout.js.map +1 -1
  46. package/dist/editor/MobileLayout.js +3 -3
  47. package/dist/editor/MobileLayout.js.map +1 -1
  48. package/dist/editor/PictureEditor.js +29 -15
  49. package/dist/editor/PictureEditor.js.map +1 -1
  50. package/dist/editor/Titlebar.js +6 -11
  51. package/dist/editor/Titlebar.js.map +1 -1
  52. package/dist/editor/ai/GhostWriter.js +1 -1
  53. package/dist/editor/ai/GhostWriter.js.map +1 -1
  54. package/dist/editor/client/EditorClient.d.ts +4 -2
  55. package/dist/editor/client/EditorClient.js +32 -11
  56. package/dist/editor/client/EditorClient.js.map +1 -1
  57. package/dist/editor/client/editContext.d.ts +4 -1
  58. package/dist/editor/client/editContext.js.map +1 -1
  59. package/dist/editor/client/operations.js +2 -2
  60. package/dist/editor/client/pageModelBuilder.js +3 -6
  61. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  62. package/dist/editor/commands/itemCommands.d.ts +2 -0
  63. package/dist/editor/commands/itemCommands.js +180 -0
  64. package/dist/editor/commands/itemCommands.js.map +1 -1
  65. package/dist/editor/field-types/MultiLineText.js +1 -1
  66. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  67. package/dist/editor/field-types/SingleLineText.js +1 -1
  68. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  69. package/dist/editor/menubar/ActiveUsers.js +98 -4
  70. package/dist/editor/menubar/ActiveUsers.js.map +1 -1
  71. package/dist/editor/menubar/{ActionsMenu.d.ts → ItemActionsMenu.d.ts} +1 -1
  72. package/dist/editor/menubar/ItemActionsMenu.js +23 -0
  73. package/dist/editor/menubar/ItemActionsMenu.js.map +1 -0
  74. package/dist/editor/menubar/ItemLanguageVersion.js +2 -2
  75. package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
  76. package/dist/editor/menubar/LanguageSelector.d.ts +1 -2
  77. package/dist/editor/menubar/LanguageSelector.js +23 -23
  78. package/dist/editor/menubar/LanguageSelector.js.map +1 -1
  79. package/dist/editor/menubar/PageSelector.js +7 -8
  80. package/dist/editor/menubar/PageSelector.js.map +1 -1
  81. package/dist/editor/menubar/PageViewerControls.js +22 -19
  82. package/dist/editor/menubar/PageViewerControls.js.map +1 -1
  83. package/dist/editor/menubar/PreviewSecondaryControls.js +2 -3
  84. package/dist/editor/menubar/PreviewSecondaryControls.js.map +1 -1
  85. package/dist/editor/menubar/User.js +1 -1
  86. package/dist/editor/menubar/User.js.map +1 -1
  87. package/dist/editor/menubar/VersionSelector.js +36 -31
  88. package/dist/editor/menubar/VersionSelector.js.map +1 -1
  89. package/dist/editor/menubar/WorkflowButton.d.ts +1 -0
  90. package/dist/editor/menubar/WorkflowButton.js +41 -0
  91. package/dist/editor/menubar/WorkflowButton.js.map +1 -0
  92. package/dist/editor/page-editor-chrome/FrameMenu.js +5 -5
  93. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  94. package/dist/editor/page-editor-chrome/SuggestionHighlightings.js +2 -2
  95. package/dist/editor/page-editor-chrome/SuggestionHighlightings.js.map +1 -1
  96. package/dist/editor/page-viewer/EditorForm.d.ts +2 -1
  97. package/dist/editor/page-viewer/EditorForm.js +61 -49
  98. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  99. package/dist/editor/page-viewer/PageViewer.d.ts +2 -1
  100. package/dist/editor/page-viewer/PageViewer.js +28 -44
  101. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  102. package/dist/editor/page-viewer/PageViewerFrame.js +1 -1
  103. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  104. package/dist/editor/reviews/Comments.js +9 -9
  105. package/dist/editor/reviews/Comments.js.map +1 -1
  106. package/dist/editor/reviews/SuggestedEdit.js +3 -3
  107. package/dist/editor/services/contentService.d.ts +18 -0
  108. package/dist/editor/services/contentService.js +6 -0
  109. package/dist/editor/services/contentService.js.map +1 -1
  110. package/dist/editor/services/editService.d.ts +5 -0
  111. package/dist/editor/services/editService.js +4 -0
  112. package/dist/editor/services/editService.js.map +1 -1
  113. package/dist/editor/services/systemService.d.ts +2 -1
  114. package/dist/editor/services/systemService.js +4 -1
  115. package/dist/editor/services/systemService.js.map +1 -1
  116. package/dist/editor/sidebar/ComponentTree.js +26 -10
  117. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  118. package/dist/editor/sidebar/Divider.d.ts +6 -0
  119. package/dist/editor/sidebar/Divider.js +6 -0
  120. package/dist/editor/sidebar/Divider.js.map +1 -0
  121. package/dist/editor/sidebar/LeftToolbar.d.ts +1 -0
  122. package/dist/editor/sidebar/LeftToolbar.js +16 -0
  123. package/dist/editor/sidebar/LeftToolbar.js.map +1 -0
  124. package/dist/editor/sidebar/SEOInfo.d.ts +1 -0
  125. package/dist/editor/sidebar/SEOInfo.js +169 -0
  126. package/dist/editor/sidebar/SEOInfo.js.map +1 -0
  127. package/dist/editor/sidebar/Sidebar.js +1 -1
  128. package/dist/editor/sidebar/Sidebar.js.map +1 -1
  129. package/dist/editor/sidebar/SidebarView.d.ts +3 -2
  130. package/dist/editor/sidebar/SidebarView.js +22 -60
  131. package/dist/editor/sidebar/SidebarView.js.map +1 -1
  132. package/dist/editor/sidebar/ViewSelector.js +66 -20
  133. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  134. package/dist/editor/ui/Icons.d.ts +4 -0
  135. package/dist/editor/ui/Icons.js +15 -3
  136. package/dist/editor/ui/Icons.js.map +1 -1
  137. package/dist/editor/ui/Section.js +1 -1
  138. package/dist/editor/ui/Section.js.map +1 -1
  139. package/dist/editor/ui/SimpleIconButton.d.ts +1 -2
  140. package/dist/editor/ui/SimpleIconButton.js +8 -13
  141. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  142. package/dist/editor/ui/SimpleTabs.js +2 -2
  143. package/dist/editor/ui/SimpleTabs.js.map +1 -1
  144. package/dist/editor/ui/SimpleToolbar.js +1 -1
  145. package/dist/editor/ui/SimpleToolbar.js.map +1 -1
  146. package/dist/editor/ui/Splitter.d.ts +4 -0
  147. package/dist/editor/ui/Splitter.js +6 -7
  148. package/dist/editor/ui/Splitter.js.map +1 -1
  149. package/dist/editor/views/CompareView.js +16 -4
  150. package/dist/editor/views/CompareView.js.map +1 -1
  151. package/dist/editor/views/SingleEditView.d.ts +2 -1
  152. package/dist/editor/views/SingleEditView.js +2 -2
  153. package/dist/editor/views/SingleEditView.js.map +1 -1
  154. package/dist/page-wizard/steps/ContentStep.js +1 -1
  155. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  156. package/dist/revision.d.ts +2 -2
  157. package/dist/revision.js +2 -2
  158. package/dist/splash-screen/NewPage.js +8 -6
  159. package/dist/splash-screen/NewPage.js.map +1 -1
  160. package/dist/splash-screen/RecentPages.js +3 -8
  161. package/dist/splash-screen/RecentPages.js.map +1 -1
  162. package/dist/styles.css +1519 -543
  163. package/dist/tour/Tour.js +79 -10
  164. package/dist/tour/Tour.js.map +1 -1
  165. package/dist/tour/default-tour.js +55 -45
  166. package/dist/tour/default-tour.js.map +1 -1
  167. package/dist/types.d.ts +19 -1
  168. package/package.json +13 -5
  169. package/src/components/ui/badge.tsx +46 -0
  170. package/src/components/ui/button.tsx +3 -3
  171. package/src/components/ui/command.tsx +184 -0
  172. package/src/components/ui/dialog.tsx +143 -0
  173. package/src/components/ui/dropdown-menu.tsx +257 -0
  174. package/src/components/ui/input.tsx +21 -0
  175. package/src/components/ui/menubar.tsx +276 -0
  176. package/src/components/ui/popover.tsx +113 -0
  177. package/src/components/ui/switch.tsx +31 -0
  178. package/src/components/ui/tooltip.tsx +61 -0
  179. package/src/config/config.tsx +102 -65
  180. package/src/config/types.ts +3 -3
  181. package/src/editor/ContentTree.tsx +1 -1
  182. package/src/editor/Editor.tsx +8 -2
  183. package/src/editor/FieldList.tsx +2 -2
  184. package/src/editor/FieldListField.tsx +1 -1
  185. package/src/editor/ImageEditor.tsx +44 -21
  186. package/src/editor/MainLayout.tsx +21 -16
  187. package/src/editor/MobileLayout.tsx +3 -2
  188. package/src/editor/PictureEditor.tsx +74 -45
  189. package/src/editor/Titlebar.tsx +12 -24
  190. package/src/editor/ai/GhostWriter.tsx +1 -1
  191. package/src/editor/client/EditorClient.tsx +55 -13
  192. package/src/editor/client/editContext.ts +5 -0
  193. package/src/editor/client/operations.ts +2 -2
  194. package/src/editor/client/pageModelBuilder.ts +3 -7
  195. package/src/editor/commands/itemCommands.tsx +272 -0
  196. package/src/editor/field-types/MultiLineText.tsx +1 -1
  197. package/src/editor/field-types/SingleLineText.tsx +1 -1
  198. package/src/editor/menubar/ActiveUsers.tsx +271 -5
  199. package/src/editor/menubar/ItemActionsMenu.tsx +89 -0
  200. package/src/editor/menubar/ItemLanguageVersion.tsx +7 -5
  201. package/src/editor/menubar/LanguageSelector.tsx +105 -134
  202. package/src/editor/menubar/PageSelector.tsx +25 -27
  203. package/src/editor/menubar/PageViewerControls.tsx +126 -78
  204. package/src/editor/menubar/PreviewSecondaryControls.tsx +0 -2
  205. package/src/editor/menubar/User.tsx +2 -2
  206. package/src/editor/menubar/VersionSelector.tsx +124 -99
  207. package/src/editor/menubar/WorkflowButton.tsx +115 -0
  208. package/src/editor/page-editor-chrome/FrameMenu.tsx +5 -5
  209. package/src/editor/page-editor-chrome/SuggestionHighlightings.tsx +2 -2
  210. package/src/editor/page-viewer/EditorForm.tsx +112 -87
  211. package/src/editor/page-viewer/PageViewer.tsx +75 -92
  212. package/src/editor/page-viewer/PageViewerFrame.tsx +1 -1
  213. package/src/editor/reviews/Comments.tsx +19 -20
  214. package/src/editor/reviews/SuggestedEdit.tsx +3 -3
  215. package/src/editor/services/contentService.ts +28 -0
  216. package/src/editor/services/editService.ts +12 -0
  217. package/src/editor/services/systemService.ts +5 -2
  218. package/src/editor/sidebar/ComponentTree.tsx +34 -12
  219. package/src/editor/sidebar/Divider.tsx +22 -0
  220. package/src/editor/sidebar/LeftToolbar.tsx +36 -0
  221. package/src/editor/sidebar/SEOInfo.tsx +265 -0
  222. package/src/editor/sidebar/Sidebar.tsx +1 -0
  223. package/src/editor/sidebar/SidebarView.tsx +77 -111
  224. package/src/editor/sidebar/ViewSelector.tsx +211 -43
  225. package/src/editor/ui/Icons.tsx +155 -10
  226. package/src/editor/ui/Section.tsx +1 -1
  227. package/src/editor/ui/SimpleIconButton.tsx +30 -28
  228. package/src/editor/ui/SimpleTabs.tsx +3 -3
  229. package/src/editor/ui/SimpleToolbar.tsx +1 -1
  230. package/src/editor/ui/Splitter.tsx +14 -7
  231. package/src/editor/views/CompareView.tsx +23 -11
  232. package/src/editor/views/SingleEditView.tsx +3 -0
  233. package/src/page-wizard/steps/ContentStep.tsx +0 -1
  234. package/src/revision.ts +2 -2
  235. package/src/splash-screen/NewPage.tsx +18 -13
  236. package/src/splash-screen/RecentPages.tsx +4 -10
  237. package/src/tour/Tour.tsx +125 -34
  238. package/src/tour/default-tour.tsx +55 -45
  239. package/src/types.ts +21 -1
  240. package/styles.css +301 -1
  241. package/dist/editor/menubar/ActionsMenu.js +0 -49
  242. package/dist/editor/menubar/ActionsMenu.js.map +0 -1
  243. package/dist/editor/menubar/SecondaryControls.d.ts +0 -1
  244. package/dist/editor/menubar/SecondaryControls.js +0 -17
  245. package/dist/editor/menubar/SecondaryControls.js.map +0 -1
  246. package/src/editor/menubar/ActionsMenu.tsx +0 -94
  247. package/src/editor/menubar/SecondaryControls.tsx +0 -45
@@ -1,44 +1,22 @@
1
- import "allotment/dist/style.css";
2
- import { Allotment, AllotmentHandle } from "allotment";
3
-
4
- import { useEffect, useRef, useState } from "react";
5
1
  import { EditContextType } from "../client/editContext";
6
2
  import { classNames } from "primereact/utils";
7
3
  import { Sidebar } from "../../config/types";
4
+ import { Splitter, SplitterPanel } from "../ui/Splitter";
5
+ import { cn } from "../../lib/utils";
8
6
 
9
7
  export function SidebarView({
10
8
  sidebar,
11
9
  editContext,
12
10
  active,
11
+ onClose,
12
+ detached,
13
13
  }: {
14
14
  sidebar: Sidebar;
15
15
  editContext: EditContextType;
16
16
  active: boolean;
17
+ onClose: () => void;
18
+ detached?: boolean;
17
19
  }) {
18
- const splitter = useRef<AllotmentHandle>(null);
19
-
20
- const [sizes, setSizes] = useState<number[]>([]);
21
- const [preferredSizes, setPreferredSizes] = useState<number[] | undefined>(
22
- undefined,
23
- );
24
- const [panelsExpanded, setPanelsExpanded] = useState<boolean[]>([]);
25
- const [sizeToSet, setSizeToSet] = useState<number[] | undefined>();
26
-
27
- const panelHeaderSize = 40;
28
- const toggle = (panelIndex: number) => {
29
- const newSize = panelsExpanded[panelIndex]
30
- ? panelHeaderSize
31
- : (preferredSizes || sizes)[panelIndex];
32
-
33
- if (newSize) resizePanel(panelIndex, newSize);
34
-
35
- setPanelsExpanded((x) => {
36
- const newState = [...x];
37
- newState[panelIndex] = !newState[panelIndex];
38
- return newState;
39
- });
40
- };
41
-
42
20
  const resolvedPanels = sidebar.panels.map((x) => {
43
21
  if (typeof x === "function") {
44
22
  return x(editContext!);
@@ -46,107 +24,95 @@ export function SidebarView({
46
24
  return x;
47
25
  });
48
26
 
49
- useEffect(() => {
50
- setPanelsExpanded(sidebar.panels.map(() => true));
51
- setPreferredSizes(() => resolvedPanels.map((x) => x.initialSize));
52
- }, [sidebar]);
53
-
54
- const resizePanel = (panelIndex: number, newSize: number) => {
55
- const totalSize = sizes.reduce((a, b) => a + b, 0);
56
- const totalOther = totalSize - sizes[panelIndex]!;
57
- const tmpSizes = [...sizes];
58
- tmpSizes[panelIndex] = newSize;
59
- const percentages = tmpSizes.map((x) => x / totalOther);
60
- percentages[panelIndex] = 0;
61
- const remaining = totalSize - newSize;
62
- const newSizes = percentages.map((x) => x * remaining);
63
- newSizes[panelIndex] = newSize;
64
- setSizes(newSizes);
65
-
66
- setSizeToSet(newSizes);
67
- };
68
-
69
- useEffect(() => {
70
- if (sizeToSet) splitter.current?.resize(sizeToSet);
71
- }, [sizeToSet]);
72
-
73
27
  const getHeader = (panel: any, index: number) => {
74
28
  if (panel.header) return panel.header({ panel, index });
75
29
 
76
30
  return (
77
- <div
78
- className={classNames(
79
- "justify relative flex cursor-pointer items-center bg-gray-50 p-2.5 text-xs text-gray-500 uppercase",
80
- panelsExpanded[index] ? "border-b border-gray-200" : "",
81
- )}
82
- onClick={() => toggle(index)}
83
- >
31
+ <div className="border-gray-3 relative flex items-center border-b p-2.5 text-xs text-gray-500 uppercase">
84
32
  {panel.icon &&
85
33
  (typeof panel.icon === "string" ? (
86
34
  <i className={classNames(panel.icon, "pi mr-1.5")}></i>
87
35
  ) : (
88
- <div className="mr-2 h-4 w-4">{panel.icon}</div>
36
+ <div className="mr-2">{panel.icon}</div>
89
37
  ))}
90
38
  <div className="mr-auto">{panel.title}</div>
91
- <i
92
- className={classNames(
93
- panelsExpanded[index] ? "pi-chevron-up" : "pi-chevron-down",
94
- "pi text-sm",
95
- )}
96
- ></i>
39
+
40
+ {/* Close button - only show on the first panel */}
41
+ {index === 0 && (
42
+ <button
43
+ onClick={onClose}
44
+ className="hover:bg-gray-5 ml-2 flex h-6 w-6 items-center justify-center rounded"
45
+ >
46
+ <i className="pi pi-times text-sm"></i>
47
+ </button>
48
+ )}
97
49
  </div>
98
50
  );
99
51
  };
100
52
 
101
- const initalSizes = resolvedPanels.map((x) => x.initialSize);
102
-
103
- return (
104
- <div className={!active ? "hidden h-full" : "h-full"}>
105
- <Allotment
106
- vertical={true}
107
- snap={true}
108
- className={!active ? "hidden h-full" : "h-full"}
109
- ref={splitter}
110
- defaultSizes={initalSizes}
111
- onChange={(s) => {
112
- if (sizes.join(",") != s.join(",")) setSizes(s);
53
+ if (!active) {
54
+ return <div className="hidden h-full" />;
55
+ }
113
56
 
114
- const newPreferred = [...(preferredSizes || s)];
115
- s.forEach((x, i) => {
116
- if (x > panelHeaderSize) newPreferred[i] = x;
117
- });
57
+ // Single panel - no splitter needed
58
+ if (resolvedPanels.length === 1) {
59
+ const panel = resolvedPanels[0];
60
+ if (!panel) return <div className="hidden h-full" />;
118
61
 
119
- setPreferredSizes(newPreferred);
120
- }}
121
- >
122
- {resolvedPanels.map((panel, index) => (
123
- <Allotment.Pane
124
- key={index}
125
- // preferredSize={(preferredSizes || initalSizes)[index] + "%"}
126
- maxSize={
127
- panelsExpanded.length <= index || panelsExpanded[index]
128
- ? 10000
129
- : panelHeaderSize
130
- }
131
- >
132
- <div className="flex h-full flex-col">
133
- {getHeader(panel, index)}
134
- {panelsExpanded[index] && (
135
- <div className="relative flex-1 overflow-hidden">
136
- <div
137
- className={classNames(
138
- "absolute inset-0",
139
- panel.noOverflow ? "" : "overflow-y-auto",
140
- )}
141
- >
142
- {panel.content}
143
- </div>
144
- </div>
62
+ return (
63
+ <div className={cn("h-full", detached ? "border-gray-3 border p-2" : "")}>
64
+ <div
65
+ className={cn(
66
+ "flex h-full flex-col bg-white",
67
+ detached ? "rounded-xl" : "",
68
+ )}
69
+ >
70
+ {getHeader(panel, 0)}
71
+ <div className="relative flex-1 overflow-hidden">
72
+ <div
73
+ className={classNames(
74
+ "absolute inset-0",
75
+ panel.noOverflow ? "" : "overflow-y-auto",
145
76
  )}
77
+ >
78
+ {panel.content}
146
79
  </div>
147
- </Allotment.Pane>
148
- ))}
149
- </Allotment>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ );
84
+ }
85
+
86
+ // Multiple panels - use existing Splitter component
87
+ const splitterPanels: SplitterPanel[] = resolvedPanels.map(
88
+ (panel, index) => ({
89
+ name: `panel-${index}`,
90
+ defaultSize: index === 0 ? panel.initialSize || 300 : "auto",
91
+ content: (
92
+ <div className="flex h-full flex-col bg-white">
93
+ {getHeader(panel, index)}
94
+ <div className="relative flex-1 overflow-hidden">
95
+ <div
96
+ className={classNames(
97
+ "absolute inset-0",
98
+ panel.noOverflow ? "" : "overflow-y-auto",
99
+ )}
100
+ >
101
+ {panel.content}
102
+ </div>
103
+ </div>
104
+ </div>
105
+ ),
106
+ }),
107
+ );
108
+
109
+ return (
110
+ <div className={cn("h-full", detached ? "p-2" : "")}>
111
+ <Splitter
112
+ panels={splitterPanels}
113
+ direction="vertical"
114
+ localStorageKey={`sidebar-${sidebar.panels.length}-panels`}
115
+ />
150
116
  </div>
151
117
  );
152
118
  }
@@ -1,60 +1,228 @@
1
- import React from "react";
1
+ import React, { useState, useMemo } from "react";
2
2
  import { classNames } from "primereact/utils";
3
3
 
4
4
  import { useEditContext } from "../client/editContext";
5
5
  import { cn } from "../../lib/utils";
6
+ import { VerticalDotsIcon, ViewToggleIcon } from "../ui/Icons";
7
+ import {
8
+ Popover,
9
+ PopoverContent,
10
+ PopoverTrigger,
11
+ } from "../../components/ui/popover";
12
+ import { Button } from "../../components/ui/button";
13
+ import {
14
+ Tooltip,
15
+ TooltipContent,
16
+ TooltipProvider,
17
+ TooltipTrigger,
18
+ } from "../../components/ui/tooltip";
19
+ import { DrawingPinFilledIcon, DrawingPinIcon } from "@radix-ui/react-icons";
6
20
 
7
21
  export function ViewSelector() {
8
22
  const editContext = useEditContext();
9
23
  const userViews = editContext?.userInfo.views;
10
24
 
11
- const views =
12
- editContext?.configuration.editor.views
13
- .filter(
14
- (x) =>
15
- (x.visible && x.visible(editContext)) || (!x.visible && !x.hidden),
16
- )
17
- .filter(
18
- (x) =>
19
- !userViews || userViews.map((view) => view.name).includes(x.name),
20
- ) ?? [];
25
+ // Get values directly from editContext, with fallbacks
26
+ const pinnedViews =
27
+ editContext?.userInfo.preferences?.pinnedViews ||
28
+ editContext?.configuration.editor.defaultPinnedViews ||
29
+ [];
30
+
31
+ const showViewNames =
32
+ editContext?.userInfo.preferences?.showViewNames ?? false;
33
+
34
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
35
+
36
+ const views = useMemo(() => {
37
+ return (
38
+ editContext?.configuration.editor.views
39
+ .filter(
40
+ (x) =>
41
+ (x.visible && x.visible(editContext)) || (!x.visible && !x.hidden),
42
+ )
43
+ .filter(
44
+ (x) =>
45
+ !userViews || userViews.map((view) => view.name).includes(x.name),
46
+ ) ?? []
47
+ );
48
+ }, [editContext, userViews]);
49
+
50
+ const { visibleViews } = useMemo(() => {
51
+ const visible = views.filter(
52
+ (view) =>
53
+ // Always show selected view
54
+ view.name === editContext?.viewName ||
55
+ // Show pinned views
56
+ pinnedViews.includes(view.name),
57
+ );
58
+
59
+ return { visibleViews: visible };
60
+ }, [views, pinnedViews, editContext?.viewName]);
61
+
62
+ const togglePin = (viewName: string) => {
63
+ const newPinnedViews = pinnedViews.includes(viewName)
64
+ ? pinnedViews.filter((name) => name !== viewName)
65
+ : [...pinnedViews, viewName];
66
+
67
+ // Save to user preferences via editContext
68
+ editContext?.setUserPreferences({ pinnedViews: newPinnedViews });
69
+ };
70
+
71
+ const toggleShowNames = () => {
72
+ const newShowNames = !showViewNames;
73
+ // Save to user preferences via editContext
74
+ editContext?.setUserPreferences({ showViewNames: newShowNames });
75
+ };
76
+
77
+ const renderViewIcon = (view: any, additionalClassName?: string) => {
78
+ if (view.icon && React.isValidElement(view.icon)) {
79
+ return React.cloneElement(view.icon as React.ReactElement<any>, {
80
+ className: cn("w-5 h-5", additionalClassName),
81
+ });
82
+ }
83
+ return null;
84
+ };
21
85
 
22
86
  return (
23
- <div
24
- className={cn(
25
- "z-10 flex items-center gap-3 bg-neutral-200 p-2 shadow-md",
26
- editContext?.isMobile
27
- ? "scrollbar-hide flex-row overflow-x-auto"
28
- : "max-w-11 flex-col",
29
- )}
30
- >
31
- {views
87
+ <TooltipProvider>
88
+ {/* Visible views (pinned + selected) */}
89
+ {visibleViews
32
90
  .filter((x) => x.icon)
33
- .map((x, i) => (
34
- <div
35
- title={x.title}
36
- key={i}
37
- className={classNames(
38
- editContext?.viewName == x.name
39
- ? "active bg-neutral-350 rounded-sm text-neutral-800"
40
- : "text-neutral-500 hover:text-gray-900",
41
- "cursor-pointer p-1.5",
91
+ .map((view, i) => (
92
+ <Tooltip key={`visible-${i}`}>
93
+ <TooltipTrigger asChild>
94
+ <div
95
+ className={classNames(
96
+ editContext?.viewName === view.name
97
+ ? "active bg-theme-secondary-light text-theme-secondary rounded-sm"
98
+ : "text-dark hover:bg-gray-5",
99
+ "relative flex cursor-pointer flex-col items-center justify-center",
100
+ showViewNames ? "p-1" : "p-1.5",
101
+ editContext?.isMobile ? "flex-shrink-0" : "",
102
+ )}
103
+ data-sidebarview-name={view.name}
104
+ onClick={() => {
105
+ if (view.name !== editContext?.viewName) {
106
+ editContext?.switchView(view.name);
107
+ }
108
+ }}
109
+ >
110
+ <div className={showViewNames ? "p-0.5" : ""}>
111
+ {renderViewIcon(view)}
112
+ </div>
113
+ {showViewNames && (
114
+ <span className="mt-1 max-w-[60px] text-center text-xs leading-tight break-words">
115
+ {view.title || view.name}
116
+ </span>
117
+ )}
118
+ </div>
119
+ </TooltipTrigger>
120
+ <TooltipContent side="right">
121
+ {view.title || view.name}
122
+ </TooltipContent>
123
+ </Tooltip>
124
+ ))}
125
+
126
+ {/* Three dots menu for non-selected views */}
127
+ {views.length > 0 && (
128
+ <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
129
+ <Tooltip>
130
+ <TooltipTrigger asChild>
131
+ <PopoverTrigger asChild>
132
+ <Button
133
+ variant="ghost"
134
+ size="icon"
135
+ className={cn(
136
+ "p-1.5 text-neutral-500 hover:text-gray-900",
137
+ editContext?.isMobile ? "flex-shrink-0" : "",
138
+ )}
139
+ >
140
+ <VerticalDotsIcon />
141
+ </Button>
142
+ </PopoverTrigger>
143
+ </TooltipTrigger>
144
+ <TooltipContent>More views</TooltipContent>
145
+ </Tooltip>
146
+ <PopoverContent
147
+ className="w-56 p-2"
148
+ side={editContext?.isMobile ? "bottom" : "right"}
149
+ align="start"
150
+ >
151
+ <div className="space-y-1">
152
+ <div className="px-2 py-1 text-xs font-medium tracking-wider text-gray-600 uppercase">
153
+ All Views
154
+ </div>
155
+ {views.map((view, i) => {
156
+ const isPinned = pinnedViews.includes(view.name);
157
+ return (
158
+ <div
159
+ key={`hidden-${i}`}
160
+ className="group flex cursor-pointer items-center justify-between rounded p-2 hover:bg-gray-100"
161
+ >
162
+ <div
163
+ className="flex flex-1 items-center gap-2"
164
+ onClick={() => {
165
+ editContext?.switchView(view.name);
166
+ setIsPopoverOpen(false);
167
+ }}
168
+ >
169
+ {renderViewIcon(view, "w-4 h-4")}
170
+ <span className="text-sm">{view.title || view.name}</span>
171
+ </div>
172
+ <Tooltip>
173
+ <TooltipTrigger asChild>
174
+ <Button
175
+ variant="ghost"
176
+ size="icon"
177
+ className={cn(
178
+ "h-6 w-6 transition-opacity",
179
+ isPinned
180
+ ? "opacity-100"
181
+ : "opacity-0 group-hover:opacity-100",
182
+ )}
183
+ onClick={(e) => {
184
+ e.stopPropagation();
185
+ togglePin(view.name);
186
+ }}
187
+ >
188
+ {isPinned ? (
189
+ <DrawingPinFilledIcon className="h-3 w-3" />
190
+ ) : (
191
+ <DrawingPinIcon className="h-3 w-3" />
192
+ )}
193
+ </Button>
194
+ </TooltipTrigger>
195
+ <TooltipContent>
196
+ {isPinned ? "Unpin view" : "Pin view"}
197
+ </TooltipContent>
198
+ </Tooltip>
199
+ </div>
200
+ );
201
+ })}
202
+ </div>
203
+ </PopoverContent>
204
+ </Popover>
205
+ )}
206
+
207
+ {/* Toggle for showing view names */}
208
+ <Tooltip>
209
+ <TooltipTrigger asChild>
210
+ <Button
211
+ variant="ghost"
212
+ size="icon"
213
+ className={cn(
214
+ "mt-auto p-1.5 text-neutral-500 hover:text-gray-900",
42
215
  editContext?.isMobile ? "flex-shrink-0" : "",
43
216
  )}
44
- data-sidebarview-name={x.name}
45
- onClick={() => {
46
- if (x.name !== editContext?.viewName) {
47
- editContext?.switchView(x.name);
48
- }
49
- }}
217
+ onClick={toggleShowNames}
50
218
  >
51
- {x.icon &&
52
- React.isValidElement(x.icon) &&
53
- React.cloneElement(x.icon as React.ReactElement<any>, {
54
- className: "w-5 h-5",
55
- })}
56
- </div>
57
- ))}
58
- </div>
219
+ {showViewNames ? <ViewToggleIcon /> : <ViewToggleIcon />}
220
+ </Button>
221
+ </TooltipTrigger>
222
+ <TooltipContent>
223
+ {showViewNames ? "Hide view names" : "Show view names"}
224
+ </TooltipContent>
225
+ </Tooltip>
226
+ </TooltipProvider>
59
227
  );
60
228
  }