Răsfoiți Sursa

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

[web] Avoid creating duplicate CM6 themes

GitOrigin-RevId: f6132d6cdd94ef353e047ce229d89147acc89603
Mathias Jakobsen 1 an în urmă
părinte
comite
d8f18f9667

+ 1 - 0
services/web/.eslintrc.js

@@ -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
 

+ 4 - 3
services/web/frontend/js/features/history/extensions/theme.ts

@@ -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,

+ 10 - 8
services/web/frontend/js/features/pdf-preview/components/visual-preview.tsx

@@ -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,

+ 7 - 3
services/web/frontend/js/features/source-editor/extensions/theme.ts

@@ -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 }),
     ]
 

+ 18 - 0
services/web/frontend/js/features/source-editor/utils/theme-cache.ts

@@ -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
+  }
+}