@searpent/react-image-annotate 2.0.0
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.
- package/.babelrc +6 -0
- package/.env +1 -0
- package/.flowconfig +2 -0
- package/.github/workflows/release-on-master.yml +32 -0
- package/.github/workflows/test.yml +16 -0
- package/.prettierrc +3 -0
- package/.releaserc.js +18 -0
- package/.storybook/addons.js +2 -0
- package/.storybook/config.js +16 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/package.json +93 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +38 -0
- package/src/Annotator/bike-pic.png +0 -0
- package/src/Annotator/bike-pic2.png +0 -0
- package/src/Annotator/dab-keyframes.story.json +1 -0
- package/src/Annotator/index.js +206 -0
- package/src/Annotator/index.story.js +727 -0
- package/src/Annotator/poses.story.js +150 -0
- package/src/Annotator/reducers/combine-reducers.js +7 -0
- package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +53 -0
- package/src/Annotator/reducers/fix-twisted.js +6 -0
- package/src/Annotator/reducers/general-reducer.js +914 -0
- package/src/Annotator/reducers/get-active-image.js +21 -0
- package/src/Annotator/reducers/get-implied-video-regions.js +115 -0
- package/src/Annotator/reducers/history-handler.js +60 -0
- package/src/Annotator/reducers/image-reducer.js +23 -0
- package/src/Annotator/reducers/video-reducer.js +85 -0
- package/src/Annotator/video.story.js +51 -0
- package/src/ClassSelectionMenu/index.js +108 -0
- package/src/Crosshairs/index.js +64 -0
- package/src/DebugSidebarBox/index.js +36 -0
- package/src/DemoSite/Editor.js +235 -0
- package/src/DemoSite/ErrorBoundaryDialog.js +34 -0
- package/src/DemoSite/index.js +41 -0
- package/src/DemoSite/index.story.js +10 -0
- package/src/DemoSite/simple-segmentation-example.json +572 -0
- package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
- package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
- package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
- package/src/FullImageSegmentationAnnotator/index.js +7 -0
- package/src/FullImageSegmentationAnnotator/index.story.js +177 -0
- package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
- package/src/HighlightBox/index.js +143 -0
- package/src/HistorySidebarBox/index.js +78 -0
- package/src/ImageCanvas/dancing-man.story.jpg +0 -0
- package/src/ImageCanvas/index.js +488 -0
- package/src/ImageCanvas/index.story.js +214 -0
- package/src/ImageCanvas/mouse_mask.story.png +0 -0
- package/src/ImageCanvas/region-tools.js +171 -0
- package/src/ImageCanvas/seves_desk.story.jpg +0 -0
- package/src/ImageCanvas/styles.js +27 -0
- package/src/ImageCanvas/use-mouse.js +168 -0
- package/src/ImageCanvas/use-project-box.js +23 -0
- package/src/ImageCanvas/use-wasd-mode.js +50 -0
- package/src/ImageMask/index.js +127 -0
- package/src/ImageMask/load-image.js +32 -0
- package/src/ImageSelectorSidebarBox/index.js +54 -0
- package/src/KeyframeTimeline/get-time-string.js +25 -0
- package/src/KeyframeTimeline/index.js +223 -0
- package/src/KeyframesSelectorSidebarBox/index.js +93 -0
- package/src/LandingPage/content.md +57 -0
- package/src/LandingPage/github-markdown.css +964 -0
- package/src/LandingPage/index.js +147 -0
- package/src/MainLayout/icon-dictionary.js +79 -0
- package/src/MainLayout/index.js +420 -0
- package/src/MainLayout/index.story.js +240 -0
- package/src/MainLayout/styles.js +26 -0
- package/src/MainLayout/types.js +156 -0
- package/src/MainLayout/use-implied-video-regions.js +17 -0
- package/src/PointDistances/index.js +90 -0
- package/src/PreventScrollToParents/index.js +48 -0
- package/src/PreventScrollToParents/index.story.js +23 -0
- package/src/RegionLabel/index.js +201 -0
- package/src/RegionLabel/styles.js +51 -0
- package/src/RegionSelectAndTransformBoxes/index.js +234 -0
- package/src/RegionSelectorSidebarBox/index.js +216 -0
- package/src/RegionSelectorSidebarBox/styles.js +54 -0
- package/src/RegionShapes/index.js +236 -0
- package/src/RegionTags/index.js +130 -0
- package/src/SettingsDialog/index.js +58 -0
- package/src/SettingsProvider/index.js +44 -0
- package/src/Shortcuts/ShortcutField.js +44 -0
- package/src/Shortcuts/index.js +129 -0
- package/src/ShortcutsManager/index.js +162 -0
- package/src/Sidebar/index.js +117 -0
- package/src/SidebarBoxContainer/index.js +93 -0
- package/src/SmallToolButton/index.js +57 -0
- package/src/TagsSidebarBox/index.js +93 -0
- package/src/TaskDescriptionSidebarBox/index.js +43 -0
- package/src/Theme/index.js +36 -0
- package/src/VideoOrImageCanvasBackground/index.js +170 -0
- package/src/colors.js +32 -0
- package/src/hooks/use-event-callback.js +11 -0
- package/src/hooks/use-exclude-pattern.js +27 -0
- package/src/hooks/use-load-image.js +21 -0
- package/src/hooks/use-window-size.js +46 -0
- package/src/hooks/xpattern.js +1 -0
- package/src/hooks/xpattern.png +0 -0
- package/src/index.js +18 -0
- package/src/lib.js +7 -0
- package/src/screenshot.png +0 -0
- package/src/site.css +5 -0
- package/src/stories.js +2 -0
- package/src/utils/get-from-local-storage.js +7 -0
- package/src/utils/get-hotkey-help-text.js +11 -0
- package/src/utils/get-landmarks-with-transform.js +23 -0
- package/src/utils/set-in-local-storage.js +6 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React, { useMemo } from "react"
|
|
2
|
+
import { HotKeys } from "react-hotkeys"
|
|
3
|
+
|
|
4
|
+
export const defaultHotkeys = [
|
|
5
|
+
{
|
|
6
|
+
id: "select_tool",
|
|
7
|
+
description: "Switch to the Select Tool",
|
|
8
|
+
binding: "escape",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "zoom_tool",
|
|
12
|
+
description: "Select the Zoom Tool",
|
|
13
|
+
binding: "z",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "create_point",
|
|
17
|
+
description: "Create a point",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "create_bounding_box",
|
|
21
|
+
description: "Create a bounding box",
|
|
22
|
+
binding: "b",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "pan_tool",
|
|
26
|
+
description: "Select the Pan Tool",
|
|
27
|
+
binding: "m",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "create_polygon",
|
|
31
|
+
description: "Create a Polygon",
|
|
32
|
+
binding: "p",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "create_pixel",
|
|
36
|
+
description: "Create a Pixel Mask",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "save_and_previous_sample",
|
|
40
|
+
description: "Save and go to previous sample",
|
|
41
|
+
binding: "ArrowLeft",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "save_and_next_sample",
|
|
45
|
+
description: "Save and go to next sample",
|
|
46
|
+
binding: "ArrowRight",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "save_and_exit_sample",
|
|
50
|
+
description: "Save and exit current sample",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "exit_sample",
|
|
54
|
+
description: "Exit sample without saving",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "delete_region",
|
|
58
|
+
description: "Delete selected region",
|
|
59
|
+
binding: "d",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "undo",
|
|
63
|
+
description: "Undo latest change",
|
|
64
|
+
binding: "Ctrl+z",
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
export const defaultKeyMap = {}
|
|
68
|
+
for (const { id, binding } of defaultHotkeys) defaultKeyMap[id] = binding
|
|
69
|
+
|
|
70
|
+
export const useDispatchHotkeyHandlers = ({ dispatch }) => {
|
|
71
|
+
const handlers = useMemo(
|
|
72
|
+
() => ({
|
|
73
|
+
select_tool: () => {
|
|
74
|
+
dispatch({
|
|
75
|
+
type: "SELECT_TOOL",
|
|
76
|
+
selectedTool: "select",
|
|
77
|
+
})
|
|
78
|
+
},
|
|
79
|
+
zoom_tool: () => {
|
|
80
|
+
dispatch({
|
|
81
|
+
type: "SELECT_TOOL",
|
|
82
|
+
selectedTool: "zoom",
|
|
83
|
+
})
|
|
84
|
+
},
|
|
85
|
+
create_point: () => {
|
|
86
|
+
dispatch({
|
|
87
|
+
type: "SELECT_TOOL",
|
|
88
|
+
selectedTool: "create-point",
|
|
89
|
+
})
|
|
90
|
+
},
|
|
91
|
+
create_bounding_box: () => {
|
|
92
|
+
dispatch({
|
|
93
|
+
type: "SELECT_TOOL",
|
|
94
|
+
selectedTool: "create-box",
|
|
95
|
+
})
|
|
96
|
+
},
|
|
97
|
+
pan_tool: () => {
|
|
98
|
+
dispatch({
|
|
99
|
+
type: "SELECT_TOOL",
|
|
100
|
+
selectedTool: "pan",
|
|
101
|
+
})
|
|
102
|
+
},
|
|
103
|
+
create_polygon: () => {
|
|
104
|
+
dispatch({
|
|
105
|
+
type: "SELECT_TOOL",
|
|
106
|
+
selectedTool: "create-polygon",
|
|
107
|
+
})
|
|
108
|
+
},
|
|
109
|
+
create_pixel: () => {
|
|
110
|
+
dispatch({
|
|
111
|
+
type: "SELECT_TOOL",
|
|
112
|
+
selectedTool: "create-pixel",
|
|
113
|
+
})
|
|
114
|
+
},
|
|
115
|
+
save_and_previous_sample: () => {
|
|
116
|
+
dispatch({
|
|
117
|
+
type: "HEADER_BUTTON_CLICKED",
|
|
118
|
+
buttonName: "Prev",
|
|
119
|
+
})
|
|
120
|
+
},
|
|
121
|
+
save_and_next_sample: () => {
|
|
122
|
+
dispatch({
|
|
123
|
+
type: "HEADER_BUTTON_CLICKED",
|
|
124
|
+
buttonName: "Next",
|
|
125
|
+
})
|
|
126
|
+
},
|
|
127
|
+
save_and_exit_sample: () => {
|
|
128
|
+
dispatch({
|
|
129
|
+
type: "HEADER_BUTTON_CLICKED",
|
|
130
|
+
buttonName: "Save",
|
|
131
|
+
})
|
|
132
|
+
},
|
|
133
|
+
delete_region: () => {
|
|
134
|
+
dispatch({
|
|
135
|
+
type: "DELETE_SELECTED_REGION",
|
|
136
|
+
})
|
|
137
|
+
},
|
|
138
|
+
undo: () => {
|
|
139
|
+
dispatch({
|
|
140
|
+
type: "RESTORE_HISTORY",
|
|
141
|
+
})
|
|
142
|
+
},
|
|
143
|
+
// TODO
|
|
144
|
+
// exit_sample: () => {
|
|
145
|
+
// dispatch({
|
|
146
|
+
// type: "",
|
|
147
|
+
// })
|
|
148
|
+
// }
|
|
149
|
+
}),
|
|
150
|
+
[dispatch]
|
|
151
|
+
)
|
|
152
|
+
return handlers
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default ({ children, dispatch }) => {
|
|
156
|
+
const handlers = useDispatchHotkeyHandlers({ dispatch })
|
|
157
|
+
return (
|
|
158
|
+
<HotKeys allowChanges handlers={handlers}>
|
|
159
|
+
{children}
|
|
160
|
+
</HotKeys>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React from "react"
|
|
4
|
+
import { styled } from "@mui/styles"
|
|
5
|
+
import { createTheme, ThemeProvider } from "@mui/material/styles"
|
|
6
|
+
import TaskDescription from "../TaskDescriptionSidebarBox"
|
|
7
|
+
import ImageSelector from "../ImageSelectorSidebarBox"
|
|
8
|
+
import RegionSelector from "../RegionSelectorSidebarBox"
|
|
9
|
+
import History from "../HistorySidebarBox"
|
|
10
|
+
import DebugBox from "../DebugSidebarBox"
|
|
11
|
+
import TagsSidebarBox from "../TagsSidebarBox"
|
|
12
|
+
import KeyframesSelector from "../KeyframesSelectorSidebarBox"
|
|
13
|
+
import type { Region } from "../ImageCanvas/region-tools.js"
|
|
14
|
+
|
|
15
|
+
const theme = createTheme()
|
|
16
|
+
const Container = styled("div")(({ theme }) => ({}))
|
|
17
|
+
|
|
18
|
+
type Image = {
|
|
19
|
+
name: string,
|
|
20
|
+
src: string,
|
|
21
|
+
cls?: string,
|
|
22
|
+
tags?: Array<string>,
|
|
23
|
+
thumbnailSrc?: string,
|
|
24
|
+
regions?: Array<Region>,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type Props = {
|
|
28
|
+
debug: any,
|
|
29
|
+
taskDescription: string,
|
|
30
|
+
images?: Array<Image>,
|
|
31
|
+
regions: Array<Region>,
|
|
32
|
+
history: Array<{ state: Object, name: string, time: Date }>,
|
|
33
|
+
|
|
34
|
+
labelImages?: boolean,
|
|
35
|
+
currentImage?: Image,
|
|
36
|
+
imageClsList?: Array<string>,
|
|
37
|
+
imageTagList?: Array<string>,
|
|
38
|
+
|
|
39
|
+
onChangeImage: (Image) => any,
|
|
40
|
+
onSelectRegion: (Region) => any,
|
|
41
|
+
onSelectImage: (Image) => any,
|
|
42
|
+
onChangeRegion: (Region) => any,
|
|
43
|
+
onDeleteRegion: (Region) => any,
|
|
44
|
+
onRestoreHistory: () => any,
|
|
45
|
+
onShortcutActionDispatched: (action: any) => any,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const emptyArr = []
|
|
49
|
+
|
|
50
|
+
export const Sidebar = ({
|
|
51
|
+
debug,
|
|
52
|
+
taskDescription,
|
|
53
|
+
keyframes,
|
|
54
|
+
images,
|
|
55
|
+
regions,
|
|
56
|
+
history,
|
|
57
|
+
labelImages,
|
|
58
|
+
currentImage,
|
|
59
|
+
currentVideoTime,
|
|
60
|
+
imageClsList,
|
|
61
|
+
imageTagList,
|
|
62
|
+
onChangeImage,
|
|
63
|
+
onSelectRegion,
|
|
64
|
+
onSelectImage,
|
|
65
|
+
onChangeRegion,
|
|
66
|
+
onDeleteRegion,
|
|
67
|
+
onRestoreHistory,
|
|
68
|
+
onChangeVideoTime,
|
|
69
|
+
onDeleteKeyframe,
|
|
70
|
+
onShortcutActionDispatched,
|
|
71
|
+
}: Props) => {
|
|
72
|
+
if (!regions) regions = emptyArr
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<ThemeProvider theme={theme}>
|
|
76
|
+
<Container>
|
|
77
|
+
{debug && <DebugBox state={debug} lastAction={debug.lastAction} />}
|
|
78
|
+
{taskDescription && (taskDescription || "").length > 1 && (
|
|
79
|
+
<TaskDescription description={taskDescription} />
|
|
80
|
+
)}
|
|
81
|
+
{labelImages && (
|
|
82
|
+
<TagsSidebarBox
|
|
83
|
+
currentImage={currentImage}
|
|
84
|
+
imageClsList={imageClsList}
|
|
85
|
+
imageTagList={imageTagList}
|
|
86
|
+
onChangeImage={onChangeImage}
|
|
87
|
+
expandedByDefault
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
{/* {images && images.length > 1 && (
|
|
91
|
+
<ImageSelector onSelect={onSelectImage} images={images} />
|
|
92
|
+
)} */}
|
|
93
|
+
<RegionSelector
|
|
94
|
+
regions={regions}
|
|
95
|
+
onSelectRegion={onSelectRegion}
|
|
96
|
+
onChangeRegion={onChangeRegion}
|
|
97
|
+
onDeleteRegion={onDeleteRegion}
|
|
98
|
+
/>
|
|
99
|
+
{keyframes && (
|
|
100
|
+
<KeyframesSelector
|
|
101
|
+
currentVideoTime={currentVideoTime}
|
|
102
|
+
keyframes={keyframes}
|
|
103
|
+
onChangeVideoTime={onChangeVideoTime}
|
|
104
|
+
onDeleteKeyframe={onDeleteKeyframe}
|
|
105
|
+
/>
|
|
106
|
+
)}
|
|
107
|
+
<History
|
|
108
|
+
history={history}
|
|
109
|
+
onRestoreHistory={() => onRestoreHistory()}
|
|
110
|
+
/>
|
|
111
|
+
{/* <Shortcuts onShortcutActionDispatched={onShortcutActionDispatched} /> */}
|
|
112
|
+
</Container>
|
|
113
|
+
</ThemeProvider>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default Sidebar
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useState, memo } from "react"
|
|
4
|
+
import Paper from "@mui/material/Paper"
|
|
5
|
+
import { makeStyles } from "@mui/styles"
|
|
6
|
+
import { createTheme, ThemeProvider } from "@mui/material/styles"
|
|
7
|
+
import ExpandIcon from "@mui/icons-material/ExpandMore"
|
|
8
|
+
import IconButton from "@mui/material/IconButton"
|
|
9
|
+
import Collapse from "@mui/material/Collapse"
|
|
10
|
+
import { grey } from "@mui/material/colors"
|
|
11
|
+
import classnames from "classnames"
|
|
12
|
+
import useEventCallback from "use-event-callback"
|
|
13
|
+
import SidebarBox from "react-material-workspace-layout/SidebarBox"
|
|
14
|
+
|
|
15
|
+
const theme = createTheme()
|
|
16
|
+
const useStyles = makeStyles((theme) => ({
|
|
17
|
+
container: { margin: 8 },
|
|
18
|
+
header: {
|
|
19
|
+
display: "flex",
|
|
20
|
+
flexDirection: "row",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
padding: 8,
|
|
23
|
+
paddingLeft: 16,
|
|
24
|
+
paddingRight: 16,
|
|
25
|
+
},
|
|
26
|
+
title: {
|
|
27
|
+
fontSize: 14,
|
|
28
|
+
fontWeight: "bold",
|
|
29
|
+
flexGrow: 1,
|
|
30
|
+
paddingLeft: 8,
|
|
31
|
+
color: grey[800],
|
|
32
|
+
"& span": {
|
|
33
|
+
color: grey[600],
|
|
34
|
+
fontSize: 12,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
expandButton: {
|
|
38
|
+
padding: 0,
|
|
39
|
+
width: 30,
|
|
40
|
+
height: 30,
|
|
41
|
+
"& .icon": {
|
|
42
|
+
marginTop: -6,
|
|
43
|
+
width: 20,
|
|
44
|
+
height: 20,
|
|
45
|
+
transition: "500ms transform",
|
|
46
|
+
"&.expanded": {
|
|
47
|
+
transform: "rotate(180deg)",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
expandedContent: {
|
|
52
|
+
maxHeight: 300,
|
|
53
|
+
overflowY: "auto",
|
|
54
|
+
"&.noScroll": {
|
|
55
|
+
overflowY: "visible",
|
|
56
|
+
overflow: "visible",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}))
|
|
60
|
+
|
|
61
|
+
export const SidebarBoxContainer = ({
|
|
62
|
+
icon,
|
|
63
|
+
title,
|
|
64
|
+
subTitle,
|
|
65
|
+
children,
|
|
66
|
+
noScroll = false,
|
|
67
|
+
expandedByDefault = false,
|
|
68
|
+
}) => {
|
|
69
|
+
const classes = useStyles()
|
|
70
|
+
const content = (
|
|
71
|
+
<div
|
|
72
|
+
className={classnames(classes.expandedContent, noScroll && "noScroll")}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
const [expanded, changeExpanded] = useState(expandedByDefault)
|
|
79
|
+
const toggleExpanded = useEventCallback(() => changeExpanded(!expanded))
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<ThemeProvider theme={theme}>
|
|
83
|
+
<SidebarBox icon={icon} title={title}>
|
|
84
|
+
{children}
|
|
85
|
+
</SidebarBox>
|
|
86
|
+
</ThemeProvider>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default memo(
|
|
91
|
+
SidebarBoxContainer,
|
|
92
|
+
(prev, next) => prev.title === next.title && prev.children === next.children
|
|
93
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext, memo } from "react"
|
|
4
|
+
import IconButton from "@mui/material/IconButton"
|
|
5
|
+
import Tooltip from "@mui/material/Tooltip"
|
|
6
|
+
import { blue } from "@mui/material/colors"
|
|
7
|
+
|
|
8
|
+
export const SelectedTool = createContext()
|
|
9
|
+
|
|
10
|
+
export const SmallToolButton = ({
|
|
11
|
+
id,
|
|
12
|
+
name,
|
|
13
|
+
icon,
|
|
14
|
+
selected,
|
|
15
|
+
togglable,
|
|
16
|
+
alwaysShowing = false,
|
|
17
|
+
}: {
|
|
18
|
+
id: string,
|
|
19
|
+
name: string,
|
|
20
|
+
icon: any,
|
|
21
|
+
alwaysShowing?: boolean,
|
|
22
|
+
selected?: boolean,
|
|
23
|
+
togglable?: boolean,
|
|
24
|
+
}) => {
|
|
25
|
+
const { enabledTools, selectedTool, onClickTool } = useContext(SelectedTool)
|
|
26
|
+
if (!enabledTools.includes(id) && !alwaysShowing) return null
|
|
27
|
+
selected = selected || selectedTool === id
|
|
28
|
+
return (
|
|
29
|
+
<Tooltip placement="right" title={name}>
|
|
30
|
+
<div>
|
|
31
|
+
<IconButton
|
|
32
|
+
disabled={!togglable ? selected : undefined}
|
|
33
|
+
aria-label={name}
|
|
34
|
+
onClick={() => onClickTool(id)}
|
|
35
|
+
size="small"
|
|
36
|
+
style={{
|
|
37
|
+
width: 50,
|
|
38
|
+
height: 50,
|
|
39
|
+
margin: 1,
|
|
40
|
+
color: selected ? blue[500] : undefined,
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
{icon}
|
|
44
|
+
</IconButton>
|
|
45
|
+
</div>
|
|
46
|
+
</Tooltip>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default memo(
|
|
51
|
+
SmallToolButton,
|
|
52
|
+
(prevProps, nextProps) =>
|
|
53
|
+
prevProps.togglable === nextProps.togglable &&
|
|
54
|
+
prevProps.selected === nextProps.selected &&
|
|
55
|
+
prevProps.name === nextProps.name &&
|
|
56
|
+
prevProps.id === nextProps.id
|
|
57
|
+
)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useMemo, memo } from "react"
|
|
4
|
+
import SidebarBoxContainer from "../SidebarBoxContainer"
|
|
5
|
+
import StyleIcon from "@mui/icons-material/Style"
|
|
6
|
+
import { grey } from "@mui/material/colors"
|
|
7
|
+
import Select from "react-select"
|
|
8
|
+
import useEventCallback from "use-event-callback"
|
|
9
|
+
import { asMutable } from "seamless-immutable"
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
tags: Array<string>,
|
|
13
|
+
currentImage: { cls?: string, tags?: Array<string> },
|
|
14
|
+
imageClsList?: Array<string>,
|
|
15
|
+
imageTagList?: Array<string>,
|
|
16
|
+
onChangeImage: (Array<string>) => any,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const emptyArr = []
|
|
20
|
+
const noop = () => null
|
|
21
|
+
|
|
22
|
+
export const TagsSidebarBox = ({
|
|
23
|
+
currentImage,
|
|
24
|
+
imageClsList = emptyArr,
|
|
25
|
+
imageTagList = emptyArr,
|
|
26
|
+
onChangeImage = noop,
|
|
27
|
+
}: Props) => {
|
|
28
|
+
const { tags = [], cls = null } = currentImage || {}
|
|
29
|
+
const onChangeClassification = useEventCallback((o) =>
|
|
30
|
+
onChangeImage({ cls: o.value })
|
|
31
|
+
)
|
|
32
|
+
const onChangeTags = useEventCallback((o) =>
|
|
33
|
+
onChangeImage({ tags: o.map((a) => a.value) })
|
|
34
|
+
)
|
|
35
|
+
const selectValue = useMemo(
|
|
36
|
+
() => (cls ? { value: cls, label: cls } : null),
|
|
37
|
+
[cls]
|
|
38
|
+
)
|
|
39
|
+
const memoImgClsList = useMemo(
|
|
40
|
+
() => asMutable(imageClsList.map((c) => ({ value: c, label: c }))),
|
|
41
|
+
[imageClsList]
|
|
42
|
+
)
|
|
43
|
+
const memoImgTagList = useMemo(
|
|
44
|
+
() => asMutable(imageTagList.map((c) => ({ value: c, label: c }))),
|
|
45
|
+
[imageTagList]
|
|
46
|
+
)
|
|
47
|
+
const memoCurrentTags = useMemo(
|
|
48
|
+
() => tags.map((r) => ({ value: r, label: r })),
|
|
49
|
+
[tags]
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if (!currentImage) return null
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<SidebarBoxContainer
|
|
56
|
+
title="Image Tags"
|
|
57
|
+
expandedByDefault
|
|
58
|
+
noScroll
|
|
59
|
+
icon={<StyleIcon style={{ color: grey[700] }} />}
|
|
60
|
+
>
|
|
61
|
+
{imageClsList.length > 0 && (
|
|
62
|
+
<div style={{ padding: 8 }}>
|
|
63
|
+
<Select
|
|
64
|
+
placeholder="Image Classification"
|
|
65
|
+
onChange={onChangeClassification}
|
|
66
|
+
value={selectValue}
|
|
67
|
+
options={memoImgClsList}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
{imageTagList.length > 0 && (
|
|
72
|
+
<div style={{ padding: 8, paddingTop: 0 }}>
|
|
73
|
+
<Select
|
|
74
|
+
isMulti
|
|
75
|
+
placeholder="Image Tags"
|
|
76
|
+
onChange={onChangeTags}
|
|
77
|
+
value={memoCurrentTags}
|
|
78
|
+
options={memoImgTagList}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</SidebarBoxContainer>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default memo(
|
|
87
|
+
TagsSidebarBox,
|
|
88
|
+
(prevProps, nextProps) =>
|
|
89
|
+
prevProps.currentImage.cls === nextProps.currentImage.cls &&
|
|
90
|
+
prevProps.currentImage.tags === nextProps.currentImage.tags &&
|
|
91
|
+
prevProps.imageClsList === nextProps.imageClsList &&
|
|
92
|
+
prevProps.imageTagList === nextProps.imageTagList
|
|
93
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { memo } from "react"
|
|
4
|
+
import SidebarBoxContainer from "../SidebarBoxContainer"
|
|
5
|
+
import DescriptionIcon from "@mui/icons-material/Description"
|
|
6
|
+
import { styled } from "@mui/material/styles"
|
|
7
|
+
import { createTheme, ThemeProvider } from "@mui/material/styles"
|
|
8
|
+
import { grey } from "@mui/material/colors"
|
|
9
|
+
import Markdown from "react-markdown"
|
|
10
|
+
|
|
11
|
+
const theme = createTheme()
|
|
12
|
+
const MarkdownContainer = styled("div")(({ theme }) => ({
|
|
13
|
+
paddingLeft: 16,
|
|
14
|
+
paddingRight: 16,
|
|
15
|
+
fontSize: 12,
|
|
16
|
+
"& h1": { fontSize: 18 },
|
|
17
|
+
"& h2": { fontSize: 14 },
|
|
18
|
+
"& h3": { fontSize: 12 },
|
|
19
|
+
"& h4": { fontSize: 12 },
|
|
20
|
+
"& h5": { fontSize: 12 },
|
|
21
|
+
"& h6": { fontSize: 12 },
|
|
22
|
+
"& p": { fontSize: 12 },
|
|
23
|
+
"& a": {},
|
|
24
|
+
"& img": { width: "100%" },
|
|
25
|
+
}))
|
|
26
|
+
|
|
27
|
+
export const TaskDescriptionSidebarBox = ({ description }) => {
|
|
28
|
+
return (
|
|
29
|
+
<ThemeProvider theme={theme}>
|
|
30
|
+
<SidebarBoxContainer
|
|
31
|
+
title="Task Description"
|
|
32
|
+
icon={<DescriptionIcon style={{ color: grey[700] }} />}
|
|
33
|
+
expandedByDefault={description && description !== "" ? false : true}
|
|
34
|
+
>
|
|
35
|
+
<MarkdownContainer>
|
|
36
|
+
<Markdown source={description} />
|
|
37
|
+
</MarkdownContainer>
|
|
38
|
+
</SidebarBoxContainer>
|
|
39
|
+
</ThemeProvider>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default memo(TaskDescriptionSidebarBox)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React from "react"
|
|
4
|
+
import { ThemeProvider, createTheme } from "@mui/material/styles"
|
|
5
|
+
import { makeStyles } from "@mui/styles"
|
|
6
|
+
|
|
7
|
+
const useStyles = makeStyles((theme) => ({
|
|
8
|
+
container: {
|
|
9
|
+
fontFamily: '"Inter", sans-serif',
|
|
10
|
+
},
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
const theme = createTheme({
|
|
14
|
+
typography: {
|
|
15
|
+
fontFamily: '"Inter", "Roboto", sans-serif',
|
|
16
|
+
},
|
|
17
|
+
overrides: {
|
|
18
|
+
MuiButton: {
|
|
19
|
+
root: {
|
|
20
|
+
textTransform: "none",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export const Theme = ({ children }: any) => {
|
|
27
|
+
const classes = useStyles()
|
|
28
|
+
return (
|
|
29
|
+
<ThemeProvider theme={theme}>
|
|
30
|
+
{/* <div className={classes.container}>{children}</div> */}
|
|
31
|
+
<div>{children}</div>
|
|
32
|
+
</ThemeProvider>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default Theme
|