diff --git a/services/web/frontend/js/features/ide-react/context/editor-properties-context.tsx b/services/web/frontend/js/features/ide-react/context/editor-properties-context.tsx index e8fb82efa1..1d75a35d5c 100644 --- a/services/web/frontend/js/features/ide-react/context/editor-properties-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/editor-properties-context.tsx @@ -6,18 +6,21 @@ import { SetStateAction, useCallback, useContext, + useEffect, useState, } from 'react' import customLocalStorage from '@/infrastructure/local-storage' -import usePersistedState from '@/shared/hooks/use-persisted-state' import getMeta from '@/utils/meta' import { useUnstableStoreSync } from '@/shared/hooks/use-unstable-store-sync' import { sendMB } from '@/infrastructure/event-tracking' +import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context' +import { getVisualEditorStorageKey } from '@/features/source-editor/utils/visual-editor' // Context value type export type EditorPropertiesContextValue = { showVisual: boolean setShowVisual: Dispatch> + showVisualForFile: (filename: string) => boolean showSymbolPalette: boolean setShowSymbolPalette: Dispatch> toggleSymbolPalette: () => void @@ -35,31 +38,58 @@ export const EditorPropertiesContext = createContext< EditorPropertiesContextValue | undefined >(undefined) -function showVisualFallbackValue() { +function migrateTexVisualMode(): boolean { const projectId = getMeta('ol-project_id') const editorModeKey = `editor.mode.${projectId}` const editorModeVal = customLocalStorage.getItem(editorModeKey) if (editorModeVal) { - // clean up the old key customLocalStorage.removeItem(editorModeKey) + return editorModeVal === 'rich-text' } - return editorModeVal === 'rich-text' + return false +} + +export function showVisualForFile(filename: string): boolean { + const key = getVisualEditorStorageKey(filename) + const stored = customLocalStorage.getItem(key) + if (stored !== null) { + return stored === 'visual' + } + if (key === 'editor.lastUsedMode') { + return migrateTexVisualMode() + } + return false } export const EditorPropertiesProvider: FC = ({ children, }) => { - const [showVisual, setShowVisual] = usePersistedState( - `editor.lastUsedMode`, - showVisualFallbackValue(), - { - converter: { - toPersisted: showVisual => (showVisual ? 'visual' : 'code'), - fromPersisted: mode => mode === 'visual', - }, - } + const { openDocName } = useEditorOpenDocContext() + + const [showVisual, setShowVisualState] = useState(() => + openDocName != null ? showVisualForFile(openDocName) : false + ) + + useEffect(() => { + setShowVisualState( + openDocName != null ? showVisualForFile(openDocName) : false + ) + }, [openDocName]) + + const setShowVisual: Dispatch> = useCallback( + value => { + setShowVisualState(prev => { + const actual = typeof value === 'function' ? value(prev) : value + if (openDocName != null) { + const key = getVisualEditorStorageKey(openDocName) + customLocalStorage.setItem(key, actual ? 'visual' : 'code') + } + return actual + }) + }, + [openDocName] ) // Sync the showVisual state with the exposed store @@ -83,6 +113,7 @@ export const EditorPropertiesProvider: FC = ({ const value = { showVisual, setShowVisual, + showVisualForFile, showSymbolPalette, setShowSymbolPalette, toggleSymbolPalette, diff --git a/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx b/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx index 73da19e3b0..eb68b51835 100644 --- a/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx @@ -49,7 +49,7 @@ export const FileTreeOpenProvider: FC = ({ const { eventEmitter, projectJoined } = useIdeReactContext() const { openDocWithId, openInitialDoc } = useEditorManagerContext() const { currentDocumentId } = useEditorOpenDocContext() - const { showVisual } = useEditorPropertiesContext() + const { showVisualForFile } = useEditorPropertiesContext() const { setOpenFile } = useLayoutContext() const [openEntity, setOpenEntity] = useState< FileTreeDocumentFindResult | FileTreeFileRefFindResult | null @@ -93,7 +93,8 @@ export const FileTreeOpenProvider: FC = ({ setOpenEntity(selected) const editorMode = - isVisualEditorAvailable(selected.entity.name) && showVisual + isVisualEditorAvailable(selected.entity.name) && + showVisualForFile(selected.entity.name) ? 'visual' : 'code' @@ -127,7 +128,7 @@ export const FileTreeOpenProvider: FC = ({ window.dispatchEvent(new CustomEvent('file-view:file-opened')) } }, - [fileTreeReady, openDocWithId, projectOwner, setOpenFile, showVisual] + [fileTreeReady, openDocWithId, projectOwner, setOpenFile, showVisualForFile] ) const handleFileTreeDelete = useCallback( diff --git a/services/web/frontend/js/features/ide-react/context/react-context-root.tsx b/services/web/frontend/js/features/ide-react/context/react-context-root.tsx index 8a4b375f19..4d891cc36f 100644 --- a/services/web/frontend/js/features/ide-react/context/react-context-root.tsx +++ b/services/web/frontend/js/features/ide-react/context/react-context-root.tsx @@ -103,9 +103,9 @@ export const ReactContextRoot: FC< - + - + @@ -151,9 +151,9 @@ export const ReactContextRoot: FC< - + - + diff --git a/services/web/frontend/js/features/source-editor/utils/visual-editor.ts b/services/web/frontend/js/features/source-editor/utils/visual-editor.ts index 02c3e91a9d..17fdf4fde1 100644 --- a/services/web/frontend/js/features/source-editor/utils/visual-editor.ts +++ b/services/web/frontend/js/features/source-editor/utils/visual-editor.ts @@ -27,3 +27,13 @@ export function getVisualEditorComponent(filename: string) { } return null } + +export function getVisualEditorStorageKey(filename: string): string { + for (const provider of visualEditorProviders) { + if (provider.import.isVisualEditorAvailable(filename)) { + const id = provider.import.id + return id != null ? `editor.lastUsedMode.${id}` : 'editor.lastUsedMode' + } + } + return 'editor.lastUsedMode' +} diff --git a/services/web/frontend/stories/source-editor/source-editor.stories.tsx b/services/web/frontend/stories/source-editor/source-editor.stories.tsx index 3f475944e4..d0dc68fd6e 100644 --- a/services/web/frontend/stories/source-editor/source-editor.stories.tsx +++ b/services/web/frontend/stories/source-editor/source-editor.stories.tsx @@ -92,6 +92,7 @@ const VisualEditorPropertiesProvider: FC = ({ const value = { showVisual, setShowVisual, + showVisualForFile: () => showVisual, showSymbolPalette: true, setShowSymbolPalette: () => undefined, toggleSymbolPalette: () => undefined, diff --git a/services/web/test/frontend/helpers/editor-providers.tsx b/services/web/test/frontend/helpers/editor-providers.tsx index bfeb21dcb2..0330ca63c0 100644 --- a/services/web/test/frontend/helpers/editor-providers.tsx +++ b/services/web/test/frontend/helpers/editor-providers.tsx @@ -636,6 +636,7 @@ export function makeEditorPropertiesProvider( const value = { showVisual, setShowVisual, + showVisualForFile: () => showVisual, showSymbolPalette, setShowSymbolPalette, toggleSymbolPalette,