Use fira code in editor (#695)

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
Tilman Vatteroth 2020-12-14 23:58:46 +01:00 committed by GitHub
parent b3288a6666
commit 8ce344512c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 311 additions and 113 deletions

View file

@ -11,11 +11,23 @@
@import '../../../../node_modules/codemirror/theme/neat';
@import './one-dark';
@import 'hints';
@import '../../../../node_modules/firacode/distr/fira_code.css';
.CodeMirror {
font-family: "Source Code Pro", "Twemoji Mozilla", Consolas, monaco, monospace;
font-family: "Fira Code", "Twemoji Mozilla", Consolas, monaco, monospace;
letter-spacing: 0.025em;
line-height: 1.25;
font-size: 18px;
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;
}
}

View file

@ -69,6 +69,7 @@ export const EditorPane: React.FC<EditorPaneProps & ScrollProps> = ({ onContentC
const [editor, setEditor] = useState<Editor>()
const [statusBarInfo, setStatusBarInfo] = useState<StatusBarInfo>(defaultState)
const editorPreferences = useSelector((state: ApplicationState) => state.editorConfig.preferences, equal)
const ligaturesEnabled = useSelector((state: ApplicationState) => state.editorConfig.ligatures, equal)
const lastScrollPosition = useRef<number>()
const [editorScroll, setEditorScroll] = useState<ScrollInfo>()
@ -163,7 +164,7 @@ export const EditorPane: React.FC<EditorPaneProps & ScrollProps> = ({ onContentC
editor={editor}
/>
<ControlledCodeMirror
className="overflow-hidden w-100 flex-fill"
className={`overflow-hidden w-100 flex-fill ${ligaturesEnabled ? '' : 'no-ligatures'}`}
value={content}
options={codeMirrorOptions}
onChange={onChange}

View file

@ -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>
)
}

View file

@ -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>
)
}

View file

@ -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>
)
}

View file

@ -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}/>
)
}

View file

@ -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'
}

View file

@ -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>
)
}

View file

@ -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>
)
}

View file

@ -4,26 +4,26 @@ 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, { Fragment, useCallback, useState } from 'react'
import equal from "fast-deep-equal"
import React, { Fragment, useState } from 'react'
import { Button, Form, ListGroup } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { ApplicationState } from '../../../../../redux'
import { setEditorPreferences } from '../../../../../redux/editor/methods'
import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon'
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 = () => {
const { t } = useTranslation()
const [showModal, setShowModal] = useState(false)
const preferences = useSelector((state: ApplicationState) => state.editorConfig.preferences, equal)
const sendPreferences = useCallback((newPreferences: EditorConfiguration) => {
setEditorPreferences(newPreferences)
}, [])
const indentWithTabs = useSelector((state: ApplicationState) => state.editorConfig.preferences.indentWithTabs ?? false, equal)
return (
<Fragment>
@ -39,32 +39,27 @@ export const EditorPreferences: React.FC = () => {
<Form>
<ListGroup>
<ListGroup.Item>
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.THEME}>
<option value='one-dark'>Dark</option>
<option value='neat'>Light</option>
</EditorPreferenceSelect>
<EditorPreferenceSelectProperty property={EditorPreferenceProperty.THEME} selections={['one-dark', 'neat']}/>
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.KEYMAP}>
<option value='sublime'>Sublime</option>
<option value='emacs'>Emacs</option>
<option value='vim'>Vim</option>
</EditorPreferenceSelect>
<EditorPreferenceSelectProperty property={EditorPreferenceProperty.KEYMAP} selections={['sublime', 'emacs', 'vim']}/>
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.INDENT_WITH_TABS}>
<option value='false'>Spaces</option>
<option value='true'>Tab</option>
</EditorPreferenceSelect>
<EditorPreferenceBooleanProperty property={EditorPreferenceProperty.INDENT_WITH_TABS}/>
</ListGroup.Item>
<ShowIf condition={!indentWithTabs}>
<ListGroup.Item>
<EditorPreferenceNumberProperty property={EditorPreferenceProperty.INDENT_UNIT}/>
</ListGroup.Item>
</ShowIf>
<ListGroup.Item>
<EditorPreferenceLigaturesSelect/>
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceSelect onChange={sendPreferences} preferences={preferences} property={EditorPreferenceProperty.INDENT_UNIT}/>
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceSelect onChange={() => alert('This feature is not yet implemented.')} preferences={preferences} property={EditorPreferenceProperty.SPELL_CHECK}>
<option value='off'>off</option>
<EditorPreferenceInput onChange={() => alert('This feature is not yet implemented.')} property={EditorPreferenceProperty.SPELL_CHECK} type={EditorPreferenceInputType.SELECT}>
<option value='off'>Off</option>
<option value='en'>English</option>
</EditorPreferenceSelect>
</EditorPreferenceInput>
</ListGroup.Item>
</ListGroup>
</Form>

View file

@ -37,7 +37,7 @@ export const FlowChart: React.FC<FlowChartProps> = ({ code }) => {
'line-color': darkModeActivated ? '#ffffff' : '#000000',
'element-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)
} catch (error) {