mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 23:24:46 -04:00
Use fira code in editor (#695)
Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
parent
b3288a6666
commit
8ce344512c
19 changed files with 311 additions and 113 deletions
|
@ -56,6 +56,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- Code blocks with 'vega-lite' as language are rendered as [vega-lite diagrams](https://vega.github.io/vega-lite/examples/).
|
- Code blocks with 'vega-lite' as language are rendered as [vega-lite diagrams](https://vega.github.io/vega-lite/examples/).
|
||||||
- Markdown files can be imported into an existing note directly from the editor.
|
- Markdown files can be imported into an existing note directly from the editor.
|
||||||
- The table button in the toolbar opens an overlay where the user can choose the number of columns and rows
|
- The table button in the toolbar opens an overlay where the user can choose the number of columns and rows
|
||||||
|
- A toggle in the editor preferences for turning ligatures on and off.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- Use KaTeX instead of MathJax. ([Why?](https://community.codimd.org/t/frequently-asked-questions/190))
|
- Use KaTeX instead of MathJax. ([Why?](https://community.codimd.org/t/frequently-asked-questions/190))
|
||||||
- The dark-mode is also applied to the read-only-view and can be toggled from there.
|
- The dark-mode is also applied to the read-only-view and can be toggled from there.
|
||||||
- Access tokens for the CLI and 3rd-party-clients can be managed in the user profile.
|
- Access tokens for the CLI and 3rd-party-clients can be managed in the user profile.
|
||||||
|
- Change editor font to "Fira Code"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,9 @@
|
||||||
"eslint-plugin-node": "11.1.0",
|
"eslint-plugin-node": "11.1.0",
|
||||||
"eslint-plugin-promise": "4.2.1",
|
"eslint-plugin-promise": "4.2.1",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
|
"firacode": "5.2.0",
|
||||||
"flowchart.js": "1.15.0",
|
"flowchart.js": "1.15.0",
|
||||||
"fontsource-source-sans-pro": "3.1.5",
|
"fontsource-source-sans-pro": "3.1.5",
|
||||||
"fontsource-source-code-pro": "3.1.5",
|
|
||||||
"fork-awesome": "1.1.7",
|
"fork-awesome": "1.1.7",
|
||||||
"highlight.js": "10.4.1",
|
"highlight.js": "10.4.1",
|
||||||
"i18next": "19.8.4",
|
"i18next": "19.8.4",
|
||||||
|
|
|
@ -389,11 +389,29 @@
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"title": "Preferences",
|
"title": "Preferences",
|
||||||
"theme": "Editor theme",
|
"theme": {
|
||||||
"keyMap": "Keymap",
|
"label": "Editor theme",
|
||||||
"indentWithTabs": "Tab character",
|
"one-dark": "Dark",
|
||||||
"indentUnit": "Tab size (when using spaces)",
|
"neat": "Light"
|
||||||
"spellcheck": "Spell checking"
|
},
|
||||||
|
"keyMap": {
|
||||||
|
"label": "Keymap",
|
||||||
|
"sublime": "Sublime",
|
||||||
|
"emacs": "Emacs",
|
||||||
|
"vim": "Vim"
|
||||||
|
},
|
||||||
|
"indentWithTabs": {
|
||||||
|
"label": "Tab character",
|
||||||
|
"on": "Tabs",
|
||||||
|
"off": "Spaces"
|
||||||
|
},
|
||||||
|
"indentUnit": "Number of spaces per tab",
|
||||||
|
"spellcheck": {
|
||||||
|
"label": "Spell checking"
|
||||||
|
},
|
||||||
|
"ligatures": {
|
||||||
|
"label": "Show ligatures"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"embeddings": {
|
"embeddings": {
|
||||||
|
@ -413,6 +431,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"yes": "Yes",
|
||||||
|
"no": "No",
|
||||||
"import": "Import",
|
"import": "Import",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
|
|
|
@ -11,11 +11,23 @@
|
||||||
@import '../../../../node_modules/codemirror/theme/neat';
|
@import '../../../../node_modules/codemirror/theme/neat';
|
||||||
@import './one-dark';
|
@import './one-dark';
|
||||||
@import 'hints';
|
@import 'hints';
|
||||||
|
@import '../../../../node_modules/firacode/distr/fira_code.css';
|
||||||
|
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
font-family: "Source Code Pro", "Twemoji Mozilla", Consolas, monaco, monospace;
|
font-family: "Fira Code", "Twemoji Mozilla", Consolas, monaco, monospace;
|
||||||
letter-spacing: 0.025em;
|
letter-spacing: 0.025em;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-ligatures .CodeMirror {
|
||||||
|
//These two properties must be set separately because otherwise node-scss breaks.
|
||||||
|
.CodeMirror-line, .CodeMirror-line-like {
|
||||||
|
font-feature-settings: inherit;
|
||||||
|
}
|
||||||
|
.CodeMirror-line, .CodeMirror-line-like {
|
||||||
|
font-variant-ligatures: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ export const EditorPane: React.FC<EditorPaneProps & ScrollProps> = ({ onContentC
|
||||||
const [editor, setEditor] = useState<Editor>()
|
const [editor, setEditor] = useState<Editor>()
|
||||||
const [statusBarInfo, setStatusBarInfo] = useState<StatusBarInfo>(defaultState)
|
const [statusBarInfo, setStatusBarInfo] = useState<StatusBarInfo>(defaultState)
|
||||||
const editorPreferences = useSelector((state: ApplicationState) => state.editorConfig.preferences, equal)
|
const editorPreferences = useSelector((state: ApplicationState) => state.editorConfig.preferences, equal)
|
||||||
|
const ligaturesEnabled = useSelector((state: ApplicationState) => state.editorConfig.ligatures, equal)
|
||||||
|
|
||||||
const lastScrollPosition = useRef<number>()
|
const lastScrollPosition = useRef<number>()
|
||||||
const [editorScroll, setEditorScroll] = useState<ScrollInfo>()
|
const [editorScroll, setEditorScroll] = useState<ScrollInfo>()
|
||||||
|
@ -163,7 +164,7 @@ export const EditorPane: React.FC<EditorPaneProps & ScrollProps> = ({ onContentC
|
||||||
editor={editor}
|
editor={editor}
|
||||||
/>
|
/>
|
||||||
<ControlledCodeMirror
|
<ControlledCodeMirror
|
||||||
className="overflow-hidden w-100 flex-fill"
|
className={`overflow-hidden w-100 flex-fill ${ligaturesEnabled ? '' : 'no-ligatures'}`}
|
||||||
value={content}
|
value={content}
|
||||||
options={codeMirrorOptions}
|
options={codeMirrorOptions}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EditorConfiguration } from 'codemirror'
|
||||||
|
import equal from "fast-deep-equal"
|
||||||
|
import React, { ChangeEvent, useCallback } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState } from '../../../../../redux'
|
||||||
|
import { mergeEditorPreferences } from '../../../../../redux/editor/methods'
|
||||||
|
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
|
||||||
|
import { EditorPreferenceProperty } from './editor-preference-property'
|
||||||
|
|
||||||
|
export interface EditorPreferenceBooleanProps {
|
||||||
|
property: EditorPreferenceProperty
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EditorPreferenceBooleanProperty: React.FC<EditorPreferenceBooleanProps> = ({ property }) => {
|
||||||
|
const preference = useSelector((state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '', equal)
|
||||||
|
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const selectedItem: boolean = event.target.value === 'true'
|
||||||
|
|
||||||
|
mergeEditorPreferences({
|
||||||
|
[property]: selectedItem
|
||||||
|
} as EditorConfiguration)
|
||||||
|
}, [property])
|
||||||
|
|
||||||
|
const i18nPrefix = `editor.modal.preferences.${property}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.SELECT} value={preference}>
|
||||||
|
<option value={'true'}>
|
||||||
|
{t(`${i18nPrefix}.on`)}
|
||||||
|
</option>
|
||||||
|
<option value={'false'}>
|
||||||
|
{t(`${i18nPrefix}.off`)}
|
||||||
|
</option>
|
||||||
|
</EditorPreferenceInput>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import React from 'react'
|
||||||
|
import { Form } from 'react-bootstrap'
|
||||||
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
export enum EditorPreferenceInputType {
|
||||||
|
SELECT,
|
||||||
|
BOOLEAN,
|
||||||
|
NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EditorPreferenceInputProps {
|
||||||
|
property: string
|
||||||
|
type: EditorPreferenceInputType
|
||||||
|
onChange: React.ChangeEventHandler<HTMLSelectElement>
|
||||||
|
value?: string | number | string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EditorPreferenceInput: React.FC<EditorPreferenceInputProps> = ({ property, type, onChange, value, children }) => {
|
||||||
|
useTranslation()
|
||||||
|
return (
|
||||||
|
<Form.Group controlId={`editor-pref-${property}`}>
|
||||||
|
<Form.Label>
|
||||||
|
<Trans i18nKey={`editor.modal.preferences.${property}${type===EditorPreferenceInputType.NUMBER ? '' : '.label'}`}/>
|
||||||
|
</Form.Label>
|
||||||
|
<Form.Control
|
||||||
|
as={type === EditorPreferenceInputType.NUMBER ? 'input' : 'select'}
|
||||||
|
size='sm'
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
type={type === EditorPreferenceInputType.NUMBER ? 'number' : ''}>
|
||||||
|
{children}
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Group>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import React, { ChangeEvent, useCallback } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState } from '../../../../../redux'
|
||||||
|
import { setEditorLigatures } from '../../../../../redux/editor/methods'
|
||||||
|
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
|
||||||
|
|
||||||
|
export const EditorPreferenceLigaturesSelect: React.FC = () => {
|
||||||
|
const ligaturesEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.ligatures).toString())
|
||||||
|
const saveLigatures = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const ligaturesActivated: boolean = event.target.value === 'true'
|
||||||
|
setEditorLigatures(ligaturesActivated)
|
||||||
|
}, [])
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EditorPreferenceInput onChange={saveLigatures} value={ligaturesEnabled} property={"ligatures"}
|
||||||
|
type={EditorPreferenceInputType.BOOLEAN}>
|
||||||
|
<option value='true'>{t(`common.yes`)}</option>
|
||||||
|
<option value='false'>{t(`common.no`)}</option>
|
||||||
|
</EditorPreferenceInput>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EditorConfiguration } from 'codemirror'
|
||||||
|
import equal from "fast-deep-equal"
|
||||||
|
import React, { ChangeEvent, useCallback } from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState } from '../../../../../redux'
|
||||||
|
import { mergeEditorPreferences } from '../../../../../redux/editor/methods'
|
||||||
|
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
|
||||||
|
import { EditorPreferenceProperty } from './editor-preference-property'
|
||||||
|
|
||||||
|
export interface EditorPreferenceNumberProps {
|
||||||
|
property: EditorPreferenceProperty
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EditorPreferenceNumberProperty: React.FC<EditorPreferenceNumberProps> = ({ property }) => {
|
||||||
|
const preference = useSelector((state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '', equal)
|
||||||
|
|
||||||
|
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const selectedItem: number = Number.parseInt(event.target.value)
|
||||||
|
|
||||||
|
mergeEditorPreferences({
|
||||||
|
[property]: selectedItem
|
||||||
|
} as EditorConfiguration)
|
||||||
|
}, [property])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.NUMBER} value={preference}/>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum EditorPreferenceProperty {
|
||||||
|
KEYMAP = 'keyMap',
|
||||||
|
THEME = 'theme',
|
||||||
|
INDENT_WITH_TABS = 'indentWithTabs',
|
||||||
|
INDENT_UNIT = 'indentUnit',
|
||||||
|
SPELL_CHECK = 'spellcheck'
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EditorConfiguration } from 'codemirror'
|
||||||
|
import equal from "fast-deep-equal"
|
||||||
|
import React, { ChangeEvent, useCallback } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState } from '../../../../../redux'
|
||||||
|
import { mergeEditorPreferences } from '../../../../../redux/editor/methods'
|
||||||
|
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
|
||||||
|
import { EditorPreferenceProperty } from './editor-preference-property'
|
||||||
|
|
||||||
|
export interface EditorPreferenceSelectPropertyProps {
|
||||||
|
property: EditorPreferenceProperty
|
||||||
|
selections: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EditorPreferenceSelectProperty: React.FC<EditorPreferenceSelectPropertyProps> = ({ property, selections }) => {
|
||||||
|
const preference = useSelector((state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '', equal)
|
||||||
|
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const selectedItem: string = event.target.value
|
||||||
|
|
||||||
|
mergeEditorPreferences({
|
||||||
|
[property]: selectedItem
|
||||||
|
} as EditorConfiguration)
|
||||||
|
}, [property])
|
||||||
|
|
||||||
|
const i18nPrefix = `editor.modal.preferences.${property}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.SELECT} value={preference}>
|
||||||
|
{selections.map(selection =>
|
||||||
|
<option key={selection} value={selection}>
|
||||||
|
{t(`${i18nPrefix}.${selection}`) }
|
||||||
|
</option>)}
|
||||||
|
</EditorPreferenceInput>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { EditorConfiguration } from 'codemirror'
|
|
||||||
import React, { ChangeEvent, useCallback, useState } from 'react'
|
|
||||||
import { Form } from 'react-bootstrap'
|
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
|
||||||
|
|
||||||
export enum EditorPreferenceProperty {
|
|
||||||
KEYMAP = 'keyMap',
|
|
||||||
THEME = 'theme',
|
|
||||||
INDENT_WITH_TABS = 'indentWithTabs',
|
|
||||||
INDENT_UNIT = 'indentUnit',
|
|
||||||
SPELL_CHECK= 'spellcheck'
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EditorPreferenceSelectProps {
|
|
||||||
onChange: (config: EditorConfiguration) => void
|
|
||||||
preferences: EditorConfiguration
|
|
||||||
property: EditorPreferenceProperty
|
|
||||||
}
|
|
||||||
|
|
||||||
export const EditorPreferenceSelect: React.FC<EditorPreferenceSelectProps> = ({ property, onChange, preferences, children }) => {
|
|
||||||
useTranslation()
|
|
||||||
const [selected, setSelected] = useState(preferences[property])
|
|
||||||
|
|
||||||
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
|
|
||||||
let selectedItem: string | boolean | number = event.target.value
|
|
||||||
if (property === EditorPreferenceProperty.INDENT_UNIT) {
|
|
||||||
selectedItem = parseInt(selectedItem)
|
|
||||||
}
|
|
||||||
setSelected(selectedItem)
|
|
||||||
if (property === EditorPreferenceProperty.INDENT_WITH_TABS) {
|
|
||||||
selectedItem = selectedItem === 'true'
|
|
||||||
}
|
|
||||||
onChange({
|
|
||||||
...preferences,
|
|
||||||
[property]: selectedItem
|
|
||||||
})
|
|
||||||
}, [preferences, property, setSelected, onChange])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form.Group controlId={`editor-pref-${property}`}>
|
|
||||||
<Form.Label>
|
|
||||||
<Trans i18nKey={`editor.modal.preferences.${property}`}/>
|
|
||||||
</Form.Label>
|
|
||||||
<Form.Control
|
|
||||||
as={property === EditorPreferenceProperty.INDENT_UNIT ? 'input' : 'select'}
|
|
||||||
size='sm'
|
|
||||||
value={selected as string | number}
|
|
||||||
onChange={selectItem}
|
|
||||||
type={property === EditorPreferenceProperty.INDENT_UNIT ? 'number' : ''}>
|
|
||||||
{ children }
|
|
||||||
</Form.Control>
|
|
||||||
</Form.Group>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -4,26 +4,26 @@ SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EditorConfiguration } from 'codemirror'
|
import equal from "fast-deep-equal"
|
||||||
import equal from 'fast-deep-equal'
|
import React, { Fragment, useState } from 'react'
|
||||||
import React, { Fragment, useCallback, useState } from 'react'
|
|
||||||
import { Button, Form, ListGroup } from 'react-bootstrap'
|
import { Button, Form, ListGroup } from 'react-bootstrap'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { ApplicationState } from '../../../../../redux'
|
import { ApplicationState } from '../../../../../redux'
|
||||||
import { setEditorPreferences } from '../../../../../redux/editor/methods'
|
|
||||||
import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon'
|
import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon'
|
||||||
import { CommonModal } from '../../../../common/modals/common-modal'
|
import { CommonModal } from '../../../../common/modals/common-modal'
|
||||||
import { EditorPreferenceProperty, EditorPreferenceSelect } from './editor-preference-select'
|
import { ShowIf } from '../../../../common/show-if/show-if'
|
||||||
|
import { EditorPreferenceBooleanProperty } from './editor-preference-boolean-property'
|
||||||
|
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
|
||||||
|
import { EditorPreferenceLigaturesSelect } from './editor-preference-ligatures-select'
|
||||||
|
import { EditorPreferenceNumberProperty } from './editor-preference-number-property'
|
||||||
|
import { EditorPreferenceProperty } from "./editor-preference-property"
|
||||||
|
import { EditorPreferenceSelectProperty } from "./editor-preference-select-property"
|
||||||
|
|
||||||
export const EditorPreferences: React.FC = () => {
|
export const EditorPreferences: React.FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [showModal, setShowModal] = useState(false)
|
const [showModal, setShowModal] = useState(false)
|
||||||
const preferences = useSelector((state: ApplicationState) => state.editorConfig.preferences, equal)
|
const indentWithTabs = useSelector((state: ApplicationState) => state.editorConfig.preferences.indentWithTabs ?? false, equal)
|
||||||
|
|
||||||
const sendPreferences = useCallback((newPreferences: EditorConfiguration) => {
|
|
||||||
setEditorPreferences(newPreferences)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
@ -39,32 +39,27 @@ export const EditorPreferences: React.FC = () => {
|
||||||
<Form>
|
<Form>
|
||||||
<ListGroup>
|
<ListGroup>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.THEME}>
|
<EditorPreferenceSelectProperty property={EditorPreferenceProperty.THEME} selections={['one-dark', 'neat']}/>
|
||||||
<option value='one-dark'>Dark</option>
|
|
||||||
<option value='neat'>Light</option>
|
|
||||||
</EditorPreferenceSelect>
|
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.KEYMAP}>
|
<EditorPreferenceSelectProperty property={EditorPreferenceProperty.KEYMAP} selections={['sublime', 'emacs', 'vim']}/>
|
||||||
<option value='sublime'>Sublime</option>
|
|
||||||
<option value='emacs'>Emacs</option>
|
|
||||||
<option value='vim'>Vim</option>
|
|
||||||
</EditorPreferenceSelect>
|
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.INDENT_WITH_TABS}>
|
<EditorPreferenceBooleanProperty property={EditorPreferenceProperty.INDENT_WITH_TABS}/>
|
||||||
<option value='false'>Spaces</option>
|
</ListGroup.Item>
|
||||||
<option value='true'>Tab</option>
|
<ShowIf condition={!indentWithTabs}>
|
||||||
</EditorPreferenceSelect>
|
<ListGroup.Item>
|
||||||
|
<EditorPreferenceNumberProperty property={EditorPreferenceProperty.INDENT_UNIT}/>
|
||||||
|
</ListGroup.Item>
|
||||||
|
</ShowIf>
|
||||||
|
<ListGroup.Item>
|
||||||
|
<EditorPreferenceLigaturesSelect/>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.INDENT_UNIT}/>
|
<EditorPreferenceInput onChange={() => alert('This feature is not yet implemented.')} property={EditorPreferenceProperty.SPELL_CHECK} type={EditorPreferenceInputType.SELECT}>
|
||||||
</ListGroup.Item>
|
<option value='off'>Off</option>
|
||||||
<ListGroup.Item>
|
|
||||||
<EditorPreferenceSelect onChange={() => alert('This feature is not yet implemented.')} preferences={preferences} property={EditorPreferenceProperty.SPELL_CHECK}>
|
|
||||||
<option value='off'>off</option>
|
|
||||||
<option value='en'>English</option>
|
<option value='en'>English</option>
|
||||||
</EditorPreferenceSelect>
|
</EditorPreferenceInput>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -37,7 +37,7 @@ export const FlowChart: React.FC<FlowChartProps> = ({ code }) => {
|
||||||
'line-color': darkModeActivated ? '#ffffff' : '#000000',
|
'line-color': darkModeActivated ? '#ffffff' : '#000000',
|
||||||
'element-color': darkModeActivated ? '#ffffff' : '#000000',
|
'element-color': darkModeActivated ? '#ffffff' : '#000000',
|
||||||
'font-color': darkModeActivated ? '#ffffff' : '#000000',
|
'font-color': darkModeActivated ? '#ffffff' : '#000000',
|
||||||
'font-family': 'Source Code Pro, "Twemoji Mozilla", monospace'
|
'font-family': 'Source Sans Pro, "Twemoji Mozilla", monospace'
|
||||||
})
|
})
|
||||||
setError(false)
|
setError(false)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
EditorConfig,
|
EditorConfig,
|
||||||
EditorConfigActionType,
|
EditorConfigActionType,
|
||||||
SetEditorConfigAction,
|
SetEditorConfigAction,
|
||||||
|
SetEditorLigaturesAction,
|
||||||
SetEditorPreferencesAction,
|
SetEditorPreferencesAction,
|
||||||
SetEditorSyncScrollAction
|
SetEditorSyncScrollAction
|
||||||
} from './types'
|
} from './types'
|
||||||
|
@ -52,12 +53,18 @@ export const setEditorSyncScroll = (syncScroll: boolean): void => {
|
||||||
store.dispatch(action)
|
store.dispatch(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setEditorPreferences = (preferences: EditorConfiguration): void => {
|
export const setEditorLigatures = (ligatures: boolean): void => {
|
||||||
|
const action: SetEditorLigaturesAction = {
|
||||||
|
type: EditorConfigActionType.SET_LIGATURES,
|
||||||
|
ligatures: ligatures
|
||||||
|
}
|
||||||
|
store.dispatch(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mergeEditorPreferences = (preferences: EditorConfiguration): void => {
|
||||||
const action: SetEditorPreferencesAction = {
|
const action: SetEditorPreferencesAction = {
|
||||||
type: EditorConfigActionType.SET_EDITOR_PREFERENCES,
|
type: EditorConfigActionType.MERGE_EDITOR_PREFERENCES,
|
||||||
preferences: {
|
preferences: preferences
|
||||||
...preferences
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
store.dispatch(action)
|
store.dispatch(action)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,14 @@ import {
|
||||||
EditorConfigActions,
|
EditorConfigActions,
|
||||||
EditorConfigActionType,
|
EditorConfigActionType,
|
||||||
SetEditorConfigAction,
|
SetEditorConfigAction,
|
||||||
|
SetEditorLigaturesAction,
|
||||||
SetEditorPreferencesAction,
|
SetEditorPreferencesAction,
|
||||||
SetEditorSyncScrollAction
|
SetEditorSyncScrollAction
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
const initialState: EditorConfig = {
|
const initialState: EditorConfig = {
|
||||||
editorMode: EditorMode.BOTH,
|
editorMode: EditorMode.BOTH,
|
||||||
|
ligatures: true,
|
||||||
syncScroll: true,
|
syncScroll: true,
|
||||||
preferences: {
|
preferences: {
|
||||||
theme: 'one-dark',
|
theme: 'one-dark',
|
||||||
|
@ -28,7 +30,7 @@ const initialState: EditorConfig = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialState = (): EditorConfig => {
|
const getInitialState = (): EditorConfig => {
|
||||||
return loadFromLocalStorage() ?? initialState
|
return { ...initialState, ...loadFromLocalStorage() }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditorConfigReducer: Reducer<EditorConfig, EditorConfigActions> = (state: EditorConfig = getInitialState(), action: EditorConfigActions) => {
|
export const EditorConfigReducer: Reducer<EditorConfig, EditorConfigActions> = (state: EditorConfig = getInitialState(), action: EditorConfigActions) => {
|
||||||
|
@ -48,10 +50,19 @@ export const EditorConfigReducer: Reducer<EditorConfig, EditorConfigActions> = (
|
||||||
}
|
}
|
||||||
saveToLocalStorage(newState)
|
saveToLocalStorage(newState)
|
||||||
return newState
|
return newState
|
||||||
case EditorConfigActionType.SET_EDITOR_PREFERENCES:
|
case EditorConfigActionType.SET_LIGATURES:
|
||||||
newState = {
|
newState = {
|
||||||
...state,
|
...state,
|
||||||
preferences: (action as SetEditorPreferencesAction).preferences
|
ligatures: (action as SetEditorLigaturesAction).ligatures
|
||||||
|
}
|
||||||
|
saveToLocalStorage(newState)
|
||||||
|
return newState
|
||||||
|
case EditorConfigActionType.MERGE_EDITOR_PREFERENCES:
|
||||||
|
newState = {
|
||||||
|
...state,
|
||||||
|
preferences: {
|
||||||
|
...state.preferences, ...(action as SetEditorPreferencesAction).preferences
|
||||||
|
}
|
||||||
}
|
}
|
||||||
saveToLocalStorage(newState)
|
saveToLocalStorage(newState)
|
||||||
return newState
|
return newState
|
||||||
|
|
|
@ -11,12 +11,14 @@ import { EditorMode } from '../../components/editor/app-bar/editor-view-mode'
|
||||||
export enum EditorConfigActionType {
|
export enum EditorConfigActionType {
|
||||||
SET_EDITOR_VIEW_MODE = 'editor/mode/set',
|
SET_EDITOR_VIEW_MODE = 'editor/mode/set',
|
||||||
SET_SYNC_SCROLL = 'editor/syncScroll/set',
|
SET_SYNC_SCROLL = 'editor/syncScroll/set',
|
||||||
SET_EDITOR_PREFERENCES = 'editor/preferences/set'
|
MERGE_EDITOR_PREFERENCES = 'editor/preferences/merge',
|
||||||
|
SET_LIGATURES = 'editor/preferences/setLigatures'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditorConfig {
|
export interface EditorConfig {
|
||||||
editorMode: EditorMode;
|
editorMode: EditorMode;
|
||||||
syncScroll: boolean;
|
syncScroll: boolean;
|
||||||
|
ligatures: boolean
|
||||||
preferences: EditorConfiguration
|
preferences: EditorConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +30,10 @@ export interface SetEditorSyncScrollAction extends EditorConfigActions {
|
||||||
syncScroll: boolean
|
syncScroll: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetEditorLigaturesAction extends EditorConfigActions {
|
||||||
|
ligatures: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface SetEditorConfigAction extends EditorConfigActions {
|
export interface SetEditorConfigAction extends EditorConfigActions {
|
||||||
mode: EditorMode
|
mode: EditorMode
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
@import "../../node_modules/bootstrap/scss/bootstrap";
|
@import "../../node_modules/bootstrap/scss/bootstrap";
|
||||||
@import '../../node_modules/react-bootstrap-typeahead/css/Typeahead';
|
@import '../../node_modules/react-bootstrap-typeahead/css/Typeahead';
|
||||||
@import "~fontsource-source-sans-pro/index.css";
|
@import "~fontsource-source-sans-pro/index.css";
|
||||||
@import "~fontsource-source-code-pro/index.css";
|
|
||||||
@import "fonts/twemoji/twemoji";
|
@import "fonts/twemoji/twemoji";
|
||||||
@import '../../node_modules/fork-awesome/css/fork-awesome.min';
|
@import '../../node_modules/fork-awesome/css/fork-awesome.min';
|
||||||
|
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -6869,6 +6869,11 @@ find-up@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
locate-path "^3.0.0"
|
locate-path "^3.0.0"
|
||||||
|
|
||||||
|
firacode@5.2.0:
|
||||||
|
version "5.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/firacode/-/firacode-5.2.0.tgz#2eab5b4f59e3197d5e84f15a25485a88f0cd3180"
|
||||||
|
integrity sha512-Q1SO7vibzYcT+KaohGK0ypGS58zLtO2o2UuiLvngTEhBbHQoZmZ4DAiugj0MNNpeM4jG9gM9NyusVDM3MxYP7A==
|
||||||
|
|
||||||
flat-cache@^2.0.1:
|
flat-cache@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
|
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
|
||||||
|
@ -6908,11 +6913,6 @@ follow-redirects@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
||||||
|
|
||||||
fontsource-source-code-pro@3.1.5:
|
|
||||||
version "3.1.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/fontsource-source-code-pro/-/fontsource-source-code-pro-3.1.5.tgz#0f000f06dfa7220f62c64f572e5d9ee1fd087a8e"
|
|
||||||
integrity sha512-eoYyrTaNcgrWc62w0pImfualDr2JE4SKpeGlEqV+Y34tHYbuD5jTIkzx3GrDH4eDw9KDS5wQdlnSVOj+SVy0Zw==
|
|
||||||
|
|
||||||
fontsource-source-sans-pro@3.1.5:
|
fontsource-source-sans-pro@3.1.5:
|
||||||
version "3.1.5"
|
version "3.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/fontsource-source-sans-pro/-/fontsource-source-sans-pro-3.1.5.tgz#575edceadf0e68603c1c74b087f4423738cce2f9"
|
resolved "https://registry.yarnpkg.com/fontsource-source-sans-pro/-/fontsource-source-sans-pro-3.1.5.tgz#575edceadf0e68603c1c74b087f4423738cce2f9"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue