Merge pull request #15474 from overleaf/td-ide-page-file-and-multiple-view

React IDE page: implement file views and file delete handling

GitOrigin-RevId: 491cad7b147e55bc4a250da387916c7e2dff14ae
This commit is contained in:
ilkin-overleaf
2023-11-03 09:00:08 +00:00
committed by Copybot
parent 0c403bf8e3
commit 2bbead57ec
28 changed files with 593 additions and 311 deletions
@@ -1,35 +1,26 @@
import { Panel, PanelGroup } from 'react-resizable-panels'
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
import React, { ElementType, useEffect } from 'react'
import React, { ElementType } from 'react'
import useScopeValue from '@/shared/hooks/use-scope-value'
import SourceEditor from '@/features/source-editor/components/source-editor'
import {
EditorScopeValue,
useEditorManagerContext,
} from '@/features/ide-react/context/editor-manager-context'
import { EditorScopeValue } from '@/features/ide-react/context/editor-manager-context'
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
import { EditorProps } from '@/features/ide-react/components/editor/editor'
import classNames from 'classnames'
import { useTranslation } from 'react-i18next'
const symbolPaletteComponents = importOverleafModules(
'sourceEditorSymbolPalette'
) as { import: { default: ElementType }; path: string }[]
export function EditorPane({
shouldPersistLayout,
openDocId,
fileTreeReady,
}: EditorProps) {
const { openDocId: openDocWithId } = useEditorManagerContext()
export type EditorPaneProps = {
shouldPersistLayout?: boolean
show: boolean
}
export function EditorPane({ shouldPersistLayout, show }: EditorPaneProps) {
const { t } = useTranslation()
const [editor] = useScopeValue<EditorScopeValue>('editor')
useEffect(() => {
if (!fileTreeReady || !openDocId) {
return
}
openDocWithId(openDocId)
}, [fileTreeReady, openDocId, openDocWithId])
return (
<PanelGroup
autoSaveId={
@@ -39,21 +30,27 @@ export function EditorPane({
}
direction="vertical"
units="pixels"
className={classNames({ hidden: !show })}
>
<Panel
id="editor"
id="sourceEditor"
order={1}
style={{
display: 'flex',
flexDirection: 'column',
}}
>
{!!editor.sharejs_doc &&
!editor.opening &&
editor.multiSelectedCount === 0 &&
!editor.error_state ? (
<SourceEditor />
{(!editor.sharejs_doc || editor.opening) &&
!editor.error_state &&
!!editor.open_doc_id ? (
<div className="loading-panel">
<span>
<i className="fa fa-spin fa-refresh" />
&nbsp;&nbsp;{t('loading')}…
</span>
</div>
) : null}
<SourceEditor />
</Panel>
{editor.showSymbolPalette ? (
<>
@@ -65,7 +62,7 @@ export function EditorPane({
minSize={250}
maxSize={336}
>
<div className="ide-react-placeholder-symbol-palette">
<div className="ide-react-symbol-palette">
{symbolPaletteComponents.map(
({ import: { default: Component }, path }) => (
<Component key={path} />
@@ -1,96 +0,0 @@
import { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import {
ImperativePanelHandle,
Panel,
PanelGroup,
} from 'react-resizable-panels'
import { HorizontalResizeHandle } from '@/features/ide-react/components/resize/horizontal-resize-handle'
import { HorizontalToggler } from '@/features/ide-react/components/resize/horizontal-toggler'
import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
import { useLayoutContext } from '@/shared/context/layout-context'
import { EditorPane } from '@/features/ide-react/components/editor/editor-pane'
import PlaceholderFile from '@/features/ide-react/components/layout/placeholder/placeholder-file'
import PlaceholderPdf from '@/features/ide-react/components/layout/placeholder/placeholder-pdf'
import classnames from 'classnames'
export type EditorProps = {
shouldPersistLayout?: boolean
openDocId: string | null
fileTreeReady: boolean
}
export default function Editor({
shouldPersistLayout = false,
openDocId,
fileTreeReady,
}: EditorProps) {
const { t } = useTranslation()
const { view, pdfLayout, changeLayout } = useLayoutContext()
const pdfPanelRef = useRef<ImperativePanelHandle>(null)
const isDualPane = pdfLayout === 'sideBySide'
const editorIsVisible = isDualPane || view === 'editor'
const pdfIsOpen = isDualPane || view === 'pdf'
useCollapsiblePanel(pdfIsOpen, pdfPanelRef)
if (view === 'file') {
return <PlaceholderFile />
}
const historyIsOpen = view === 'history'
function setPdfIsOpen(isOpen: boolean) {
if (isOpen) {
changeLayout('sideBySide')
} else {
changeLayout('flat', 'editor')
}
}
return (
<PanelGroup
autoSaveId={
shouldPersistLayout ? 'ide-react-editor-and-pdf-layout' : undefined
}
direction="horizontal"
className={classnames({ hide: historyIsOpen })}
>
{editorIsVisible ? (
<Panel id="editor" order={1} defaultSize={50}>
<EditorPane
shouldPersistLayout={shouldPersistLayout}
openDocId={openDocId}
fileTreeReady={fileTreeReady}
/>
</Panel>
) : null}
{isDualPane ? (
<HorizontalResizeHandle>
<HorizontalToggler
id="editor-pdf"
togglerType="east"
isOpen={pdfIsOpen}
setIsOpen={isOpen => setPdfIsOpen(isOpen)}
tooltipWhenOpen={t('tooltip_hide_pdf')}
tooltipWhenClosed={t('tooltip_show_pdf')}
/>
</HorizontalResizeHandle>
) : null}
{pdfIsOpen ? (
<Panel
ref={pdfPanelRef}
id="pdf"
order={2}
defaultSize={50}
minSize={5}
collapsible
onCollapse={collapsed => setPdfIsOpen(!collapsed)}
>
<PlaceholderPdf />
</Panel>
) : null}
</PanelGroup>
)
}
@@ -0,0 +1,17 @@
import { useTranslation } from 'react-i18next'
export default function MultipleSelectionPane({
selectedEntityCount,
}: {
selectedEntityCount: number
}) {
const { t } = useTranslation()
return (
<div className="multi-selection-ongoing">
<div className="multi-selection-message">
<h4>{`${selectedEntityCount} ${t('files_selected')}`}</h4>
</div>
</div>
)
}
@@ -0,0 +1,14 @@
import { useTranslation } from 'react-i18next'
export default function NoOpenDocPane() {
const { t } = useTranslation()
return (
<div className="loading-panel">
<span>
<i className="fa fa-arrow-left" />
&nbsp;&nbsp;{t('open_a_file_on_the_left')}
</span>
</div>
)
}
@@ -0,0 +1,13 @@
import { useTranslation } from 'react-i18next'
export default function NoSelectionPane() {
const { t } = useTranslation()
return (
<div className="no-file-selection">
<div className="no-file-selection-message">
<h3>{t('no_selection_select_file')}</h3>
</div>
</div>
)
}