@markopolo_ai_inc/markopolo-email-editor 1.0.3

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 (91) hide show
  1. package/README.md +63 -0
  2. package/build/asset-manifest.json +12 -0
  3. package/build/favicon.ico +0 -0
  4. package/build/index.html +1 -0
  5. package/build/logo192.png +0 -0
  6. package/build/logo512.png +0 -0
  7. package/build/manifest.json +25 -0
  8. package/build/robots.txt +3 -0
  9. package/build/static/css/main.588cb535.css +9 -0
  10. package/build/static/js/206.a4343501.chunk.js +1 -0
  11. package/build/static/js/main.053d366a.js +2 -0
  12. package/build/static/js/main.053d366a.js.LICENSE.txt +56 -0
  13. package/package.json +64 -0
  14. package/public/favicon.ico +0 -0
  15. package/public/index.html +50 -0
  16. package/public/logo192.png +0 -0
  17. package/public/logo512.png +0 -0
  18. package/public/manifest.json +25 -0
  19. package/public/robots.txt +3 -0
  20. package/src/App.js +15 -0
  21. package/src/components/EmailEditor/assets/App.css +339 -0
  22. package/src/components/EmailEditor/assets/Columns.css +309 -0
  23. package/src/components/EmailEditor/assets/Header.css +174 -0
  24. package/src/components/EmailEditor/assets/ImageBlock.css +12 -0
  25. package/src/components/EmailEditor/assets/Preview.css +30 -0
  26. package/src/components/EmailEditor/assets/RichText.css +199 -0
  27. package/src/components/EmailEditor/assets/RightSettings.css +520 -0
  28. package/src/components/EmailEditor/assets/Sidebar.css +195 -0
  29. package/src/components/EmailEditor/components/BlockItems/ButtonBlock.js +25 -0
  30. package/src/components/EmailEditor/components/BlockItems/DividerBlock.js +19 -0
  31. package/src/components/EmailEditor/components/BlockItems/HeadingBlock.js +16 -0
  32. package/src/components/EmailEditor/components/BlockItems/ImageBlock.js +28 -0
  33. package/src/components/EmailEditor/components/BlockItems/MenuBlock.js +52 -0
  34. package/src/components/EmailEditor/components/BlockItems/SocialLinkBlocks.js +26 -0
  35. package/src/components/EmailEditor/components/BlockItems/SpacerBlock.js +23 -0
  36. package/src/components/EmailEditor/components/BlockItems/TextBlock.js +16 -0
  37. package/src/components/EmailEditor/components/BlockItems/index.js +25 -0
  38. package/src/components/EmailEditor/components/ColorPicker/index.js +26 -0
  39. package/src/components/EmailEditor/components/Column/index.js +253 -0
  40. package/src/components/EmailEditor/components/Header/index.js +243 -0
  41. package/src/components/EmailEditor/components/LeftSideBar/index.js +253 -0
  42. package/src/components/EmailEditor/components/Main/index.js +281 -0
  43. package/src/components/EmailEditor/components/Preview/index.js +97 -0
  44. package/src/components/EmailEditor/components/RichText/Bold.js +37 -0
  45. package/src/components/EmailEditor/components/RichText/FontColor.js +39 -0
  46. package/src/components/EmailEditor/components/RichText/InsertOrderedList.js +36 -0
  47. package/src/components/EmailEditor/components/RichText/InsertUnorderedList.js +36 -0
  48. package/src/components/EmailEditor/components/RichText/Italic.js +36 -0
  49. package/src/components/EmailEditor/components/RichText/Link.js +99 -0
  50. package/src/components/EmailEditor/components/RichText/RichTextLayout.js +53 -0
  51. package/src/components/EmailEditor/components/RichText/Strikethrough.js +36 -0
  52. package/src/components/EmailEditor/components/RichText/TextAlign.js +58 -0
  53. package/src/components/EmailEditor/components/RichText/Underline.js +36 -0
  54. package/src/components/EmailEditor/components/RichText/index.js +210 -0
  55. package/src/components/EmailEditor/components/RightSetting/index.js +126 -0
  56. package/src/components/EmailEditor/components/StyleSettings/ButtonStyleSettings.js +141 -0
  57. package/src/components/EmailEditor/components/StyleSettings/ColumnStyleSettings.js +241 -0
  58. package/src/components/EmailEditor/components/StyleSettings/DividerStyleSettings.js +111 -0
  59. package/src/components/EmailEditor/components/StyleSettings/HeadingStyleSettings.js +162 -0
  60. package/src/components/EmailEditor/components/StyleSettings/ImageStyleSettings.js +217 -0
  61. package/src/components/EmailEditor/components/StyleSettings/MenuStyleSettings.js +177 -0
  62. package/src/components/EmailEditor/components/StyleSettings/PaddingSettings.js +30 -0
  63. package/src/components/EmailEditor/components/StyleSettings/SocialLinkSettings.js +250 -0
  64. package/src/components/EmailEditor/components/StyleSettings/SpacerStyleSettings.js +38 -0
  65. package/src/components/EmailEditor/components/StyleSettings/TextStyleSettings.js +108 -0
  66. package/src/components/EmailEditor/components/StyleSettings/index.js +32 -0
  67. package/src/components/EmailEditor/configs/getBlockConfigsList.js +263 -0
  68. package/src/components/EmailEditor/configs/getColumnConfigFunc.js +59 -0
  69. package/src/components/EmailEditor/configs/getColumnsSettings.js +246 -0
  70. package/src/components/EmailEditor/configs/useDataSource.js +19 -0
  71. package/src/components/EmailEditor/index.js +93 -0
  72. package/src/components/EmailEditor/reducers/index.js +173 -0
  73. package/src/components/EmailEditor/translation/en.js +166 -0
  74. package/src/components/EmailEditor/translation/index.js +39 -0
  75. package/src/components/EmailEditor/translation/zh.js +166 -0
  76. package/src/components/EmailEditor/utils/classNames.js +5 -0
  77. package/src/components/EmailEditor/utils/dataToHTML.js +323 -0
  78. package/src/components/EmailEditor/utils/exportValidation.js +296 -0
  79. package/src/components/EmailEditor/utils/helpers.js +48 -0
  80. package/src/components/EmailEditor/utils/pexels.js +20 -0
  81. package/src/components/EmailEditor/utils/useSection.js +24 -0
  82. package/src/components/EmailEditor/utils/useStyleLayout.js +82 -0
  83. package/src/index.css +99 -0
  84. package/src/index.js +15 -0
  85. package/src/logo.svg +1 -0
  86. package/src/pages/AppPage/index.js +10 -0
  87. package/src/pages/Dashboard/Header.js +192 -0
  88. package/src/pages/Dashboard/defaultBlockList.json +1758 -0
  89. package/src/pages/Dashboard/index.js +48 -0
  90. package/src/reportWebVitals.js +13 -0
  91. package/src/setupTests.js +5 -0
@@ -0,0 +1,243 @@
1
+ import { useState, useContext, useEffect } from "react";
2
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3
+ import {
4
+ faDesktop,
5
+ faMobileAlt,
6
+ faUndo,
7
+ faRedo,
8
+ faEye,
9
+ faTabletAlt,
10
+ faTimes,
11
+ } from "@fortawesome/free-solid-svg-icons";
12
+ import classNames from "../../utils/classNames";
13
+ // import { deepClone } from "../../utils/helpers";
14
+ import { GlobalContext } from "../../reducers";
15
+ import { Drawer } from "antd";
16
+ import dataToHtml from "../../utils/dataToHTML";
17
+ import { deepClone } from "../../utils/helpers";
18
+
19
+ const Header = () => {
20
+ const {
21
+ previewMode,
22
+ setPreviewMode,
23
+ bodySettings,
24
+ blockList,
25
+ actionType,
26
+ setBlockList,
27
+ setBodySettings,
28
+ } = useContext(GlobalContext);
29
+ const [modalPreview, setModalPreview] = useState(previewMode);
30
+ const [blockListHistory, setBlockListHistory] = useState({
31
+ histories: [],
32
+ index: 0,
33
+ });
34
+ const [isPreviewModalOpen, setIsPreviewModalOpen] = useState(false);
35
+ const { histories, index } = blockListHistory;
36
+
37
+ useEffect(() => {
38
+ // Do not add to history on first render
39
+ const newBlockList = deepClone(blockList);
40
+ const newBodySettings = deepClone(bodySettings);
41
+ if (actionType === "firstRender") {
42
+ setBlockListHistory({
43
+ histories: [
44
+ {
45
+ blockList: newBlockList,
46
+ bodySettings: newBodySettings,
47
+ },
48
+ ],
49
+ index: 0,
50
+ });
51
+ } else if (!actionType.includes("set_history")) {
52
+ let newHistories = deepClone(histories);
53
+
54
+ newHistories = newHistories.slice(0, index + 1);
55
+ newHistories.push({
56
+ blockList: newBlockList,
57
+ bodySettings: newBodySettings,
58
+ });
59
+
60
+ setBlockListHistory({
61
+ histories: newHistories,
62
+ index: index + 1,
63
+ });
64
+ }
65
+ // Intentionally omit actionType, histories, index to avoid effect loop on history update
66
+ // eslint-disable-next-line react-hooks/exhaustive-deps
67
+ }, [blockList, bodySettings]);
68
+
69
+ const closeModal = () => {
70
+ setIsPreviewModalOpen(false);
71
+ };
72
+
73
+ const openModal = () => {
74
+ setIsPreviewModalOpen(true);
75
+ };
76
+
77
+ const prevHistory = () => {
78
+ if (histories[index - 1]) {
79
+ const newHistories = deepClone(histories[index - 1]);
80
+ setBlockListHistory({ ...blockListHistory, index: index - 1 });
81
+ setBlockList(newHistories.blockList, `set_history_${index - 1}`);
82
+ setBodySettings(newHistories.bodySettings);
83
+ }
84
+ };
85
+
86
+ const nextHistory = () => {
87
+ if (histories[index + 1]) {
88
+ const newHistories = deepClone(histories[index + 1]);
89
+ setBlockListHistory({ ...blockListHistory, index: index + 1 });
90
+ setBlockList(newHistories.blockList, `set_history_${index + 1}`);
91
+ setBodySettings(newHistories.bodySettings);
92
+ }
93
+ };
94
+
95
+ return (
96
+ <>
97
+ <div className="header">
98
+ <div className="header-box">
99
+ <FontAwesomeIcon
100
+ icon={faEye}
101
+ onClick={openModal}
102
+ className={classNames(
103
+ "header-icon-small",
104
+ isPreviewModalOpen === "desktop" && "header-icon_active",
105
+ isPreviewModalOpen !== "desktop" && "header-icon_disabled"
106
+ )}
107
+ />
108
+ <FontAwesomeIcon
109
+ onClick={() => setPreviewMode("desktop")}
110
+ icon={faDesktop}
111
+ className={classNames(
112
+ "header-icon-small",
113
+ previewMode === "desktop" && "header-icon_active",
114
+ previewMode !== "desktop" && "header-icon_disabled"
115
+ )}
116
+ />
117
+ <FontAwesomeIcon
118
+ icon={faMobileAlt}
119
+ onClick={() => setPreviewMode("mobile")}
120
+ className={classNames(
121
+ "header-icon-small",
122
+ previewMode === "mobile" && "header-icon_active",
123
+ previewMode !== "mobile" && "header-icon_disabled"
124
+ )}
125
+ />
126
+ </div>
127
+ <div className="header-box text-center"></div>
128
+ <div className="header-box text-right">
129
+ <FontAwesomeIcon
130
+ onClick={prevHistory}
131
+ icon={faUndo}
132
+ className={classNames(
133
+ "header-icon-history",
134
+ histories[index - 1] && "header-icon-history_active",
135
+ !histories[index - 1] && "header-icon-history_disabled"
136
+ )}
137
+ />
138
+ <FontAwesomeIcon
139
+ onClick={nextHistory}
140
+ icon={faRedo}
141
+ className={classNames(
142
+ "header-icon-history",
143
+ histories[index + 1] && "header-icon-history_active",
144
+ !histories[index + 1] && "header-icon-history_disabled"
145
+ )}
146
+ />
147
+ </div>
148
+ </div>
149
+
150
+ <Drawer
151
+ className="ee-preview-drawer"
152
+ title={
153
+ <div className="flex justify-between">
154
+ <div className="header-box text-center"></div>
155
+ <div className="header-box text-center">
156
+ <FontAwesomeIcon
157
+ onClick={() => {
158
+ setModalPreview("desktop");
159
+ setPreviewMode("desktop");
160
+ }}
161
+ icon={faDesktop}
162
+ className={classNames(
163
+ "header-icon",
164
+ modalPreview === "desktop" && "header-icon_active",
165
+ modalPreview !== "desktop" && "header-icon_disabled"
166
+ )}
167
+ />
168
+ <FontAwesomeIcon
169
+ icon={faTabletAlt}
170
+ onClick={() => {
171
+ setModalPreview("tablet");
172
+ }}
173
+ className={classNames(
174
+ "header-icon",
175
+ modalPreview === "tablet" && "header-icon_active",
176
+ modalPreview !== "tablet" && "header-icon_disabled"
177
+ )}
178
+ />
179
+ <FontAwesomeIcon
180
+ icon={faMobileAlt}
181
+ onClick={() => {
182
+ setModalPreview("mobile");
183
+ setPreviewMode("mobile");
184
+ }}
185
+ className={classNames(
186
+ "header-icon",
187
+ modalPreview === "mobile" && "header-icon_active",
188
+ modalPreview !== "mobile" && "header-icon_disabled"
189
+ )}
190
+ />
191
+ </div>
192
+ <div className="header-box text-right">
193
+ <div onClick={closeModal} className="header-drawer-close">
194
+ <FontAwesomeIcon icon={faTimes} className="text-sm" />
195
+ </div>
196
+ </div>
197
+ </div>
198
+ }
199
+ open={isPreviewModalOpen}
200
+ zIndex={1100}
201
+ closable={false}
202
+ onCancel={closeModal}
203
+ footer={false}
204
+ width="100vw"
205
+ style={{
206
+ top: 0,
207
+ bottom: 0,
208
+ padding: 0,
209
+ height: "100%",
210
+ }}
211
+ >
212
+ <div
213
+ className="header-drawer-body"
214
+ style={{
215
+ width:
216
+ (modalPreview === "desktop" && "100%") ||
217
+ (modalPreview === "tablet" && 768) ||
218
+ (modalPreview === "mobile" && 364),
219
+ }}
220
+ >
221
+ <div className="header-drawer-head">
222
+ <div className="header-drawer-head-item"></div>
223
+ <div className="header-drawer-head-item"></div>
224
+ <div className="header-drawer-head-item"></div>
225
+ </div>
226
+ <div className="header-drawer-content">
227
+ <iframe
228
+ src={
229
+ "data:text/html," +
230
+ encodeURIComponent(dataToHtml({ bodySettings, blockList }))
231
+ }
232
+ title="preview"
233
+ scrolling="no"
234
+ className="header-drawer-iframe"
235
+ ></iframe>
236
+ </div>
237
+ </div>
238
+ </Drawer>
239
+ </>
240
+ );
241
+ };
242
+
243
+ export default Header;
@@ -0,0 +1,253 @@
1
+ import { useContext } from "react";
2
+ import { motion } from "framer-motion";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+
5
+ import {
6
+ faColumns,
7
+ faMinusSquare,
8
+ faHeading,
9
+ faFont,
10
+ faGripLines,
11
+ faImage,
12
+ faShareAltSquare,
13
+ faArrowsAltV,
14
+ faBars,
15
+ } from "@fortawesome/free-solid-svg-icons";
16
+ import { GlobalContext } from "../../reducers";
17
+ import { deepClone } from "../../utils/helpers";
18
+
19
+ import useDataSource from "../../configs/useDataSource";
20
+
21
+ const LeftSideBar = (props) => {
22
+ const { clearStyles } = props;
23
+ const { setCurrentItem, setIsDragStart, blockList, setActionType } =
24
+ useContext(GlobalContext);
25
+ const { blockConfigsList } = useDataSource();
26
+
27
+ // const sidebarTabsList = [
28
+ // { name: t("blocks"), icon: faCubes, key: "blocks" },
29
+ // { name: t("photos"), icon: faImages, key: "photos" },
30
+ // ];
31
+ // const [photos, setPhotos] = useState({
32
+ // list: null,
33
+ // pagination: 1,
34
+ // query: "",
35
+ // isLoading: true,
36
+ // scrollLoading: false,
37
+ // });
38
+
39
+ const icons = {
40
+ column: faColumns,
41
+ text: faFont,
42
+ heading: faHeading,
43
+ button: faMinusSquare,
44
+ divider: faGripLines,
45
+ spacer: faArrowsAltV,
46
+ menu: faBars,
47
+ image: faImage,
48
+ social_link: faShareAltSquare,
49
+ };
50
+
51
+ const dragEnd = (event) => {
52
+ event.target.style.border = "";
53
+ event.target.children[0] &&
54
+ event.target.children[0].classList.remove("sidebar-block-move");
55
+ setTimeout(() => {
56
+ setIsDragStart(false);
57
+ clearStyles();
58
+ }, 50);
59
+ };
60
+
61
+ const dragStart = (item) => (event) => {
62
+ setCurrentItem({
63
+ data: deepClone(item),
64
+ type: "add",
65
+ index: blockList.length + 1,
66
+ });
67
+ setIsDragStart(true);
68
+ event.target.style.border = "1px dashed #ccc";
69
+ event.target.children[0] &&
70
+ event.target.children[0].classList.add("sidebar-block-move");
71
+ setActionType("add");
72
+ };
73
+
74
+ const blocksElement = () => {
75
+ return (
76
+ <motion.div
77
+ className="side-bar-blocks"
78
+ initial={{ opacity: 0, y: -10 }}
79
+ animate={{ opacity: 1, y: 0 }}
80
+ exit={{ opacity: 0, y: 10 }}
81
+ transition={{ duration: 0.3 }}
82
+ key="blocks"
83
+ >
84
+ <div className="side-bar-blocks-container">
85
+ {blockConfigsList.map((item) => {
86
+ return (
87
+ <div
88
+ className="side-bar-blocks-item"
89
+ data-block_type="header"
90
+ draggable="true"
91
+ key={item.key}
92
+ onDragEnd={dragEnd}
93
+ onDragStart={dragStart(item)}
94
+ >
95
+ <div className="sidebar-block">
96
+ <FontAwesomeIcon
97
+ icon={icons[item.key]}
98
+ className="sidebar-block-icon"
99
+ />
100
+ <div className="sidebar-block-text">{item.name}</div>
101
+ </div>
102
+ </div>
103
+ );
104
+ })}
105
+ </div>
106
+ </motion.div>
107
+ );
108
+ };
109
+
110
+ // Uncomment to restore Pexels photos tab.
111
+ // const searchPhotos = (value) => {
112
+ // setPhotos({ ...photos, list: [], isLoading: true });
113
+ // fetchPhotos(1, "40", value).then((response) =>
114
+ // setPhotos({
115
+ // ...photos,
116
+ // list: response.photos,
117
+ // isLoading: false,
118
+ // query: value,
119
+ // pagination: 1,
120
+ // })
121
+ // );
122
+ // };
123
+ // const photosElement = () => {
124
+ // const imageBlock = blockConfigsList.find(({ key }) => key === "image");
125
+ // let leftHeight = 0;
126
+ // let rightHeight = 0;
127
+ // let leftPhotos = [];
128
+ // let rightPhotos = [];
129
+ // if (!photos.list) {
130
+ // fetchPhotos(photos.pagination, "20", photos.query).then((response) =>
131
+ // setPhotos({
132
+ // ...photos,
133
+ // list: response.photos,
134
+ // isLoading: false,
135
+ // scrollLoading: false,
136
+ // })
137
+ // );
138
+ // } else {
139
+ // photos.list.forEach((item) => {
140
+ // const { height, width } = item;
141
+ // const imageHeight = (200 / width) * height;
142
+ // if (leftHeight <= rightHeight) {
143
+ // leftPhotos.push(item);
144
+ // leftHeight += imageHeight;
145
+ // } else {
146
+ // rightPhotos.push(item);
147
+ // rightHeight += imageHeight;
148
+ // }
149
+ // });
150
+ // }
151
+ // const openPexels = () => window.open("https://www.pexels.com");
152
+ // return (
153
+ // <motion.div
154
+ // className="photo-container"
155
+ // initial={{ opacity: 0, y: -10 }}
156
+ // animate={{ opacity: 1, y: 0 }}
157
+ // exit={{ opacity: 0, y: 10 }}
158
+ // transition={{ duration: 0.3 }}
159
+ // key="photos"
160
+ // >
161
+ // <div className="margin-bottom-12">
162
+ // <Input.Search onSearch={searchPhotos} loading={photos.isLoading || photos.scrollLoading} />
163
+ // <div className="pexels-link" onClick={openPexels}>{t("powered_by_pexels")}</div>
164
+ // </div>
165
+ // <div className="photos-body">
166
+ // <div className="photos-container default-scrollbar" style={{ overflowAnchor: "none" }}
167
+ // onScroll={(event) => {
168
+ // let scrollBottom = event.target.scrollHeight - event.target.offsetHeight - event.target.scrollTop;
169
+ // if (scrollBottom < 20 && !photos.scrollLoading) {
170
+ // setPhotos({ ...photos, scrollLoading: true });
171
+ // setTimeout(async () => {
172
+ // const response = await fetchPhotos(photos.pagination + 1, "20", photos.query);
173
+ // event.target.scrollTop = event.target.scrollTop - 50;
174
+ // setPhotos({
175
+ // ...photos,
176
+ // pagination: photos.pagination + 1,
177
+ // list: photos.list.concat(response.photos),
178
+ // scrollLoading: false,
179
+ // isLoading: false,
180
+ // });
181
+ // }, 1000);
182
+ // }
183
+ // }}
184
+ // >
185
+ // <div>
186
+ // {leftPhotos.map((image, index) => (
187
+ // <motion.div key={index} initial={{ y: -index * 100, opacity: 0 }} animate={{ y: 0, opacity: 1 }}
188
+ // draggable onDragEnd={dragEnd}
189
+ // onDragStart={dragStart({ ...imageBlock, src: image.src.large, alt: image.alt })}
190
+ // className="photo-item">
191
+ // <img src={image.src.large} alt={image.alt} className="width-full" />
192
+ // </motion.div>
193
+ // ))}
194
+ // </div>
195
+ // <div>
196
+ // {rightPhotos.map((image, index) => (
197
+ // <motion.div key={index} initial={{ y: -index * 100, opacity: 0 }} animate={{ y: 0, opacity: 1 }}
198
+ // draggable onDragEnd={dragEnd}
199
+ // onDragStart={dragStart({ ...imageBlock, src: image.src.large, alt: image.alt })}
200
+ // className="photo-item">
201
+ // <img src={image.src.large} alt={image.alt} className="width-full" />
202
+ // </motion.div>
203
+ // ))}
204
+ // </div>
205
+ // </div>
206
+ // {photos.scrollLoading && <div className="scroll-loading-context">{t("loading")}</div>}
207
+ // {photos.isLoading && <div className="loading-spinner"><Spin /></div>}
208
+ // </div>
209
+ // </motion.div>
210
+ // );
211
+ // };
212
+
213
+ return (
214
+ <div className="side-bar">
215
+ {/* Tabs bar hidden: always show blocks. Uncomment to restore Blocks/Photos tabs.
216
+ <div className="side-bar-tabs">
217
+ {sidebarTabsList.map((item) => {
218
+ const { key, icon, name } = item;
219
+ return (
220
+ <div
221
+ onClick={() => {
222
+ if (key !== currentSideBarKey) {
223
+ setCurrentSideBarKey(key);
224
+ setPhotos({ list: null, pagination: 1, isLoading: true, scrollLoading: false, query: "" });
225
+ }
226
+ }}
227
+ className={classNames(
228
+ currentSideBarKey === key ? "side-bar-tab-item-active" : "side-bar-tab-item",
229
+ "side-bar-item-default"
230
+ )}
231
+ key={key}
232
+ >
233
+ <FontAwesomeIcon icon={icon} className="text-18" />
234
+ <div className="side-bar-icon-title">{name}</div>
235
+ </div>
236
+ );
237
+ })}
238
+ </div>
239
+ */}
240
+ <div className="side-bar-content">
241
+ {/* Always show blocks; tabs removed. Uncomment below to restore tab switching.
242
+ <AnimatePresence mode="wait">
243
+ {currentSideBarKey === "blocks" && blocksElement()}
244
+ {currentSideBarKey === "photos" && photosElement()}
245
+ </AnimatePresence>
246
+ */}
247
+ {blocksElement()}
248
+ </div>
249
+ </div>
250
+ );
251
+ };
252
+
253
+ export default LeftSideBar;