mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Desktop: Added search list for configuration font input fields (#10248)
This commit is contained in:
parent
dd28c9f4d7
commit
7ec02fc8d8
@ -167,6 +167,7 @@ packages/app-desktop/gui/Button/Button.js
|
|||||||
packages/app-desktop/gui/ClipperConfigScreen.js
|
packages/app-desktop/gui/ClipperConfigScreen.js
|
||||||
packages/app-desktop/gui/ConfigScreen/ButtonBar.js
|
packages/app-desktop/gui/ConfigScreen/ButtonBar.js
|
||||||
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js
|
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js
|
||||||
|
packages/app-desktop/gui/ConfigScreen/FontSearch.js
|
||||||
packages/app-desktop/gui/ConfigScreen/Sidebar.js
|
packages/app-desktop/gui/ConfigScreen/Sidebar.js
|
||||||
packages/app-desktop/gui/ConfigScreen/controls/MissingPasswordHelpLink.js
|
packages/app-desktop/gui/ConfigScreen/controls/MissingPasswordHelpLink.js
|
||||||
packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
|
packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -147,6 +147,7 @@ packages/app-desktop/gui/Button/Button.js
|
|||||||
packages/app-desktop/gui/ClipperConfigScreen.js
|
packages/app-desktop/gui/ClipperConfigScreen.js
|
||||||
packages/app-desktop/gui/ConfigScreen/ButtonBar.js
|
packages/app-desktop/gui/ConfigScreen/ButtonBar.js
|
||||||
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js
|
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js
|
||||||
|
packages/app-desktop/gui/ConfigScreen/FontSearch.js
|
||||||
packages/app-desktop/gui/ConfigScreen/Sidebar.js
|
packages/app-desktop/gui/ConfigScreen/Sidebar.js
|
||||||
packages/app-desktop/gui/ConfigScreen/controls/MissingPasswordHelpLink.js
|
packages/app-desktop/gui/ConfigScreen/controls/MissingPasswordHelpLink.js
|
||||||
packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
|
packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
|
||||||
|
@ -4,7 +4,7 @@ import ButtonBar from './ButtonBar';
|
|||||||
import Button, { ButtonLevel, ButtonSize } from '../Button/Button';
|
import Button, { ButtonLevel, ButtonSize } from '../Button/Button';
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
import bridge from '../../services/bridge';
|
import bridge from '../../services/bridge';
|
||||||
import Setting, { AppType, SyncStartupOperation } from '@joplin/lib/models/Setting';
|
import Setting, { AppType, SettingItemSubType, SyncStartupOperation } from '@joplin/lib/models/Setting';
|
||||||
import control_PluginsStates from './controls/plugins/PluginsStates';
|
import control_PluginsStates from './controls/plugins/PluginsStates';
|
||||||
import EncryptionConfigScreen from '../EncryptionConfigScreen/EncryptionConfigScreen';
|
import EncryptionConfigScreen from '../EncryptionConfigScreen/EncryptionConfigScreen';
|
||||||
import { reg } from '@joplin/lib/registry';
|
import { reg } from '@joplin/lib/registry';
|
||||||
@ -20,12 +20,23 @@ import ToggleAdvancedSettingsButton from './controls/ToggleAdvancedSettingsButto
|
|||||||
import shouldShowMissingPasswordWarning from '@joplin/lib/components/shared/config/shouldShowMissingPasswordWarning';
|
import shouldShowMissingPasswordWarning from '@joplin/lib/components/shared/config/shouldShowMissingPasswordWarning';
|
||||||
import MacOSMissingPasswordHelpLink from './controls/MissingPasswordHelpLink';
|
import MacOSMissingPasswordHelpLink from './controls/MissingPasswordHelpLink';
|
||||||
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');
|
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');
|
||||||
|
import FontSearch from './FontSearch';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
const settingKeyToControl: any = {
|
const settingKeyToControl: any = {
|
||||||
'plugins.states': control_PluginsStates,
|
'plugins.states': control_PluginsStates,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface Font {
|
||||||
|
family: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
queryLocalFonts(): Promise<Font[]>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
class ConfigScreenComponent extends React.Component<any, any> {
|
class ConfigScreenComponent extends React.Component<any, any> {
|
||||||
|
|
||||||
@ -44,6 +55,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
|||||||
screenName: '',
|
screenName: '',
|
||||||
changedSettingKeys: [],
|
changedSettingKeys: [],
|
||||||
needRestart: false,
|
needRestart: false,
|
||||||
|
fonts: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
this.rowStyle_ = {
|
this.rowStyle_ = {
|
||||||
@ -78,12 +90,16 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
|||||||
this.setState({ settings: this.props.settings });
|
this.setState({ settings: this.props.settings });
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public async componentDidMount() {
|
||||||
if (this.props.defaultSection) {
|
if (this.props.defaultSection) {
|
||||||
this.setState({ selectedSectionName: this.props.defaultSection }, () => {
|
this.setState({ selectedSectionName: this.props.defaultSection }, () => {
|
||||||
void this.switchSection(this.props.defaultSection);
|
void this.switchSection(this.props.defaultSection);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fonts = (await window.queryLocalFonts()).map((font: Font) => font.family);
|
||||||
|
const uniqueFonts = [...new Set(fonts)];
|
||||||
|
this.setState({ fonts: uniqueFonts });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSettingButton(key: string) {
|
private async handleSettingButton(key: string) {
|
||||||
@ -591,22 +607,32 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
|||||||
const onTextChange = (event: any) => {
|
const onTextChange = (event: any) => {
|
||||||
updateSettingValue(key, event.target.value);
|
updateSettingValue(key, event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={key} style={rowStyle}>
|
<div key={key} style={rowStyle}>
|
||||||
<div style={labelStyle}>
|
<div style={labelStyle}>
|
||||||
<label>{md.label()}</label>
|
<label>{md.label()}</label>
|
||||||
</div>
|
</div>
|
||||||
<input
|
{
|
||||||
type={inputType}
|
md.subType === SettingItemSubType.FontFamily || md.subType === SettingItemSubType.MonospaceFontFamily ?
|
||||||
style={inputStyle}
|
<FontSearch
|
||||||
value={this.state.settings[key]}
|
type={inputType}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
style={inputStyle}
|
||||||
onChange={(event: any) => {
|
value={this.state.settings[key]}
|
||||||
onTextChange(event);
|
availableFonts={this.state.fonts}
|
||||||
}}
|
onChange={fontFamily => updateSettingValue(key, fontFamily)}
|
||||||
spellCheck={false}
|
subtype={md.subType}
|
||||||
/>
|
/> :
|
||||||
|
<input
|
||||||
|
type={inputType}
|
||||||
|
style={inputStyle}
|
||||||
|
value={this.state.settings[key]}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
|
onChange={(event: any) => {
|
||||||
|
onTextChange(event);
|
||||||
|
}}
|
||||||
|
spellCheck={false}
|
||||||
|
/>
|
||||||
|
}
|
||||||
<div style={{ width: inputStyle.width, minWidth: inputStyle.minWidth }}>
|
<div style={{ width: inputStyle.width, minWidth: inputStyle.minWidth }}>
|
||||||
{descriptionComp}
|
{descriptionComp}
|
||||||
</div>
|
</div>
|
||||||
|
232
packages/app-desktop/gui/ConfigScreen/FontSearch.tsx
Normal file
232
packages/app-desktop/gui/ConfigScreen/FontSearch.tsx
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
import React = require('react');
|
||||||
|
import { useMemo, useState, useCallback, CSSProperties, useEffect, useRef } from 'react';
|
||||||
|
import { _ } from '@joplin/lib/locale';
|
||||||
|
import { SettingItemSubType } from '@joplin/lib/models/Setting';
|
||||||
|
import { focus } from '@joplin/lib/utils/focusHandler';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type: string;
|
||||||
|
style: CSSProperties;
|
||||||
|
value: string;
|
||||||
|
availableFonts: string[];
|
||||||
|
onChange: (font: string)=> void;
|
||||||
|
subtype: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FontSearch = (props: Props) => {
|
||||||
|
const { type, style, value, availableFonts, onChange, subtype } = props;
|
||||||
|
const [filteredAvailableFonts, setFilteredAvailableFonts] = useState(availableFonts);
|
||||||
|
const [inputText, setInputText] = useState(value);
|
||||||
|
const [showList, setShowList] = useState(false);
|
||||||
|
const [isListHovered, setIsListHovered] = useState(false);
|
||||||
|
const [isFontSelected, setIsFontSelected] = useState(value !== '');
|
||||||
|
const [visibleFonts, setVisibleFonts] = useState<string[]>([]);
|
||||||
|
const [isMonoBoxChecked, setIsMonoBoxChecked] = useState(false);
|
||||||
|
const isLoadingFonts = filteredAvailableFonts.length === 0;
|
||||||
|
const fontInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (subtype === SettingItemSubType.MonospaceFontFamily) {
|
||||||
|
setIsMonoBoxChecked(true);
|
||||||
|
}
|
||||||
|
}, [subtype]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isMonoBoxChecked) return setFilteredAvailableFonts(availableFonts);
|
||||||
|
const localMonospacedFonts = availableFonts.filter((font: string) =>
|
||||||
|
monospaceKeywords.some((word: string) => font.toLowerCase().includes(word)) ||
|
||||||
|
knownMonospacedFonts.includes(font.toLowerCase()),
|
||||||
|
);
|
||||||
|
setFilteredAvailableFonts(localMonospacedFonts);
|
||||||
|
}, [isMonoBoxChecked, availableFonts]);
|
||||||
|
|
||||||
|
const displayedFonts = useMemo(() => {
|
||||||
|
if (isFontSelected) return filteredAvailableFonts;
|
||||||
|
return filteredAvailableFonts.filter((font: string) =>
|
||||||
|
font.toLowerCase().startsWith(inputText.toLowerCase()),
|
||||||
|
);
|
||||||
|
}, [filteredAvailableFonts, inputText, isFontSelected]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setVisibleFonts(displayedFonts.slice(0, 20));
|
||||||
|
}, [displayedFonts]);
|
||||||
|
|
||||||
|
// Lazy loading
|
||||||
|
const handleListScroll: React.UIEventHandler<HTMLDivElement> = useCallback((event) => {
|
||||||
|
const scrollTop = (event.target as HTMLDivElement).scrollTop;
|
||||||
|
const scrollHeight = (event.target as HTMLDivElement).scrollHeight;
|
||||||
|
const clientHeight = (event.target as HTMLDivElement).clientHeight;
|
||||||
|
|
||||||
|
// Check if the user has scrolled to the bottom of the container
|
||||||
|
// A small buffer of 20 pixels is subtracted from the total scrollHeight to ensure new content starts loading slightly before the user reaches the absolute bottom, providing a smoother experience.
|
||||||
|
if (scrollTop + clientHeight >= scrollHeight - 20) {
|
||||||
|
// Load the next 20 fonts
|
||||||
|
const remainingFonts = displayedFonts.slice(visibleFonts.length, visibleFonts.length + 20);
|
||||||
|
|
||||||
|
setVisibleFonts([...visibleFonts, ...remainingFonts]);
|
||||||
|
}
|
||||||
|
}, [displayedFonts, visibleFonts]);
|
||||||
|
|
||||||
|
const handleTextChange: React.ChangeEventHandler<HTMLInputElement> = useCallback((event) => {
|
||||||
|
setIsFontSelected(false);
|
||||||
|
setInputText(event.target.value);
|
||||||
|
onChange(event.target.value);
|
||||||
|
}, [onChange]);
|
||||||
|
|
||||||
|
const handleFocus: React.FocusEventHandler<HTMLInputElement> = useCallback(() => setShowList(true), []);
|
||||||
|
|
||||||
|
const handleBlur: React.FocusEventHandler<HTMLInputElement> = useCallback(() => {
|
||||||
|
if (!isListHovered) {
|
||||||
|
setShowList(false);
|
||||||
|
}
|
||||||
|
}, [isListHovered]);
|
||||||
|
|
||||||
|
const handleFontClick: React.MouseEventHandler<HTMLDivElement> = useCallback((event) => {
|
||||||
|
const font = (event.target as HTMLDivElement).innerText;
|
||||||
|
setInputText(font);
|
||||||
|
setShowList(false);
|
||||||
|
onChange(font);
|
||||||
|
setIsFontSelected(true);
|
||||||
|
}, [onChange]);
|
||||||
|
|
||||||
|
const handleListHover: React.MouseEventHandler<HTMLDivElement> = useCallback(() => setIsListHovered(true), []);
|
||||||
|
|
||||||
|
const handleListLeave: React.MouseEventHandler<HTMLDivElement> = useCallback(() => setIsListHovered(false), []);
|
||||||
|
|
||||||
|
const handleMonoBoxCheck: React.ChangeEventHandler<HTMLInputElement> = useCallback(() => {
|
||||||
|
setIsMonoBoxChecked(!isMonoBoxChecked);
|
||||||
|
focus('FontSearch::fontInputRef', fontInputRef.current);
|
||||||
|
}, [isMonoBoxChecked]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
style={style}
|
||||||
|
value={inputText}
|
||||||
|
onChange={handleTextChange}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
spellCheck={false}
|
||||||
|
ref={fontInputRef}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={'font-search-list'}
|
||||||
|
style={{ display: showList ? 'block' : 'none' }}
|
||||||
|
onMouseEnter={handleListHover}
|
||||||
|
onMouseLeave={handleListLeave}
|
||||||
|
onScroll={handleListScroll}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
isLoadingFonts ? <div>{_('Loading...')}</div> :
|
||||||
|
<>
|
||||||
|
<div className='monospace-checkbox'>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={isMonoBoxChecked}
|
||||||
|
onChange={handleMonoBoxCheck}
|
||||||
|
id={`show-monospace-fonts_${subtype}`}
|
||||||
|
/>
|
||||||
|
<label htmlFor={`show-monospace-fonts_${subtype}`}>{_('Show monospace fonts only.')}</label>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
visibleFonts.map((font: string) =>
|
||||||
|
<div
|
||||||
|
key={font}
|
||||||
|
style={{ fontFamily: `"${font}"` }}
|
||||||
|
onClick={handleFontClick}
|
||||||
|
className='font-search-item'
|
||||||
|
>
|
||||||
|
{font}
|
||||||
|
</div>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FontSearch;
|
||||||
|
|
||||||
|
// Known monospaced fonts from wikipedia
|
||||||
|
// https://en.wikipedia.org/wiki/List_of_monospaced_typefaces
|
||||||
|
// https://en.wikipedia.org/wiki/Category:Monospaced_typefaces
|
||||||
|
// Make sure to add the fonts in lower case
|
||||||
|
// cSpell:disable
|
||||||
|
const knownMonospacedFonts = [
|
||||||
|
'andalé mono',
|
||||||
|
'anonymous pro',
|
||||||
|
'bitstream vera sans mono',
|
||||||
|
'cascadia code',
|
||||||
|
'century schoolbook monospace',
|
||||||
|
'comic mono',
|
||||||
|
'computer modern mono/typewriter',
|
||||||
|
'consolas',
|
||||||
|
'courier',
|
||||||
|
'courier final draft',
|
||||||
|
'courier new',
|
||||||
|
'courier prime',
|
||||||
|
'courier screenplay',
|
||||||
|
'cousine',
|
||||||
|
'dejavu sans mono',
|
||||||
|
'droid sans mono',
|
||||||
|
'envy code r',
|
||||||
|
'everson mono',
|
||||||
|
'fantasque sans mono',
|
||||||
|
'fira code',
|
||||||
|
'fira mono',
|
||||||
|
'fixed',
|
||||||
|
'fixedsys',
|
||||||
|
'freemono',
|
||||||
|
'go mono',
|
||||||
|
'hack',
|
||||||
|
'hyperfont',
|
||||||
|
'ibm courier',
|
||||||
|
'ibm plex mono',
|
||||||
|
'inconsolata',
|
||||||
|
'input',
|
||||||
|
'iosevka',
|
||||||
|
'jetbrains mono',
|
||||||
|
'juliamono',
|
||||||
|
'letter gothic',
|
||||||
|
'liberation mono',
|
||||||
|
'lucida console',
|
||||||
|
'menlo',
|
||||||
|
'monaco',
|
||||||
|
'monofur',
|
||||||
|
'monospace (unicode)',
|
||||||
|
'nimbus mono l',
|
||||||
|
'nk57 monospace',
|
||||||
|
'noto mono',
|
||||||
|
'ocr-a',
|
||||||
|
'ocr-b',
|
||||||
|
'operator mono',
|
||||||
|
'overpass mono',
|
||||||
|
'oxygen mono',
|
||||||
|
'pragmatapro',
|
||||||
|
'profont',
|
||||||
|
'pt mono',
|
||||||
|
'recursive mono',
|
||||||
|
'roboto mono',
|
||||||
|
'sf mono',
|
||||||
|
'source code pro',
|
||||||
|
'spleen',
|
||||||
|
'terminal',
|
||||||
|
'terminus',
|
||||||
|
'tex gyre cursor',
|
||||||
|
'ubuntu mono',
|
||||||
|
'victor mono',
|
||||||
|
'wumpus mono',
|
||||||
|
];
|
||||||
|
|
||||||
|
const monospaceKeywords = [
|
||||||
|
'mono',
|
||||||
|
'code',
|
||||||
|
'courier',
|
||||||
|
'console',
|
||||||
|
'source code',
|
||||||
|
'terminal',
|
||||||
|
'fixed',
|
||||||
|
];
|
@ -12,3 +12,35 @@
|
|||||||
.config-screen-content > .section:last-child {
|
.config-screen-content > .section:last-child {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-search-list {
|
||||||
|
background-color: var(--joplin-background-color);
|
||||||
|
max-height: 200px;
|
||||||
|
width: 50%;
|
||||||
|
min-width: 20em;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid var(--joplin-border-color4);
|
||||||
|
border-radius: 5px;
|
||||||
|
display: none;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-search-list > div {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-search-item {
|
||||||
|
border-bottom: 1px solid var(--joplin-border-color4);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-search-item:hover {
|
||||||
|
color: var(--joplin-background-color);
|
||||||
|
background-color: var(--joplin-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monospace-checkbox {
|
||||||
|
background-color: var(--joplin-background-color3);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
@ -36,6 +36,8 @@ export enum SettingItemSubType {
|
|||||||
FilePathAndArgs = 'file_path_and_args',
|
FilePathAndArgs = 'file_path_and_args',
|
||||||
FilePath = 'file_path', // Not supported on mobile!
|
FilePath = 'file_path', // Not supported on mobile!
|
||||||
DirectoryPath = 'directory_path', // Not supported on mobile!
|
DirectoryPath = 'directory_path', // Not supported on mobile!
|
||||||
|
FontFamily = 'font_family',
|
||||||
|
MonospaceFontFamily = 'monospace_font_family',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeysOptions {
|
interface KeysOptions {
|
||||||
@ -1360,6 +1362,7 @@ class Setting extends BaseModel {
|
|||||||
_('Used for most text in the markdown editor. If not found, a generic proportional (variable width) font is used.'),
|
_('Used for most text in the markdown editor. If not found, a generic proportional (variable width) font is used.'),
|
||||||
storage: SettingStorage.File,
|
storage: SettingStorage.File,
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
|
subType: SettingItemSubType.FontFamily,
|
||||||
},
|
},
|
||||||
'style.editor.monospaceFontFamily': {
|
'style.editor.monospaceFontFamily': {
|
||||||
value: '',
|
value: '',
|
||||||
@ -1372,6 +1375,7 @@ class Setting extends BaseModel {
|
|||||||
_('Used where a fixed width font is needed to lay out text legibly (e.g. tables, checkboxes, code). If not found, a generic monospace (fixed width) font is used.'),
|
_('Used where a fixed width font is needed to lay out text legibly (e.g. tables, checkboxes, code). If not found, a generic monospace (fixed width) font is used.'),
|
||||||
storage: SettingStorage.File,
|
storage: SettingStorage.File,
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
|
subType: SettingItemSubType.MonospaceFontFamily,
|
||||||
},
|
},
|
||||||
|
|
||||||
'style.editor.contentMaxWidth': { value: 0, type: SettingItemType.Int, public: true, storage: SettingStorage.File, isGlobal: true, appTypes: [AppType.Desktop], section: 'appearance', label: () => _('Editor maximum width'), description: () => _('Set it to 0 to make it take the complete available space. Recommended width is 600.') },
|
'style.editor.contentMaxWidth': { value: 0, type: SettingItemType.Int, public: true, storage: SettingStorage.File, isGlobal: true, appTypes: [AppType.Desktop], section: 'appearance', label: () => _('Editor maximum width'), description: () => _('Set it to 0 to make it take the complete available space. Recommended width is 600.') },
|
||||||
|
Loading…
Reference in New Issue
Block a user