mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 14:43:46 +01:00
[ide-react] Improve file tree and outline components in the editor sidebar (#16225)
* Upgrade react-resizable-panels * Add FileTreeOpenProvider * Add OutlineProvider and OutlineContainer * Convert Outline tests to Cypress GitOrigin-RevId: afd9ae8190edf37642e36a4ffb331f1182c8982d
This commit is contained in:
@@ -2,7 +2,6 @@ import React, { FC, useState } from 'react'
|
||||
import { Panel, PanelGroup } from 'react-resizable-panels'
|
||||
import NoSelectionPane from '@/features/ide-react/components/editor/no-selection-pane'
|
||||
import FileView from '@/features/file-view/components/file-view'
|
||||
import { fileViewFile } from '@/features/ide-react/hooks/use-file-tree'
|
||||
import MultipleSelectionPane from '@/features/ide-react/components/editor/multiple-selection-pane'
|
||||
import { HorizontalResizeHandle } from '@/features/ide-react/components/resize/horizontal-resize-handle'
|
||||
import { HorizontalToggler } from '@/features/ide-react/components/resize/horizontal-toggler'
|
||||
@@ -12,12 +11,12 @@ import { usePdfPane } from '@/features/ide-react/hooks/use-pdf-pane'
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import classNames from 'classnames'
|
||||
import { fileViewFile } from '@/features/ide-react/util/file-view'
|
||||
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
|
||||
|
||||
export const EditorAndPdf: FC<{
|
||||
editorPane: React.ReactNode
|
||||
selectedEntityCount: number
|
||||
openEntity: any // TODO
|
||||
}> = ({ editorPane, selectedEntityCount, openEntity }) => {
|
||||
}> = ({ editorPane }) => {
|
||||
const [resizing, setResizing] = useState(false)
|
||||
|
||||
const { t } = useTranslation()
|
||||
@@ -33,6 +32,8 @@ export const EditorAndPdf: FC<{
|
||||
|
||||
const { view, pdfLayout } = useLayoutContext()
|
||||
|
||||
const { selectedEntityCount, openEntity } = useFileTreeOpenContext()
|
||||
|
||||
const editorIsOpen =
|
||||
view === 'editor' || view === 'file' || pdfLayout === 'sideBySide'
|
||||
|
||||
@@ -50,8 +51,8 @@ export const EditorAndPdf: FC<{
|
||||
<Panel
|
||||
id="panel-main"
|
||||
order={1}
|
||||
defaultSizePercentage={50}
|
||||
minSizePercentage={25}
|
||||
defaultSize={50}
|
||||
minSize={25}
|
||||
className={classNames('ide-react-panel', {
|
||||
'ide-panel-group-resizing': resizing,
|
||||
})}
|
||||
@@ -96,8 +97,8 @@ export const EditorAndPdf: FC<{
|
||||
ref={pdfPanelRef}
|
||||
id="panel-pdf"
|
||||
order={2}
|
||||
defaultSizePercentage={50}
|
||||
minSizePercentage={25}
|
||||
defaultSize={50}
|
||||
minSize={25}
|
||||
collapsible
|
||||
onCollapse={handlePdfPaneCollapse}
|
||||
onExpand={handlePdfPaneExpand}
|
||||
|
||||
@@ -1,47 +1,45 @@
|
||||
import React from 'react'
|
||||
import { Panel, PanelGroup } from 'react-resizable-panels'
|
||||
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
|
||||
import { FileTree } from '@/features/ide-react/components/file-tree'
|
||||
import {
|
||||
FileTreeDeleteHandler,
|
||||
FileTreeSelectHandler,
|
||||
} from '@/features/ide-react/types/file-tree'
|
||||
import classNames from 'classnames'
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import { OutlineContainer } from '@/features/outline/components/outline-container'
|
||||
import { useOutlinePane } from '@/features/ide-react/hooks/use-outline-pane'
|
||||
|
||||
type EditorSidebarProps = {
|
||||
shouldShow?: boolean
|
||||
onFileTreeInit: () => void
|
||||
onFileTreeSelect: FileTreeSelectHandler
|
||||
onFileTreeDelete: FileTreeDeleteHandler
|
||||
}
|
||||
export default function EditorSidebar() {
|
||||
const { view } = useLayoutContext()
|
||||
|
||||
const { outlineDisabled, outlineRef } = useOutlinePane()
|
||||
|
||||
export default function EditorSidebar({
|
||||
shouldShow = false,
|
||||
onFileTreeInit,
|
||||
onFileTreeSelect,
|
||||
onFileTreeDelete,
|
||||
}: EditorSidebarProps) {
|
||||
return (
|
||||
<aside
|
||||
className={classNames('ide-react-editor-sidebar', {
|
||||
hidden: !shouldShow,
|
||||
hidden: view === 'history',
|
||||
})}
|
||||
>
|
||||
<PanelGroup autoSaveId="ide-editor-sidebar-layout" direction="vertical">
|
||||
<Panel
|
||||
defaultSizePercentage={75}
|
||||
defaultSize={50}
|
||||
minSize={25}
|
||||
className="ide-react-file-tree-panel"
|
||||
id="panel-file-tree"
|
||||
order={1}
|
||||
>
|
||||
<FileTree
|
||||
onInit={onFileTreeInit}
|
||||
onSelect={onFileTreeSelect}
|
||||
onDelete={onFileTreeDelete}
|
||||
/>
|
||||
<FileTree />
|
||||
</Panel>
|
||||
<VerticalResizeHandle />
|
||||
<Panel defaultSizePercentage={25} id="panel-outline">
|
||||
<div className="outline-container" />
|
||||
|
||||
<VerticalResizeHandle disabled={outlineDisabled} />
|
||||
|
||||
<Panel
|
||||
defaultSize={50}
|
||||
maxSize={75}
|
||||
id="panel-outline"
|
||||
order={2}
|
||||
collapsible
|
||||
ref={outlineRef}
|
||||
style={{ minHeight: 32 }} // keep the header visible
|
||||
>
|
||||
<OutlineContainer />
|
||||
</Panel>
|
||||
</PanelGroup>
|
||||
</aside>
|
||||
|
||||
@@ -7,13 +7,15 @@ import classNames from 'classnames'
|
||||
import { LoadingPane } from '@/features/ide-react/components/editor/loading-pane'
|
||||
import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
|
||||
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
|
||||
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
|
||||
|
||||
const SymbolPalettePane = lazy(
|
||||
() => import('@/features/ide-react/components/editor/symbol-palette-pane')
|
||||
)
|
||||
|
||||
export const EditorPane: FC<{ show: boolean }> = ({ show }) => {
|
||||
export const EditorPane: FC = () => {
|
||||
const [editor] = useScopeValue<EditorScopeValue>('editor')
|
||||
const { selectedEntityCount, openEntity } = useFileTreeOpenContext()
|
||||
|
||||
const isLoading = Boolean(
|
||||
(!editor.sharejs_doc || editor.opening) &&
|
||||
@@ -22,12 +24,12 @@ export const EditorPane: FC<{ show: boolean }> = ({ show }) => {
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="ide-react-editor-content full-size">
|
||||
<PanelGroup
|
||||
autoSaveId="ide-editor-layout"
|
||||
direction="vertical"
|
||||
className={classNames({ hidden: !show })}
|
||||
>
|
||||
<div
|
||||
className={classNames('ide-react-editor-content', 'full-size', {
|
||||
hidden: openEntity?.type !== 'doc' || selectedEntityCount !== 1,
|
||||
})}
|
||||
>
|
||||
<PanelGroup autoSaveId="ide-editor-layout" direction="vertical">
|
||||
<Panel
|
||||
id="panel-source-editor"
|
||||
order={1}
|
||||
@@ -43,9 +45,9 @@ export const EditorPane: FC<{ show: boolean }> = ({ show }) => {
|
||||
<Panel
|
||||
id="panel-symbol-palette"
|
||||
order={2}
|
||||
defaultSizePixels={250}
|
||||
minSizePixels={250}
|
||||
maxSizePixels={336}
|
||||
defaultSize={25}
|
||||
minSize={10}
|
||||
maxSize={50}
|
||||
>
|
||||
<Suspense fallback={<FullSizeLoadingSpinner delay={500} />}>
|
||||
<SymbolPalettePane />
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
import FileTreeRoot from '@/features/file-tree/components/file-tree-root'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useUserContext } from '@/shared/context/user-context'
|
||||
import { useReferencesContext } from '@/features/ide-react/context/references-context'
|
||||
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
|
||||
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import {
|
||||
FileTreeDeleteHandler,
|
||||
FileTreeSelectHandler,
|
||||
} from '@/features/ide-react/types/file-tree'
|
||||
import { RefProviders } from '../../../../../types/user'
|
||||
import FileTreeRoot from '@/features/file-tree/components/file-tree-root'
|
||||
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
|
||||
|
||||
type FileTreeProps = {
|
||||
onInit: () => void
|
||||
onSelect: FileTreeSelectHandler
|
||||
onDelete: FileTreeDeleteHandler
|
||||
}
|
||||
|
||||
export function FileTree({ onInit, onSelect, onDelete }: FileTreeProps) {
|
||||
export function FileTree() {
|
||||
const user = useUserContext()
|
||||
const { indexAllReferences } = useReferencesContext()
|
||||
const { setStartedFreeTrial } = useIdeReactContext()
|
||||
const { isConnected } = useConnectionContext()
|
||||
const { handleFileTreeInit, handleFileTreeSelect, handleFileTreeDelete } =
|
||||
useFileTreeOpenContext()
|
||||
|
||||
const [refProviders, setRefProviders] = useState<RefProviders>(
|
||||
() => user.refProviders || {}
|
||||
@@ -45,9 +38,9 @@ export function FileTree({ onInit, onSelect, onDelete }: FileTreeProps) {
|
||||
setRefProviderEnabled={setRefProviderEnabled}
|
||||
setStartedFreeTrial={setStartedFreeTrial}
|
||||
isConnected={isConnected}
|
||||
onInit={onInit}
|
||||
onSelect={onSelect}
|
||||
onDelete={onDelete}
|
||||
onInit={handleFileTreeInit}
|
||||
onSelect={handleFileTreeSelect}
|
||||
onDelete={handleFileTreeDelete}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -11,11 +11,11 @@ import { HistoryProvider } from '@/features/history/context/history-context'
|
||||
import History from '@/features/ide-react/components/history'
|
||||
import EditorSidebar from '@/features/ide-react/components/editor-sidebar'
|
||||
import { EditorPane } from '@/features/ide-react/components/editor/editor-pane'
|
||||
import { useFileTree } from '@/features/ide-react/hooks/use-file-tree'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSidebarPane } from '@/features/ide-react/hooks/use-sidebar-pane'
|
||||
import { useChatPane } from '@/features/ide-react/hooks/use-chat-pane'
|
||||
import { EditorAndPdf } from '@/features/ide-react/components/editor-and-pdf'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
|
||||
export const MainLayout: FC = () => {
|
||||
const { view } = useLayoutContext()
|
||||
@@ -43,23 +43,12 @@ export const MainLayout: FC = () => {
|
||||
handlePaneExpand: handleChatExpand,
|
||||
} = useChatPane()
|
||||
|
||||
const {
|
||||
selectedEntityCount,
|
||||
openEntity,
|
||||
openDocId,
|
||||
handleFileTreeInit,
|
||||
handleFileTreeSelect,
|
||||
handleFileTreeDelete,
|
||||
} = useFileTree()
|
||||
const { currentDocumentId } = useEditorManagerContext()
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
// keep the editor pane open
|
||||
const editorPane = openDocId ? (
|
||||
<EditorPane
|
||||
show={openEntity?.type === 'doc' && selectedEntityCount === 1}
|
||||
/>
|
||||
) : null
|
||||
// keep the editor pane open when a doc is open, even if the history view is open
|
||||
const editorPane = currentDocumentId ? <EditorPane /> : null
|
||||
|
||||
return (
|
||||
<div className="ide-react-main">
|
||||
@@ -78,18 +67,14 @@ export const MainLayout: FC = () => {
|
||||
ref={sidebarPanelRef}
|
||||
id="panel-sidebar"
|
||||
order={1}
|
||||
defaultSizePixels={200}
|
||||
minSizePixels={150}
|
||||
defaultSize={10}
|
||||
minSize={10}
|
||||
maxSize={30}
|
||||
collapsible
|
||||
onCollapse={handleSidebarCollapse}
|
||||
onExpand={handleSidebarExpand}
|
||||
>
|
||||
<EditorSidebar
|
||||
shouldShow={view !== 'history'}
|
||||
onFileTreeInit={handleFileTreeInit}
|
||||
onFileTreeSelect={handleFileTreeSelect}
|
||||
onFileTreeDelete={handleFileTreeDelete}
|
||||
/>
|
||||
<EditorSidebar />
|
||||
{view === 'history' && <HistorySidebar />}
|
||||
</Panel>
|
||||
|
||||
@@ -120,11 +105,7 @@ export const MainLayout: FC = () => {
|
||||
<History />
|
||||
</HistoryProvider>
|
||||
) : (
|
||||
<EditorAndPdf
|
||||
editorPane={editorPane}
|
||||
selectedEntityCount={selectedEntityCount}
|
||||
openEntity={openEntity}
|
||||
/>
|
||||
<EditorAndPdf editorPane={editorPane} />
|
||||
)}
|
||||
</Panel>
|
||||
|
||||
@@ -139,8 +120,9 @@ export const MainLayout: FC = () => {
|
||||
ref={chatPanelRef}
|
||||
id="panel-chat"
|
||||
order={2}
|
||||
defaultSizePixels={200}
|
||||
minSizePixels={150}
|
||||
defaultSize={20}
|
||||
minSize={10}
|
||||
maxSize={30}
|
||||
collapsible
|
||||
onCollapse={handleChatCollapse}
|
||||
onExpand={handleChatExpand}
|
||||
|
||||
+7
-1
@@ -1,13 +1,19 @@
|
||||
import { PanelResizeHandle } from 'react-resizable-panels'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { PanelResizeHandleProps } from 'react-resizable-panels/dist/declarations/src/PanelResizeHandle'
|
||||
import classNames from 'classnames'
|
||||
|
||||
export function VerticalResizeHandle(props: PanelResizeHandleProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<PanelResizeHandle {...props}>
|
||||
<div className="vertical-resize-handle" title={t('resize')} />
|
||||
<div
|
||||
className={classNames('vertical-resize-handle', {
|
||||
'vertical-resize-handle-enabled': !props.disabled,
|
||||
})}
|
||||
title={t('resize')}
|
||||
/>
|
||||
</PanelResizeHandle>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user