Merge pull request #27099 from overleaf/mj-no-duplicate-themes

[web] Avoid creating duplicate CM6 themes

GitOrigin-RevId: f6132d6cdd94ef353e047ce229d89147acc89603
This commit is contained in:
Mathias Jakobsen
2025-08-04 09:28:52 +01:00
committed by Copybot
parent 86e3fd468e
commit 0c76afff76
5 changed files with 40 additions and 14 deletions

View File

@@ -321,6 +321,7 @@ module.exports = {
'react/no-did-update-set-state': 'error',
'react/no-unused-prop-types': 'error',
'react/prop-types': 'error',
'@overleaf/no-generated-editor-themes': 'error',
// "react/react-in-jsx-scope": "error",
// END: inline standard-react rules

View File

@@ -1,6 +1,7 @@
import { EditorView } from '@codemirror/view'
import { Compartment, TransactionSpec } from '@codemirror/state'
import { FontFamily, LineHeight, userStyles } from '@/shared/utils/styles'
import { ThemeCache } from '@/features/source-editor/utils/theme-cache'
export type Options = {
fontSize: number
@@ -15,6 +16,8 @@ export const theme = (options: Options) => [
optionsThemeConf.of(createThemeFromOptions(options)),
]
const tooltipThemeCache = new ThemeCache()
const createThemeFromOptions = ({
fontSize = 12,
fontFamily = 'monaco',
@@ -33,9 +36,7 @@ const createThemeFromOptions = ({
.map(([key, value]) => `${key}: ${value}`)
.join(';'),
}),
// Set variables for tooltips, which are outside the editor
// TODO: set these on document.body, or a new container element for the tooltips, without using a style mod
EditorView.theme({
tooltipThemeCache.get({
'.cm-tooltip': {
'--font-size': styles.fontSize,
'--source-font-family': styles.fontFamily,

View File

@@ -31,6 +31,15 @@ import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-ope
import { isValidTeXFile } from '@/main/is-valid-tex-file'
import { mousedown } from '@/features/source-editor/extensions/visual/selection'
const visualPreviewTheme = EditorView.theme({
'&.cm-editor': {
background: '#fff',
},
'.ol-cm-preamble-wrapper, .ol-cm-end-document-widget': {
visibility: 'hidden',
},
})
export const VisualPreview: FC<{ view: EditorView }> = ({ view }) => {
const [previewState, setPreviewState] = useState<EditorState>()
@@ -71,14 +80,7 @@ export const VisualPreview: FC<{ view: EditorView }> = ({ view }) => {
lineHeight: 'normal',
activeOverallTheme: 'light',
}),
EditorView.theme({
'&.cm-editor': {
background: '#fff',
},
'.ol-cm-preamble-wrapper, .ol-cm-end-document-widget': {
visibility: 'hidden',
},
}),
visualPreviewTheme,
visualTheme,
visualHighlightStyle,
tableGeneratorTheme,

View File

@@ -5,6 +5,7 @@ import { classHighlighter } from './class-highlighter'
import classNames from 'classnames'
import { FontFamily, LineHeight, userStyles } from '@/shared/utils/styles'
import { ActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
import { ThemeCache } from '../utils/theme-cache'
const optionsThemeConf = new Compartment()
const selectedThemeConf = new Compartment()
@@ -50,6 +51,8 @@ const svgUrl = (content: string) =>
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">${content}</svg>`
)}')`
const tooltipThemeCache = new ThemeCache()
const createThemeFromOptions = ({
fontSize = 12,
fontFamily = 'monaco',
@@ -74,9 +77,7 @@ const createThemeFromOptions = ({
.map(([key, value]) => `${key}: ${value}`)
.join(';'),
}),
// set variables for tooltips, which are outside the editor
// TODO: set these on document.body, or a new container element for the tooltips, without using a style mod
EditorView.theme({
tooltipThemeCache.get({
'.cm-tooltip': {
'--font-size': styles.fontSize,
'--source-font-family': styles.fontFamily,
@@ -280,8 +281,11 @@ const loadSelectedTheme = async (editorTheme: string) => {
/* webpackChunkName: "cm6-theme" */ `../themes/cm6/${editorTheme}.json`
)
// We store these in a cache, so we'll reuse after the first load
const extension = [
// eslint-disable-next-line @overleaf/no-generated-editor-themes
EditorView.theme(theme, { dark }),
// eslint-disable-next-line @overleaf/no-generated-editor-themes
EditorView.theme(highlightStyle, { dark }),
]

View File

@@ -0,0 +1,18 @@
import { Extension } from '@codemirror/state'
import { EditorView } from '@codemirror/view'
export class ThemeCache {
private cache: Map<string, Extension> = new Map()
public get: typeof EditorView.theme = (styleMod, options) => {
const key = JSON.stringify({ styleMod, options })
const existing = this.cache.get(key)
if (existing) {
return existing
}
// eslint-disable-next-line @overleaf/no-generated-editor-themes
const theme = EditorView.theme(styleMod, options)
this.cache.set(key, theme)
return theme
}
}