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

Commit 401a7c4

Browse files
committed
Rebase metadata gui editor
Signed-off-by: Tilman Vatteroth <[email protected]>
1 parent 8a2d26f commit 401a7c4

19 files changed

+506
-257
lines changed

package.json

+21-20
Original file line numberDiff line numberDiff line change
@@ -48,26 +48,27 @@
4848
"eslint-plugin-flowtype": "5.2.0",
4949
"eslint-plugin-import": "2.22.1",
5050
"eslint-plugin-jsx-a11y": "6.4.1",
51-
"eslint-plugin-node": "11.1.0",
52-
"eslint-plugin-promise": "4.2.1",
53-
"fast-deep-equal": "3.1.3",
54-
"firacode": "5.2.0",
55-
"flowchart.js": "1.15.0",
56-
"fork-awesome": "1.1.7",
57-
"highlight.js": "10.5.0",
58-
"i18next": "19.8.7",
59-
"i18next-browser-languagedetector": "6.0.1",
60-
"i18next-http-backend": "1.1.0",
61-
"js-yaml": "4.0.0",
62-
"katex": "0.12.0",
63-
"luxon": "1.25.0",
64-
"markdown-it": "12.0.4",
65-
"markdown-it-abbr": "1.0.4",
66-
"markdown-it-anchor": "7.0.2",
67-
"markdown-it-container": "3.0.0",
68-
"markdown-it-deflist": "2.1.0",
69-
"markdown-it-emoji": "2.0.0",
70-
"markdown-it-footnote": "3.0.2",
51+
"eslint-plugin-node": "11.1.0",
52+
"eslint-plugin-promise": "4.2.1",
53+
"fast-deep-equal": "3.1.3",
54+
"firacode": "5.2.0",
55+
"flowchart.js": "1.15.0",
56+
"fork-awesome": "1.1.7",
57+
"highlight.js": "10.5.0",
58+
"i18next": "19.8.7",
59+
"i18next-browser-languagedetector": "6.0.1",
60+
"i18next-http-backend": "1.1.0",
61+
"iso-639-1": "2.1.8",
62+
"js-yaml": "4.0.0",
63+
"katex": "0.12.0",
64+
"luxon": "1.25.0",
65+
"markdown-it": "12.0.4",
66+
"markdown-it-abbr": "1.0.4",
67+
"markdown-it-anchor": "7.0.2",
68+
"markdown-it-container": "3.0.0",
69+
"markdown-it-deflist": "2.1.0",
70+
"markdown-it-emoji": "2.0.0",
71+
"markdown-it-footnote": "3.0.2",
7172
"markdown-it-front-matter": "0.2.3",
7273
"markdown-it-imsize": "2.0.1",
7374
"markdown-it-ins": "3.0.1",

public/locales/en.json

+38-19
Original file line numberDiff line numberDiff line change
@@ -338,26 +338,45 @@
338338
"modal": {
339339
"snippetImport": {
340340
"title": "Import from Snippet",
341-
"selectProject": "Select From Available Projects",
342-
"selectSnippet": "Select From Available Snippets"
341+
"selectProject": "Select From Available Projects",
342+
"selectSnippet": "Select From Available Snippets"
343343
},
344-
"documentInfo": {
345-
"title": "Document info",
346-
"created": "<0></0> created this note <1></1>",
347-
"edited": "<0></0> was the last editor <1></1>",
348-
"usersContributed": "<0></0> users contributed to this document",
349-
"revisions": "<0></0> revisions are saved"
350-
},
351-
"gistImport": {
352-
"title": "Import from Gist",
353-
"insertGistUrl": "Paste your gist url here…"
354-
},
355-
"snippetExport": {
356-
"title": "Export to Snippet",
357-
"visibilityLevel": "Select Visibility Level"
358-
},
359-
"revision": {
360-
"title": "Revisions",
344+
"documentInfo": {
345+
"title": "Document info",
346+
"created": "<0></0> created this note <1></1>",
347+
"edited": "<0></0> was the last editor <1></1>",
348+
"usersContributed": "<0></0> users contributed to this document",
349+
"revisions": "<0></0> revisions are saved"
350+
},
351+
"metadataEditor": {
352+
"title": "Edit Metadata",
353+
"labels": {
354+
"title": "Title",
355+
"type": "Document type",
356+
"description": "Description",
357+
"tags": "Tags",
358+
"lang": "Language",
359+
"dir": "Text direction",
360+
"breaks": "New line style",
361+
"robots": "Robots",
362+
"GA": "Google Analytics",
363+
"disqus": "Disqus",
364+
"LTR": "left to right",
365+
"RTL": "right to left",
366+
"breaksOn": "hedgedoc style",
367+
"breaksOff": "markdown style"
368+
}
369+
},
370+
"gistImport": {
371+
"title": "Import from Gist",
372+
"insertGistUrl": "Paste your gist url here…"
373+
},
374+
"snippetExport": {
375+
"title": "Export to Snippet",
376+
"visibilityLevel": "Select Visibility Level"
377+
},
378+
"revision": {
379+
"title": "Revisions",
361380
"revertButton": "Revert",
362381
"error": "An error occurred while fetching the revisions of this note.",
363382
"length": "Length",
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
2-
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3-
4-
SPDX-License-Identifier: AGPL-3.0-only
2+
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
55
*/
66

7-
import React from 'react'
7+
import React, { MouseEventHandler } from 'react'
88
import { IconName, IconSize } from './types'
99

1010
export interface ForkAwesomeIconProps {
@@ -13,14 +13,15 @@ export interface ForkAwesomeIconProps {
1313
fixedWidth?: boolean
1414
size?: IconSize
1515
stacked?: boolean
16+
onClick?: MouseEventHandler<HTMLElement>
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-page/document-bar/share/share-modal.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { CopyableField } from '../../../common/copyable/copyable-field/copyable-
1616
import { CommonModal } from '../../../common/modals/common-modal'
1717
import { ShowIf } from '../../../common/show-if/show-if'
1818
import { EditorPagePathParams } from '../../editor-page'
19+
import { NoteType } from '../../note-frontmatter/note-frontmatter'
1920

2021
export interface ShareModalProps {
2122
show: boolean,
@@ -44,7 +45,7 @@ export const ShareModal: React.FC<ShareModalProps> = ({ show, onHide }) => {
4445
<CopyableField content={ `${ baseUrl }/p/${ id }` } nativeShareButton={ true }
4546
url={ `${ baseUrl }/p/${ id }` }/>
4647
</ShowIf>
47-
<ShowIf condition={ noteFrontmatter.type === '' }>
48+
<ShowIf condition={ noteFrontmatter.type === NoteType.DOCUMENT }>
4849
<Trans i18nKey={ 'editor.modal.shareLink.viewOnlyDescription' }/>
4950
<CopyableField content={ `${ baseUrl }/s/${ id }` } nativeShareButton={ true }
5051
url={ `${ baseUrl }/s/${ id }` }/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
*/
6+
7+
import React from 'react'
8+
import { ToggleButton, ToggleButtonGroup } from 'react-bootstrap'
9+
import { Trans, useTranslation } from 'react-i18next'
10+
import { MetadataInputFieldProps } from './metadata-editor'
11+
12+
enum ButtonState {
13+
ON,
14+
OFF
15+
}
16+
17+
export const BreaksMetadataInput: React.FC<MetadataInputFieldProps<boolean>> = ({ id, content, onContentChange }) => {
18+
const { t } = useTranslation()
19+
20+
return (
21+
<ToggleButtonGroup
22+
type="radio"
23+
name={ id }
24+
id={ id }
25+
value={ content ? ButtonState.ON : ButtonState.OFF }
26+
className={ 'd-block' }>
27+
<ToggleButton
28+
value={ ButtonState.ON }
29+
variant="outline-secondary"
30+
title={ t('editor.modal.metadataEditor.labels.breaksOn') }
31+
onChange={ () => onContentChange(true) }>
32+
<Trans i18nKey={ 'editor.modal.metadataEditor.labels.breaksOn' }/>
33+
</ToggleButton>
34+
<ToggleButton
35+
value={ ButtonState.OFF }
36+
variant="outline-secondary"
37+
title={ t('editor.modal.metadataEditor.labels.breaksOff') }
38+
onChange={ () => onContentChange(false) }>
39+
<Trans i18nKey={ 'editor.modal.metadataEditor.labels.breaksOff' }/>
40+
</ToggleButton>
41+
</ToggleButtonGroup>
42+
)
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
*/
6+
7+
import React, { Fragment, useCallback } from 'react'
8+
import { MetadataInputFieldProps, SelectMetadataOptions } from './metadata-editor'
9+
10+
export const DatalistMetadataInput: React.FC<MetadataInputFieldProps<string> & SelectMetadataOptions<string>> = ({ id, content, onContentChange, options }) => {
11+
const onChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
12+
onContentChange(event.currentTarget.value)
13+
}, [onContentChange])
14+
15+
return (
16+
<Fragment>
17+
<input list={ id } onChange={ onChange } value={ content } className={ 'form-control' }/>
18+
<datalist id={ id }>
19+
{ options.map(option => {
20+
return (
21+
<option value={ option }>
22+
{ option }
23+
</option>
24+
)
25+
}) }
26+
</datalist>
27+
</Fragment>
28+
)
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
*/
6+
7+
.tighter {
8+
margin-bottom: -0.5px !important;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
*/
6+
7+
import React from 'react'
8+
import './input-label.scss'
9+
import { Form } from 'react-bootstrap'
10+
11+
export interface InputLabelProps {
12+
id: string
13+
label: string
14+
}
15+
16+
export const InputLabel: React.FC<InputLabelProps> = ({ id, label, children }) => {
17+
return (
18+
<Form.Group className={ 'pb-3' }>
19+
<label className='small font-weight-lighter tighter' htmlFor={ id }>{ label }</label>
20+
{ children }
21+
</Form.Group>
22+
)
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
*/
6+
7+
import ISO from 'iso-639-1'
8+
import React, { useCallback } from 'react'
9+
import { Col, Modal, Row } from 'react-bootstrap'
10+
import { useTranslation } from 'react-i18next'
11+
import { useSelector } from 'react-redux'
12+
import { ApplicationState } from '../../../redux'
13+
import { setNoteFrontmatter } from '../../../redux/note-details/methods'
14+
import { CommonModal } from '../../common/modals/common-modal'
15+
import { NoteFrontmatter, NoteType } from '../note-frontmatter/note-frontmatter'
16+
import { BreaksMetadataInput } from './breaks-metadata-input'
17+
import { DatalistMetadataInput } from './datalist-metadata-input'
18+
import { InputLabel } from './input-label'
19+
import { StringMetadataInput } from './string-metadata-input'
20+
import { StringMetadataTextarea } from './string-metadata-textarea'
21+
import { TagsMetadataInput } from './tags-metadata-input'
22+
import { TextDirectionMetadataInput } from './text-direction-metadata-input'
23+
24+
export interface MetadataEditorProps {
25+
show: boolean,
26+
onHide: () => void
27+
}
28+
29+
export interface MetadataInputFieldProps<T> {
30+
id: string
31+
content: T
32+
onContentChange: (newContent: T) => void
33+
}
34+
35+
export interface SelectMetadataOptions<T> {
36+
options: T[]
37+
}
38+
39+
export const MetadataEditor: React.FC<MetadataEditorProps> = ({ show, onHide }) => {
40+
const { t } = useTranslation()
41+
const yamlMetadata = useSelector((state: ApplicationState) => state.noteDetails.frontmatter)
42+
const noteDetails = useSelector((state: ApplicationState) => state.noteDetails.markdownContent)
43+
/*const [yamlMetadata, setNoteFrontmatter] = useState<Omit<YAMLMetaData, 'opengraph'>>({
44+
title: "Test Title",
45+
description: "Test Description\nwith two lines",
46+
tags: ["tag1", "tag2"],
47+
robots: "",
48+
lang: "de-at",
49+
dir: TextDirection.LTR,
50+
breaks: false,
51+
GA: "test GA string",
52+
disqus: "test disqus string",
53+
type: '',
54+
deprecatedTagsSyntax: false
55+
})*/
56+
57+
const setMarkdown = useCallback((changes: Partial<NoteFrontmatter>) => {
58+
const newMetadata = Object.assign(yamlMetadata, changes)
59+
60+
// setnoteDetails(noteDetails)
61+
}, [noteDetails])
62+
63+
return (
64+
<CommonModal
65+
size='lg'
66+
show={ show }
67+
onHide={ onHide }
68+
closeButton={ true }
69+
titleI18nKey={ 'editor.modal.metadataEditor.title' }>
70+
<Modal.Body>
71+
<Row>
72+
<Col xs={ 6 }>
73+
<InputLabel id={ 'title' } label={ t('editor.modal.metadataEditor.labels.title') }>
74+
<StringMetadataInput id={ 'title' } content={ yamlMetadata.title }
75+
onContentChange={ title => setNoteFrontmatter({ ...yamlMetadata, title }) }/>
76+
</InputLabel>
77+
<InputLabel id={ 'type' } label={ t('editor.modal.metadataEditor.labels.type') }>
78+
<DatalistMetadataInput id={ 'type' } options={ Object.values(NoteType) } content={ yamlMetadata.type }
79+
onContentChange={ type => setNoteFrontmatter({ ...yamlMetadata, type: (type as NoteType) }) }/>
80+
</InputLabel>
81+
<InputLabel id={ 'dir' } label={ t('editor.modal.metadataEditor.labels.dir') }>
82+
<TextDirectionMetadataInput id={ 'dir' } content={ yamlMetadata.dir }
83+
onContentChange={ dir => setNoteFrontmatter({ ...yamlMetadata, dir }) }/>
84+
</InputLabel>
85+
<InputLabel id={ 'description' } label={ t('editor.modal.metadataEditor.labels.description') }>
86+
<StringMetadataTextarea id={ 'description' } content={ yamlMetadata.description }
87+
onContentChange={ description => setNoteFrontmatter({ ...yamlMetadata, description }) }/>
88+
</InputLabel>
89+
<InputLabel id={ 'disqus' } label={ t('editor.modal.metadataEditor.labels.disqus') }>
90+
<StringMetadataInput id={ 'disqus' } content={ yamlMetadata.disqus }
91+
onContentChange={ disqus => setNoteFrontmatter({ ...yamlMetadata, disqus }) }/>
92+
</InputLabel>
93+
</Col>
94+
<Col xs={ 6 }>
95+
<InputLabel id={ 'lang' } label={ t('editor.modal.metadataEditor.labels.lang') }>
96+
<DatalistMetadataInput id={ 'lang' } options={ ISO.getAllCodes() } content={ yamlMetadata.lang }
97+
onContentChange={ lang => setNoteFrontmatter({ ...yamlMetadata, lang }) }/>
98+
</InputLabel>
99+
<InputLabel id={ 'robots' } label={ t('editor.modal.metadataEditor.labels.robots') }>
100+
<StringMetadataInput id={ 'robots' } content={ yamlMetadata.robots }
101+
onContentChange={ robots => setNoteFrontmatter({ ...yamlMetadata, robots }) }/>
102+
</InputLabel>
103+
<InputLabel id={ 'breaks' } label={ t('editor.modal.metadataEditor.labels.breaks') }>
104+
<BreaksMetadataInput id={ 'breaks' } content={ yamlMetadata.breaks }
105+
onContentChange={ breaks => setNoteFrontmatter({ ...yamlMetadata, breaks }) }/>
106+
</InputLabel>
107+
<InputLabel id={ 'tags' } label={ t('editor.modal.metadataEditor.labels.tags') }>
108+
<TagsMetadataInput id={ 'tags' } content={ yamlMetadata.tags }
109+
onContentChange={ tags => setNoteFrontmatter({ ...yamlMetadata, tags }) }/>
110+
</InputLabel>
111+
<InputLabel id={ 'GA' } label={ t('editor.modal.metadataEditor.labels.GA') }>
112+
<StringMetadataInput id={ 'GA' } content={ yamlMetadata.GA }
113+
onContentChange={ GA => setNoteFrontmatter({ ...yamlMetadata, GA }) }/>
114+
</InputLabel>
115+
</Col>
116+
</Row>
117+
</Modal.Body>
118+
</CommonModal>
119+
)
120+
}

0 commit comments

Comments
 (0)