diff --git a/packages/models/src/Domain/Syncable/UserPrefs/EditorFontFamily.ts b/packages/models/src/Domain/Syncable/UserPrefs/EditorFontFamily.ts new file mode 100644 index 00000000000..dc778bcc75c --- /dev/null +++ b/packages/models/src/Domain/Syncable/UserPrefs/EditorFontFamily.ts @@ -0,0 +1,25 @@ +export enum EditorFontFamily { + SansSerif = 'SansSerif', + Monospace = 'Monospace', + Serif = 'Serif', + Lora = 'Lora', + Merriweather = 'Merriweather', + OpenSans = 'OpenSans', + RobotoMono = 'RobotoMono', + Dyslexic = 'Dyslexic', + Quicksand = 'Quicksand', + ComicSans = 'ComicSans', +} + +export const EditorFontFamilyValues: { [key in EditorFontFamily]: string } = { + SansSerif: 'var(--sn-stylekit-sans-serif-font)', + Monospace: 'var(--sn-stylekit-monospace-font)', + Serif: 'Georgia, Times New Roman, Times, serif', + Lora: 'Lora, Georgia, serif', + Merriweather: 'Merriweather, Georgia, serif', + OpenSans: 'Open Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif', + RobotoMono: 'Roboto Mono, var(--sn-stylekit-monospace-font)', + Dyslexic: 'Comic Neue, Comic Sans MS, sans-serif', + Quicksand: 'Quicksand, Open Sans, Segoe UI, sans-serif', + ComicSans: 'Comic Sans MS, Comic Sans, Comic Neue, cursive, sans-serif', +} diff --git a/packages/models/src/Domain/Syncable/UserPrefs/index.ts b/packages/models/src/Domain/Syncable/UserPrefs/index.ts index 859f7e4de00..2c58241aea9 100644 --- a/packages/models/src/Domain/Syncable/UserPrefs/index.ts +++ b/packages/models/src/Domain/Syncable/UserPrefs/index.ts @@ -7,3 +7,4 @@ export * from './EditorLineWidth' export * from './NewNoteTitleFormat' export * from './ComponentPreferences' export * from './PrefDefaults' +export * from './EditorFontFamily' diff --git a/packages/services/src/Domain/Preferences/LocalPrefKey.ts b/packages/services/src/Domain/Preferences/LocalPrefKey.ts index 51e89e02fa8..5496c814b30 100644 --- a/packages/services/src/Domain/Preferences/LocalPrefKey.ts +++ b/packages/services/src/Domain/Preferences/LocalPrefKey.ts @@ -1,4 +1,4 @@ -import { EditorFontSize, EditorLineHeight, EditorLineWidth } from '@standardnotes/models' +import { EditorFontSize, EditorLineHeight, EditorLineWidth, EditorFontFamily } from '@standardnotes/models' import { NativeFeatureIdentifier } from '@standardnotes/features' export enum LocalPrefKey { @@ -14,6 +14,7 @@ export enum LocalPrefKey { EditorLineHeight = 'editorLineHeight', EditorLineWidth = 'editorLineWidth', EditorFontSize = 'editorFontSize', + EditorFontFamily = 'editorFontFamily', } export type LocalPrefValue = { @@ -29,6 +30,7 @@ export type LocalPrefValue = { [LocalPrefKey.EditorLineHeight]: EditorLineHeight [LocalPrefKey.EditorLineWidth]: EditorLineWidth [LocalPrefKey.EditorFontSize]: EditorFontSize + [LocalPrefKey.EditorFontFamily]: EditorFontFamily } export const LocalPrefDefaults = { @@ -44,6 +46,7 @@ export const LocalPrefDefaults = { [LocalPrefKey.EditorLineHeight]: EditorLineHeight.Normal, [LocalPrefKey.EditorLineWidth]: EditorLineWidth.FullWidth, [LocalPrefKey.EditorFontSize]: EditorFontSize.Normal, + [LocalPrefKey.EditorFontFamily]: EditorFontFamily.SansSerif, } satisfies { [key in LocalPrefKey]: LocalPrefValue[key] } diff --git a/packages/web/src/index.html b/packages/web/src/index.html index bb112e0c9c2..2a5f1fbeeb2 100644 --- a/packages/web/src/index.html +++ b/packages/web/src/index.html @@ -22,6 +22,10 @@ Notes ยท Standard Notes + + + + diff --git a/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMenu.tsx b/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMenu.tsx index d92d2cd765f..4b81a65642e 100644 --- a/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMenu.tsx +++ b/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMenu.tsx @@ -13,6 +13,8 @@ import { SNNote, ContentType, LocalPrefKey, + LocalPrefDefaults, + EditorFontFamily, } from '@standardnotes/snjs' import { FunctionComponent, useCallback, useEffect, useState } from 'react' import { EditorMenuGroup } from '@/Components/NotesOptions/EditorMenuGroup' @@ -131,7 +133,18 @@ const ChangeEditorMenu: FunctionComponent = ({ setCurrentFeature(application.componentManager.editorForNote(note)) if (uiFeature.featureIdentifier === NativeFeatureIdentifier.TYPES.PlainEditor) { - reloadFont(application.preferences.getLocalValue(LocalPrefKey.EditorMonospaceEnabled)) + let fontFamily = application.preferences.getLocalValue( + LocalPrefKey.EditorFontFamily, + LocalPrefDefaults[LocalPrefKey.EditorFontFamily], + ) + const legacyMonospace = application.preferences.getLocalValue( + LocalPrefKey.EditorMonospaceEnabled, + LocalPrefDefaults[LocalPrefKey.EditorMonospaceEnabled], + ) + if (fontFamily === EditorFontFamily.SansSerif && legacyMonospace) { + fontFamily = EditorFontFamily.Monospace + } + reloadFont(fontFamily) } }, [application], diff --git a/packages/web/src/javascripts/Components/NoteView/FontFunctions.ts b/packages/web/src/javascripts/Components/NoteView/FontFunctions.ts index b50ec318526..31588a32ef5 100644 --- a/packages/web/src/javascripts/Components/NoteView/FontFunctions.ts +++ b/packages/web/src/javascripts/Components/NoteView/FontFunctions.ts @@ -1,10 +1,19 @@ -export const reloadFont = (monospaceFont?: boolean) => { +import { EditorFontFamily, EditorFontFamilyValues } from '@standardnotes/snjs' + +export const reloadFont = (fontFamily?: EditorFontFamily | boolean) => { const root = document.querySelector(':root') as HTMLElement const propertyName = '--sn-stylekit-editor-font-family' - if (monospaceFont) { - root.style.setProperty(propertyName, 'var(--sn-stylekit-monospace-font)') - } else { - root.style.setProperty(propertyName, 'var(--sn-stylekit-sans-serif-font)') + + let resolvedFont: EditorFontFamily = EditorFontFamily.SansSerif + if (typeof fontFamily === 'boolean') { + resolvedFont = fontFamily ? EditorFontFamily.Monospace : EditorFontFamily.SansSerif + } else if (fontFamily) { + resolvedFont = fontFamily } - document.documentElement.classList.toggle('monospace-font', monospaceFont) + + const value = EditorFontFamilyValues[resolvedFont] || EditorFontFamilyValues[EditorFontFamily.SansSerif] + root.style.setProperty(propertyName, value) + + const isMonospace = resolvedFont === EditorFontFamily.Monospace || resolvedFont === EditorFontFamily.RobotoMono + document.documentElement.classList.toggle('monospace-font', isMonospace) } diff --git a/packages/web/src/javascripts/Components/NoteView/NoteView.tsx b/packages/web/src/javascripts/Components/NoteView/NoteView.tsx index 98f953413e1..464300f8975 100644 --- a/packages/web/src/javascripts/Components/NoteView/NoteView.tsx +++ b/packages/web/src/javascripts/Components/NoteView/NoteView.tsx @@ -28,6 +28,8 @@ import { SNNote, VaultUserServiceEvent, LocalPrefKey, + LocalPrefDefaults, + EditorFontFamily, } from '@standardnotes/snjs' import { confirmDialog, DELETE_NOTE_KEYBOARD_COMMAND, KeyboardKey } from '@standardnotes/ui-services' import { ChangeEventHandler, createRef, FocusEvent, KeyboardEventHandler, RefObject } from 'react' @@ -75,7 +77,7 @@ type State = { spellcheck: boolean stackComponentViewers: ComponentViewerInterface[] syncTakingTooLong: boolean - monospaceFont?: boolean + fontFamily?: EditorFontFamily editorFocused?: boolean paneGestureEnabled?: boolean noteLastEditedByUuid?: string @@ -547,7 +549,7 @@ class NoteView extends AbstractComponent { editorStateDidLoad: true, }) } else { - reloadFont(this.state.monospaceFont) + reloadFont(this.state.fontFamily) this.setState({ editorStateDidLoad: true, }) @@ -654,7 +656,7 @@ class NoteView extends AbstractComponent { async reloadSpellcheck() { const spellcheck = this.application.notesController.getSpellcheckStateForNote(this.note) if (spellcheck !== this.state.spellcheck) { - reloadFont(this.state.monospaceFont) + reloadFont(this.state.fontFamily) this.setState({ spellcheck }) } } @@ -669,11 +671,20 @@ class NoteView extends AbstractComponent { async reloadPreferences() { log(LoggingDomain.NoteView, 'Reload preferences') - const monospaceFont = this.application.preferences.getLocalValue( + let fontFamily = this.application.preferences.getLocalValue( + LocalPrefKey.EditorFontFamily, + LocalPrefDefaults[LocalPrefKey.EditorFontFamily], + ) + + const legacyMonospace = this.application.preferences.getLocalValue( LocalPrefKey.EditorMonospaceEnabled, - PrefDefaults[LocalPrefKey.EditorMonospaceEnabled], + LocalPrefDefaults[LocalPrefKey.EditorMonospaceEnabled], ) + if (fontFamily === EditorFontFamily.SansSerif && legacyMonospace) { + fontFamily = EditorFontFamily.Monospace + } + const updateSavingIndicator = this.application.getPreference( PrefKey.UpdateSavingStatusIndicator, PrefDefaults[PrefKey.UpdateSavingStatusIndicator], @@ -689,12 +700,12 @@ class NoteView extends AbstractComponent { this.reloadLineWidth() this.setState({ - monospaceFont, + fontFamily, updateSavingIndicator, paneGestureEnabled, }) - reloadFont(monospaceFont) + reloadFont(fontFamily) } async reloadStackComponents() { diff --git a/packages/web/src/javascripts/Components/Preferences/Panes/Appearance/EditorAppearance.tsx b/packages/web/src/javascripts/Components/Preferences/Panes/Appearance/EditorAppearance.tsx index 956ff8460ba..72b3bf459be 100644 --- a/packages/web/src/javascripts/Components/Preferences/Panes/Appearance/EditorAppearance.tsx +++ b/packages/web/src/javascripts/Components/Preferences/Panes/Appearance/EditorAppearance.tsx @@ -2,8 +2,7 @@ import { WebApplication } from '@/Application/WebApplication' import Dropdown from '@/Components/Dropdown/Dropdown' import Icon from '@/Components/Icon/Icon' import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator' -import Switch from '@/Components/Switch/Switch' -import { EditorFontSize, EditorLineHeight, EditorLineWidth, LocalPrefKey } from '@standardnotes/snjs' +import { EditorFontSize, EditorLineHeight, EditorLineWidth, LocalPrefKey, EditorFontFamily } from '@standardnotes/snjs' import { useCallback, useMemo } from 'react' import { Subtitle, Title, Text } from '../../PreferencesComponents/Content' import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup' @@ -31,11 +30,27 @@ const EditorDefaults = ({ application }: Props) => { [], ) - const [monospaceFont, setMonospaceFont] = useLocalPreference(LocalPrefKey.EditorMonospaceEnabled) - const toggleMonospaceFont = () => { - setMonospaceFont(!monospaceFont) + const [fontFamily, setFontFamily] = useLocalPreference(LocalPrefKey.EditorFontFamily) + const handleFontFamilyChange = (value: string) => { + setFontFamily(value as EditorFontFamily) } + const fontFamilyDropdownOptions = useMemo( + () => [ + { label: 'Sans-serif (System default)', value: EditorFontFamily.SansSerif }, + { label: 'Monospace (System default)', value: EditorFontFamily.Monospace }, + { label: 'Serif (Georgia)', value: EditorFontFamily.Serif }, + { label: 'Lora (Serif)', value: EditorFontFamily.Lora }, + { label: 'Merriweather (Serif)', value: EditorFontFamily.Merriweather }, + { label: 'Open Sans (Modern sans-serif)', value: EditorFontFamily.OpenSans }, + { label: 'Roboto Mono (Modern monospace)', value: EditorFontFamily.RobotoMono }, + { label: 'Dyslexic-friendly (Comic Neue)', value: EditorFontFamily.Dyslexic }, + { label: 'Quicksand (Rounded sans-serif)', value: EditorFontFamily.Quicksand }, + { label: 'Comic Sans', value: EditorFontFamily.ComicSans }, + ], + [], + ) + const [fontSize, setFontSize] = useLocalPreference(LocalPrefKey.EditorFontSize) const handleFontSizeChange = (value: string) => { setFontSize(value as EditorFontSize) @@ -61,12 +76,17 @@ const EditorDefaults = ({ application }: Props) => { Editor
-
-
- Monospace Font - Toggles the font style in plaintext and Super notes +
+ Font family + Sets the font family in plaintext and Super notes +
+
-