mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Add keyboard shortcuts for Layout actions (#30494)
GitOrigin-RevId: 7978a579e719c4cd593c02662406e364b19f87e0
This commit is contained in:
+3
-33
@@ -1,4 +1,4 @@
|
|||||||
import { memo, useCallback, forwardRef } from 'react'
|
import { memo, forwardRef } from 'react'
|
||||||
import {
|
import {
|
||||||
Dropdown,
|
Dropdown,
|
||||||
DropdownItem,
|
DropdownItem,
|
||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
useLayoutContext,
|
useLayoutContext,
|
||||||
} from '../../../shared/context/layout-context'
|
} from '../../../shared/context/layout-context'
|
||||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||||
import useEventListener from '../../../shared/hooks/use-event-listener'
|
|
||||||
import { DetachRole } from '@/shared/context/detach-context'
|
import { DetachRole } from '@/shared/context/detach-context'
|
||||||
import MaterialIcon from '@/shared/components/material-icon'
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
import OLTooltip from '@/shared/components/ol/ol-tooltip'
|
import OLTooltip from '@/shared/components/ol/ol-tooltip'
|
||||||
@@ -96,43 +95,14 @@ function BS5DetachDisabled() {
|
|||||||
|
|
||||||
function LayoutDropdownButton() {
|
function LayoutDropdownButton() {
|
||||||
const {
|
const {
|
||||||
reattach,
|
|
||||||
detach,
|
|
||||||
detachIsLinked,
|
detachIsLinked,
|
||||||
detachRole,
|
detachRole,
|
||||||
changeLayout,
|
|
||||||
view,
|
view,
|
||||||
pdfLayout,
|
pdfLayout,
|
||||||
|
handleChangeLayout,
|
||||||
|
handleDetach,
|
||||||
} = useLayoutContext()
|
} = useLayoutContext()
|
||||||
|
|
||||||
const handleDetach = useCallback(() => {
|
|
||||||
detach()
|
|
||||||
eventTracking.sendMB('project-layout-detach')
|
|
||||||
}, [detach])
|
|
||||||
|
|
||||||
const handleReattach = useCallback(() => {
|
|
||||||
if (detachRole !== 'detacher') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
reattach()
|
|
||||||
eventTracking.sendMB('project-layout-reattach')
|
|
||||||
}, [detachRole, reattach])
|
|
||||||
|
|
||||||
// reattach when the PDF pane opens
|
|
||||||
useEventListener('ui:pdf-open', handleReattach)
|
|
||||||
|
|
||||||
const handleChangeLayout = useCallback(
|
|
||||||
(newLayout: IdeLayout, newView?: IdeView) => {
|
|
||||||
handleReattach()
|
|
||||||
changeLayout(newLayout, newView)
|
|
||||||
eventTracking.sendMB('project-layout-change', {
|
|
||||||
layout: newLayout,
|
|
||||||
view: newView,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
[changeLayout, handleReattach]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutDropdownButtonUi
|
<LayoutDropdownButtonUi
|
||||||
processing={!detachIsLinked && detachRole === 'detacher'}
|
processing={!detachIsLinked && detachRole === 'detacher'}
|
||||||
|
|||||||
+39
-40
@@ -7,12 +7,13 @@ import {
|
|||||||
IdeView,
|
IdeView,
|
||||||
useLayoutContext,
|
useLayoutContext,
|
||||||
} from '@/shared/context/layout-context'
|
} from '@/shared/context/layout-context'
|
||||||
import React, { useCallback } from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import useEventListener from '@/shared/hooks/use-event-listener'
|
|
||||||
import { DetachRole } from '@/shared/context/detach-context'
|
import { DetachRole } from '@/shared/context/detach-context'
|
||||||
import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
|
|
||||||
import OLSpinner from '@/shared/components/ol/ol-spinner'
|
import OLSpinner from '@/shared/components/ol/ol-spinner'
|
||||||
|
import { isMac } from '@/shared/utils/os'
|
||||||
|
import { Shortcut } from '@/shared/components/shortcut'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
type LayoutOption = 'sideBySide' | 'editorOnly' | 'pdfOnly' | 'detachedPdf'
|
type LayoutOption = 'sideBySide' | 'editorOnly' | 'pdfOnly' | 'detachedPdf'
|
||||||
|
|
||||||
@@ -53,77 +54,63 @@ const LayoutDropdownItem = ({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
processing = false,
|
processing = false,
|
||||||
leadingIcon,
|
leadingIcon,
|
||||||
|
trailingIcon,
|
||||||
onClick,
|
onClick,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
active: boolean
|
active: boolean
|
||||||
leadingIcon: string
|
leadingIcon: React.ReactNode
|
||||||
|
trailingIcon?: React.ReactNode
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
processing?: boolean
|
processing?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}) => {
|
}) => {
|
||||||
let trailingIcon: string | React.ReactNode | null = null
|
|
||||||
if (processing) {
|
if (processing) {
|
||||||
trailingIcon = <OLSpinner size="sm" />
|
leadingIcon = <OLSpinner size="sm" />
|
||||||
} else if (active) {
|
} else if (active) {
|
||||||
trailingIcon = 'check'
|
leadingIcon = 'check'
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
active={active}
|
active={active}
|
||||||
aria-current={active}
|
aria-current={active}
|
||||||
trailingIcon={trailingIcon}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
leadingIcon={leadingIcon}
|
leadingIcon={leadingIcon}
|
||||||
|
trailingIcon={trailingIcon}
|
||||||
|
className={classNames({ 'dropdown-item-wide': isMac })}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shortcuts: Record<LayoutOption, string[] | null> = isMac
|
||||||
|
? {
|
||||||
|
editorOnly: ['⌃', '⌘', '←'],
|
||||||
|
pdfOnly: ['⌃', '⌘', '→'],
|
||||||
|
sideBySide: ['⌃', '⌘', '↓'],
|
||||||
|
detachedPdf: ['⌃', '⌘', '↑'],
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
editorOnly: null,
|
||||||
|
pdfOnly: null,
|
||||||
|
sideBySide: null,
|
||||||
|
detachedPdf: null,
|
||||||
|
}
|
||||||
|
|
||||||
export default function ChangeLayoutOptions() {
|
export default function ChangeLayoutOptions() {
|
||||||
const { sendEvent } = useEditorAnalytics()
|
|
||||||
const {
|
const {
|
||||||
reattach,
|
|
||||||
detach,
|
|
||||||
detachIsLinked,
|
detachIsLinked,
|
||||||
detachRole,
|
detachRole,
|
||||||
changeLayout,
|
|
||||||
view,
|
view,
|
||||||
pdfLayout,
|
pdfLayout,
|
||||||
|
handleChangeLayout,
|
||||||
|
handleDetach,
|
||||||
} = useLayoutContext()
|
} = useLayoutContext()
|
||||||
|
|
||||||
const handleDetach = useCallback(() => {
|
|
||||||
detach()
|
|
||||||
sendEvent('project-layout-detach')
|
|
||||||
}, [detach, sendEvent])
|
|
||||||
|
|
||||||
const handleReattach = useCallback(() => {
|
|
||||||
if (detachRole !== 'detacher') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
reattach()
|
|
||||||
sendEvent('project-layout-reattach')
|
|
||||||
}, [detachRole, reattach, sendEvent])
|
|
||||||
|
|
||||||
// reattach when the PDF pane opens
|
|
||||||
useEventListener('ui:pdf-open', handleReattach)
|
|
||||||
|
|
||||||
const handleChangeLayout = useCallback(
|
|
||||||
(newLayout: IdeLayout, newView?: IdeView) => {
|
|
||||||
handleReattach()
|
|
||||||
changeLayout(newLayout, newView)
|
|
||||||
sendEvent('project-layout-change', {
|
|
||||||
layout: newLayout,
|
|
||||||
view: newView,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
[changeLayout, handleReattach, sendEvent]
|
|
||||||
)
|
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const detachable = 'BroadcastChannel' in window
|
const detachable = 'BroadcastChannel' in window
|
||||||
@@ -143,6 +130,9 @@ export default function ChangeLayoutOptions() {
|
|||||||
onClick={() => handleChangeLayout('sideBySide')}
|
onClick={() => handleChangeLayout('sideBySide')}
|
||||||
active={activeLayoutOption === 'sideBySide'}
|
active={activeLayoutOption === 'sideBySide'}
|
||||||
leadingIcon="splitscreen_right"
|
leadingIcon="splitscreen_right"
|
||||||
|
trailingIcon={
|
||||||
|
shortcuts.sideBySide && <Shortcut keys={shortcuts.sideBySide} />
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t('split_view')}
|
{t('split_view')}
|
||||||
</LayoutDropdownItem>
|
</LayoutDropdownItem>
|
||||||
@@ -150,6 +140,9 @@ export default function ChangeLayoutOptions() {
|
|||||||
onClick={() => handleChangeLayout('flat', 'editor')}
|
onClick={() => handleChangeLayout('flat', 'editor')}
|
||||||
active={activeLayoutOption === 'editorOnly'}
|
active={activeLayoutOption === 'editorOnly'}
|
||||||
leadingIcon="edit"
|
leadingIcon="edit"
|
||||||
|
trailingIcon={
|
||||||
|
shortcuts.editorOnly && <Shortcut keys={shortcuts.editorOnly} />
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t('editor_only')}
|
{t('editor_only')}
|
||||||
</LayoutDropdownItem>
|
</LayoutDropdownItem>
|
||||||
@@ -157,6 +150,9 @@ export default function ChangeLayoutOptions() {
|
|||||||
onClick={() => handleChangeLayout('flat', 'pdf')}
|
onClick={() => handleChangeLayout('flat', 'pdf')}
|
||||||
active={activeLayoutOption === 'pdfOnly'}
|
active={activeLayoutOption === 'pdfOnly'}
|
||||||
leadingIcon="picture_as_pdf"
|
leadingIcon="picture_as_pdf"
|
||||||
|
trailingIcon={
|
||||||
|
shortcuts.pdfOnly && <Shortcut keys={shortcuts.pdfOnly} />
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t('pdf_only')}
|
{t('pdf_only')}
|
||||||
</LayoutDropdownItem>
|
</LayoutDropdownItem>
|
||||||
@@ -165,6 +161,9 @@ export default function ChangeLayoutOptions() {
|
|||||||
active={activeLayoutOption === 'detachedPdf' && detachIsLinked}
|
active={activeLayoutOption === 'detachedPdf' && detachIsLinked}
|
||||||
disabled={!detachable}
|
disabled={!detachable}
|
||||||
leadingIcon="open_in_new"
|
leadingIcon="open_in_new"
|
||||||
|
trailingIcon={
|
||||||
|
shortcuts.detachedPdf && <Shortcut keys={shortcuts.detachedPdf} />
|
||||||
|
}
|
||||||
processing={waitingForDetachedLink}
|
processing={waitingForDetachedLink}
|
||||||
>
|
>
|
||||||
{t('open_pdf_in_separate_tab')}
|
{t('open_pdf_in_separate_tab')}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import classNames from 'classnames'
|
|
||||||
import {
|
import {
|
||||||
Dropdown,
|
Dropdown,
|
||||||
DropdownDivider,
|
DropdownDivider,
|
||||||
@@ -11,6 +10,7 @@ import {
|
|||||||
} from '@/shared/components/dropdown/dropdown-menu'
|
} from '@/shared/components/dropdown/dropdown-menu'
|
||||||
import FormControl from '@/shared/components/form/form-control'
|
import FormControl from '@/shared/components/form/form-control'
|
||||||
import { isMac } from '@/shared/utils/os'
|
import { isMac } from '@/shared/utils/os'
|
||||||
|
import { Shortcut } from '@/shared/components/shortcut'
|
||||||
|
|
||||||
const shortcuts = isMac
|
const shortcuts = isMac
|
||||||
? {
|
? {
|
||||||
@@ -171,21 +171,4 @@ function PdfZoomDropdown({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Shortcut({ keys }: { keys: string[] }) {
|
|
||||||
return (
|
|
||||||
<span className="float-end">
|
|
||||||
{keys.map((key, idx) => (
|
|
||||||
<span
|
|
||||||
className={classNames({
|
|
||||||
'pdfjs-zoom-dropdown-mac-shortcut-char': key.length === 1,
|
|
||||||
})}
|
|
||||||
key={`${key}${idx}`}
|
|
||||||
>
|
|
||||||
{key}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PdfZoomDropdown
|
export default PdfZoomDropdown
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
export function Shortcut({ keys }: { keys: string[] }) {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{keys.map((key, idx) => (
|
||||||
|
<span
|
||||||
|
className={classNames({
|
||||||
|
'dropdown-shortcut-char': key.length === 1,
|
||||||
|
})}
|
||||||
|
key={`${key}${idx}`}
|
||||||
|
>
|
||||||
|
{key}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import { sendSearchEvent } from '@/features/event-tracking/search-events'
|
|||||||
import { useRailContext } from '@/features/ide-redesign/contexts/rail-context'
|
import { useRailContext } from '@/features/ide-redesign/contexts/rail-context'
|
||||||
import usePersistedState from '@/shared/hooks/use-persisted-state'
|
import usePersistedState from '@/shared/hooks/use-persisted-state'
|
||||||
import { repositionAllTooltips } from '@/features/source-editor/extensions/tooltips-reposition'
|
import { repositionAllTooltips } from '@/features/source-editor/extensions/tooltips-reposition'
|
||||||
|
import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
|
||||||
|
|
||||||
export type IdeLayout = 'sideBySide' | 'flat'
|
export type IdeLayout = 'sideBySide' | 'flat'
|
||||||
export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
|
export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
|
||||||
@@ -63,6 +64,8 @@ export type LayoutContextValue = LayoutContextOwnStates & {
|
|||||||
setProjectSearchIsOpen: Dispatch<SetStateAction<boolean>>
|
setProjectSearchIsOpen: Dispatch<SetStateAction<boolean>>
|
||||||
setOpenFile: Dispatch<SetStateAction<BinaryFile | null>>
|
setOpenFile: Dispatch<SetStateAction<BinaryFile | null>>
|
||||||
restoreView: () => void
|
restoreView: () => void
|
||||||
|
handleChangeLayout: (newLayout: IdeLayout, newView?: IdeView) => void
|
||||||
|
handleDetach: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const debugPdfDetach = getMeta('ol-debugPdfDetach')
|
const debugPdfDetach = getMeta('ol-debugPdfDetach')
|
||||||
@@ -89,6 +92,7 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
|||||||
const [prevRailIsOpen, setPrevRailIsOpen] = useState(railIsOpen)
|
const [prevRailIsOpen, setPrevRailIsOpen] = useState(railIsOpen)
|
||||||
// Whether we came from a file or a document when we left the ide
|
// Whether we came from a file or a document when we left the ide
|
||||||
const lastIdeView = useRef<IdeView>('editor')
|
const lastIdeView = useRef<IdeView>('editor')
|
||||||
|
const { sendEvent } = useEditorAnalytics()
|
||||||
|
|
||||||
const setView = useCallback(
|
const setView = useCallback(
|
||||||
(value: IdeView | null) => {
|
(value: IdeView | null) => {
|
||||||
@@ -258,6 +262,68 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
|||||||
changeLayout,
|
changeLayout,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const handleDetach = useCallback(() => {
|
||||||
|
detach()
|
||||||
|
sendEvent('project-layout-detach')
|
||||||
|
}, [detach, sendEvent])
|
||||||
|
|
||||||
|
const handleReattach = useCallback(() => {
|
||||||
|
if (detachRole !== 'detacher') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reattach()
|
||||||
|
sendEvent('project-layout-reattach')
|
||||||
|
}, [detachRole, reattach, sendEvent])
|
||||||
|
|
||||||
|
const handleChangeLayout = useCallback(
|
||||||
|
(newLayout: IdeLayout, newView?: IdeView) => {
|
||||||
|
handleReattach()
|
||||||
|
changeLayout(newLayout, newView)
|
||||||
|
sendEvent('project-layout-change', {
|
||||||
|
layout: newLayout,
|
||||||
|
view: newView,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[changeLayout, handleReattach, sendEvent]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEventListener(
|
||||||
|
'keydown',
|
||||||
|
useCallback(
|
||||||
|
(event: KeyboardEvent) => {
|
||||||
|
if (
|
||||||
|
isMac &&
|
||||||
|
event.metaKey &&
|
||||||
|
event.ctrlKey &&
|
||||||
|
!event.shiftKey &&
|
||||||
|
!event.altKey
|
||||||
|
) {
|
||||||
|
switch (event.code) {
|
||||||
|
case 'ArrowLeft': // Editor only
|
||||||
|
event.preventDefault()
|
||||||
|
handleChangeLayout('flat', 'editor')
|
||||||
|
break
|
||||||
|
case 'ArrowRight': // PDF only
|
||||||
|
event.preventDefault()
|
||||||
|
handleChangeLayout('flat', 'pdf')
|
||||||
|
break
|
||||||
|
case 'ArrowDown': // Split view
|
||||||
|
event.preventDefault()
|
||||||
|
handleChangeLayout('sideBySide')
|
||||||
|
break
|
||||||
|
case 'ArrowUp': // Open PDF in separate tab (detach)
|
||||||
|
event.preventDefault()
|
||||||
|
if ('BroadcastChannel' in window && detachRole !== 'detacher') {
|
||||||
|
handleDetach()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[detachRole, handleChangeLayout, handleDetach]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const value = useMemo<LayoutContextValue>(
|
const value = useMemo<LayoutContextValue>(
|
||||||
() => ({
|
() => ({
|
||||||
reattach,
|
reattach,
|
||||||
@@ -285,6 +351,8 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
|||||||
setView,
|
setView,
|
||||||
view,
|
view,
|
||||||
restoreView,
|
restoreView,
|
||||||
|
handleChangeLayout,
|
||||||
|
handleDetach,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
reattach,
|
reattach,
|
||||||
@@ -312,6 +380,8 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
|||||||
setView,
|
setView,
|
||||||
view,
|
view,
|
||||||
restoreView,
|
restoreView,
|
||||||
|
handleChangeLayout,
|
||||||
|
handleDetach,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -272,3 +272,13 @@ $dropdown-item-min-height: 36px;
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-shortcut-char {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item-wide {
|
||||||
|
min-width: 264px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -385,12 +385,6 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pdfjs-zoom-dropdown-mac-shortcut-char {
|
|
||||||
display: inline-block;
|
|
||||||
width: 1em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pdfjs-custom-zoom-menu-item {
|
.pdfjs-custom-zoom-menu-item {
|
||||||
display: block;
|
display: block;
|
||||||
pointer-events: initial !important;
|
pointer-events: initial !important;
|
||||||
|
|||||||
+2
@@ -96,6 +96,8 @@ const createInitialValue = () =>
|
|||||||
openFile: null,
|
openFile: null,
|
||||||
setOpenFile: cy.stub(),
|
setOpenFile: cy.stub(),
|
||||||
restoreView: cy.stub(),
|
restoreView: cy.stub(),
|
||||||
|
handleChangeLayout: cy.stub(),
|
||||||
|
handleDetach: cy.stub(),
|
||||||
}) satisfies LayoutContextValue
|
}) satisfies LayoutContextValue
|
||||||
|
|
||||||
const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import {
|
|||||||
import { UserId } from '../../../types/user'
|
import { UserId } from '../../../types/user'
|
||||||
import { ProjectCompiler } from '../../../types/project-settings'
|
import { ProjectCompiler } from '../../../types/project-settings'
|
||||||
import { ReferencesContext } from '@/features/ide-react/context/references-context'
|
import { ReferencesContext } from '@/features/ide-react/context/references-context'
|
||||||
|
import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
|
||||||
|
|
||||||
// these constants can be imported in tests instead of
|
// these constants can be imported in tests instead of
|
||||||
// using magic strings
|
// using magic strings
|
||||||
@@ -429,6 +430,8 @@ const makeLayoutProvider = (
|
|||||||
layout.loadingStyleSheet
|
layout.loadingStyleSheet
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const { sendEvent } = useEditorAnalytics()
|
||||||
|
|
||||||
useEventListener(
|
useEventListener(
|
||||||
'ui.toggle-review-panel',
|
'ui.toggle-review-panel',
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
@@ -453,8 +456,34 @@ const makeLayoutProvider = (
|
|||||||
isLinked: detachIsLinked,
|
isLinked: detachIsLinked,
|
||||||
role: detachRole,
|
role: detachRole,
|
||||||
} = useDetachLayout()
|
} = useDetachLayout()
|
||||||
|
|
||||||
|
const handleDetach = useCallback(() => {
|
||||||
|
detach()
|
||||||
|
sendEvent('project-layout-detach')
|
||||||
|
}, [detach, sendEvent])
|
||||||
|
|
||||||
|
const handleReattach = useCallback(() => {
|
||||||
|
if (detachRole !== 'detacher') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reattach()
|
||||||
|
sendEvent('project-layout-reattach')
|
||||||
|
}, [detachRole, reattach, sendEvent])
|
||||||
|
|
||||||
|
const handleChangeLayout = useCallback(
|
||||||
|
(newLayout: IdeLayout, newView?: IdeView) => {
|
||||||
|
handleReattach()
|
||||||
|
changeLayout(newLayout, newView)
|
||||||
|
sendEvent('project-layout-change', {
|
||||||
|
layout: newLayout,
|
||||||
|
view: newView,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[changeLayout, handleReattach, sendEvent]
|
||||||
|
)
|
||||||
const pdfPreviewOpen =
|
const pdfPreviewOpen =
|
||||||
pdfLayout === 'sideBySide' || view === 'pdf' || detachRole === 'detacher'
|
pdfLayout === 'sideBySide' || view === 'pdf' || detachRole === 'detacher'
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
reattach,
|
reattach,
|
||||||
@@ -482,6 +511,8 @@ const makeLayoutProvider = (
|
|||||||
setView,
|
setView,
|
||||||
view,
|
view,
|
||||||
restoreView,
|
restoreView,
|
||||||
|
handleChangeLayout,
|
||||||
|
handleDetach,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
reattach,
|
reattach,
|
||||||
@@ -509,6 +540,8 @@ const makeLayoutProvider = (
|
|||||||
setView,
|
setView,
|
||||||
view,
|
view,
|
||||||
restoreView,
|
restoreView,
|
||||||
|
handleChangeLayout,
|
||||||
|
handleDetach,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user