Skip to content
This repository was archived by the owner on Nov 23, 2022. It is now read-only.

Commit 925d4a5

Browse files
committed
finished the GUI Metadata
Signed-off-by: Philip Molares <philip.molares@udo.edu>
1 parent 2a63a01 commit 925d4a5

File tree

12 files changed

+148
-74
lines changed

12 files changed

+148
-74
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"i18next": "19.8.4",
5959
"i18next-browser-languagedetector": "6.0.1",
6060
"i18next-http-backend": "1.0.22",
61+
"iso-639-1": "^2.1.7",
6162
"js-yaml": "4.0.0",
6263
"katex": "0.12.0",
6364
"luxon": "1.25.0",

public/locales/en.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,23 @@
348348
"revisions": "<0></0> revisions are saved"
349349
},
350350
"metadataEditor": {
351-
"title": "Metadata"
351+
"title": "Edit Metadata",
352+
"labels": {
353+
"title": "Title",
354+
"type": "Document type",
355+
"description": "Description",
356+
"tags": "Tags",
357+
"lang": "Language",
358+
"dir": "Text direction",
359+
"breaks": "Breaks",
360+
"robots": "Robots",
361+
"GA": "Google Analytics",
362+
"disqus": "Disqus",
363+
"LTR": "left to right",
364+
"RTL": "right to left",
365+
"breaksOn": "hedgedoc newline style",
366+
"breaksOff": "markdown newline style"
367+
}
352368
},
353369
"gistImport": {
354370
"title": "Import from Gist",

src/components/common/fork-awesome/fork-awesome-icon.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ export interface ForkAwesomeIconProps {
1313
fixedWidth?: boolean
1414
size?: IconSize
1515
stacked?: boolean
16+
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void
1617
}
1718

18-
export const ForkAwesomeIcon: React.FC<ForkAwesomeIconProps> = ({ icon, fixedWidth = false, size, className, stacked = false }) => {
19+
export const ForkAwesomeIcon: React.FC<ForkAwesomeIconProps> = ({ icon, fixedWidth = false, size, className, stacked = false, onClick }) => {
1920
const fixedWithClass = fixedWidth ? 'fa-fw' : ''
2021
const sizeClass = size ? `-${size}` : (stacked ? '-1x' : '')
2122
const stackClass = stacked ? '-stack' : ''
2223
const extraClasses = `${className ?? ''} ${sizeClass || stackClass ? `fa${stackClass}${sizeClass}` : ''}`
2324
return (
24-
<i className={`fa ${fixedWithClass} fa-${icon} ${extraClasses}`}/>
25+
<i className={`fa ${fixedWithClass} fa-${icon} ${extraClasses}`} onClick={onClick}/>
2526
)
2627
}

src/components/editor/document-bar/metadata-editor/boolean-metadata-input.tsx

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,45 @@
44
* SPDX-License-Identifier: AGPL-3.0-only
55
*/
66

7-
import React, { useCallback } from 'react'
8-
import { InputLabelProps } from './input-label'
7+
import React from 'react'
8+
import { ToggleButton, ToggleButtonGroup } from 'react-bootstrap'
9+
import { useTranslation } from 'react-i18next'
10+
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
11+
import { ForkAwesomeStack } from '../../../common/fork-awesome/fork-awesome-stack'
912
import { MetadataInputFieldProps } from './metadata-editor'
1013

11-
export const BooleanMetadataInput: React.FC<MetadataInputFieldProps<boolean> & InputLabelProps> = ({ label, content, onContentChange }) => {
12-
const onChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
13-
onContentChange(event.currentTarget.checked)
14-
}, [onContentChange])
14+
enum ButtonState {
15+
ON,
16+
OFF
17+
}
18+
19+
export const BooleanMetadataInput: React.FC<MetadataInputFieldProps<boolean>> = ({ id, content, onContentChange }) => {
20+
const {t} = useTranslation();
1521

1622
return (
17-
<div className='d-flex flex-row'>
18-
<input type="checkbox"
19-
className="left"
20-
checked={content}
21-
onChange={onChange}
22-
/>
23-
&nbsp;
24-
{label}
25-
</div>
23+
<ToggleButtonGroup
24+
type="radio"
25+
name={id}
26+
id={id}
27+
value={content ? ButtonState.ON : ButtonState.OFF}
28+
className={'ml-2'}
29+
>
30+
<ToggleButton
31+
value={ButtonState.ON}
32+
variant="outline-secondary"
33+
title={t('editor.modal.metadataEditor.labels.breaksOn')}
34+
onChange={() => onContentChange(true)}
35+
>
36+
{t('editor.modal.metadataEditor.labels.breaksOn')}
37+
</ToggleButton>
38+
<ToggleButton
39+
value={ButtonState.OFF}
40+
variant="outline-secondary"
41+
title={t('editor.modal.metadataEditor.labels.breaksOff')}
42+
onChange={() => onContentChange(false)}
43+
>
44+
{t('editor.modal.metadataEditor.labels.breaksOff')}
45+
</ToggleButton>
46+
</ToggleButtonGroup>
2647
)
2748
}

src/components/editor/document-bar/metadata-editor/datalist-metadata-input.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,18 @@
55
*/
66

77
import React, { Fragment, useCallback } from 'react'
8-
import { iso6391 } from '../../yaml-metadata/yaml-metadata'
98
import { MetadataInputFieldProps, SelectMetadataOptions } from './metadata-editor'
109

11-
export const DatalistMetadataInput: React.FC<MetadataInputFieldProps<string> & SelectMetadataOptions<iso6391>> = ({ id, content, onContentChange, options }) => {
10+
export const DatalistMetadataInput: React.FC<MetadataInputFieldProps<string> & SelectMetadataOptions<string>> = ({ id, content, onContentChange, options }) => {
1211
const onChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
1312
onContentChange(event.currentTarget.value)
1413
}, [onContentChange])
1514

1615
return (
1716
<Fragment>
18-
<input list={id} onChange={onChange} value={content}/>
17+
<input list={id} onChange={onChange} value={content} className={'ml-2'}/>
1918
<datalist id={id}>
20-
{options.map((option: iso6391) => {
19+
{options.map(option => {
2120
return (
2221
<option value={option}>
2322
{option}

src/components/editor/document-bar/metadata-editor/metadata-editor.tsx

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@
44
* SPDX-License-Identifier: AGPL-3.0-only
55
*/
66

7-
import React, { useState } from 'react'
8-
import { Modal } from 'react-bootstrap'
7+
import ISO from 'iso-639-1'
8+
import React, { useCallback } from 'react'
9+
import { Modal, Row } from 'react-bootstrap'
10+
import { useTranslation } from 'react-i18next'
11+
import { useSelector } from 'react-redux'
12+
import { ApplicationState } from '../../../../redux'
13+
import { setDocumentContent } from '../../../../redux/document-content/methods'
914
import { CommonModal } from '../../../common/modals/common-modal'
10-
import { TextDirection, YAMLMetaData } from '../../yaml-metadata/yaml-metadata'
15+
import { supportedDocumentTypes, YAMLMetaData } from '../../yaml-metadata/yaml-metadata'
1116
import { BooleanMetadataInput } from './boolean-metadata-input'
12-
import { InputLabel } from './input-label'
1317
import { DatalistMetadataInput } from './datalist-metadata-input'
14-
import { TextDirectionMetadataInput } from './text-direction-metadata-input'
18+
import { InputLabel } from './input-label'
1519
import { StringMetadataInput } from './string-metadata-input'
1620
import { StringMetadataTextarea } from './string-metadata-textarea'
1721
import { TagsMetadataInput } from './tags-metadata-input'
22+
import { TextDirectionMetadataInput } from './text-direction-metadata-input'
1823

1924
export interface MetadataEditorProps {
2025
show: boolean,
@@ -32,7 +37,10 @@ export interface SelectMetadataOptions<T> {
3237
}
3338

3439
export const MetadataEditor: React.FC<MetadataEditorProps> = ({ show, onHide }) => {
35-
const [yamlMetadata, setYamlMetadata] = useState<Omit<YAMLMetaData, 'opengraph'>>({
40+
const { t } = useTranslation();
41+
const yamlMetadata = useSelector((state: ApplicationState) => state.documentContent.metadata);
42+
const documentContent = useSelector((state: ApplicationState) => state.documentContent.content);
43+
/*const [yamlMetadata, setYamlMetadata] = useState<Omit<YAMLMetaData, 'opengraph'>>({
3644
title: "Test Title",
3745
description: "Test Description\nwith two lines",
3846
tags: ["tag1", "tag2"],
@@ -44,46 +52,62 @@ export const MetadataEditor: React.FC<MetadataEditorProps> = ({ show, onHide })
4452
disqus: "test disqus string",
4553
type: '',
4654
deprecatedTagsSyntax: false
47-
})
55+
})*/
56+
57+
const setMarkdown = useCallback((changes: Partial<YAMLMetaData>) => {
58+
const newMetadata = Object.assign(yamlMetadata, changes);
59+
60+
setDocumentContent(documentContent);
61+
}, [documentContent])
4862

4963
return (
5064
<CommonModal
65+
size='xl'
5166
show={show}
5267
onHide={onHide}
5368
closeButton={true}
5469
titleI18nKey={'editor.modal.metadataEditor.title'}>
5570
<Modal.Body>
56-
<InputLabel id={'title'} label={"title"}>
57-
<StringMetadataInput id={'title'} content={yamlMetadata.title} onContentChange={title => setYamlMetadata({...yamlMetadata, title})}/>
58-
</InputLabel>
59-
<InputLabel id={'description'} label={"description"}>
60-
<StringMetadataTextarea id={'description'} content={yamlMetadata.description} onContentChange={description => setYamlMetadata({...yamlMetadata, description})}/>
61-
</InputLabel>
62-
<InputLabel id={'tags'} label={"tags"}>
63-
<TagsMetadataInput id={'tags'} content={yamlMetadata.tags} onContentChange={tags => setYamlMetadata({...yamlMetadata, tags})}/>
64-
</InputLabel>
65-
<InputLabel id={'robots'} label={"robots"}>
66-
<StringMetadataInput id={'robots'} content={yamlMetadata.robots} onContentChange={robots => setYamlMetadata({...yamlMetadata, robots})}/>
67-
</InputLabel>
68-
<InputLabel id={'lang'} label={"lang"}>
69-
<DatalistMetadataInput id={'lang'} options={['aa', 'ab', 'af', 'de-at']} content={yamlMetadata.lang} onContentChange={lang => setYamlMetadata({...yamlMetadata, lang})}/>
70-
</InputLabel>
71-
<InputLabel id={'dir'} label={"dir"}>
72-
<TextDirectionMetadataInput
73-
id={'dir'}
74-
content={yamlMetadata.dir}
75-
onContentChange={dir => setYamlMetadata({...yamlMetadata, dir })}
76-
/>
77-
</InputLabel>
78-
<InputLabel id={'breaks'} label={"breaks"}>
79-
<BooleanMetadataInput id={'breaks'} label={"breaks"} content={yamlMetadata.breaks} onContentChange={breaks => setYamlMetadata({...yamlMetadata, breaks})}/>
80-
</InputLabel>
81-
<InputLabel id={'GA'} label={"GA"}>
82-
<StringMetadataInput id={'GA'} content={yamlMetadata.GA} onContentChange={GA => setYamlMetadata({...yamlMetadata, GA})}/>
83-
</InputLabel>
84-
<InputLabel id={'disqus'} label={"disqus"}>
85-
<StringMetadataInput id={'disqus'} content={yamlMetadata.disqus} onContentChange={disqus => setYamlMetadata({...yamlMetadata, disqus})}/>
86-
</InputLabel>
71+
<Row>
72+
<div className='col-6'>
73+
<InputLabel id={'title'} label={t('editor.modal.metadataEditor.labels.title')}>
74+
<StringMetadataInput id={'title'} content={yamlMetadata.title} onContentChange={title => setYamlMetadata({...yamlMetadata, title})}/>
75+
</InputLabel>
76+
<InputLabel id={'type'} label={t('editor.modal.metadataEditor.labels.type')}>
77+
<DatalistMetadataInput id={'type'} options={supportedDocumentTypes} content={yamlMetadata.type} onContentChange={type => setYamlMetadata({...yamlMetadata, type})}/>
78+
</InputLabel>
79+
<InputLabel id={'dir'} label={t('editor.modal.metadataEditor.labels.dir')}>
80+
<TextDirectionMetadataInput
81+
id={'dir'}
82+
content={yamlMetadata.dir}
83+
onContentChange={dir => setYamlMetadata({...yamlMetadata, dir })}
84+
/>
85+
</InputLabel>
86+
<InputLabel id={'description'} label={t('editor.modal.metadataEditor.labels.description')}>
87+
<StringMetadataTextarea id={'description'} content={yamlMetadata.description} onContentChange={description => setYamlMetadata({...yamlMetadata, description})}/>
88+
</InputLabel>
89+
<InputLabel id={'disqus'} label={t('editor.modal.metadataEditor.labels.disqus')}>
90+
<StringMetadataInput id={'disqus'} content={yamlMetadata.disqus} onContentChange={disqus => setYamlMetadata({...yamlMetadata, disqus})}/>
91+
</InputLabel>
92+
</div>
93+
<div className='col-6'>
94+
<InputLabel id={'lang'} label={t('editor.modal.metadataEditor.labels.lang')}>
95+
<DatalistMetadataInput id={'lang'} options={ISO.getAllCodes()} content={yamlMetadata.lang} onContentChange={lang => setYamlMetadata({...yamlMetadata, lang})}/>
96+
</InputLabel>
97+
<InputLabel id={'robots'} label={t('editor.modal.metadataEditor.labels.robots')}>
98+
<StringMetadataInput id={'robots'} content={yamlMetadata.robots} onContentChange={robots => setYamlMetadata({...yamlMetadata, robots})}/>
99+
</InputLabel>
100+
<InputLabel id={'breaks'} label={t('editor.modal.metadataEditor.labels.breaks')}>
101+
<BooleanMetadataInput id={'breaks'} content={yamlMetadata.breaks} onContentChange={breaks => setYamlMetadata({...yamlMetadata, breaks})}/>
102+
</InputLabel>
103+
<InputLabel id={'tags'} label={t('editor.modal.metadataEditor.labels.tags')}>
104+
<TagsMetadataInput id={'tags'} content={yamlMetadata.tags} onContentChange={tags => setYamlMetadata({...yamlMetadata, tags})}/>
105+
</InputLabel>
106+
<InputLabel id={'GA'} label={t('editor.modal.metadataEditor.labels.GA')}>
107+
<StringMetadataInput id={'GA'} content={yamlMetadata.GA} onContentChange={GA => setYamlMetadata({...yamlMetadata, GA})}/>
108+
</InputLabel>
109+
</div>
110+
</Row>
87111
</Modal.Body>
88112
</CommonModal>
89113
)

src/components/editor/document-bar/metadata-editor/string-metadata-input.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const StringMetadataInput: React.FC<MetadataInputFieldProps<string>> = ({
1515
return (
1616
<input id={id}
1717
type="text"
18+
className={'ml-2'}
1819
value={content}
1920
onChange={onChange}
2021
/>

src/components/editor/document-bar/metadata-editor/string-metadata-textarea.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const StringMetadataTextarea: React.FC<MetadataInputFieldProps<string>> =
1515
return (
1616
<textarea
1717
id={id}
18+
className={'ml-2'}
1819
value={content}
1920
onChange={onChange}
2021
/>

src/components/editor/document-bar/metadata-editor/tags-metadata-input.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,27 @@ export const TagsMetadataInput: React.FC<MetadataInputFieldProps<string[]>> = ({
3030
setNewTag(event.currentTarget.value);
3131
}, [])
3232

33+
const dismissTag = useCallback((clickedTag: string) => {
34+
onContentChange(content.filter(tag => tag !== clickedTag))
35+
}, [content, onContentChange])
36+
3337
return (
3438
<Fragment>
35-
<div className='pl-1 d-flex flex-row mb-2 mt-1 overflow-x-scroll'>
39+
<div className='pl-1 d-flex flex-row mb-2 mt-1 overflow-x-scroll ml-2'>
3640
{
3741
content.map(tag => {
3842
return (
3943
<div className='rounded-pill mr-1 px-2 bg-primary tag-bubble' key={tag}>
4044
{tag}
41-
<ForkAwesomeIcon icon={'times'} className='pl-1'/>
45+
<ForkAwesomeIcon icon={'times'} className='pl-1' onClick={() => dismissTag(tag)}/>
4246
</div>
4347
)
4448
})
4549
}
4650
</div>
4751
<input type="text"
4852
id={id}
49-
className='w-100 px-2'
53+
className='w-100 px-2 ml-2'
5054
value={newTag}
5155
onKeyDown={onKeyDown}
5256
onChange={onChange}

src/components/editor/document-bar/metadata-editor/text-direction-metadata-input.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,42 @@ SPDX-License-Identifier: AGPL-3.0-only
66

77
import React from 'react'
88
import { ToggleButton, ToggleButtonGroup } from 'react-bootstrap'
9+
import { useTranslation } from 'react-i18next'
910
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
1011
import { TextDirection } from '../../yaml-metadata/yaml-metadata'
1112
import { MetadataInputFieldProps } from './metadata-editor'
1213

1314

1415
export const TextDirectionMetadataInput: React.FC<MetadataInputFieldProps<TextDirection>> = ({ id, content, onContentChange }) => {
16+
const {t} = useTranslation();
17+
1518
return (
1619
<ToggleButtonGroup
1720
type="radio"
1821
name={id}
1922
id={id}
2023
value={content}
21-
className="ml-2"
24+
className={'ml-2'}
2225
>
2326
<ToggleButton
2427
value={TextDirection.LTR}
2528
variant="outline-secondary"
26-
title={'ltr'}
29+
title={t('editor.modal.metadataEditor.labels.LTR')}
2730
onChange={() => onContentChange(TextDirection.LTR)}
2831
>
2932
<ForkAwesomeIcon icon={'align-left'}/>
3033
&nbsp;
31-
left to right
34+
{t('editor.modal.metadataEditor.labels.LTR')}
3235
</ToggleButton>
3336
<ToggleButton
3437
value={TextDirection.RTL}
3538
variant="outline-secondary"
36-
title={'ltr'}
39+
title={t('editor.modal.metadataEditor.labels.RTL')}
3740
onChange={() => onContentChange(TextDirection.RTL)}
3841
>
3942
<ForkAwesomeIcon icon={'align-right'}/>
4043
&nbsp;
41-
right to left
44+
{t('editor.modal.metadataEditor.labels.RTL')}
4245
</ToggleButton>
4346
</ToggleButtonGroup>
4447
)

0 commit comments

Comments
 (0)