mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #26735 from overleaf/mj-system-theme
[web] Add new system theme to the editor GitOrigin-RevId: b65083c5e96abc493556e901c861689cb7e3bbf7
This commit is contained in:
committed by
Copybot
parent
72aca352fc
commit
39b4581e1d
@@ -201,6 +201,9 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
||||
if (res.locals.isIEEE(brandVariation?.brand_id)) {
|
||||
return enableIeeeBranding ? 'ieee-' : ''
|
||||
} else if (userSettings && userSettings.overallTheme != null) {
|
||||
if (!['', 'light-'].includes(userSettings.overallTheme)) {
|
||||
return ''
|
||||
}
|
||||
return userSettings.overallTheme
|
||||
}
|
||||
}
|
||||
@@ -350,6 +353,11 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
||||
val: 'light-',
|
||||
path: res.locals.buildCssPath('light-'),
|
||||
},
|
||||
{
|
||||
name: 'System',
|
||||
val: 'system',
|
||||
path: res.locals.buildCssPath(),
|
||||
},
|
||||
]
|
||||
}
|
||||
next()
|
||||
|
||||
@@ -4,7 +4,7 @@ import { saveUserSettings } from '../utils/api'
|
||||
import { UserSettings } from '../../../../../types/user-settings'
|
||||
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { isIEEEBranded } from '@/utils/is-ieee-branded'
|
||||
import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
|
||||
|
||||
export default function useSetOverallTheme() {
|
||||
const { userSettings, setUserSettings } = useUserSettingsContext()
|
||||
@@ -16,13 +16,13 @@ export default function useSetOverallTheme() {
|
||||
},
|
||||
[setUserSettings]
|
||||
)
|
||||
const activeOverallTheme = useActiveOverallTheme()
|
||||
|
||||
useEffect(() => {
|
||||
// Sets the body's data-theme attribute for theming
|
||||
const theme =
|
||||
overallTheme === 'light-' && !isIEEEBranded() ? 'light' : 'default'
|
||||
document.body.dataset.theme = theme
|
||||
}, [overallTheme])
|
||||
document.body.dataset.theme =
|
||||
activeOverallTheme === 'dark' ? 'default' : 'light'
|
||||
}, [activeOverallTheme])
|
||||
|
||||
return useCallback(
|
||||
(newOverallTheme: UserSettings['overallTheme']) => {
|
||||
|
||||
@@ -69,7 +69,7 @@ export const VisualPreview: FC<{ view: EditorView }> = ({ view }) => {
|
||||
fontSize: 14,
|
||||
fontFamily: 'monaco',
|
||||
lineHeight: 'normal',
|
||||
overallTheme: 'light-',
|
||||
activeOverallTheme: 'light',
|
||||
}),
|
||||
EditorView.theme({
|
||||
'&.cm-editor': {
|
||||
|
||||
@@ -3,12 +3,8 @@ import { Annotation, Compartment, TransactionSpec } from '@codemirror/state'
|
||||
import { syntaxHighlighting } from '@codemirror/language'
|
||||
import { classHighlighter } from './class-highlighter'
|
||||
import classNames from 'classnames'
|
||||
import {
|
||||
FontFamily,
|
||||
LineHeight,
|
||||
OverallTheme,
|
||||
userStyles,
|
||||
} from '@/shared/utils/styles'
|
||||
import { FontFamily, LineHeight, userStyles } from '@/shared/utils/styles'
|
||||
import { ActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
|
||||
|
||||
const optionsThemeConf = new Compartment()
|
||||
const selectedThemeConf = new Compartment()
|
||||
@@ -18,7 +14,7 @@ type Options = {
|
||||
fontSize: number
|
||||
fontFamily: FontFamily
|
||||
lineHeight: LineHeight
|
||||
overallTheme: OverallTheme
|
||||
activeOverallTheme: ActiveOverallTheme
|
||||
}
|
||||
|
||||
export const theme = (options: Options) => [
|
||||
@@ -58,7 +54,7 @@ const createThemeFromOptions = ({
|
||||
fontSize = 12,
|
||||
fontFamily = 'monaco',
|
||||
lineHeight = 'normal',
|
||||
overallTheme = '',
|
||||
activeOverallTheme = 'dark',
|
||||
}: Options) => {
|
||||
// Theme styles that depend on settings.
|
||||
const styles = userStyles({ fontSize, fontFamily, lineHeight })
|
||||
@@ -66,7 +62,9 @@ const createThemeFromOptions = ({
|
||||
return [
|
||||
EditorView.editorAttributes.of({
|
||||
class: classNames(
|
||||
overallTheme === '' ? 'overall-theme-dark' : 'overall-theme-light'
|
||||
activeOverallTheme === 'dark'
|
||||
? 'overall-theme-dark'
|
||||
: 'overall-theme-light'
|
||||
),
|
||||
style: Object.entries({
|
||||
'--font-size': styles.fontSize,
|
||||
|
||||
@@ -59,6 +59,7 @@ import { usePermissionsContext } from '@/features/ide-react/context/permissions-
|
||||
import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
|
||||
import { SearchQuery } from '@codemirror/search'
|
||||
import { beforeChangeDocEffect } from '@/features/source-editor/extensions/before-change-doc'
|
||||
import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
|
||||
|
||||
function useCodeMirrorScope(view: EditorView) {
|
||||
const { fileTreeData } = useFileTreeData()
|
||||
@@ -79,7 +80,6 @@ function useCodeMirrorScope(view: EditorView) {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
overallTheme,
|
||||
autoComplete,
|
||||
editorTheme,
|
||||
autoPairDelimiters,
|
||||
@@ -89,6 +89,7 @@ function useCodeMirrorScope(view: EditorView) {
|
||||
referencesSearchMode,
|
||||
enableNewEditor,
|
||||
} = userSettings
|
||||
const activeOverallTheme = useActiveOverallTheme()
|
||||
|
||||
const { onlineUserCursorHighlights } = useOnlineUsersContext()
|
||||
|
||||
@@ -119,7 +120,7 @@ function useCodeMirrorScope(view: EditorView) {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
overallTheme,
|
||||
activeOverallTheme,
|
||||
editorTheme,
|
||||
})
|
||||
|
||||
@@ -128,7 +129,7 @@ function useCodeMirrorScope(view: EditorView) {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
overallTheme,
|
||||
activeOverallTheme,
|
||||
editorTheme,
|
||||
}
|
||||
|
||||
@@ -137,14 +138,14 @@ function useCodeMirrorScope(view: EditorView) {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
overallTheme,
|
||||
activeOverallTheme,
|
||||
})
|
||||
)
|
||||
|
||||
setEditorTheme(editorTheme).then(spec => {
|
||||
view.dispatch(spec)
|
||||
})
|
||||
}, [view, fontFamily, fontSize, lineHeight, overallTheme, editorTheme])
|
||||
}, [view, fontFamily, fontSize, lineHeight, activeOverallTheme, editorTheme])
|
||||
|
||||
const settingsRef = useRef({
|
||||
autoComplete,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
import { OverallTheme } from '@/shared/utils/styles'
|
||||
import { isIEEEBranded } from '@/utils/is-ieee-branded'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
export type ActiveOverallTheme = 'dark' | 'light'
|
||||
|
||||
const mediaWatcher = window.matchMedia?.('(prefers-color-scheme: dark)') ?? {
|
||||
// If matchMedia is not supported, use the default (dark) theme
|
||||
matches: true,
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {},
|
||||
}
|
||||
|
||||
function getTheme(
|
||||
overallTheme: OverallTheme,
|
||||
prefersDark: boolean
|
||||
): ActiveOverallTheme {
|
||||
if (isIEEEBranded()) {
|
||||
return 'dark'
|
||||
}
|
||||
if (overallTheme === 'light-') {
|
||||
return 'light'
|
||||
}
|
||||
if (overallTheme === 'system') {
|
||||
return prefersDark ? 'dark' : 'light'
|
||||
}
|
||||
return 'dark'
|
||||
}
|
||||
|
||||
export const useActiveOverallTheme = (): ActiveOverallTheme => {
|
||||
const [browserPrefersDarkMode, setBrowserPrefersDarkMode] = useState(
|
||||
mediaWatcher.matches
|
||||
)
|
||||
const {
|
||||
userSettings: { overallTheme },
|
||||
} = useUserSettingsContext()
|
||||
|
||||
const activeOverallTheme = useMemo<ActiveOverallTheme>(() => {
|
||||
return getTheme(overallTheme, browserPrefersDarkMode)
|
||||
}, [overallTheme, browserPrefersDarkMode])
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (e: MediaQueryListEvent) => {
|
||||
setBrowserPrefersDarkMode(e.matches)
|
||||
}
|
||||
mediaWatcher.addEventListener('change', listener)
|
||||
return () => {
|
||||
mediaWatcher.removeEventListener('change', listener)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return activeOverallTheme
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export type OverallTheme = '' | 'light-'
|
||||
export type OverallTheme = '' | 'light-' | 'system'
|
||||
|
||||
export const fontFamilies = {
|
||||
monaco: ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'monospace'],
|
||||
|
||||
@@ -37,6 +37,7 @@ import { FullProjectSearchResults } from './full-project-search-results'
|
||||
import { signalWithTimeout } from '@/utils/abort-signal'
|
||||
import { useIsNewEditorEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
import RailPanelHeader from '@/features/ide-redesign/components/rail-panel-header'
|
||||
import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
|
||||
|
||||
const FullProjectSearchUI: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -57,6 +58,7 @@ const FullProjectSearchUI: FC = () => {
|
||||
() => userStyles(userSettings),
|
||||
[userSettings]
|
||||
)
|
||||
const activeOverallTheme = useActiveOverallTheme()
|
||||
|
||||
const abortControllerRef = useRef<AbortController | null>(null)
|
||||
|
||||
@@ -183,7 +185,7 @@ const FullProjectSearchUI: FC = () => {
|
||||
<div
|
||||
className="full-project-search"
|
||||
style={variableStyle}
|
||||
data-bs-theme={userSettings.overallTheme === 'light-' ? 'light' : 'dark'}
|
||||
data-bs-theme={activeOverallTheme === 'light' ? 'light' : 'dark'}
|
||||
>
|
||||
{newEditor ? (
|
||||
<RailPanelHeader title={t('search')} />
|
||||
|
||||
Reference in New Issue
Block a user