first commit

This commit is contained in:
2025-04-24 13:11:28 +08:00
commit ff9c54d5e4
5960 changed files with 834111 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
import { useCallback, useEffect } from 'react'
import { useIdeContext } from '../../../shared/context/ide-context'
import useScopeValue from '../../../shared/hooks/use-scope-value'
import type { ProjectSettings } from '../utils/api'
export default function useProjectWideSettingsSocketListener() {
const { socket } = useIdeContext()
const [project, setProject] = useScopeValue<ProjectSettings | undefined>(
'project'
)
const setCompiler = useCallback(
(compiler: ProjectSettings['compiler']) => {
if (project) {
setProject({ ...project, compiler })
}
},
[project, setProject]
)
const setImageName = useCallback(
(imageName: ProjectSettings['imageName']) => {
if (project) {
setProject({ ...project, imageName })
}
},
[project, setProject]
)
const setSpellCheckLanguage = useCallback(
(spellCheckLanguage: ProjectSettings['spellCheckLanguage']) => {
if (project) {
setProject({ ...project, spellCheckLanguage })
}
},
[project, setProject]
)
useEffect(() => {
// data is not available on initial mounting
const dataAvailable = !!project
if (dataAvailable && socket) {
socket.on('compilerUpdated', setCompiler)
socket.on('imageNameUpdated', setImageName)
socket.on('spellCheckLanguageUpdated', setSpellCheckLanguage)
return () => {
socket.removeListener('compilerUpdated', setCompiler)
socket.removeListener('imageNameUpdated', setImageName)
socket.removeListener(
'spellCheckLanguageUpdated',
setSpellCheckLanguage
)
}
}
}, [socket, project, setCompiler, setImageName, setSpellCheckLanguage])
}

View File

@@ -0,0 +1,41 @@
import { useCallback } from 'react'
import useScopeValue from '../../../shared/hooks/use-scope-value'
import type { ProjectSettings } from '../utils/api'
import useRootDocId from './use-root-doc-id'
import useSaveProjectSettings from './use-save-project-settings'
import useSetSpellCheckLanguage from './use-set-spell-check-language'
import { debugConsole } from '@/utils/debugging'
export default function useProjectWideSettings() {
// The value will be undefined on mount
const [project] = useScopeValue<ProjectSettings | undefined>('project')
const saveProjectSettings = useSaveProjectSettings()
const setCompiler = useCallback(
(newCompiler: ProjectSettings['compiler']) => {
saveProjectSettings('compiler', newCompiler).catch(debugConsole.error)
},
[saveProjectSettings]
)
const setImageName = useCallback(
(newImageName: ProjectSettings['imageName']) => {
saveProjectSettings('imageName', newImageName).catch(debugConsole.error)
},
[saveProjectSettings]
)
const { setRootDocId, rootDocId } = useRootDocId()
const setSpellCheckLanguage = useSetSpellCheckLanguage()
return {
compiler: project?.compiler,
setCompiler,
imageName: project?.imageName,
setImageName,
rootDocId,
setRootDocId,
spellCheckLanguage: project?.spellCheckLanguage,
setSpellCheckLanguage,
}
}

View File

@@ -0,0 +1,34 @@
import { useCallback } from 'react'
import { useEditorContext } from '../../../shared/context/editor-context'
import useScopeValue from '../../../shared/hooks/use-scope-value'
import type { ProjectSettings } from '../utils/api'
import useSaveProjectSettings from './use-save-project-settings'
export default function useRootDocId() {
const [rootDocId] =
useScopeValue<ProjectSettings['rootDocId']>('project.rootDoc_id')
const { permissionsLevel } = useEditorContext()
const saveProjectSettings = useSaveProjectSettings()
const setRootDocIdFunc = useCallback(
async (newRootDocId: ProjectSettings['rootDocId']) => {
// rootDocId will be undefined on angular scope on initialisation
const allowUpdate =
typeof rootDocId !== 'undefined' && permissionsLevel !== 'readOnly'
if (allowUpdate) {
try {
await saveProjectSettings('rootDocId', newRootDocId)
} catch (err) {
// TODO: retry mechanism (max 10x before failed completely and rollback the old value)
}
}
},
[permissionsLevel, rootDocId, saveProjectSettings]
)
return {
rootDocId,
setRootDocId: setRootDocIdFunc,
}
}

View File

@@ -0,0 +1,32 @@
import { type ProjectSettings, saveProjectSettings } from '../utils/api'
import { useProjectContext } from '../../../shared/context/project-context'
import useScopeValue from '../../../shared/hooks/use-scope-value'
export default function useSaveProjectSettings() {
// projectSettings value will be undefined on mount
const [projectSettings, setProjectSettings] = useScopeValue<
ProjectSettings | undefined
>('project')
const { _id: projectId } = useProjectContext()
return async (
key: keyof ProjectSettings,
newSetting: ProjectSettings[keyof ProjectSettings]
) => {
if (projectSettings) {
const currentSetting = projectSettings[key]
if (currentSetting !== newSetting) {
await saveProjectSettings(projectId, {
[key]: newSetting,
})
// rootDocId is used in our tsx and our endpoint, but rootDoc_id is used in our project $scope, etc
// as we use both namings in many files, and convert back and forth,
// its complicated to seperate and choose one name for all usages
// todo: make rootDocId or rootDoc_id consistent, and remove need for this/ other conversions
const settingsKey = key === 'rootDocId' ? 'rootDoc_id' : key
setProjectSettings({ ...projectSettings, [settingsKey]: newSetting })
}
}
}
}

View File

@@ -0,0 +1,19 @@
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
import { saveUserSettings } from '../utils/api'
import { UserSettings } from '../../../../../types/user-settings'
export default function useSaveUserSettings() {
const { userSettings, setUserSettings } = useUserSettingsContext()
return (
key: keyof UserSettings,
newSetting: UserSettings[keyof UserSettings]
) => {
const currentSetting = userSettings[key]
if (currentSetting !== newSetting) {
setUserSettings({ ...userSettings, [key]: newSetting })
saveUserSettings(key, newSetting)
}
}
}

View File

@@ -0,0 +1,43 @@
import { useCallback, useEffect } from 'react'
import _ from 'lodash'
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'
export default function useSetOverallTheme() {
const { userSettings, setUserSettings } = useUserSettingsContext()
const { overallTheme } = userSettings
const setOverallTheme = useCallback(
(overallTheme: UserSettings['overallTheme']) => {
setUserSettings(settings => ({ ...settings, overallTheme }))
},
[setUserSettings]
)
useEffect(() => {
// Sets the body's data-theme attribute for theming
const theme =
overallTheme === 'light-' && !isIEEEBranded() ? 'light' : 'default'
document.body.dataset.theme = theme
}, [overallTheme])
return useCallback(
(newOverallTheme: UserSettings['overallTheme']) => {
if (overallTheme !== newOverallTheme) {
const chosenTheme = _.find(
getMeta('ol-overallThemes'),
theme => theme.val === newOverallTheme
)
if (chosenTheme) {
setOverallTheme(newOverallTheme)
saveUserSettings('overallTheme', newOverallTheme)
}
}
},
[overallTheme, setOverallTheme]
)
}

View File

@@ -0,0 +1,32 @@
import { useCallback } from 'react'
import useScopeValue from '../../../shared/hooks/use-scope-value'
import { type ProjectSettings, saveUserSettings } from '../utils/api'
import useSaveProjectSettings from './use-save-project-settings'
export default function useSetSpellCheckLanguage() {
const [spellCheckLanguage, setSpellCheckLanguage] = useScopeValue<
ProjectSettings['spellCheckLanguage']
>('project.spellCheckLanguage')
const saveProjectSettings = useSaveProjectSettings()
return useCallback(
(newSpellCheckLanguage: ProjectSettings['spellCheckLanguage']) => {
const allowUpdate =
spellCheckLanguage != null &&
newSpellCheckLanguage !== spellCheckLanguage
if (allowUpdate) {
setSpellCheckLanguage(newSpellCheckLanguage)
// Save project settings is created from hooks because it will save the value on
// both server-side and client-side (angular scope)
saveProjectSettings('spellCheckLanguage', newSpellCheckLanguage)
// For user settings, we only need to save it on server-side,
// so we import the function directly without hooks
saveUserSettings('spellCheckLanguage', newSpellCheckLanguage)
}
},
[setSpellCheckLanguage, spellCheckLanguage, saveProjectSettings]
)
}

View File

@@ -0,0 +1,120 @@
import { useCallback } from 'react'
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
import useSetOverallTheme from './use-set-overall-theme'
import useSaveUserSettings from './use-save-user-settings'
import { UserSettings } from '../../../../../types/user-settings'
export default function useUserWideSettings() {
const saveUserSettings = useSaveUserSettings()
const { userSettings } = useUserSettingsContext()
const {
overallTheme,
autoComplete,
autoPairDelimiters,
syntaxValidation,
editorTheme,
mode,
fontSize,
fontFamily,
lineHeight,
pdfViewer,
mathPreview,
} = userSettings
const setOverallTheme = useSetOverallTheme()
const setAutoComplete = useCallback(
(autoComplete: UserSettings['autoComplete']) => {
saveUserSettings('autoComplete', autoComplete)
},
[saveUserSettings]
)
const setAutoPairDelimiters = useCallback(
(autoPairDelimiters: UserSettings['autoPairDelimiters']) => {
saveUserSettings('autoPairDelimiters', autoPairDelimiters)
},
[saveUserSettings]
)
const setSyntaxValidation = useCallback(
(syntaxValidation: UserSettings['syntaxValidation']) => {
saveUserSettings('syntaxValidation', syntaxValidation)
},
[saveUserSettings]
)
const setEditorTheme = useCallback(
(editorTheme: UserSettings['editorTheme']) => {
saveUserSettings('editorTheme', editorTheme)
},
[saveUserSettings]
)
const setMode = useCallback(
(mode: UserSettings['mode']) => {
saveUserSettings('mode', mode)
},
[saveUserSettings]
)
const setFontSize = useCallback(
(fontSize: UserSettings['fontSize']) => {
saveUserSettings('fontSize', fontSize)
},
[saveUserSettings]
)
const setFontFamily = useCallback(
(fontFamily: UserSettings['fontFamily']) => {
saveUserSettings('fontFamily', fontFamily)
},
[saveUserSettings]
)
const setLineHeight = useCallback(
(lineHeight: UserSettings['lineHeight']) => {
saveUserSettings('lineHeight', lineHeight)
},
[saveUserSettings]
)
const setPdfViewer = useCallback(
(pdfViewer: UserSettings['pdfViewer']) => {
saveUserSettings('pdfViewer', pdfViewer)
},
[saveUserSettings]
)
const setMathPreview = useCallback(
(mathPreview: UserSettings['mathPreview']) => {
saveUserSettings('mathPreview', mathPreview)
},
[saveUserSettings]
)
return {
autoComplete,
setAutoComplete,
autoPairDelimiters,
setAutoPairDelimiters,
syntaxValidation,
setSyntaxValidation,
editorTheme,
setEditorTheme,
overallTheme,
setOverallTheme,
mode,
setMode,
fontSize,
setFontSize,
fontFamily,
setFontFamily,
lineHeight,
setLineHeight,
pdfViewer,
setPdfViewer,
mathPreview,
setMathPreview,
}
}