diff --git a/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx b/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx index c2e04dc15b..aa19d15350 100644 --- a/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx +++ b/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx @@ -8,7 +8,14 @@ import { import { EditorView, lineNumbers } from '@codemirror/view' import { indentationMarkers } from '@replit/codemirror-indentation-markers' import { highlights, setHighlightsEffect } from '../../extensions/highlights' -import { theme } from '../../extensions/theme' +import useScopeValue from '../../../../shared/hooks/use-scope-value' +import { + theme, + Options, + setOptionsTheme, + FontFamily, + LineHeight, +} from '../../extensions/theme' import { indentUnit } from '@codemirror/language' import { Highlight } from '../../services/types/doc' import useIsMounted from '../../../../shared/hooks/use-is-mounted' @@ -21,7 +28,7 @@ import Icon from '../../../../shared/components/icon' import { useTranslation } from 'react-i18next' import { inlineBackground } from '../../../source-editor/extensions/inline-background' -function extensions(): Extension[] { +function extensions(themeOptions: Options): Extension[] { return [ EditorView.editable.of(false), EditorView.contentAttributes.of({ tabindex: '0' }), @@ -31,7 +38,7 @@ function extensions(): Extension[] { indentationMarkers({ hideFirstIndent: true, highlightActiveBlock: false }), highlights(), highlightLocations(), - theme(), + theme(themeOptions), inlineBackground(false), ] } @@ -43,13 +50,20 @@ function DocumentDiffViewer({ doc: string highlights: Highlight[] }) { + const [fontFamily] = useScopeValue('settings.fontFamily') + const [fontSize] = useScopeValue('settings.fontSize') + const [lineHeight] = useScopeValue('settings.lineHeight') const isMounted = useIsMounted() const { t } = useTranslation() const [state, setState] = useState(() => { return EditorState.create({ doc, - extensions: extensions(), + extensions: extensions({ + fontSize, + fontFamily, + lineHeight, + }), }) }) @@ -107,6 +121,18 @@ function DocumentDiffViewer({ }) }, [doc, highlights, view]) + // Update the document diff viewer theme whenever the font size, font family + // or line height user setting changes + useEffect(() => { + view.dispatch( + setOptionsTheme({ + fontSize, + fontFamily, + lineHeight, + }) + ) + }, [view, fontSize, fontFamily, lineHeight]) + return (
diff --git a/services/web/frontend/js/features/history/extensions/theme.ts b/services/web/frontend/js/features/history/extensions/theme.ts index 1677f43f00..706fdd1609 100644 --- a/services/web/frontend/js/features/history/extensions/theme.ts +++ b/services/web/frontend/js/features/history/extensions/theme.ts @@ -1,32 +1,72 @@ import { EditorView } from '@codemirror/view' +import { Compartment, TransactionSpec } from '@codemirror/state' -const fontFamily = 'Monaco, Menlo, Ubuntu Mono, Consolas, monospace' +export type FontFamily = 'monaco' | 'lucida' +export type LineHeight = 'compact' | 'normal' | 'wide' -export const theme = () => - EditorView.theme({ - '&.cm-editor': { - '--font-size': '12px', - '--source-font-family': fontFamily, - '--line-height': 1.6, - }, - '.cm-content': { - fontSize: 'var(--font-size)', - fontFamily: 'var(--source-font-family)', - lineHeight: 'var(--line-height)', - color: '#000', - }, - '.cm-gutters': { - fontSize: 'var(--font-size)', - lineHeight: 'var(--line-height)', - }, - '.cm-tooltip': { - // Set variables for tooltips, which are outside the editor - '--font-size': '12px', - '--source-font-family': fontFamily, - // NOTE: fontFamily is not set here, as most tooltips use the UI font - fontSize: 'var(--font-size)', - }, - '.cm-lineNumbers': { - fontFamily: 'var(--source-font-family)', - }, - }) +export type Options = { + fontSize: number + fontFamily: FontFamily + lineHeight: LineHeight +} + +const optionsThemeConf = new Compartment() + +export const theme = (options: Options) => [ + optionsThemeConf.of(createThemeFromOptions(options)), +] + +export const lineHeights: Record = { + compact: 1.33, + normal: 1.6, + wide: 2, +} + +const fontFamilies: Record = { + monaco: ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'monospace'], + lucida: ['Lucida Console', 'Source Code Pro', 'monospace'], +} + +const createThemeFromOptions = ({ + fontSize = 12, + fontFamily = 'monaco', + lineHeight = 'normal', +}: Options) => { + // Theme styles that depend on settings + const fontFamilyValue = fontFamilies[fontFamily]?.join(', ') + return [ + EditorView.theme({ + '&.cm-editor': { + '--font-size': `${fontSize}px`, + '--source-font-family': fontFamilyValue, + '--line-height': lineHeights[lineHeight], + }, + '.cm-content': { + fontSize: 'var(--font-size)', + fontFamily: 'var(--source-font-family)', + lineHeight: 'var(--line-height)', + color: '#000', + }, + '.cm-gutters': { + fontSize: 'var(--font-size)', + lineHeight: 'var(--line-height)', + }, + '.cm-tooltip': { + // Set variables for tooltips, which are outside the editor + '--font-size': `${fontSize}px`, + '--source-font-family': fontFamilyValue, + // NOTE: fontFamily is not set here, as most tooltips use the UI font + fontSize: 'var(--font-size)', + }, + '.cm-lineNumbers': { + fontFamily: 'var(--source-font-family)', + }, + }), + ] +} + +export const setOptionsTheme = (options: Options): TransactionSpec => { + return { + effects: optionsThemeConf.reconfigure(createThemeFromOptions(options)), + } +}