@searpent/react-image-annotate 2.0.1 → 2.0.4

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.
@@ -87,6 +87,106 @@ export const testRegions = [
87
87
  },
88
88
  ]
89
89
 
90
+ export const testRegionsBoxes = [
91
+ {
92
+ type: "box",
93
+ id: "box1",
94
+ cls: "title",
95
+ highlighted: false,
96
+ groupHighlighted: false,
97
+ x: 0.315,
98
+ y: 0.63,
99
+ w: 0.067,
100
+ h: 0.045,
101
+ visible: true,
102
+ color: "#ff4133",
103
+ groupColor: "#2436ff",
104
+ groupId: "alpha",
105
+ text: "first box text"
106
+ },
107
+ {
108
+ type: "box",
109
+ id: "box2",
110
+ cls: "text",
111
+ highlighted: false,
112
+ groupHighlighted: false,
113
+ x: 0.415,
114
+ y: 0.63,
115
+ w: 0.067,
116
+ h: 0.045,
117
+ visible: true,
118
+ color: "#ff9924",
119
+ groupColor: "#2436ff",
120
+ groupId: "alpha",
121
+ text: "second box text"
122
+ },
123
+ {
124
+ type: "box",
125
+ id: "boxBeta1",
126
+ cls: "title",
127
+ highlighted: false,
128
+ groupHighlighted: false,
129
+ x: 0.315,
130
+ y: 0.43,
131
+ w: 0.067,
132
+ h: 0.045,
133
+ visible: true,
134
+ color: "#ff4133",
135
+ groupColor: "#78ffa7",
136
+ groupId: "beta",
137
+ text: "third box text"
138
+ },
139
+ {
140
+ type: "box",
141
+ id: "boxBeta2",
142
+ cls: "subtitle",
143
+ highlighted: false,
144
+ groupHighlighted: false,
145
+ x: 0.415,
146
+ y: 0.43,
147
+ w: 0.067,
148
+ h: 0.045,
149
+ visible: true,
150
+ color: "#ff9924",
151
+ groupColor: "#78ffa7",
152
+ groupId: "beta",
153
+ text: "fourth box text"
154
+ },
155
+ {
156
+ type: "box",
157
+ id: "boxBeta3",
158
+ cls: "text",
159
+ highlighted: false,
160
+ groupHighlighted: false,
161
+ x: 0.415,
162
+ y: 0.53,
163
+ w: 0.067,
164
+ h: 0.045,
165
+ visible: true,
166
+ color: "#007efc",
167
+ groupColor: "#78ffa7",
168
+ groupId: "beta",
169
+ text: "fifth box text"
170
+ },
171
+ {
172
+ type: "box",
173
+ id: "boxBeta4",
174
+ cls: "text",
175
+ highlighted: false,
176
+ groupHighlighted: false,
177
+ x: 0.415,
178
+ y: 0.73,
179
+ w: 0.067,
180
+ h: 0.045,
181
+ visible: true,
182
+ color: "#007efc",
183
+ groupColor: "#78ffa7",
184
+ groupId: "beta",
185
+ text: "sixth box text"
186
+ },
187
+
188
+ ]
189
+
90
190
  const events = {
91
191
  // Ignore common mouse movements, they fill the action log
92
192
  onMouseMove: () => null, //action("onMouseMove"),
@@ -6,12 +6,12 @@ import React, { useCallback, useRef } from "react"
6
6
  import { makeStyles } from "@mui/styles"
7
7
  import { createTheme, ThemeProvider } from "@mui/material/styles"
8
8
  import { styled } from "@mui/material/styles"
9
-
10
9
  import ClassSelectionMenu from "../ClassSelectionMenu"
11
10
  import DebugBox from "../DebugSidebarBox"
12
11
  import HistorySidebarBox from "../HistorySidebarBox"
13
12
  import ImageCanvas from "../ImageCanvas"
14
13
  import ImageSelector from "../ImageSelectorSidebarBox"
14
+ import GroupSelector from "../GroupSelectorSidebarBox"
15
15
  import KeyframeTimeline from "../KeyframeTimeline"
16
16
  import KeyframesSelector from "../KeyframesSelectorSidebarBox"
17
17
  import type { Node } from "react"
@@ -19,6 +19,7 @@ import RegionSelector from "../RegionSelectorSidebarBox"
19
19
  import SettingsDialog from "../SettingsDialog"
20
20
  import TagsSidebarBox from "../TagsSidebarBox"
21
21
  import TaskDescription from "../TaskDescriptionSidebarBox"
22
+ import MetadataEditor from "../MetadataEditorSidebarBox"
22
23
  import Workspace from "react-material-workspace-layout/Workspace"
23
24
  import classnames from "classnames"
24
25
  import getActiveImage from "../Annotator/reducers/get-active-image"
@@ -31,6 +32,9 @@ import useImpliedVideoRegions from "./use-implied-video-regions"
31
32
  import useKey from "use-key-hook"
32
33
  import { useSettings } from "../SettingsProvider"
33
34
  import { withHotKeys } from "react-hotkeys"
35
+ import Editor from "../Editor"
36
+ import regionsToBlocks from '../utils/regions-to-blocks';
37
+ import PagesSelector from "../PageSelector"
34
38
 
35
39
  // import Fullscreen from "../Fullscreen"
36
40
 
@@ -53,6 +57,12 @@ const FullScreenContainer = styled("div")(({ theme }) => ({
53
57
  },
54
58
  }))
55
59
 
60
+ const EditorWrapper = styled("div")(({ theme }) => ({
61
+ width: "45%",
62
+ padding: "1rem",
63
+ paddingLeft: "2rem"
64
+ }))
65
+
56
66
  type Props = {
57
67
  state: MainLayoutState,
58
68
  RegionEditLabel?: Node,
@@ -62,6 +72,18 @@ type Props = {
62
72
  onRegionClassAdded: () => {},
63
73
  hideHeader?: boolean,
64
74
  hideHeaderText?: boolean,
75
+ groups?: Array<any>,
76
+ onGroupSelect?: (any) => any,
77
+ hideHistory?: boolean,
78
+ hideNotEditingLabel?: boolean,
79
+ showEditor?: boolean,
80
+ showPageSelector?: boolean,
81
+ onRecalc?: (any) => any,
82
+ onSave?: (any) => any,
83
+ recalcActive?: boolean,
84
+ saveActive?: boolean,
85
+ allowedGroups?: boolean,
86
+ onMetadataChange: (any) => any
65
87
  }
66
88
 
67
89
  export const MainLayout = ({
@@ -79,6 +101,18 @@ export const MainLayout = ({
79
101
  hideSettings = false,
80
102
  hideFullScreen = false,
81
103
  hideSave = false,
104
+ groups = [],
105
+ onGroupSelect = () => { },
106
+ hideHistory = false,
107
+ hideNotEditingLabel = false,
108
+ showEditor = false,
109
+ showPageSelector = false,
110
+ onRecalc = () => { },
111
+ onSave = () => { },
112
+ recalcActive = false,
113
+ saveActive = false,
114
+ allowedGroups = {},
115
+ onMetadataChange
82
116
  }: Props) => {
83
117
  const classes = useStyles()
84
118
  const settings = useSettings()
@@ -93,154 +127,190 @@ export const MainLayout = ({
93
127
  const fn = (...args: any) =>
94
128
  params.length > 0
95
129
  ? dispatch(
96
- ({
97
- type,
98
- ...params.reduce((acc, p, i) => ((acc[p] = args[i]), acc), {}),
99
- }: any)
130
+ ({
131
+ type,
132
+ ...params.reduce((acc, p, i) => ((acc[p] = args[i]), acc), {}),
133
+ }: any)
100
134
  )
101
135
  : dispatch({ type, ...args[0] })
102
- memoizedActionFns.current[fnKey] = fn
103
- return fn
104
- }
136
+ memoizedActionFns.current[fnKey] = fn
137
+ return fn
138
+ }
105
139
 
106
- const { currentImageIndex, activeImage } = getActiveImage(state)
107
- let nextImage
108
- if (currentImageIndex !== null) {
109
- nextImage = state.images[currentImageIndex + 1]
110
- }
140
+ const { currentImageIndex, activeImage } = getActiveImage(state)
141
+ let nextImage
142
+ if (currentImageIndex !== null) {
143
+ nextImage = state.images[currentImageIndex + 1]
144
+ }
111
145
 
112
- useKey(() => dispatch({ type: "CANCEL" }), {
113
- detectKeys: [27],
114
- })
146
+ useKey(() => dispatch({ type: "CANCEL" }), {
147
+ detectKeys: [27],
148
+ })
115
149
 
116
- const isAVideoFrame = activeImage && activeImage.frameTime !== undefined
117
- const innerContainerRef = useRef()
118
- const hotkeyHandlers = useDispatchHotkeyHandlers({ dispatch })
150
+ const isAVideoFrame = activeImage && activeImage.frameTime !== undefined
151
+ const innerContainerRef = useRef()
152
+ const hotkeyHandlers = useDispatchHotkeyHandlers({ dispatch })
119
153
 
120
- let impliedVideoRegions = useImpliedVideoRegions(state)
154
+ let impliedVideoRegions = useImpliedVideoRegions(state)
121
155
 
122
- const refocusOnMouseEvent = useCallback((e) => {
123
- if (!innerContainerRef.current) return
124
- if (innerContainerRef.current.contains(document.activeElement)) return
125
- if (innerContainerRef.current.contains(e.target)) {
126
- innerContainerRef.current.focus()
127
- e.target.focus()
156
+ const refocusOnMouseEvent = useCallback((e) => {
157
+ if (!innerContainerRef.current) return
158
+ if (innerContainerRef.current.contains(document.activeElement)) return
159
+ if (innerContainerRef.current.contains(e.target)) {
160
+ innerContainerRef.current.focus()
161
+ e.target.focus()
162
+ }
163
+ }, [])
164
+
165
+ const canvas = (
166
+ <ImageCanvas
167
+ {...settings}
168
+ showCrosshairs={
169
+ settings.showCrosshairs &&
170
+ !["select", "pan", "zoom"].includes(state.selectedTool)
171
+ }
172
+ key={state.selectedImage}
173
+ showMask={state.showMask}
174
+ fullImageSegmentationMode={state.fullImageSegmentationMode}
175
+ autoSegmentationOptions={state.autoSegmentationOptions}
176
+ showTags={state.showTags}
177
+ allowedArea={state.allowedArea}
178
+ modifyingAllowedArea={state.selectedTool === "modify-allowed-area"}
179
+ regionClsList={state.regionClsList}
180
+ regionTagList={state.regionTagList}
181
+ regions={
182
+ state.annotationType === "image"
183
+ ? activeImage.regions || []
184
+ : impliedVideoRegions
185
+ }
186
+ realSize={activeImage ? activeImage.realSize : undefined}
187
+ videoPlaying={state.videoPlaying}
188
+ imageSrc={state.annotationType === "image" ? activeImage.src : null}
189
+ videoSrc={state.annotationType === "video" ? state.videoSrc : null}
190
+ pointDistancePrecision={state.pointDistancePrecision}
191
+ createWithPrimary={state.selectedTool.includes("create")}
192
+ dragWithPrimary={state.selectedTool === "pan"}
193
+ zoomWithPrimary={state.selectedTool === "zoom"}
194
+ showPointDistances={state.showPointDistances}
195
+ videoTime={
196
+ state.annotationType === "image"
197
+ ? state.selectedImageFrameTime
198
+ : state.currentVideoTime
128
199
  }
129
- }, [])
200
+ keypointDefinitions={state.keypointDefinitions}
201
+ onMouseMove={action("MOUSE_MOVE")}
202
+ onMouseDown={action("MOUSE_DOWN")}
203
+ onMouseUp={action("MOUSE_UP")}
204
+ onChangeRegion={action("CHANGE_REGION", "region")}
205
+ onBeginRegionEdit={action("OPEN_REGION_EDITOR", "region")}
206
+ onCloseRegionEdit={action("CLOSE_REGION_EDITOR", "region")}
207
+ onDeleteRegion={action("DELETE_REGION", "region")}
208
+ onBeginBoxTransform={action("BEGIN_BOX_TRANSFORM", "box", "directions")}
209
+ onBeginMovePolygonPoint={action(
210
+ "BEGIN_MOVE_POLYGON_POINT",
211
+ "polygon",
212
+ "pointIndex"
213
+ )}
214
+ onBeginMoveKeypoint={action(
215
+ "BEGIN_MOVE_KEYPOINT",
216
+ "region",
217
+ "keypointId"
218
+ )}
219
+ onAddPolygonPoint={action(
220
+ "ADD_POLYGON_POINT",
221
+ "polygon",
222
+ "point",
223
+ "pointIndex"
224
+ )}
225
+ onSelectRegion={action("SELECT_REGION", "region")}
226
+ onBeginMovePoint={action("BEGIN_MOVE_POINT", "point")}
227
+ onImageLoaded={action("IMAGE_LOADED", "image")}
228
+ RegionEditLabel={RegionEditLabel}
229
+ onImageOrVideoLoaded={action("IMAGE_OR_VIDEO_LOADED", "metadata")}
230
+ onChangeVideoTime={action("CHANGE_VIDEO_TIME", "newTime")}
231
+ onChangeVideoPlaying={action("CHANGE_VIDEO_PLAYING", "isPlaying")}
232
+ onRegionClassAdded={onRegionClassAdded}
233
+ allowComments={state.allowComments}
234
+ hideNotEditingLabel={hideNotEditingLabel}
235
+ allowedGroups={allowedGroups}
236
+ />
237
+ )
130
238
 
131
- const canvas = (
132
- <ImageCanvas
133
- {...settings}
134
- showCrosshairs={
135
- settings.showCrosshairs &&
136
- !["select", "pan", "zoom"].includes(state.selectedTool)
137
- }
138
- key={state.selectedImage}
139
- showMask={state.showMask}
140
- fullImageSegmentationMode={state.fullImageSegmentationMode}
141
- autoSegmentationOptions={state.autoSegmentationOptions}
142
- showTags={state.showTags}
143
- allowedArea={state.allowedArea}
144
- modifyingAllowedArea={state.selectedTool === "modify-allowed-area"}
145
- regionClsList={state.regionClsList}
146
- regionTagList={state.regionTagList}
147
- regions={
148
- state.annotationType === "image"
149
- ? activeImage.regions || []
150
- : impliedVideoRegions
151
- }
152
- realSize={activeImage ? activeImage.realSize : undefined}
153
- videoPlaying={state.videoPlaying}
154
- imageSrc={state.annotationType === "image" ? activeImage.src : null}
155
- videoSrc={state.annotationType === "video" ? state.videoSrc : null}
156
- pointDistancePrecision={state.pointDistancePrecision}
157
- createWithPrimary={state.selectedTool.includes("create")}
158
- dragWithPrimary={state.selectedTool === "pan"}
159
- zoomWithPrimary={state.selectedTool === "zoom"}
160
- showPointDistances={state.showPointDistances}
161
- videoTime={
162
- state.annotationType === "image"
163
- ? state.selectedImageFrameTime
164
- : state.currentVideoTime
165
- }
166
- keypointDefinitions={state.keypointDefinitions}
167
- onMouseMove={action("MOUSE_MOVE")}
168
- onMouseDown={action("MOUSE_DOWN")}
169
- onMouseUp={action("MOUSE_UP")}
170
- onChangeRegion={action("CHANGE_REGION", "region")}
171
- onBeginRegionEdit={action("OPEN_REGION_EDITOR", "region")}
172
- onCloseRegionEdit={action("CLOSE_REGION_EDITOR", "region")}
173
- onDeleteRegion={action("DELETE_REGION", "region")}
174
- onBeginBoxTransform={action("BEGIN_BOX_TRANSFORM", "box", "directions")}
175
- onBeginMovePolygonPoint={action(
176
- "BEGIN_MOVE_POLYGON_POINT",
177
- "polygon",
178
- "pointIndex"
179
- )}
180
- onBeginMoveKeypoint={action(
181
- "BEGIN_MOVE_KEYPOINT",
182
- "region",
183
- "keypointId"
184
- )}
185
- onAddPolygonPoint={action(
186
- "ADD_POLYGON_POINT",
187
- "polygon",
188
- "point",
189
- "pointIndex"
190
- )}
191
- onSelectRegion={action("SELECT_REGION", "region")}
192
- onBeginMovePoint={action("BEGIN_MOVE_POINT", "point")}
193
- onImageLoaded={action("IMAGE_LOADED", "image")}
194
- RegionEditLabel={RegionEditLabel}
195
- onImageOrVideoLoaded={action("IMAGE_OR_VIDEO_LOADED", "metadata")}
196
- onChangeVideoTime={action("CHANGE_VIDEO_TIME", "newTime")}
197
- onChangeVideoPlaying={action("CHANGE_VIDEO_PLAYING", "isPlaying")}
198
- onRegionClassAdded={onRegionClassAdded}
199
- allowComments={state.allowComments}
200
- />
201
- )
239
+ const onClickIconSidebarItem = useEventCallback((item) => {
240
+ dispatch({ type: "SELECT_TOOL", selectedTool: item.name })
241
+ })
202
242
 
203
- const onClickIconSidebarItem = useEventCallback((item) => {
204
- dispatch({ type: "SELECT_TOOL", selectedTool: item.name })
205
- })
243
+ const onClickHeaderItem = useEventCallback((item) => {
244
+ if (item.name === "Fullscreen") {
245
+ fullScreenHandle.enter()
246
+ } else if (item.name === "Window") {
247
+ fullScreenHandle.exit()
248
+ }
249
+ dispatch({ type: "HEADER_BUTTON_CLICKED", buttonName: item.name })
250
+ })
206
251
 
207
- const onClickHeaderItem = useEventCallback((item) => {
208
- if (item.name === "Fullscreen") {
209
- fullScreenHandle.enter()
210
- } else if (item.name === "Window") {
211
- fullScreenHandle.exit()
212
- }
213
- dispatch({ type: "HEADER_BUTTON_CLICKED", buttonName: item.name })
214
- })
252
+ const debugModeOn = Boolean(window.localStorage.$ANNOTATE_DEBUG_MODE && state)
253
+ const nextImageHasRegions =
254
+ !nextImage || (nextImage.regions && nextImage.regions.length > 0)
215
255
 
216
- const debugModeOn = Boolean(window.localStorage.$ANNOTATE_DEBUG_MODE && state)
217
- const nextImageHasRegions =
218
- !nextImage || (nextImage.regions && nextImage.regions.length > 0)
256
+ // Editor.js blocks
257
+ const selectedGroupId = state.images[state.selectedImage]?.selectedGroupId || null;
258
+ const editorBlocks = regionsToBlocks(state.images[state.selectedImage]?.regions || []);
259
+ const blocks = editorBlocks.filter(i => i?.data?.groupId === selectedGroupId);
219
260
 
220
- return (
221
- <ThemeProvider theme={theme}>
222
- <FullScreenContainer>
223
- <FullScreen
224
- handle={fullScreenHandle}
225
- onChange={(open) => {
226
- if (!open) {
227
- fullScreenHandle.exit()
228
- action("HEADER_BUTTON_CLICKED", "buttonName")("Window")
229
- }
230
- }}
261
+ const handleEditorChange = ({ imageIndex, data }) => {
262
+ const newRegions = data.blocks.map(i => ({
263
+ id: i.id,
264
+ cls: i.data.labelName,
265
+ text: i.data.text
266
+ }))
267
+ dispatch({ type: "UPDATE_REGIONS", regions: newRegions, imageIndex })
268
+ }
269
+
270
+ const pages = state.images.map((i, idx) => ({
271
+ id: idx,
272
+ src: i.src,
273
+ isActive: idx === state.selectedImage,
274
+ pageNumber: i?.metadata?.find(md => md.key === "page").value || null
275
+ }))
276
+
277
+ const handlePageClick = (pageIndex) => {
278
+ dispatch({ type: "SELECT_IMAGE", imageIndex: pageIndex })
279
+ }
280
+
281
+ return (
282
+ <ThemeProvider theme={theme}>
283
+ <FullScreenContainer>
284
+ <FullScreen
285
+ handle={fullScreenHandle}
286
+ onChange={(open) => {
287
+ if (!open) {
288
+ fullScreenHandle.exit()
289
+ action("HEADER_BUTTON_CLICKED", "buttonName")("Window")
290
+ }
291
+ }}
292
+ >
293
+ <HotkeyDiv
294
+ tabIndex={-1}
295
+ divRef={innerContainerRef}
296
+ onMouseDown={refocusOnMouseEvent}
297
+ onMouseOver={refocusOnMouseEvent}
298
+ allowChanges
299
+ handlers={hotkeyHandlers}
300
+ className={classnames(
301
+ classes.container,
302
+ state.fullScreen && "Fullscreen"
303
+ )}
231
304
  >
232
- <HotkeyDiv
233
- tabIndex={-1}
234
- divRef={innerContainerRef}
235
- onMouseDown={refocusOnMouseEvent}
236
- onMouseOver={refocusOnMouseEvent}
237
- allowChanges
238
- handlers={hotkeyHandlers}
239
- className={classnames(
240
- classes.container,
241
- state.fullScreen && "Fullscreen"
242
- )}
243
- >
305
+ <div style={{
306
+ display: 'flex',
307
+ flexDirection: 'row'
308
+ }}>
309
+ {
310
+ showPageSelector && (
311
+ <PagesSelector pages={pages} onPageClick={handlePageClick} onRecalc={onRecalc} onSave={onSave} saveActive={saveActive} recalcActive={recalcActive} />
312
+ )
313
+ }
244
314
  <Workspace
245
315
  allowFullscreen
246
316
  iconDictionary={iconDictionary}
@@ -264,16 +334,16 @@ export const MainLayout = ({
264
334
  state.annotationType !== "video"
265
335
  ? null
266
336
  : !state.videoPlaying
267
- ? { name: "Play" }
268
- : { name: "Pause" },
337
+ ? { name: "Play" }
338
+ : { name: "Pause" },
269
339
  !hideClone &&
270
- !nextImageHasRegions &&
271
- activeImage.regions && { name: "Clone" },
340
+ !nextImageHasRegions &&
341
+ activeImage.regions && { name: "Clone" },
272
342
  !hideSettings && { name: "Settings" },
273
343
  !hideFullScreen &&
274
- (state.fullScreen
275
- ? { name: "Window" }
276
- : { name: "Fullscreen" }),
344
+ (state.fullScreen
345
+ ? { name: "Window" }
346
+ : { name: "Fullscreen" }),
277
347
  !hideSave && { name: "Save" },
278
348
  ].filter(Boolean)}
279
349
  onClickHeaderItem={onClickHeaderItem}
@@ -377,6 +447,15 @@ export const MainLayout = ({
377
447
  // images={state.images}
378
448
  // />
379
449
  // ),
450
+ // groups && (
451
+ // <GroupSelector
452
+ // title="Articles"
453
+ // groups={groups}
454
+ // selectedGroupId={selectedGroupId}
455
+ // onSelect={onGroupSelect}
456
+ // />
457
+ // )
458
+ ,
380
459
  <RegionSelector
381
460
  regions={activeImage ? activeImage.regions : emptyArr}
382
461
  onSelectRegion={action("SELECT_REGION", "region")}
@@ -393,28 +472,39 @@ export const MainLayout = ({
393
472
  keyframes={state.keyframes}
394
473
  />
395
474
  ),
396
- <HistorySidebarBox
397
- history={state.history}
398
- onRestoreHistory={action("RESTORE_HISTORY")}
399
- />,
475
+ !hideHistory && (
476
+ <HistorySidebarBox
477
+ history={state.history}
478
+ onRestoreHistory={action("RESTORE_HISTORY")}
479
+ />
480
+ ),
481
+ <MetadataEditor state={state} onMetadataChange={onMetadataChange} />
400
482
  ].filter(Boolean)}
401
483
  >
402
484
  {canvas}
403
485
  </Workspace>
404
- <SettingsDialog
405
- open={state.settingsOpen}
406
- onClose={() =>
407
- dispatch({
408
- type: "HEADER_BUTTON_CLICKED",
409
- buttonName: "Settings",
410
- })
411
- }
412
- />
413
- </HotkeyDiv>
414
- </FullScreen>
415
- </FullScreenContainer>
416
- </ThemeProvider>
417
- )
486
+ {
487
+ (showEditor) && (
488
+ <EditorWrapper id="editor-wrapper">
489
+ <Editor id="editor" blocks={blocks} imageIndex={state.selectedImage} key={`${state.selectedImage}#${selectedGroupId}`} onChange={handleEditorChange} />
490
+ </EditorWrapper>
491
+ )
492
+ }
493
+ </div>
494
+ <SettingsDialog
495
+ open={state.settingsOpen}
496
+ onClose={() =>
497
+ dispatch({
498
+ type: "HEADER_BUTTON_CLICKED",
499
+ buttonName: "Settings",
500
+ })
501
+ }
502
+ />
503
+ </HotkeyDiv>
504
+ </FullScreen>
505
+ </FullScreenContainer>
506
+ </ThemeProvider >
507
+ )
418
508
  }
419
509
 
420
510
  export default MainLayout