Revize c73aecde
Přidáno uživatelem Dominik Poch před asi 3 roky(ů)
webapp/components/annotation/AnnotationItem.tsx | ||
---|---|---|
1 |
import { Col, Container, Row, Stack } from 'react-bootstrap'; |
|
2 |
import { Occurrence, Tag } from '../types/tag'; |
|
3 |
import { ChangeEvent, useContext, useState } from 'react'; |
|
4 |
|
|
5 |
import 'antd/dist/antd.css'; |
|
6 |
import { Button, Input } from 'antd'; |
|
7 |
import { |
|
8 |
PlusOutlined, |
|
9 |
EyeOutlined, |
|
10 |
DownOutlined, |
|
11 |
DeleteOutlined, |
|
12 |
} from '@ant-design/icons'; |
|
13 |
import { AnnotationContext } from '../../contexts/AnnotationContext'; |
|
14 |
|
|
15 |
export function AnnotationItem(props: { tag: Tag }) { |
|
16 |
const [visibleProperties, setVisibleProperties] = useState(false); |
|
17 |
const { |
|
18 |
addOccurrence, |
|
19 |
deleteOccurrence, |
|
20 |
changeVisibility, |
|
21 |
changePosition, |
|
22 |
changeLength, |
|
23 |
} = useContext(AnnotationContext); |
|
24 |
|
|
25 |
const onAddOccurrence = () => { |
|
26 |
addOccurrence(props.tag); |
|
27 |
}; |
|
28 |
|
|
29 |
const onDeleteOccurrence = (occurrence: Occurrence) => (e: any) => { |
|
30 |
deleteOccurrence(occurrence); |
|
31 |
}; |
|
32 |
|
|
33 |
const onChangeVisibility = () => { |
|
34 |
changeVisibility(props.tag); |
|
35 |
}; |
|
36 |
|
|
37 |
const onChangePosition = |
|
38 |
(occurrence: Occurrence) => (e: ChangeEvent<HTMLInputElement>) => { |
|
39 |
changePosition(occurrence, Number(e.currentTarget.value)); |
|
40 |
}; |
|
41 |
|
|
42 |
const onChangeLength = |
|
43 |
(occurrence: Occurrence) => (e: ChangeEvent<HTMLInputElement>) => { |
|
44 |
changeLength(occurrence, Number(e.currentTarget.value)); |
|
45 |
}; |
|
46 |
|
|
47 |
const changePropertiesVisibility = () => { |
|
48 |
setVisibleProperties(!visibleProperties); |
|
49 |
}; |
|
50 |
|
|
51 |
return ( |
|
52 |
<Container> |
|
53 |
<Row> |
|
54 |
<Col className="d-flex align-items-center">{props.tag.name}</Col> |
|
55 |
<Col sm="auto"> |
|
56 |
<Button |
|
57 |
type="text" |
|
58 |
shape="circle" |
|
59 |
icon={<PlusOutlined />} |
|
60 |
onClick={onAddOccurrence} |
|
61 |
/> |
|
62 |
<Button |
|
63 |
type="text" |
|
64 |
shape="circle" |
|
65 |
icon={<EyeOutlined />} |
|
66 |
onClick={onChangeVisibility} |
|
67 |
/> |
|
68 |
<Button |
|
69 |
type="text" |
|
70 |
shape="circle" |
|
71 |
icon={<DownOutlined />} |
|
72 |
onClick={changePropertiesVisibility} |
|
73 |
/> |
|
74 |
</Col> |
|
75 |
</Row> |
|
76 |
{visibleProperties && ( |
|
77 |
<Stack> |
|
78 |
<div>Kategorie: {props.tag.category}</div> |
|
79 |
<div>Výskyty:</div> |
|
80 |
{props.tag.occurrences.map((occurrence, index) => { |
|
81 |
return ( |
|
82 |
<div key={index} id={props.tag.name + index}> |
|
83 |
<Container> |
|
84 |
<Row> |
|
85 |
<Col> |
|
86 |
<Row> |
|
87 |
<Col className="d-flex align-items-center"> |
|
88 |
Pozice: |
|
89 |
</Col> |
|
90 |
<Col sm="auto"> |
|
91 |
<Input |
|
92 |
value={occurrence.position} |
|
93 |
onChange={onChangePosition( |
|
94 |
occurrence |
|
95 |
)} |
|
96 |
/> |
|
97 |
</Col> |
|
98 |
</Row> |
|
99 |
<Row> |
|
100 |
<Col className="d-flex align-items-center"> |
|
101 |
Délka: |
|
102 |
</Col> |
|
103 |
<Col sm="auto"> |
|
104 |
<Input |
|
105 |
value={occurrence.length} |
|
106 |
onChange={onChangeLength( |
|
107 |
occurrence |
|
108 |
)} |
|
109 |
/> |
|
110 |
</Col> |
|
111 |
</Row> |
|
112 |
</Col> |
|
113 |
<Col |
|
114 |
sm="auto" |
|
115 |
className="d-flex align-items-center" |
|
116 |
> |
|
117 |
<Button |
|
118 |
icon={<DeleteOutlined />} |
|
119 |
onClick={onDeleteOccurrence(occurrence)} |
|
120 |
></Button> |
|
121 |
</Col> |
|
122 |
</Row> |
|
123 |
</Container> |
|
124 |
</div> |
|
125 |
); |
|
126 |
})} |
|
127 |
</Stack> |
|
128 |
)} |
|
129 |
</Container> |
|
130 |
); |
|
131 |
} |
webapp/components/annotation/AnnotationPanel.tsx | ||
---|---|---|
1 |
import { Stack } from 'react-bootstrap'; |
|
2 |
import { AnnotationItem } from './AnnotationItem'; |
|
3 |
import { useContext } from 'react'; |
|
4 |
import { AnnotationContext } from '../../contexts/AnnotationContext'; |
|
5 |
import { Tag } from '../types/tag'; |
|
6 |
|
|
7 |
/** |
|
8 |
* Creates a panel in the annotation screen that contains a list of annotations. |
|
9 |
* @returns Panel with a list of annotations. |
|
10 |
*/ |
|
11 |
export function AnnotationPanel() { |
|
12 |
//const { tags } = useContext(AnnotationContext); |
|
13 |
|
|
14 |
const tags: Tag[] = [ |
|
15 |
{ |
|
16 |
name: 'tag a', |
|
17 |
category: 'kategorie 1', |
|
18 |
visible: true, |
|
19 |
occurrences: [ |
|
20 |
{ position: 2, length: 5 }, |
|
21 |
{ position: 10, length: 2 }, |
|
22 |
], |
|
23 |
}, |
|
24 |
{ |
|
25 |
name: 'tag b', |
|
26 |
category: 'kategorie 2', |
|
27 |
visible: true, |
|
28 |
occurrences: [ |
|
29 |
{ position: 546, length: 432 }, |
|
30 |
{ position: 767, length: 123 }, |
|
31 |
], |
|
32 |
}, |
|
33 |
]; |
|
34 |
|
|
35 |
return ( |
|
36 |
<div> |
|
37 |
<Stack> |
|
38 |
{tags?.map((tag, index) => { |
|
39 |
return <AnnotationItem key={index} tag={tag} />; |
|
40 |
})} |
|
41 |
</Stack> |
|
42 |
</div> |
|
43 |
); |
|
44 |
} |
webapp/components/annotation/DocumentAnnotationView.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates an annotation view of a document. |
|
3 |
* @returns The annotation view. |
|
4 |
*/ |
|
5 |
export function DocumentAnnotationView() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Main view with a rendered document</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/annotation/TagPanel.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates a panel in the annotation screen that contains a list of tag. |
|
3 |
* @returns Panel with a list of tags. |
|
4 |
*/ |
|
5 |
export function TagPanel() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Panel with a list of tags</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/annotation/annotationItem.tsx | ||
---|---|---|
1 |
import { Col, Container, Row, Stack } from 'react-bootstrap'; |
|
2 |
import { Occurrence, Tag } from '../models/tag'; |
|
3 |
import { ChangeEvent, ChangeEventHandler, useState } from 'react'; |
|
4 |
|
|
5 |
import 'antd/dist/antd.css'; |
|
6 |
import { Button, Input } from 'antd'; |
|
7 |
import { |
|
8 |
PlusOutlined, |
|
9 |
EyeOutlined, |
|
10 |
DownOutlined, |
|
11 |
DeleteOutlined, |
|
12 |
} from '@ant-design/icons'; |
|
13 |
|
|
14 |
type AnnotationItemProps = { |
|
15 |
tag: Tag; |
|
16 |
onAddOccurrence: (tag: Tag) => void; |
|
17 |
onDeleteOccurrence: (occurrence: Occurrence) => void; |
|
18 |
onChangeVisibility: (tag: Tag) => void; |
|
19 |
onChangePosition: (occurrence: Occurrence, newValue: number) => void; |
|
20 |
onChangeLength: (occurrence: Occurrence, newValue: number) => void; |
|
21 |
}; |
|
22 |
|
|
23 |
export function AnnotationItem(props: AnnotationItemProps) { |
|
24 |
const [visibleProperties, setVisibleProperties] = useState(false); |
|
25 |
|
|
26 |
const addOccurrence = () => { |
|
27 |
props.onAddOccurrence(props.tag); |
|
28 |
}; |
|
29 |
|
|
30 |
const deleteOccurrence = (occurrence: Occurrence) => (e: any) => { |
|
31 |
props.onDeleteOccurrence(occurrence); |
|
32 |
}; |
|
33 |
|
|
34 |
const changeVisibility = () => { |
|
35 |
props.onChangeVisibility(props.tag); |
|
36 |
}; |
|
37 |
|
|
38 |
const changePropertiesVisibility = () => { |
|
39 |
setVisibleProperties(!visibleProperties); |
|
40 |
}; |
|
41 |
|
|
42 |
const changePosition = |
|
43 |
(occurrence: Occurrence) => (e: ChangeEvent<HTMLInputElement>) => { |
|
44 |
props.onChangePosition(occurrence, Number(e.currentTarget.value)); |
|
45 |
}; |
|
46 |
|
|
47 |
const changeLength = |
|
48 |
(occurrence: Occurrence) => (e: ChangeEvent<HTMLInputElement>) => { |
|
49 |
props.onChangeLength(occurrence, Number(e.currentTarget.value)); |
|
50 |
}; |
|
51 |
|
|
52 |
return ( |
|
53 |
<div> |
|
54 |
<Row> |
|
55 |
<Col className="d-flex align-items-center">{props.tag.name}</Col> |
|
56 |
<Col sm="auto"> |
|
57 |
<Button |
|
58 |
type="text" |
|
59 |
shape="circle" |
|
60 |
icon={<PlusOutlined />} |
|
61 |
onClick={addOccurrence} |
|
62 |
/> |
|
63 |
<Button |
|
64 |
type="text" |
|
65 |
shape="circle" |
|
66 |
icon={<EyeOutlined />} |
|
67 |
onClick={changeVisibility} |
|
68 |
/> |
|
69 |
<Button |
|
70 |
type="text" |
|
71 |
shape="circle" |
|
72 |
icon={<DownOutlined />} |
|
73 |
onClick={changePropertiesVisibility} |
|
74 |
/> |
|
75 |
</Col> |
|
76 |
</Row> |
|
77 |
{visibleProperties && ( |
|
78 |
<Stack> |
|
79 |
<div>Kategorie: {props.tag.category}</div> |
|
80 |
<div>Výskyty:</div> |
|
81 |
{props.tag.occurrences.map((occurrence, index) => { |
|
82 |
return ( |
|
83 |
<div key={index} id={props.tag.name + index}> |
|
84 |
<Container> |
|
85 |
<Row> |
|
86 |
<Col> |
|
87 |
<Row> |
|
88 |
Pozice: |
|
89 |
<Input |
|
90 |
value={occurrence.position} |
|
91 |
onChange={changePosition(occurrence)} |
|
92 |
/> |
|
93 |
</Row> |
|
94 |
<Row> |
|
95 |
Délka: |
|
96 |
<Input |
|
97 |
value={occurrence.length} |
|
98 |
onChange={changeLength(occurrence)} |
|
99 |
/> |
|
100 |
</Row> |
|
101 |
</Col> |
|
102 |
<Col |
|
103 |
sm="auto" |
|
104 |
className="d-flex align-items-center" |
|
105 |
> |
|
106 |
<Button |
|
107 |
icon={<DeleteOutlined />} |
|
108 |
onClick={deleteOccurrence(occurrence)} |
|
109 |
></Button> |
|
110 |
</Col> |
|
111 |
</Row> |
|
112 |
</Container> |
|
113 |
</div> |
|
114 |
); |
|
115 |
})} |
|
116 |
</Stack> |
|
117 |
)} |
|
118 |
</div> |
|
119 |
); |
|
120 |
} |
webapp/components/annotation/annotationPanel.tsx | ||
---|---|---|
1 |
import { Stack } from 'react-bootstrap'; |
|
2 |
import { AnnotationItem } from './annotationItem'; |
|
3 |
import { Occurrence, Tag } from '../models/tag'; |
|
4 |
import { useContext } from 'react'; |
|
5 |
import { AnnotationContext } from '../../contexts/AnnotationContext'; |
|
6 |
|
|
7 |
type AnnotationPanelProps = { |
|
8 |
tags: Tag[]; |
|
9 |
onAddOccurrence: (tag: Tag) => void; |
|
10 |
onDeleteOccurrence: (occurrence: Occurrence) => void; |
|
11 |
onChangeVisibility: (tag: Tag) => void; |
|
12 |
onChangePosition: (occurrence: Occurrence, newValue: number) => void; |
|
13 |
onChangeLength: (occurrence: Occurrence, newValue: number) => void; |
|
14 |
}; |
|
15 |
|
|
16 |
/** |
|
17 |
* Creates a panel in the annotation screen that contains a list of annotations. |
|
18 |
* @returns Panel with a list of annotations. |
|
19 |
*/ |
|
20 |
export function AnnotationPanel(props: AnnotationPanelProps) { |
|
21 |
const { tags } = useContext(AnnotationContext); |
|
22 |
|
|
23 |
return ( |
|
24 |
<div> |
|
25 |
<p>Panel with a list of annotations</p> |
|
26 |
<Stack> |
|
27 |
{props.tags.map((tag, index) => { |
|
28 |
return ( |
|
29 |
<AnnotationItem |
|
30 |
key={index} |
|
31 |
tag={tag} |
|
32 |
onAddOccurrence={props.onAddOccurrence} |
|
33 |
onDeleteOccurrence={props.onDeleteOccurrence} |
|
34 |
onChangeVisibility={props.onChangeVisibility} |
|
35 |
onChangePosition={props.onChangePosition} |
|
36 |
onChangeLength={props.onChangeLength} |
|
37 |
/> |
|
38 |
); |
|
39 |
})} |
|
40 |
</Stack> |
|
41 |
</div> |
|
42 |
); |
|
43 |
} |
webapp/components/annotation/documentAnnotationView.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates an annotation view of a document. |
|
3 |
* @returns The annotation view. |
|
4 |
*/ |
|
5 |
export function DocumentAnnotationView() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Main view with a rendered document</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/annotation/tagPanel.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates a panel in the annotation screen that contains a list of tag. |
|
3 |
* @returns Panel with a list of tags. |
|
4 |
*/ |
|
5 |
export function TagPanel() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Panel with a list of tags</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/modals/AddDocument.tsx | ||
---|---|---|
1 |
import { message, Button, Modal, Upload } from 'antd'; |
|
2 |
import { InboxOutlined } from '@ant-design/icons'; |
|
3 |
import 'antd/dist/antd.css'; |
|
4 |
|
|
5 |
const { Dragger } = Upload; |
|
6 |
|
|
7 |
/** |
|
8 |
* Creates a modal window that loads documents to the app. |
|
9 |
* @returns The modal window. |
|
10 |
*/ |
|
11 |
export function AddDocument(afterClose: () => {}) { |
|
12 |
/** |
|
13 |
* Settings of a file loader. |
|
14 |
*/ |
|
15 |
const props = { |
|
16 |
name: 'file', |
|
17 |
multiple: true, |
|
18 |
directory: true, |
|
19 |
/** |
|
20 |
@todo: Probably will be needed to change the uploading URL |
|
21 |
**/ |
|
22 |
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', |
|
23 |
onChange(info: any) { |
|
24 |
const { status } = info.file; |
|
25 |
|
|
26 |
if (status !== 'uploading') { |
|
27 |
console.log(info.file, info.fileList); |
|
28 |
} |
|
29 |
|
|
30 |
if (status === 'done') { |
|
31 |
message.success(`${info.file.name} file uploaded successfully.`); |
|
32 |
} else if (status === 'error') { |
|
33 |
message.error(`${info.file.name} file upload failed.`); |
|
34 |
} |
|
35 |
}, |
|
36 |
onDrop(e: any) { |
|
37 |
console.log('Dropped files', e.dataTransfer.files); |
|
38 |
}, |
|
39 |
}; |
|
40 |
|
|
41 |
/** |
|
42 |
* Handles successfull closing of the modal window. |
|
43 |
*/ |
|
44 |
const handleOk = () => { |
|
45 |
/** |
|
46 |
@todo: Send documents to a server when all files are loaded |
|
47 |
**/ |
|
48 |
console.log('Document is loaded'); |
|
49 |
afterClose(); |
|
50 |
}; |
|
51 |
|
|
52 |
/** |
|
53 |
* Handles cancelling of the model window. |
|
54 |
*/ |
|
55 |
const handleCancel = () => { |
|
56 |
console.log('Loading of documents is cancelled.'); |
|
57 |
afterClose(); |
|
58 |
}; |
|
59 |
|
|
60 |
return ( |
|
61 |
<Modal |
|
62 |
title="Nový dokument" |
|
63 |
onOk={handleOk} |
|
64 |
onCancel={handleCancel} |
|
65 |
footer={[ |
|
66 |
<Button key="back" onClick={handleCancel}> |
|
67 |
Storno |
|
68 |
</Button>, |
|
69 |
<Button key="submit" type="primary" onClick={handleOk}> |
|
70 |
Nahrát |
|
71 |
</Button>, |
|
72 |
]} |
|
73 |
> |
|
74 |
<Dragger> |
|
75 |
<p className="ant-upload-drag-icon"> |
|
76 |
<InboxOutlined /> |
|
77 |
</p> |
|
78 |
<p className="ant-upload-text"> |
|
79 |
Soubory lze nahrát stisknutím nebo přetažením... |
|
80 |
</p> |
|
81 |
</Dragger> |
|
82 |
</Modal> |
|
83 |
); |
|
84 |
} |
webapp/components/modals/addDocument.tsx | ||
---|---|---|
1 |
import { message, Button, Modal, Upload } from 'antd'; |
|
2 |
import { useState } from 'react'; |
|
3 |
import { InboxOutlined } from '@ant-design/icons'; |
|
4 |
import 'antd/dist/antd.css'; |
|
5 |
|
|
6 |
const { Dragger } = Upload; |
|
7 |
|
|
8 |
/** |
|
9 |
* Creates a modal window that loads documents to the app. |
|
10 |
* @returns The modal window. |
|
11 |
*/ |
|
12 |
export function AddDocument() { |
|
13 |
const [visible, setVisible] = useState(true); |
|
14 |
|
|
15 |
/** |
|
16 |
* Settings of a file loader. |
|
17 |
*/ |
|
18 |
const props = { |
|
19 |
name: 'file', |
|
20 |
multiple: true, |
|
21 |
directory: true, |
|
22 |
/** |
|
23 |
@todo: Probably will be needed to change the uploading URL |
|
24 |
**/ |
|
25 |
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', |
|
26 |
onChange(info: any) { |
|
27 |
const { status } = info.file; |
|
28 |
|
|
29 |
if (status !== 'uploading') { |
|
30 |
console.log(info.file, info.fileList); |
|
31 |
} |
|
32 |
|
|
33 |
if (status === 'done') { |
|
34 |
message.success(`${info.file.name} file uploaded successfully.`); |
|
35 |
} else if (status === 'error') { |
|
36 |
message.error(`${info.file.name} file upload failed.`); |
|
37 |
} |
|
38 |
}, |
|
39 |
onDrop(e: any) { |
|
40 |
console.log('Dropped files', e.dataTransfer.files); |
|
41 |
}, |
|
42 |
}; |
|
43 |
|
|
44 |
/** |
|
45 |
* Handles successfull closing of the modal window. |
|
46 |
*/ |
|
47 |
const handleOk = () => { |
|
48 |
setVisible(false); |
|
49 |
/** |
|
50 |
@todo: Send documents to a server when all files are loaded |
|
51 |
**/ |
|
52 |
console.log('Document is loaded'); |
|
53 |
}; |
|
54 |
|
|
55 |
/** |
|
56 |
* Handles cancelling of the model window. |
|
57 |
*/ |
|
58 |
const handleCancel = () => { |
|
59 |
setVisible(false); |
|
60 |
console.log('Loading of documents is cancelled.'); |
|
61 |
}; |
|
62 |
|
|
63 |
return ( |
|
64 |
<Modal |
|
65 |
visible={visible} |
|
66 |
title="Nový dokument" |
|
67 |
onOk={handleOk} |
|
68 |
onCancel={handleCancel} |
|
69 |
footer={[ |
|
70 |
<Button key="back" onClick={handleCancel}> |
|
71 |
Storno |
|
72 |
</Button>, |
|
73 |
<Button key="submit" type="primary" onClick={handleOk}> |
|
74 |
Nahrát |
|
75 |
</Button>, |
|
76 |
]} |
|
77 |
> |
|
78 |
<Dragger> |
|
79 |
<p className="ant-upload-drag-icon"> |
|
80 |
<InboxOutlined /> |
|
81 |
</p> |
|
82 |
<p className="ant-upload-text"> |
|
83 |
Soubory lze nahrát stisknutím nebo přetažením... |
|
84 |
</p> |
|
85 |
</Dragger> |
|
86 |
</Modal> |
|
87 |
); |
|
88 |
} |
webapp/components/models/tag.tsx | ||
---|---|---|
1 |
export type Tag = { |
|
2 |
name: string; |
|
3 |
category: string; |
|
4 |
visible: boolean; |
|
5 |
occurrences: Occurrence[]; |
|
6 |
}; |
|
7 |
|
|
8 |
export type Occurrence = { |
|
9 |
position: number; |
|
10 |
length: number; |
|
11 |
}; |
webapp/components/navigation/AdminNavBar.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates a navigation bar of an admin. |
|
3 |
* @returns Navigation bar of an admin. |
|
4 |
*/ |
|
5 |
export function AdminNavBar() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Navigation bar of an admin.</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/navigation/UserNavBar.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates a navigation bar of a normal user (annotator). |
|
3 |
* @returns Navigation bar of a user. |
|
4 |
*/ |
|
5 |
export function UserNavBar() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Navigation bar of a normal user.</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/navigation/adminNavBar.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates a navigation bar of an admin. |
|
3 |
* @returns Navigation bar of an admin. |
|
4 |
*/ |
|
5 |
export function AdminNavBar() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Navigation bar of an admin.</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/navigation/userNavBar.tsx | ||
---|---|---|
1 |
/** |
|
2 |
* Creates a navigation bar of a normal user (annotator). |
|
3 |
* @returns Navigation bar of a user. |
|
4 |
*/ |
|
5 |
export function UserNavBar() { |
|
6 |
return ( |
|
7 |
<div> |
|
8 |
<p>Navigation bar of a normal user.</p> |
|
9 |
</div> |
|
10 |
); |
|
11 |
} |
webapp/components/types/layoutProps.tsx | ||
---|---|---|
1 |
import React from 'react'; |
|
2 |
|
|
3 |
/** |
|
4 |
* Props prepared for a react stucture that is passed to a layout. |
|
5 |
*/ |
|
6 |
export type LayoutProps = { |
|
7 |
children: React.ReactNode; |
|
8 |
}; |
webapp/components/types/tag.tsx | ||
---|---|---|
1 |
export type Tag = { |
|
2 |
name: string; |
|
3 |
category: string; |
|
4 |
visible: boolean; |
|
5 |
occurrences: Occurrence[]; |
|
6 |
}; |
|
7 |
|
|
8 |
export type Occurrence = { |
|
9 |
position: number; |
|
10 |
length: number; |
|
11 |
}; |
webapp/contexts/AnnotationContext.tsx | ||
---|---|---|
1 | 1 |
import React, { createContext, useContext, useEffect, useState } from 'react'; |
2 | 2 |
import { TagInstanceInfo } from '../api'; |
3 |
import { Occurrence, Tag } from '../components/models/tag';
|
|
3 |
import { Occurrence, Tag } from '../components/types/tag';
|
|
4 | 4 |
|
5 | 5 |
interface IAnnotationContextProvider { |
6 | 6 |
tags: TagInstanceInfo[] | null; |
7 | 7 |
setTags: (newTags: TagInstanceInfo[] | null) => void; |
8 |
addOccurrence: () => void; |
|
8 |
addOccurrence: (tag: Tag) => void;
|
|
9 | 9 |
changeVisibility: (tag: Tag) => void; |
10 | 10 |
deleteOccurrence: (occurrence: Occurrence) => void; |
11 | 11 |
changePosition: (occurrence: Occurrence, newValue: number) => void; |
... | ... | |
17 | 17 |
setTags: (v) => { |
18 | 18 |
return; |
19 | 19 |
}, |
20 |
addOccurrence: () => { |
|
20 |
addOccurrence: (tag: Tag) => {
|
|
21 | 21 |
return; |
22 | 22 |
}, |
23 | 23 |
changeVisibility: (tag: Tag) => { |
... | ... | |
36 | 36 |
|
37 | 37 |
const AnnotationProvider = (props: { children: React.ReactNode }) => { |
38 | 38 |
const [tags, setTags] = useState<TagInstanceInfo[] | null>(null); |
39 |
const addOccurrence = () => {}; |
|
39 |
const addOccurrence = (tag: Tag) => {};
|
|
40 | 40 |
const changeVisibility = (tag: Tag) => {}; |
41 | 41 |
const deleteOccurrence = (occurrence: Occurrence) => {}; |
42 | 42 |
const changePosition = (occurrence: Occurrence, newValue: number) => {}; |
webapp/layouts/LoginLayout.tsx | ||
---|---|---|
1 |
import logo from '/public/usp-logo.svg'; |
|
2 |
import Image from 'next/image'; |
|
3 |
import styles from '/styles/Login.module.scss'; |
|
4 |
import { Col, Container, Row, Stack } from 'react-bootstrap'; |
|
5 |
import React from 'react'; |
|
6 |
|
|
7 |
/** |
|
8 |
* Creates layout of a login screen. |
|
9 |
* @param props Html structure of a login form. |
|
10 |
* @returns The login screen. |
|
11 |
*/ |
|
12 |
export function LoginLayout(props: { children: React.ReactNode }) { |
|
13 |
return ( |
|
14 |
<Container> |
|
15 |
<Row className="min-vh-100 align-items-center"> |
|
16 |
<Col md={8}> |
|
17 |
<Stack gap={5}> |
|
18 |
<div> |
|
19 |
<Image |
|
20 |
src={logo} |
|
21 |
alt="Ústav státu a práva Akademie věd ČR" |
|
22 |
></Image> |
|
23 |
</div> |
|
24 |
<h1 className={styles.title}> |
|
25 |
Vítejte na stránkách Ústavu státu a práva Akademie věd ČR pro |
|
26 |
anotaci dokumentů v rámci projektu TAČR TL03000152 - Umělá |
|
27 |
inteligence, média a právo |
|
28 |
</h1> |
|
29 |
</Stack> |
|
30 |
</Col> |
|
31 |
<Col md={4}> |
|
32 |
<main>{props.children}</main> |
|
33 |
</Col> |
|
34 |
</Row> |
|
35 |
</Container> |
|
36 |
); |
|
37 |
} |
webapp/layouts/MainLayout.tsx | ||
---|---|---|
1 |
import { UserNavBar } from '../components/navigation/UserNavBar'; |
|
2 |
import { AdminNavBar } from '../components/navigation/AdminNavBar'; |
|
3 |
import 'antd/dist/antd.css'; |
|
4 |
import styles from '/styles/MainLayout.module.scss'; |
|
5 |
import React from 'react'; |
|
6 |
|
|
7 |
/** |
|
8 |
* Creates layout of main screens. |
|
9 |
* @param props Html structure of a login form. |
|
10 |
* @returns The login screen. |
|
11 |
*/ |
|
12 |
export function MainLayout(props: { children: React.ReactNode }) { |
|
13 |
return ( |
|
14 |
<div className={styles.layoutWrapper}> |
|
15 |
<div className={styles.header}> |
|
16 |
{/** |
|
17 |
@todo: Select correct navigation bar |
|
18 |
{user && <UserNavBar />} |
|
19 |
{admin && <AdminNavBar />} |
|
20 |
**/} |
|
21 |
</div> |
|
22 |
<main className={styles.content}>{props.children}</main> |
|
23 |
<div className={styles.footer}></div> |
|
24 |
</div> |
|
25 |
); |
|
26 |
} |
webapp/layouts/loginLayout.tsx | ||
---|---|---|
1 |
import logo from '/public/usp-logo.svg'; |
|
2 |
import Image from 'next/image'; |
|
3 |
import styles from '/styles/login.module.scss'; |
|
4 |
import { Col, Container, Row, Stack } from 'react-bootstrap'; |
|
5 |
import { LayoutProps } from '../components/types/layoutProps'; |
|
6 |
|
|
7 |
/** |
|
8 |
* Creates layout of a login screen. |
|
9 |
* @param props Html structure of a login form. |
|
10 |
* @returns The login screen. |
|
11 |
*/ |
|
12 |
export function LoginLayout(props: LayoutProps) { |
|
13 |
return ( |
|
14 |
<Container> |
|
15 |
<Row className="min-vh-100 align-items-center"> |
|
16 |
<Col md={8}> |
|
17 |
<Stack gap={5}> |
|
18 |
<div> |
|
19 |
<Image |
|
20 |
src={logo} |
|
21 |
alt="Ústav státu a práva Akademie věd ČR" |
|
22 |
></Image> |
|
23 |
</div> |
|
24 |
<h1 className={styles.title}> |
|
25 |
Vítejte na stránkách Ústavu státu a práva Akademie věd ČR pro |
|
26 |
anotaci dokumentů v rámci projektu TAČR TL03000152 - Umělá |
|
27 |
inteligence, média a právo |
|
28 |
</h1> |
|
29 |
</Stack> |
|
30 |
</Col> |
|
31 |
<Col md={4}> |
|
32 |
<main>{props.children}</main> |
|
33 |
</Col> |
|
34 |
</Row> |
|
35 |
</Container> |
|
36 |
); |
|
37 |
} |
webapp/layouts/mainLayout.tsx | ||
---|---|---|
1 |
import { LayoutProps } from '../components/types/layoutProps'; |
|
2 |
import { UserNavBar } from '../components/navigation/userNavBar'; |
|
3 |
import { AdminNavBar } from '../components/navigation/adminNavBar'; |
|
4 |
import 'antd/dist/antd.css'; |
|
5 |
import styles from '/styles/mainLayout.module.scss'; |
|
6 |
|
|
7 |
/** |
|
8 |
* Creates layout of main screens. |
|
9 |
* @param props Html structure of a login form. |
|
10 |
* @returns The login screen. |
|
11 |
*/ |
|
12 |
export function MainLayout(props: LayoutProps) { |
|
13 |
return ( |
|
14 |
<div className={styles.layoutwrapper}> |
|
15 |
<div className={styles.header}> |
|
16 |
{/** |
|
17 |
@todo: Select correct navigation bar |
|
18 |
{user && <UserNavBar />} |
|
19 |
{admin && <AdminNavBar />} |
|
20 |
**/} |
|
21 |
</div> |
|
22 |
<main className={styles.content}>{props.children}</main> |
|
23 |
<div className={styles.footer}></div> |
|
24 |
</div> |
|
25 |
); |
|
26 |
} |
webapp/pages/annotation/index.tsx | ||
---|---|---|
1 |
import { AnnotationPanel } from '../../components/annotation/annotationPanel';
|
|
2 |
import { DocumentAnnotationView } from '../../components/annotation/documentAnnotationView';
|
|
3 |
import { TagPanel } from '../../components/annotation/tagPanel';
|
|
4 |
import { MainLayout } from '../../layouts/mainLayout';
|
|
1 |
import { AnnotationPanel } from '../../components/annotation/AnnotationPanel';
|
|
2 |
import { DocumentAnnotationView } from '../../components/annotation/DocumentAnnotationView';
|
|
3 |
import { TagPanel } from '../../components/annotation/TagPanel';
|
|
4 |
import { MainLayout } from '../../layouts/MainLayout';
|
|
5 | 5 |
import 'antd/dist/antd.css'; |
6 |
import styles from '/styles/annotation.module.scss'; |
|
7 |
import { Occurrence, Tag } from '../../components/models/tag'; |
|
8 |
import AnnotationProvider from '../../contexts/AnnotationContext'; |
|
6 |
import styles from '/styles/Annotation.module.scss'; |
|
7 |
import AnnotationProvider, { AnnotationContext } from '../../contexts/AnnotationContext'; |
|
9 | 8 |
|
10 | 9 |
/** |
11 | 10 |
* Creates an annotation screen. |
12 | 11 |
* @returns The annotation screen. |
13 | 12 |
*/ |
14 | 13 |
function Annotation() { |
15 |
const tags = [ |
|
16 |
{ |
|
17 |
name: 'tag a', |
|
18 |
category: 'kategorie 1', |
|
19 |
visible: true, |
|
20 |
occurrences: [ |
|
21 |
{ position: 2, length: 5 }, |
|
22 |
{ position: 10, length: 2 }, |
|
23 |
], |
|
24 |
}, |
|
25 |
{ |
|
26 |
name: 'tag b', |
|
27 |
category: 'kategorie 2', |
|
28 |
visible: true, |
|
29 |
occurrences: [ |
|
30 |
{ position: 546, length: 432 }, |
|
31 |
{ position: 767, length: 123 }, |
|
32 |
], |
|
33 |
}, |
|
34 |
]; |
|
35 |
|
|
36 |
const addOccurrence = () => {}; |
|
37 |
|
|
38 |
const changeVisibility = (tag: Tag) => {}; |
|
39 |
|
|
40 |
const deleteOccurrence = (occurrence: Occurrence) => {}; |
|
41 |
|
|
42 |
const changePosition = (occurrence: Occurrence, newValue: number) => {}; |
|
43 |
|
|
44 |
const changeLength = (occurrence: Occurrence, newValue: number) => {}; |
|
45 |
|
|
46 | 14 |
return ( |
47 | 15 |
<AnnotationProvider> |
48 | 16 |
<MainLayout> |
49 |
<div className={styles.layoutwrapper}>
|
|
17 |
<div className={styles.layoutWrapper}>
|
|
50 | 18 |
<div className={styles.tags}> |
51 | 19 |
<TagPanel /> |
52 | 20 |
</div> |
... | ... | |
54 | 22 |
<DocumentAnnotationView /> |
55 | 23 |
</div> |
56 | 24 |
<div className={styles.annotations}> |
57 |
<AnnotationPanel |
|
58 |
tags={tags} |
|
59 |
onAddOccurrence={addOccurrence} |
|
60 |
onChangeVisibility={changeVisibility} |
|
61 |
onDeleteOccurrence={deleteOccurrence} |
|
62 |
onChangePosition={changePosition} |
|
63 |
onChangeLength={changeLength} |
|
64 |
/> |
|
25 |
<AnnotationPanel /> |
|
65 | 26 |
</div> |
66 | 27 |
</div> |
67 | 28 |
</MainLayout> |
webapp/pages/login/index.tsx | ||
---|---|---|
1 | 1 |
import { Form, Input, Button } from 'antd'; |
2 | 2 |
import { UserOutlined, LockOutlined } from '@ant-design/icons'; |
3 | 3 |
import 'antd/dist/antd.css'; |
4 |
import { LoginLayout } from '../../layouts/loginLayout';
|
|
4 |
import { LoginLayout } from '../../layouts/LoginLayout';
|
|
5 | 5 |
|
6 | 6 |
/** |
7 | 7 |
* Creates a login screen. |
webapp/styles/Annotation.module.scss | ||
---|---|---|
1 |
.layoutWrapper { |
|
2 |
display: grid; |
|
3 |
|
|
4 |
grid: |
|
5 |
[main-start] 'tags document annotations' [main-end] |
|
6 |
/ 1fr 3fr 1fr; |
|
7 |
|
|
8 |
width:100%; |
|
9 |
height:100%; |
|
10 |
place-items: stretch; |
|
11 |
place-content: stretch; |
|
12 |
gap: 3px; |
|
13 |
} |
|
14 |
|
|
15 |
%annotationContent { |
|
16 |
background-color: white; |
|
17 |
padding: 10px 0px 10px 10px; |
|
18 |
overflow-y: scroll; |
|
19 |
} |
|
20 |
|
|
21 |
.tags { |
|
22 |
@extend %annotationContent; |
|
23 |
grid-area: tags; |
|
24 |
} |
|
25 |
|
|
26 |
.annotations { |
|
27 |
@extend %annotationContent; |
|
28 |
grid-area: annotations; |
|
29 |
|
|
30 |
|
|
31 |
} |
|
32 |
|
|
33 |
.document { |
|
34 |
@extend %annotationContent; |
|
35 |
grid-area: document; |
|
36 |
} |
webapp/styles/Login.module.scss | ||
---|---|---|
1 |
.title { |
|
2 |
font-size: x-large; |
|
3 |
font-family:Arial, Helvetica, sans-serif |
|
4 |
} |
webapp/styles/MainLayout.module.scss | ||
---|---|---|
1 |
.layoutWrapper { |
|
2 |
background-color: lightgray; |
|
3 |
display: grid; |
|
4 |
|
|
5 |
grid: |
|
6 |
[header-start] 'header' 60px [header-end] |
|
7 |
[main-start] 'content' [main-end] |
|
8 |
[footer-start] 'footer' 30px [footer-end]; |
|
9 |
|
|
10 |
place-items: stretch; |
|
11 |
place-content: stretch; |
|
12 |
|
|
13 |
width: 100vw; |
|
14 |
height: 100vh; |
|
15 |
|
|
16 |
gap: 3px; |
|
17 |
} |
|
18 |
|
|
19 |
.header { |
|
20 |
grid-area: header; |
|
21 |
|
|
22 |
} |
|
23 |
|
|
24 |
.content { |
|
25 |
grid-area: content; |
|
26 |
overflow-y: hidden; |
|
27 |
} |
|
28 |
|
|
29 |
.footer { |
|
30 |
grid-area: footer; |
|
31 |
} |
webapp/styles/annotation.module.scss | ||
---|---|---|
1 |
%lightBackground { |
|
2 |
background-color: white; |
|
3 |
} |
|
4 |
|
|
5 |
.layoutwrapper { |
|
6 |
display: grid; |
|
7 |
|
|
8 |
grid: |
|
9 |
[main-start] 'tags document annotations' [main-end] |
|
10 |
/ 1fr 3fr 1fr; |
|
11 |
|
|
12 |
width:100%; |
|
13 |
height:100%; |
|
14 |
place-items: stretch; |
|
15 |
place-content: stretch; |
|
16 |
gap: 3px; |
|
17 |
} |
|
18 |
|
|
19 |
|
|
20 |
.tags { |
|
21 |
@extend %lightBackground; |
|
22 |
grid-area: tags; |
|
23 |
} |
|
24 |
|
|
25 |
.annotations { |
|
26 |
@extend %lightBackground; |
|
27 |
grid-area: annotations; |
|
28 |
} |
|
29 |
|
|
30 |
.document { |
|
31 |
@extend %lightBackground; |
|
32 |
grid-area: document; |
|
33 |
} |
webapp/styles/login.module.scss | ||
---|---|---|
1 |
.title { |
|
2 |
font-size: x-large; |
|
3 |
font-family:Arial, Helvetica, sans-serif |
|
4 |
} |
webapp/styles/mainLayout.module.scss | ||
---|---|---|
1 |
.layoutwrapper { |
|
2 |
background-color: lightgray; |
|
3 |
display: grid; |
|
4 |
|
|
5 |
grid: |
|
6 |
[header-start] 'header' 60px [header-end] |
|
7 |
[main-start] 'content' [main-end] |
|
8 |
[footer-start] 'footer' 30px [footer-end]; |
|
9 |
|
|
10 |
place-items: stretch; |
|
11 |
place-content: stretch; |
|
12 |
|
|
13 |
width: 100vw; |
|
14 |
height: 100vh; |
|
15 |
|
|
16 |
gap: 3px; |
|
17 |
} |
|
18 |
|
|
19 |
.header { |
|
20 |
grid-area: header; |
|
21 |
} |
|
22 |
|
|
23 |
.content { |
|
24 |
grid-area: content; |
|
25 |
} |
|
26 |
|
|
27 |
.footer { |
|
28 |
grid-area: footer; |
|
29 |
} |
Také k dispozici: Unified diff
Renamed files, fixed overflow in annotation view, added access to the AnnotationContext in annotation view, deleted visiblity from add document modal window, deleted LayoutProps