mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 06:03:45 +01:00
[web] Add a focus mode to the editor (#32245)
* Basic focus mode implementation * Exit button * Toggle between editor pdf mode * Keep the rail and file tree mounted for editor tabs to work properly * Hide Switch to editor button in focus mode * Show shortcuts in layout menu * Gate the feature behind a focus-mode feature flag * Add split test badges in the focus mode dropdown item and top bar * Add analytics tracking for focusMode changes * Cleanup leftover IdeView value * Allow passing focusMode value in layout test provider * Remove redundant listener for focus mode shortcut * Update focus mode and full project search listeners to use the event key * Post-rebase cleanup --------- Co-authored-by: Anna Fields <acfields11@gmail.com> GitOrigin-RevId: 207f8d136fa6662558c474cca4a867a9842191e7
This commit is contained in:
committed by
Copybot
co-authored by
Anna Fields
parent
757735b075
commit
c8a3bdd13f
@@ -24,6 +24,7 @@ import { useRailContext } from '@/features/ide-react/context/rail-context'
|
||||
import usePersistedState from '@/shared/hooks/use-persisted-state'
|
||||
import { repositionAllTooltips } from '@/features/source-editor/extensions/tooltips-reposition'
|
||||
import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
|
||||
import { useFeatureFlag } from './split-test-context'
|
||||
|
||||
export type IdeLayout = 'sideBySide' | 'flat'
|
||||
export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
|
||||
@@ -38,6 +39,7 @@ export type LayoutContextOwnStates = {
|
||||
pdfLayout: IdeLayout
|
||||
projectSearchIsOpen: boolean
|
||||
openFile: BinaryFile | null
|
||||
focusMode: boolean
|
||||
}
|
||||
|
||||
export type LayoutContextValue = LayoutContextOwnStates & {
|
||||
@@ -66,6 +68,7 @@ export type LayoutContextValue = LayoutContextOwnStates & {
|
||||
restoreView: () => void
|
||||
handleChangeLayout: (newLayout: IdeLayout, newView?: IdeView) => void
|
||||
handleDetach: () => void
|
||||
setFocusMode: Dispatch<SetStateAction<LayoutContextValue['focusMode']>>
|
||||
}
|
||||
|
||||
const debugPdfDetach = getMeta('ol-debugPdfDetach')
|
||||
@@ -154,6 +157,37 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
// whether the project search is open
|
||||
const [projectSearchIsOpen, setProjectSearchIsOpen] = useState(false)
|
||||
|
||||
// whether to display the editor and preview side-by-side or full-width ("flat")
|
||||
const [pdfLayout, setPdfLayout] = useState<IdeLayout>('sideBySide')
|
||||
|
||||
const [persistedFocusMode, setPersistedFocusMode] =
|
||||
usePersistedState<boolean>('ui.focus-mode', false)
|
||||
|
||||
const focusModeEnabled = useFeatureFlag('focus-mode')
|
||||
|
||||
const focusMode = focusModeEnabled && persistedFocusMode
|
||||
const setFocusMode = useCallback(
|
||||
(value: SetStateAction<boolean>) => {
|
||||
if (focusModeEnabled) {
|
||||
const newValue = typeof value === 'function' ? value(focusMode) : value
|
||||
setPersistedFocusMode(newValue)
|
||||
sendEvent('project-layout-change', {
|
||||
layout: pdfLayout,
|
||||
view: view ?? undefined,
|
||||
focusMode: newValue,
|
||||
})
|
||||
}
|
||||
},
|
||||
[
|
||||
focusMode,
|
||||
focusModeEnabled,
|
||||
pdfLayout,
|
||||
sendEvent,
|
||||
setPersistedFocusMode,
|
||||
view,
|
||||
]
|
||||
)
|
||||
|
||||
useEventListener(
|
||||
'ui.toggle-left-menu',
|
||||
useCallback(
|
||||
@@ -172,14 +206,21 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
}, [setReviewPanelOpen])
|
||||
)
|
||||
|
||||
// TODO ide-redesign-cleanup: remove this listener as we have an equivalent in rail-context
|
||||
useEventListener(
|
||||
'keydown',
|
||||
useCallback((event: KeyboardEvent) => {
|
||||
'ui.toggle-focus-mode',
|
||||
useCallback(() => {
|
||||
setFocusMode(mode => !mode)
|
||||
}, [setFocusMode])
|
||||
)
|
||||
|
||||
// Global keyboard shortcut handlers
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
// Cmd/Ctrl+Shift+F for full project search
|
||||
if (
|
||||
(isMac ? event.metaKey : event.ctrlKey) &&
|
||||
event.shiftKey &&
|
||||
event.code === 'KeyF'
|
||||
event.key === 'F'
|
||||
) {
|
||||
event.preventDefault()
|
||||
sendSearchEvent('search-open', {
|
||||
@@ -188,11 +229,25 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
})
|
||||
setProjectSearchIsOpen(true)
|
||||
}
|
||||
}, [])
|
||||
)
|
||||
// Cmd/Ctrl+Shift+M for focus mode
|
||||
if (
|
||||
focusModeEnabled &&
|
||||
(isMac ? event.metaKey : event.ctrlKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === 'M'
|
||||
) {
|
||||
event.preventDefault()
|
||||
setFocusMode(mode => !mode)
|
||||
}
|
||||
}
|
||||
|
||||
// whether to display the editor and preview side-by-side or full-width ("flat")
|
||||
const [pdfLayout, setPdfLayout] = useState<IdeLayout>('sideBySide')
|
||||
// Use capture phase to ensure we get the event even if something else stops propagation
|
||||
window.addEventListener('keydown', handleKeyDown, true)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown, true)
|
||||
}
|
||||
}, [focusModeEnabled, setFocusMode, setProjectSearchIsOpen])
|
||||
|
||||
// whether stylesheet on theme is loading
|
||||
const [loadingStyleSheet, setLoadingStyleSheet] = useState(false)
|
||||
@@ -282,9 +337,10 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
sendEvent('project-layout-change', {
|
||||
layout: newLayout,
|
||||
view: newView,
|
||||
focusMode,
|
||||
})
|
||||
},
|
||||
[changeLayout, handleReattach, sendEvent]
|
||||
[changeLayout, focusMode, handleReattach, sendEvent]
|
||||
)
|
||||
|
||||
useEventListener(
|
||||
@@ -353,6 +409,8 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
restoreView,
|
||||
handleChangeLayout,
|
||||
handleDetach,
|
||||
focusMode,
|
||||
setFocusMode,
|
||||
}),
|
||||
[
|
||||
reattach,
|
||||
@@ -382,6 +440,8 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
restoreView,
|
||||
handleChangeLayout,
|
||||
handleDetach,
|
||||
focusMode,
|
||||
setFocusMode,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user