first commit
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsAutoCloseBrackets() {
|
||||
const { t } = useTranslation()
|
||||
const { autoPairDelimiters, setAutoPairDelimiters } =
|
||||
useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setAutoPairDelimiters}
|
||||
value={autoPairDelimiters}
|
||||
options={[
|
||||
{
|
||||
value: true,
|
||||
label: t('on'),
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: t('off'),
|
||||
},
|
||||
]}
|
||||
label={t('auto_close_brackets')}
|
||||
name="autoPairDelimiters"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsAutoComplete() {
|
||||
const { t } = useTranslation()
|
||||
const { autoComplete, setAutoComplete } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setAutoComplete}
|
||||
value={autoComplete}
|
||||
options={[
|
||||
{
|
||||
value: true,
|
||||
label: t('on'),
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: t('off'),
|
||||
},
|
||||
]}
|
||||
label={t('auto_complete')}
|
||||
name="autoComplete"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { ProjectCompiler } from '../../../../../../types/project-settings'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsCompiler() {
|
||||
const { t } = useTranslation()
|
||||
const { write } = usePermissionsContext()
|
||||
const { compiler, setCompiler } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect<ProjectCompiler>
|
||||
onChange={setCompiler}
|
||||
value={compiler}
|
||||
disabled={!write}
|
||||
options={[
|
||||
{
|
||||
value: 'pdflatex',
|
||||
label: 'pdfLaTeX',
|
||||
},
|
||||
{
|
||||
value: 'latex',
|
||||
label: 'LaTeX',
|
||||
},
|
||||
{
|
||||
value: 'xelatex',
|
||||
label: 'XeLaTeX',
|
||||
},
|
||||
{
|
||||
value: 'lualatex',
|
||||
label: 'LuaLaTeX',
|
||||
},
|
||||
]}
|
||||
label={t('compiler')}
|
||||
name="compiler"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import DictionaryModal from '../../../dictionary/components/dictionary-modal'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
|
||||
import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
|
||||
|
||||
export default function SettingsDictionary() {
|
||||
const { t } = useTranslation()
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
|
||||
return (
|
||||
<OLFormGroup className="left-menu-setting">
|
||||
<OLFormLabel htmlFor="dictionary-settings">{t('dictionary')}</OLFormLabel>
|
||||
<OLButton
|
||||
id="dictionary-settings"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => setShowModal(true)}
|
||||
>
|
||||
{t('edit')}
|
||||
</OLButton>
|
||||
|
||||
<DictionaryModal
|
||||
show={showModal}
|
||||
handleHide={() => setShowModal(false)}
|
||||
/>
|
||||
</OLFormGroup>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { isValidTeXFile } from '../../../../main/is-valid-tex-file'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import type { Option } from './settings-menu-select'
|
||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
||||
|
||||
export default function SettingsDocument() {
|
||||
const { t } = useTranslation()
|
||||
const { write } = usePermissionsContext()
|
||||
const { docs } = useFileTreeData()
|
||||
const { rootDocId, setRootDocId } = useProjectSettingsContext()
|
||||
|
||||
const validDocsOptions = useMemo(() => {
|
||||
const filteredDocs =
|
||||
docs?.filter(
|
||||
doc => isValidTeXFile(doc.doc.name) || rootDocId === doc.doc.id
|
||||
) ?? []
|
||||
|
||||
const mappedDocs: Array<Option> = filteredDocs.map(doc => ({
|
||||
value: doc.doc.id,
|
||||
label: doc.path,
|
||||
}))
|
||||
|
||||
if (!rootDocId) {
|
||||
mappedDocs.unshift({
|
||||
value: '',
|
||||
label: 'None',
|
||||
disabled: true,
|
||||
})
|
||||
}
|
||||
|
||||
return mappedDocs
|
||||
}, [docs, rootDocId])
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setRootDocId}
|
||||
value={rootDocId ?? ''}
|
||||
disabled={!write}
|
||||
options={validDocsOptions}
|
||||
label={t('main_document')}
|
||||
name="rootDocId"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import type { Option } from './settings-menu-select'
|
||||
|
||||
export default function SettingsEditorTheme() {
|
||||
const { t } = useTranslation()
|
||||
const editorThemes = getMeta('ol-editorThemes')
|
||||
const legacyEditorThemes = getMeta('ol-legacyEditorThemes')
|
||||
const { editorTheme, setEditorTheme } = useProjectSettingsContext()
|
||||
|
||||
const options = useMemo(() => {
|
||||
const editorThemeOptions: Array<Option> =
|
||||
editorThemes?.map(theme => ({
|
||||
value: theme,
|
||||
label: theme.replace(/_/g, ' '),
|
||||
})) ?? []
|
||||
|
||||
const dividerOption: Option = {
|
||||
value: '-',
|
||||
label: '—————————————————',
|
||||
disabled: true,
|
||||
}
|
||||
|
||||
const legacyEditorThemeOptions: Array<Option> =
|
||||
legacyEditorThemes?.map(theme => ({
|
||||
value: theme,
|
||||
label: theme.replace(/_/g, ' ') + ' (Legacy)',
|
||||
})) ?? []
|
||||
|
||||
return [...editorThemeOptions, dividerOption, ...legacyEditorThemeOptions]
|
||||
}, [editorThemes, legacyEditorThemes])
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setEditorTheme}
|
||||
value={editorTheme}
|
||||
options={options}
|
||||
label={t('editor_theme')}
|
||||
name="editorTheme"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import BetaBadge from '@/shared/components/beta-badge'
|
||||
import { FontFamily } from '@/shared/utils/styles'
|
||||
|
||||
export default function SettingsFontFamily() {
|
||||
const { t } = useTranslation()
|
||||
const { fontFamily, setFontFamily } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<div className="left-menu-setting-position">
|
||||
<SettingsMenuSelect<FontFamily>
|
||||
onChange={setFontFamily}
|
||||
value={fontFamily}
|
||||
options={[
|
||||
{
|
||||
value: 'monaco',
|
||||
label: 'Monaco / Menlo / Consolas',
|
||||
},
|
||||
{
|
||||
value: 'lucida',
|
||||
label: 'Lucida / Source Code Pro',
|
||||
},
|
||||
{
|
||||
value: 'opendyslexicmono',
|
||||
label: 'OpenDyslexic Mono',
|
||||
},
|
||||
]}
|
||||
label={t('font_family')}
|
||||
name="fontFamily"
|
||||
/>
|
||||
<BetaBadge
|
||||
phase="release"
|
||||
link={{
|
||||
href: 'https://docs.google.com/forms/d/e/1FAIpQLScOt_IHTrcaM_uitP9dgCo_r4dl4cy9Ry6LhYYcwTN4qDTDUg/viewform',
|
||||
className: 'left-menu-setting-icon',
|
||||
}}
|
||||
tooltip={{
|
||||
id: 'font-family-tooltip',
|
||||
text: `${t('new_font_open_dyslexic')} ${t('click_to_give_feedback')}`,
|
||||
placement: 'right',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import type { Option } from './settings-menu-select'
|
||||
|
||||
const sizes = [10, 11, 12, 13, 14, 16, 18, 20, 22, 24]
|
||||
const options: Option<number>[] = sizes.map(size => ({
|
||||
value: size,
|
||||
label: `${size}px`,
|
||||
}))
|
||||
|
||||
export default function SettingsFontSize() {
|
||||
const { t } = useTranslation()
|
||||
const { fontSize, setFontSize } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setFontSize}
|
||||
value={fontSize}
|
||||
options={options}
|
||||
label={t('font_size')}
|
||||
name="fontSize"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import type { Option } from './settings-menu-select'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
|
||||
export default function SettingsImageName() {
|
||||
const { t } = useTranslation()
|
||||
const { imageName, setImageName } = useProjectSettingsContext()
|
||||
const { write } = usePermissionsContext()
|
||||
|
||||
const allowedImageNames = useMemo(
|
||||
() => getMeta('ol-allowedImageNames') || [],
|
||||
[]
|
||||
)
|
||||
|
||||
const options: Array<Option> = useMemo(
|
||||
() =>
|
||||
allowedImageNames.map(({ imageName, imageDesc }) => ({
|
||||
value: imageName,
|
||||
label: imageDesc,
|
||||
})),
|
||||
[allowedImageNames]
|
||||
)
|
||||
|
||||
if (allowedImageNames.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setImageName}
|
||||
value={imageName}
|
||||
disabled={!write}
|
||||
options={options}
|
||||
label={t('tex_live_version')}
|
||||
name="imageName"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { Keybindings } from '../../../../../../types/user-settings'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsKeybindings() {
|
||||
const { t } = useTranslation()
|
||||
const { mode, setMode } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect<Keybindings>
|
||||
onChange={setMode}
|
||||
value={mode}
|
||||
options={[
|
||||
{
|
||||
value: 'default',
|
||||
label: 'None',
|
||||
},
|
||||
{
|
||||
value: 'vim',
|
||||
label: 'Vim',
|
||||
},
|
||||
{
|
||||
value: 'emacs',
|
||||
label: 'Emacs',
|
||||
},
|
||||
]}
|
||||
label={t('keybindings')}
|
||||
name="mode"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import { LineHeight } from '@/shared/utils/styles'
|
||||
|
||||
export default function SettingsLineHeight() {
|
||||
const { t } = useTranslation()
|
||||
const { lineHeight, setLineHeight } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect<LineHeight>
|
||||
onChange={setLineHeight}
|
||||
value={lineHeight}
|
||||
options={[
|
||||
{
|
||||
value: 'compact',
|
||||
label: t('compact'),
|
||||
},
|
||||
{
|
||||
value: 'normal',
|
||||
label: t('normal'),
|
||||
},
|
||||
{
|
||||
value: 'wide',
|
||||
label: t('wide'),
|
||||
},
|
||||
]}
|
||||
label={t('line_height')}
|
||||
name="lineHeight"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsMathPreview() {
|
||||
const { t } = useTranslation()
|
||||
const { mathPreview, setMathPreview } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setMathPreview}
|
||||
value={mathPreview}
|
||||
options={[
|
||||
{
|
||||
value: true,
|
||||
label: t('on'),
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: t('off'),
|
||||
},
|
||||
]}
|
||||
label={t('equation_preview')}
|
||||
name="mathPreview"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
|
||||
import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
|
||||
import OLFormSelect from '@/features/ui/components/ol/ol-form-select'
|
||||
import { ChangeEventHandler, useCallback, useEffect, useRef } from 'react'
|
||||
import { Spinner } from 'react-bootstrap-5'
|
||||
import { useEditorLeftMenuContext } from '@/features/editor-left-menu/components/editor-left-menu-context'
|
||||
|
||||
type PossibleValue = string | number | boolean
|
||||
|
||||
export type Option<T extends PossibleValue = string> = {
|
||||
value: T
|
||||
label: string
|
||||
ariaHidden?: 'true' | 'false'
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export type Optgroup<T extends PossibleValue = string> = {
|
||||
label: string
|
||||
options: Array<Option<T>>
|
||||
}
|
||||
|
||||
type SettingsMenuSelectProps<T extends PossibleValue = string> = {
|
||||
label: string
|
||||
name: string
|
||||
options: Array<Option<T>>
|
||||
optgroup?: Optgroup<T>
|
||||
loading?: boolean
|
||||
onChange: (val: T) => void
|
||||
value?: T
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function SettingsMenuSelect<T extends PossibleValue = string>({
|
||||
label,
|
||||
name,
|
||||
options,
|
||||
optgroup,
|
||||
loading,
|
||||
onChange,
|
||||
value,
|
||||
disabled = false,
|
||||
}: SettingsMenuSelectProps<T>) {
|
||||
const handleChange: ChangeEventHandler<HTMLSelectElement> = useCallback(
|
||||
event => {
|
||||
const selectedValue = event.target.value
|
||||
let onChangeValue: PossibleValue = selectedValue
|
||||
if (typeof value === 'boolean') {
|
||||
onChangeValue = selectedValue === 'true'
|
||||
} else if (typeof value === 'number') {
|
||||
onChangeValue = parseInt(selectedValue, 10)
|
||||
}
|
||||
onChange(onChangeValue as T)
|
||||
},
|
||||
[onChange, value]
|
||||
)
|
||||
|
||||
const { settingToFocus } = useEditorLeftMenuContext()
|
||||
|
||||
const selectRef = useRef<HTMLSelectElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (settingToFocus === name && selectRef.current) {
|
||||
selectRef.current.scrollIntoView({
|
||||
block: 'center',
|
||||
behavior: 'smooth',
|
||||
})
|
||||
selectRef.current.focus()
|
||||
}
|
||||
|
||||
// clear the focus setting
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('ui.focus-setting', { detail: undefined })
|
||||
)
|
||||
}, [name, settingToFocus])
|
||||
|
||||
return (
|
||||
<OLFormGroup
|
||||
controlId={`settings-menu-${name}`}
|
||||
className="left-menu-setting"
|
||||
>
|
||||
<OLFormLabel>{label}</OLFormLabel>
|
||||
{loading ? (
|
||||
<p className="mb-0">
|
||||
<Spinner
|
||||
animation="border"
|
||||
aria-hidden="true"
|
||||
size="sm"
|
||||
role="status"
|
||||
/>
|
||||
</p>
|
||||
) : (
|
||||
<OLFormSelect
|
||||
size="sm"
|
||||
onChange={handleChange}
|
||||
value={value?.toString()}
|
||||
disabled={disabled}
|
||||
ref={selectRef}
|
||||
>
|
||||
{options.map(option => (
|
||||
<option
|
||||
key={`${name}-${option.value}`}
|
||||
value={option.value.toString()}
|
||||
aria-hidden={option.ariaHidden}
|
||||
disabled={option.disabled}
|
||||
>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
{optgroup ? (
|
||||
<optgroup label={optgroup.label}>
|
||||
{optgroup.options.map(option => (
|
||||
<option
|
||||
value={option.value.toString()}
|
||||
key={option.value.toString()}
|
||||
>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
) : null}
|
||||
</OLFormSelect>
|
||||
)}
|
||||
</OLFormGroup>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLayoutContext } from '../../../../shared/context/layout-context'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import SettingsMenuSelect, { Option } from './settings-menu-select'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import type { OverallThemeMeta } from '../../../../../../types/project-settings'
|
||||
import { isIEEEBranded } from '@/utils/is-ieee-branded'
|
||||
import { OverallTheme } from '@/shared/utils/styles'
|
||||
|
||||
export default function SettingsOverallTheme() {
|
||||
const { t } = useTranslation()
|
||||
const overallThemes = getMeta('ol-overallThemes') as
|
||||
| OverallThemeMeta[]
|
||||
| undefined
|
||||
const { loadingStyleSheet } = useLayoutContext()
|
||||
const { overallTheme, setOverallTheme } = useProjectSettingsContext()
|
||||
|
||||
const options: Array<Option<OverallTheme>> = useMemo(
|
||||
() =>
|
||||
overallThemes?.map(({ name, val }) => ({
|
||||
value: val,
|
||||
label: name,
|
||||
})) ?? [],
|
||||
[overallThemes]
|
||||
)
|
||||
|
||||
if (!overallThemes || isIEEEBranded()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect<OverallTheme>
|
||||
onChange={setOverallTheme}
|
||||
value={overallTheme}
|
||||
options={options}
|
||||
loading={loadingStyleSheet}
|
||||
label={t('overall_theme')}
|
||||
name="overallTheme"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { PdfViewer } from '../../../../../../types/user-settings'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsPdfViewer() {
|
||||
const { t } = useTranslation()
|
||||
const { pdfViewer, setPdfViewer } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect<PdfViewer>
|
||||
onChange={setPdfViewer}
|
||||
value={pdfViewer}
|
||||
options={[
|
||||
{
|
||||
value: 'pdfjs',
|
||||
label: t('overleaf'),
|
||||
},
|
||||
{
|
||||
value: 'native',
|
||||
label: t('browser'),
|
||||
},
|
||||
]}
|
||||
label={t('pdf_viewer')}
|
||||
name="pdfViewer"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
import type { Optgroup } from './settings-menu-select'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
import { supportsWebAssembly } from '@/utils/wasm'
|
||||
|
||||
export default function SettingsSpellCheckLanguage() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { spellCheckLanguage, setSpellCheckLanguage } =
|
||||
useProjectSettingsContext()
|
||||
const { permissionsLevel } = useEditorContext()
|
||||
|
||||
const optgroup: Optgroup = useMemo(() => {
|
||||
const options = (getMeta('ol-languages') ?? [])
|
||||
// only include spell-check languages that are available in the client
|
||||
.filter(language => language.dic !== undefined)
|
||||
|
||||
return {
|
||||
label: 'Language',
|
||||
options: options.map(language => ({
|
||||
value: language.code,
|
||||
label: language.name,
|
||||
})),
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect
|
||||
onChange={setSpellCheckLanguage}
|
||||
value={supportsWebAssembly() ? spellCheckLanguage : ''}
|
||||
options={[{ value: '', label: t('off') }]}
|
||||
optgroup={optgroup}
|
||||
label={t('spell_check')}
|
||||
name="spellCheckLanguage"
|
||||
disabled={permissionsLevel === 'readOnly' || !supportsWebAssembly()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import SettingsMenuSelect from './settings-menu-select'
|
||||
|
||||
export default function SettingsSyntaxValidation() {
|
||||
const { t } = useTranslation()
|
||||
const { syntaxValidation, setSyntaxValidation } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<SettingsMenuSelect<boolean>
|
||||
onChange={setSyntaxValidation}
|
||||
value={syntaxValidation}
|
||||
options={[
|
||||
{
|
||||
value: true,
|
||||
label: t('on'),
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: t('off'),
|
||||
},
|
||||
]}
|
||||
label={t('syntax_validation')}
|
||||
name="syntaxValidation"
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user