mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[ide-react] Tidy IDE page layout components (#15953)
* Defer script loading * Refactor loading * Wait for project:joined * Only mount IdePage once everything has connected * Add useConnectionState hook and comments * Remove placeholder components * Move props into EditorAndSidebar * Move props into MainLayout * Tidy editor and sidebar components * Lazy-load the symbol palette pane and separate the loading pane GitOrigin-RevId: 4b721a06d6aba0ae0ec91768e6a6e29cf15e2083
This commit is contained in:
parent
a4ca117640
commit
23593f8650
24 changed files with 206 additions and 575 deletions
|
@ -14,14 +14,10 @@ import { DefaultSynctexControl } from '@/features/pdf-preview/components/detach-
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
export type EditorProps = {
|
export type EditorProps = {
|
||||||
shouldPersistLayout?: boolean
|
|
||||||
editorContent: ReactNode
|
editorContent: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EditorAndPdf({
|
export default function EditorAndPdf({ editorContent }: EditorProps) {
|
||||||
shouldPersistLayout = false,
|
|
||||||
editorContent,
|
|
||||||
}: EditorProps) {
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { view, pdfLayout, changeLayout, detachRole, reattach } =
|
const { view, pdfLayout, changeLayout, detachRole, reattach } =
|
||||||
useLayoutContext()
|
useLayoutContext()
|
||||||
|
@ -49,9 +45,7 @@ export default function EditorAndPdf({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelGroup
|
<PanelGroup
|
||||||
autoSaveId={
|
autoSaveId="ide-react-editor-and-pdf-layout"
|
||||||
shouldPersistLayout ? 'ide-react-editor-and-pdf-layout' : undefined
|
|
||||||
}
|
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
className={classnames('ide-react-editor-and-pdf', {
|
className={classnames('ide-react-editor-and-pdf', {
|
||||||
hide: historyIsOpen,
|
hide: historyIsOpen,
|
||||||
|
|
|
@ -26,12 +26,6 @@ import { BinaryFile } from '@/features/file-view/types/binary-file'
|
||||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||||
import { useSelectFileTreeEntity } from '@/features/ide-react/hooks/use-select-file-tree-entity'
|
import { useSelectFileTreeEntity } from '@/features/ide-react/hooks/use-select-file-tree-entity'
|
||||||
|
|
||||||
type EditorAndSidebarProps = {
|
|
||||||
shouldPersistLayout: boolean
|
|
||||||
leftColumnDefaultSize: number
|
|
||||||
setLeftColumnDefaultSize: React.Dispatch<React.SetStateAction<number>>
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertFileRefToBinaryFile(fileRef: FileRef): BinaryFile {
|
function convertFileRefToBinaryFile(fileRef: FileRef): BinaryFile {
|
||||||
return {
|
return {
|
||||||
_id: fileRef._id,
|
_id: fileRef._id,
|
||||||
|
@ -58,11 +52,8 @@ function fileViewFile(fileRef: FileRef) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EditorAndSidebar({
|
export function EditorAndSidebar() {
|
||||||
shouldPersistLayout,
|
const [leftColumnDefaultSize, setLeftColumnDefaultSize] = useState(20)
|
||||||
leftColumnDefaultSize,
|
|
||||||
setLeftColumnDefaultSize,
|
|
||||||
}: EditorAndSidebarProps) {
|
|
||||||
const [leftColumnIsOpen, setLeftColumnIsOpen] = useState(true)
|
const [leftColumnIsOpen, setLeftColumnIsOpen] = useState(true)
|
||||||
const { rootDocId } = useProjectContext()
|
const { rootDocId } = useProjectContext()
|
||||||
const { eventEmitter } = useIdeReactContext()
|
const { eventEmitter } = useIdeReactContext()
|
||||||
|
@ -75,9 +66,6 @@ export function EditorAndSidebar({
|
||||||
const { projectJoined } = useIdeReactContext()
|
const { projectJoined } = useIdeReactContext()
|
||||||
const { selectEntity } = useSelectFileTreeEntity()
|
const { selectEntity } = useSelectFileTreeEntity()
|
||||||
const [, setOpenFile] = useScopeValue<BinaryFile | null>('openFile')
|
const [, setOpenFile] = useScopeValue<BinaryFile | null>('openFile')
|
||||||
|
|
||||||
const historyIsOpen = view === 'history'
|
|
||||||
|
|
||||||
const [openEntity, setOpenEntity] = useState<
|
const [openEntity, setOpenEntity] = useState<
|
||||||
FileTreeDocumentFindResult | FileTreeFileRefFindResult | null
|
FileTreeDocumentFindResult | FileTreeFileRefFindResult | null
|
||||||
>(null)
|
>(null)
|
||||||
|
@ -157,40 +145,49 @@ export function EditorAndSidebar({
|
||||||
}
|
}
|
||||||
}, [fileTreeReady, openInitialDoc, projectJoined, rootDocId])
|
}, [fileTreeReady, openInitialDoc, projectJoined, rootDocId])
|
||||||
|
|
||||||
// Keep the editor file tree around so that it is available and up to date
|
// Keep the editor file tree around so that it is available and up to date when restoring a file
|
||||||
// when restoring a file
|
const editorSidebar = (
|
||||||
const leftColumnContent = (
|
|
||||||
<>
|
|
||||||
<EditorSidebar
|
<EditorSidebar
|
||||||
shouldShow={!historyIsOpen}
|
shouldShow={view !== 'history'}
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
onFileTreeInit={handleFileTreeInit}
|
onFileTreeInit={handleFileTreeInit}
|
||||||
onFileTreeSelect={handleFileTreeSelect}
|
onFileTreeSelect={handleFileTreeSelect}
|
||||||
onFileTreeDelete={handleFileTreeDelete}
|
onFileTreeDelete={handleFileTreeDelete}
|
||||||
/>
|
/>
|
||||||
{historyIsOpen ? <HistorySidebar /> : null}
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let rightColumnContent
|
if (view === 'history') {
|
||||||
|
return (
|
||||||
if (historyIsOpen) {
|
<TwoColumnMainContent
|
||||||
rightColumnContent = (
|
leftColumnId="editor-left-column"
|
||||||
|
leftColumnContent={
|
||||||
|
<>
|
||||||
|
{editorSidebar}
|
||||||
|
<HistorySidebar />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
leftColumnDefaultSize={leftColumnDefaultSize}
|
||||||
|
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
||||||
|
rightColumnContent={
|
||||||
<HistoryProvider>
|
<HistoryProvider>
|
||||||
<History />
|
<History />
|
||||||
</HistoryProvider>
|
</HistoryProvider>
|
||||||
|
}
|
||||||
|
leftColumnIsOpen={leftColumnIsOpen}
|
||||||
|
setLeftColumnIsOpen={setLeftColumnIsOpen}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
let editorContent = null
|
|
||||||
|
|
||||||
// Always have the editor mounted when not in history view, and hide and
|
// Always have the editor mounted when not in history view, and hide and
|
||||||
// show it as necessary
|
// show it as necessary
|
||||||
const editorPane = (
|
const editorPane = (
|
||||||
<EditorPane
|
<EditorPane
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
show={openEntity?.type === 'doc' && selectedEntityCount === 1}
|
show={openEntity?.type === 'doc' && selectedEntityCount === 1}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let rightColumnContent
|
||||||
|
|
||||||
if (openDocId === undefined) {
|
if (openDocId === undefined) {
|
||||||
rightColumnContent = <NoOpenDocPane />
|
rightColumnContent = <NoOpenDocPane />
|
||||||
} else if (selectedEntityCount === 0) {
|
} else if (selectedEntityCount === 0) {
|
||||||
|
@ -201,44 +198,40 @@ export function EditorAndSidebar({
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
} else if (selectedEntityCount > 1) {
|
} else if (selectedEntityCount > 1) {
|
||||||
editorContent = (
|
rightColumnContent = (
|
||||||
|
<EditorAndPdf
|
||||||
|
editorContent={
|
||||||
<>
|
<>
|
||||||
{editorPane}
|
{editorPane}
|
||||||
<MultipleSelectionPane selectedEntityCount={selectedEntityCount} />
|
<MultipleSelectionPane selectedEntityCount={selectedEntityCount} />
|
||||||
</>
|
</>
|
||||||
)
|
|
||||||
} else if (openEntity) {
|
|
||||||
editorContent =
|
|
||||||
openEntity.type === 'doc' ? (
|
|
||||||
editorPane
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{editorPane}
|
|
||||||
<FileView file={fileViewFile(openEntity.entity)} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editorContent) {
|
|
||||||
rightColumnContent = (
|
|
||||||
<EditorAndPdf
|
|
||||||
editorContent={editorContent}
|
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
} else if (openEntity) {
|
||||||
|
rightColumnContent = (
|
||||||
|
<EditorAndPdf
|
||||||
|
editorContent={
|
||||||
|
<>
|
||||||
|
{editorPane}
|
||||||
|
{openEntity.type !== 'doc' && (
|
||||||
|
<FileView file={fileViewFile(openEntity.entity)} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TwoColumnMainContent
|
<TwoColumnMainContent
|
||||||
leftColumnId="editor-left-column"
|
leftColumnId="editor-left-column"
|
||||||
leftColumnContent={leftColumnContent}
|
leftColumnContent={editorSidebar}
|
||||||
leftColumnDefaultSize={leftColumnDefaultSize}
|
leftColumnDefaultSize={leftColumnDefaultSize}
|
||||||
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
||||||
rightColumnContent={rightColumnContent}
|
rightColumnContent={rightColumnContent}
|
||||||
leftColumnIsOpen={leftColumnIsOpen}
|
leftColumnIsOpen={leftColumnIsOpen}
|
||||||
setLeftColumnIsOpen={setLeftColumnIsOpen}
|
setLeftColumnIsOpen={setLeftColumnIsOpen}
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,31 +9,26 @@ import {
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
type EditorSidebarProps = {
|
type EditorSidebarProps = {
|
||||||
shouldShow: boolean
|
shouldShow?: boolean
|
||||||
shouldPersistLayout: boolean
|
|
||||||
onFileTreeInit: () => void
|
onFileTreeInit: () => void
|
||||||
onFileTreeSelect: FileTreeSelectHandler
|
onFileTreeSelect: FileTreeSelectHandler
|
||||||
onFileTreeDelete: FileTreeDeleteHandler
|
onFileTreeDelete: FileTreeDeleteHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EditorSidebar({
|
export default function EditorSidebar({
|
||||||
shouldShow,
|
shouldShow = false,
|
||||||
shouldPersistLayout,
|
|
||||||
onFileTreeInit,
|
onFileTreeInit,
|
||||||
onFileTreeSelect,
|
onFileTreeSelect,
|
||||||
onFileTreeDelete,
|
onFileTreeDelete,
|
||||||
}: EditorSidebarProps) {
|
}: EditorSidebarProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<aside
|
<aside
|
||||||
className={classNames('ide-react-editor-sidebar', {
|
className={classNames('ide-react-editor-sidebar', {
|
||||||
hidden: !shouldShow,
|
hidden: !shouldShow,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<PanelGroup
|
<PanelGroup
|
||||||
autoSaveId={
|
autoSaveId="ide-react-editor-sidebar-layout"
|
||||||
shouldPersistLayout ? 'ide-react-editor-sidebar-layout' : undefined
|
|
||||||
}
|
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
>
|
>
|
||||||
<Panel defaultSize={75} className="ide-react-file-tree-panel">
|
<Panel defaultSize={75} className="ide-react-file-tree-panel">
|
||||||
|
@ -49,6 +44,5 @@ export default function EditorSidebar({
|
||||||
</Panel>
|
</Panel>
|
||||||
</PanelGroup>
|
</PanelGroup>
|
||||||
</aside>
|
</aside>
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +1,39 @@
|
||||||
import { Panel, PanelGroup } from 'react-resizable-panels'
|
import { Panel, PanelGroup } from 'react-resizable-panels'
|
||||||
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
|
import React, { FC, lazy, Suspense } from 'react'
|
||||||
import React, { ElementType } from 'react'
|
|
||||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||||
import SourceEditor from '@/features/source-editor/components/source-editor'
|
import SourceEditor from '@/features/source-editor/components/source-editor'
|
||||||
import { EditorScopeValue } 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 classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useTranslation } from 'react-i18next'
|
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'
|
||||||
|
|
||||||
const symbolPaletteComponents = importOverleafModules(
|
const SymbolPalettePane = lazy(
|
||||||
'sourceEditorSymbolPalette'
|
() => import('@/features/ide-react/components/editor/symbol-palette-pane')
|
||||||
) as { import: { default: ElementType }; path: string }[]
|
)
|
||||||
|
|
||||||
export type EditorPaneProps = {
|
export const EditorPane: FC<{ show: boolean }> = ({ show }) => {
|
||||||
shouldPersistLayout?: boolean
|
|
||||||
show: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EditorPane({ shouldPersistLayout, show }: EditorPaneProps) {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [editor] = useScopeValue<EditorScopeValue>('editor')
|
const [editor] = useScopeValue<EditorScopeValue>('editor')
|
||||||
|
|
||||||
|
const isLoading = Boolean(
|
||||||
|
(!editor.sharejs_doc || editor.opening) &&
|
||||||
|
!editor.error_state &&
|
||||||
|
editor.open_doc_id
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelGroup
|
<PanelGroup
|
||||||
autoSaveId={
|
autoSaveId="ide-react-editor-and-symbol-palette-layout"
|
||||||
shouldPersistLayout
|
|
||||||
? 'ide-react-editor-and-symbol-palette-layout'
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
units="pixels"
|
units="pixels"
|
||||||
className={classNames({ hidden: !show })}
|
className={classNames({ hidden: !show })}
|
||||||
>
|
>
|
||||||
<Panel
|
<Panel id="sourceEditor" order={1} className="ide-react-editor-panel">
|
||||||
id="sourceEditor"
|
|
||||||
order={1}
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SourceEditor />
|
<SourceEditor />
|
||||||
{(!editor.sharejs_doc || editor.opening) &&
|
{isLoading && <LoadingPane />}
|
||||||
!editor.error_state &&
|
|
||||||
!!editor.open_doc_id ? (
|
|
||||||
<div className="loading-panel">
|
|
||||||
<span>
|
|
||||||
<i className="fa fa-spin fa-refresh" />
|
|
||||||
{t('loading')}…
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</Panel>
|
</Panel>
|
||||||
{editor.showSymbolPalette ? (
|
|
||||||
|
{editor.showSymbolPalette && (
|
||||||
<>
|
<>
|
||||||
<VerticalResizeHandle id="editor-symbol-palette" />
|
<VerticalResizeHandle id="editor-symbol-palette" />
|
||||||
<Panel
|
<Panel
|
||||||
|
@ -62,16 +43,12 @@ export function EditorPane({ shouldPersistLayout, show }: EditorPaneProps) {
|
||||||
minSize={250}
|
minSize={250}
|
||||||
maxSize={336}
|
maxSize={336}
|
||||||
>
|
>
|
||||||
<div className="ide-react-symbol-palette">
|
<Suspense fallback={<FullSizeLoadingSpinner delay={500} />}>
|
||||||
{symbolPaletteComponents.map(
|
<SymbolPalettePane />
|
||||||
({ import: { default: Component }, path }) => (
|
</Suspense>
|
||||||
<Component key={path} />
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Panel>
|
</Panel>
|
||||||
</>
|
</>
|
||||||
) : null}
|
)}
|
||||||
</PanelGroup>
|
</PanelGroup>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
export const LoadingPane: FC = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="loading-panel">
|
||||||
|
<span>
|
||||||
|
<i className="fa fa-spin fa-refresh" />
|
||||||
|
{t('loading')}…
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React, { ElementType, FC } from 'react'
|
||||||
|
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||||
|
|
||||||
|
const symbolPaletteComponents = importOverleafModules(
|
||||||
|
'sourceEditorSymbolPalette'
|
||||||
|
) as { import: { default: ElementType }; path: string }[]
|
||||||
|
|
||||||
|
const SymbolPalettePane: FC = () => {
|
||||||
|
return (
|
||||||
|
<div className="ide-react-symbol-palette">
|
||||||
|
{symbolPaletteComponents.map(
|
||||||
|
({ import: { default: Component }, path }) => (
|
||||||
|
<Component key={path} />
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SymbolPalettePane
|
|
@ -1,71 +1,28 @@
|
||||||
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { Alerts } from '@/features/ide-react/components/alerts/alerts'
|
import { Alerts } from '@/features/ide-react/components/alerts/alerts'
|
||||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
|
||||||
import MainLayout from '@/features/ide-react/components/layout/main-layout'
|
import MainLayout from '@/features/ide-react/components/layout/main-layout'
|
||||||
import { EditorAndSidebar } from '@/features/ide-react/components/editor-and-sidebar'
|
|
||||||
import EditorLeftMenu from '@/features/editor-left-menu/components/editor-left-menu'
|
import EditorLeftMenu from '@/features/editor-left-menu/components/editor-left-menu'
|
||||||
import EditorNavigationToolbar from '@/features/ide-react/components/editor-navigation-toolbar'
|
|
||||||
import ChatPane from '@/features/chat/components/chat-pane'
|
|
||||||
import { useLayoutEventTracking } from '@/features/ide-react/hooks/use-layout-event-tracking'
|
import { useLayoutEventTracking } from '@/features/ide-react/hooks/use-layout-event-tracking'
|
||||||
import useSocketListeners from '@/features/ide-react/hooks/use-socket-listeners'
|
import useSocketListeners from '@/features/ide-react/hooks/use-socket-listeners'
|
||||||
import { useModalsContext } from '@/features/ide-react/context/modals-context'
|
|
||||||
import { useOpenFile } from '@/features/ide-react/hooks/use-open-file'
|
import { useOpenFile } from '@/features/ide-react/hooks/use-open-file'
|
||||||
import { useEditingSessionHeartbeat } from '@/features/ide-react/hooks/use-editing-session-heartbeat'
|
import { useEditingSessionHeartbeat } from '@/features/ide-react/hooks/use-editing-session-heartbeat'
|
||||||
import { useRegisterUserActivity } from '@/features/ide-react/hooks/use-register-user-activity'
|
import { useRegisterUserActivity } from '@/features/ide-react/hooks/use-register-user-activity'
|
||||||
import { useHasLintingError } from '@/features/ide-react/hooks/use-has-linting-error'
|
import { useHasLintingError } from '@/features/ide-react/hooks/use-has-linting-error'
|
||||||
|
import { useConnectionState } from '@/features/ide-react/hooks/use-connection-state'
|
||||||
|
|
||||||
// This is filled with placeholder content while the real content is migrated
|
|
||||||
// away from Angular
|
|
||||||
export default function IdePage() {
|
export default function IdePage() {
|
||||||
useLayoutEventTracking()
|
useLayoutEventTracking() // send event when the layout changes
|
||||||
useSocketListeners()
|
useSocketListeners() // listen for project-related websocket messages
|
||||||
useEditingSessionHeartbeat()
|
useEditingSessionHeartbeat() // send a batched event when user is active
|
||||||
useRegisterUserActivity()
|
useRegisterUserActivity() // record activity and ensure connection when user is active
|
||||||
useHasLintingError()
|
useHasLintingError() // pass editor:lint hasLintingError to the compiler
|
||||||
|
useOpenFile() // create ide.binaryFilesManager (TODO: move to the history file restore component)
|
||||||
// This returns a function to open a binary file but for now we just use the
|
useConnectionState() // show modal when editor is forcefully disconnected
|
||||||
// fact that it also patches in ide.binaryFilesManager. Once Angular is gone,
|
|
||||||
// we can remove this hook from here and use it in the history file restore
|
|
||||||
// component instead.
|
|
||||||
useOpenFile()
|
|
||||||
|
|
||||||
const [leftColumnDefaultSize, setLeftColumnDefaultSize] = useState(20)
|
|
||||||
const { connectionState } = useConnectionContext()
|
|
||||||
const { showLockEditorMessageModal } = useModalsContext()
|
|
||||||
|
|
||||||
// Show modal when editor is forcefully disconnected
|
|
||||||
useEffect(() => {
|
|
||||||
if (connectionState.forceDisconnected) {
|
|
||||||
showLockEditorMessageModal(connectionState.forcedDisconnectDelay)
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
connectionState.forceDisconnected,
|
|
||||||
connectionState.forcedDisconnectDelay,
|
|
||||||
showLockEditorMessageModal,
|
|
||||||
])
|
|
||||||
|
|
||||||
const { chatIsOpen } = useLayoutContext()
|
|
||||||
|
|
||||||
const mainContent = (
|
|
||||||
<EditorAndSidebar
|
|
||||||
leftColumnDefaultSize={leftColumnDefaultSize}
|
|
||||||
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
|
||||||
shouldPersistLayout
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Alerts />
|
<Alerts />
|
||||||
<EditorLeftMenu />
|
<EditorLeftMenu />
|
||||||
<MainLayout
|
<MainLayout />
|
||||||
headerContent={<EditorNavigationToolbar />}
|
|
||||||
chatContent={<ChatPane />}
|
|
||||||
mainContent={mainContent}
|
|
||||||
chatIsOpen={chatIsOpen}
|
|
||||||
shouldPersistLayout
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
import { useState } from 'react'
|
|
||||||
import PlaceholderHeader from '@/features/ide-react/components/layout/placeholder/placeholder-header'
|
|
||||||
import PlaceholderChat from '@/features/ide-react/components/layout/placeholder/placeholder-chat'
|
|
||||||
import PlaceholderHistory from '@/features/ide-react/components/layout/placeholder/placeholder-history'
|
|
||||||
import PlaceholderEditorMainContent from '@/features/ide-react/components/layout/placeholder/placeholder-editor-main-content'
|
|
||||||
import MainLayout from '@/features/ide-react/components/layout/main-layout'
|
|
||||||
|
|
||||||
export default function LayoutWithPlaceholders({
|
|
||||||
shouldPersistLayout,
|
|
||||||
}: {
|
|
||||||
shouldPersistLayout: boolean
|
|
||||||
}) {
|
|
||||||
const [chatIsOpen, setChatIsOpen] = useState(false)
|
|
||||||
const [historyIsOpen, setHistoryIsOpen] = useState(false)
|
|
||||||
const [leftColumnDefaultSize, setLeftColumnDefaultSize] = useState(20)
|
|
||||||
|
|
||||||
const headerContent = (
|
|
||||||
<PlaceholderHeader
|
|
||||||
chatIsOpen={chatIsOpen}
|
|
||||||
setChatIsOpen={setChatIsOpen}
|
|
||||||
historyIsOpen={historyIsOpen}
|
|
||||||
setHistoryIsOpen={setHistoryIsOpen}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
const chatContent = <PlaceholderChat />
|
|
||||||
const mainContent = historyIsOpen ? (
|
|
||||||
<PlaceholderHistory
|
|
||||||
shouldPersistLayout
|
|
||||||
leftColumnDefaultSize={leftColumnDefaultSize}
|
|
||||||
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<PlaceholderEditorMainContent
|
|
||||||
shouldPersistLayout
|
|
||||||
leftColumnDefaultSize={leftColumnDefaultSize}
|
|
||||||
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MainLayout
|
|
||||||
headerContent={headerContent}
|
|
||||||
chatContent={chatContent}
|
|
||||||
mainContent={mainContent}
|
|
||||||
chatIsOpen={chatIsOpen}
|
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,31 +1,23 @@
|
||||||
import { Panel, PanelGroup } from 'react-resizable-panels'
|
import { Panel, PanelGroup } from 'react-resizable-panels'
|
||||||
import { ReactNode, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { HorizontalResizeHandle } from '../resize/horizontal-resize-handle'
|
import { HorizontalResizeHandle } from '../resize/horizontal-resize-handle'
|
||||||
import useFixedSizeColumn from '@/features/ide-react/hooks/use-fixed-size-column'
|
import useFixedSizeColumn from '@/features/ide-react/hooks/use-fixed-size-column'
|
||||||
import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
|
import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||||
|
import EditorNavigationToolbar from '@/features/ide-react/components/editor-navigation-toolbar'
|
||||||
|
import ChatPane from '@/features/chat/components/chat-pane'
|
||||||
|
import { EditorAndSidebar } from '@/features/ide-react/components/editor-and-sidebar'
|
||||||
|
|
||||||
const CHAT_DEFAULT_SIZE = 20
|
const CHAT_DEFAULT_SIZE = 20
|
||||||
|
|
||||||
type PageProps = {
|
|
||||||
headerContent: ReactNode
|
|
||||||
chatContent: ReactNode
|
|
||||||
mainContent: ReactNode
|
|
||||||
chatIsOpen: boolean
|
|
||||||
shouldPersistLayout: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// The main area below the header is split into two: the main content and chat.
|
// The main area below the header is split into two: the main content and chat.
|
||||||
// The reason for not splitting the left column containing the file tree and
|
// The reason for not splitting the left column containing the file tree and
|
||||||
// outline here is that the history view has its own file tree, so it is more
|
// outline here is that the history view has its own file tree, so it is more
|
||||||
// convenient to replace the whole of the main content when in history view.
|
// convenient to replace the whole of the main content when in history view.
|
||||||
export default function MainLayout({
|
export default function MainLayout() {
|
||||||
headerContent,
|
const { chatIsOpen } = useLayoutContext()
|
||||||
chatContent,
|
|
||||||
mainContent,
|
|
||||||
chatIsOpen,
|
|
||||||
shouldPersistLayout,
|
|
||||||
}: PageProps) {
|
|
||||||
const { fixedPanelRef: chatPanelRef, handleLayout } = useFixedSizeColumn(
|
const { fixedPanelRef: chatPanelRef, handleLayout } = useFixedSizeColumn(
|
||||||
CHAT_DEFAULT_SIZE,
|
CHAT_DEFAULT_SIZE,
|
||||||
chatIsOpen
|
chatIsOpen
|
||||||
|
@ -37,10 +29,10 @@ export default function MainLayout({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ide-react-main">
|
<div className="ide-react-main">
|
||||||
{headerContent}
|
<EditorNavigationToolbar />
|
||||||
<div className="ide-react-body">
|
<div className="ide-react-body">
|
||||||
<PanelGroup
|
<PanelGroup
|
||||||
autoSaveId={shouldPersistLayout ? 'ide-react-chat-layout' : undefined}
|
autoSaveId="ide-react-chat-layout"
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
onLayout={handleLayout}
|
onLayout={handleLayout}
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
@ -48,7 +40,7 @@ export default function MainLayout({
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Panel id="main" order={1}>
|
<Panel id="main" order={1}>
|
||||||
{mainContent}
|
<EditorAndSidebar />
|
||||||
</Panel>
|
</Panel>
|
||||||
{chatIsOpen ? (
|
{chatIsOpen ? (
|
||||||
<>
|
<>
|
||||||
|
@ -61,7 +53,7 @@ export default function MainLayout({
|
||||||
minSize={5}
|
minSize={5}
|
||||||
collapsible
|
collapsible
|
||||||
>
|
>
|
||||||
{chatContent}
|
<ChatPane />
|
||||||
</Panel>
|
</Panel>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export default function PlaceholderChat() {
|
|
||||||
return (
|
|
||||||
<aside className="chat ide-react-placeholder-chat">Chat placeholder</aside>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
import React, { useRef, useState } 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 { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
|
|
||||||
import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
|
|
||||||
|
|
||||||
type PlaceholderEditorAndPdfProps = {
|
|
||||||
shouldPersistLayout?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PlaceholderEditorAndPdf({
|
|
||||||
shouldPersistLayout = false,
|
|
||||||
}: PlaceholderEditorAndPdfProps) {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [pdfIsOpen, setPdfIsOpen] = useState(false)
|
|
||||||
const [symbolPaletteIsOpen, setSymbolPaletteIsOpen] = useState(false)
|
|
||||||
|
|
||||||
const pdfPanelRef = useRef<ImperativePanelHandle>(null)
|
|
||||||
useCollapsiblePanel(pdfIsOpen, pdfPanelRef)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PanelGroup
|
|
||||||
autoSaveId={
|
|
||||||
shouldPersistLayout ? 'ide-react-editor-and-pdf-layout' : undefined
|
|
||||||
}
|
|
||||||
direction="horizontal"
|
|
||||||
>
|
|
||||||
<Panel defaultSize={50}>
|
|
||||||
<PanelGroup
|
|
||||||
autoSaveId={
|
|
||||||
shouldPersistLayout
|
|
||||||
? 'ide-react-editor-and-symbol-palette-layout'
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
direction="vertical"
|
|
||||||
units="pixels"
|
|
||||||
>
|
|
||||||
<Panel id="editor" order={1}>
|
|
||||||
Editor placeholder
|
|
||||||
<br />
|
|
||||||
<button onClick={() => setSymbolPaletteIsOpen(value => !value)}>
|
|
||||||
Toggle symbol palette
|
|
||||||
</button>
|
|
||||||
</Panel>
|
|
||||||
{symbolPaletteIsOpen ? (
|
|
||||||
<>
|
|
||||||
<VerticalResizeHandle id="editor-symbol-palette" />
|
|
||||||
<Panel
|
|
||||||
id="symbol-palette"
|
|
||||||
order={2}
|
|
||||||
defaultSize={250}
|
|
||||||
minSize={250}
|
|
||||||
maxSize={336}
|
|
||||||
>
|
|
||||||
<div className="ide-react-symbol-palette ">
|
|
||||||
Symbol palette placeholder
|
|
||||||
</div>
|
|
||||||
</Panel>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</PanelGroup>
|
|
||||||
</Panel>
|
|
||||||
<HorizontalResizeHandle onDoubleClick={() => setPdfIsOpen(!pdfIsOpen)}>
|
|
||||||
<HorizontalToggler
|
|
||||||
id="editor-pdf"
|
|
||||||
togglerType="east"
|
|
||||||
isOpen={pdfIsOpen}
|
|
||||||
setIsOpen={setPdfIsOpen}
|
|
||||||
tooltipWhenOpen={t('tooltip_hide_pdf')}
|
|
||||||
tooltipWhenClosed={t('tooltip_show_pdf')}
|
|
||||||
/>
|
|
||||||
</HorizontalResizeHandle>
|
|
||||||
<Panel
|
|
||||||
ref={pdfPanelRef}
|
|
||||||
defaultSize={50}
|
|
||||||
minSize={5}
|
|
||||||
collapsible
|
|
||||||
onCollapse={collapsed => setPdfIsOpen(!collapsed)}
|
|
||||||
>
|
|
||||||
PDF placeholder
|
|
||||||
</Panel>
|
|
||||||
</PanelGroup>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import React, { useState } from 'react'
|
|
||||||
import TwoColumnMainContent from '@/features/ide-react/components/layout/two-column-main-content'
|
|
||||||
import PlaceholderEditorAndPdf from '@/features/ide-react/components/layout/placeholder/placeholder-editor-and-pdf'
|
|
||||||
import PlaceholderEditorSidebar from '@/features/ide-react/components/layout/placeholder/placeholder-editor-sidebar'
|
|
||||||
|
|
||||||
type PlaceholderEditorMainContentProps = {
|
|
||||||
shouldPersistLayout: boolean
|
|
||||||
leftColumnDefaultSize: number
|
|
||||||
setLeftColumnDefaultSize: React.Dispatch<React.SetStateAction<number>>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PlaceholderEditorMainContent({
|
|
||||||
shouldPersistLayout,
|
|
||||||
leftColumnDefaultSize,
|
|
||||||
setLeftColumnDefaultSize,
|
|
||||||
}: PlaceholderEditorMainContentProps) {
|
|
||||||
const [leftColumnIsOpen, setLeftColumnIsOpen] = useState(true)
|
|
||||||
|
|
||||||
const leftColumnContent = (
|
|
||||||
<PlaceholderEditorSidebar shouldPersistLayout={shouldPersistLayout} />
|
|
||||||
)
|
|
||||||
const rightColumnContent = (
|
|
||||||
<PlaceholderEditorAndPdf shouldPersistLayout={shouldPersistLayout} />
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TwoColumnMainContent
|
|
||||||
leftColumnId="editor-left-column"
|
|
||||||
leftColumnContent={leftColumnContent}
|
|
||||||
leftColumnDefaultSize={leftColumnDefaultSize}
|
|
||||||
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
|
||||||
rightColumnContent={rightColumnContent}
|
|
||||||
leftColumnIsOpen={leftColumnIsOpen}
|
|
||||||
setLeftColumnIsOpen={setLeftColumnIsOpen}
|
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { Panel, PanelGroup } from 'react-resizable-panels'
|
|
||||||
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
|
|
||||||
|
|
||||||
type PlaceholderEditorSidebarProps = {
|
|
||||||
shouldPersistLayout: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PlaceholderEditorSidebar({
|
|
||||||
shouldPersistLayout,
|
|
||||||
}: PlaceholderEditorSidebarProps) {
|
|
||||||
return (
|
|
||||||
<aside className="ide-react-editor-sidebar">
|
|
||||||
<PanelGroup
|
|
||||||
autoSaveId={
|
|
||||||
shouldPersistLayout ? 'ide-react-editor-sidebar-layout' : undefined
|
|
||||||
}
|
|
||||||
direction="vertical"
|
|
||||||
>
|
|
||||||
<Panel defaultSize={75}>File tree placeholder</Panel>
|
|
||||||
<VerticalResizeHandle />
|
|
||||||
<Panel defaultSize={25}>File outline placeholder</Panel>
|
|
||||||
</PanelGroup>
|
|
||||||
</aside>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export default function PlaceholderFile() {
|
|
||||||
return <div className="file-view full-size">File placeholder</div>
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import ChatToggleButton from '@/features/editor-navigation-toolbar/components/chat-toggle-button'
|
|
||||||
import HistoryToggleButton from '@/features/editor-navigation-toolbar/components/history-toggle-button'
|
|
||||||
|
|
||||||
type PlaceholderHeaderProps = {
|
|
||||||
chatIsOpen: boolean
|
|
||||||
setChatIsOpen: (chatIsOpen: boolean) => void
|
|
||||||
historyIsOpen: boolean
|
|
||||||
setHistoryIsOpen: (historyIsOpen: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PlaceholderHeader({
|
|
||||||
chatIsOpen,
|
|
||||||
setChatIsOpen,
|
|
||||||
historyIsOpen,
|
|
||||||
setHistoryIsOpen,
|
|
||||||
}: PlaceholderHeaderProps) {
|
|
||||||
function toggleChatOpen() {
|
|
||||||
setChatIsOpen(!chatIsOpen)
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleHistoryOpen() {
|
|
||||||
setHistoryIsOpen(!historyIsOpen)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header className="toolbar toolbar-header">
|
|
||||||
<div className="toolbar-left">Header placeholder</div>
|
|
||||||
<div className="toolbar-right">
|
|
||||||
<HistoryToggleButton
|
|
||||||
historyIsOpen={historyIsOpen}
|
|
||||||
onClick={toggleHistoryOpen}
|
|
||||||
/>
|
|
||||||
<ChatToggleButton
|
|
||||||
chatIsOpen={chatIsOpen}
|
|
||||||
onClick={toggleChatOpen}
|
|
||||||
unreadMessageCount={0}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import React, { useState } from 'react'
|
|
||||||
import TwoColumnMainContent from '@/features/ide-react/components/layout/two-column-main-content'
|
|
||||||
|
|
||||||
type PlaceholderHistoryProps = {
|
|
||||||
shouldPersistLayout: boolean
|
|
||||||
leftColumnDefaultSize: number
|
|
||||||
setLeftColumnDefaultSize: React.Dispatch<React.SetStateAction<number>>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PlaceholderHistory({
|
|
||||||
shouldPersistLayout,
|
|
||||||
leftColumnDefaultSize,
|
|
||||||
setLeftColumnDefaultSize,
|
|
||||||
}: PlaceholderHistoryProps) {
|
|
||||||
const [leftColumnIsOpen, setLeftColumnIsOpen] = useState(true)
|
|
||||||
|
|
||||||
const leftColumnContent = (
|
|
||||||
<aside className="ide-react-editor-sidebar history-file-tree">
|
|
||||||
History file tree placeholder
|
|
||||||
</aside>
|
|
||||||
)
|
|
||||||
const rightColumnContent = (
|
|
||||||
<div>History document diff viewer and versions list placeholder</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TwoColumnMainContent
|
|
||||||
leftColumnId="editor-left-column"
|
|
||||||
leftColumnContent={leftColumnContent}
|
|
||||||
leftColumnDefaultSize={leftColumnDefaultSize}
|
|
||||||
setLeftColumnDefaultSize={setLeftColumnDefaultSize}
|
|
||||||
rightColumnContent={rightColumnContent}
|
|
||||||
leftColumnIsOpen={leftColumnIsOpen}
|
|
||||||
setLeftColumnIsOpen={setLeftColumnIsOpen}
|
|
||||||
shouldPersistLayout={shouldPersistLayout}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export default function PlaceholderPdf() {
|
|
||||||
return <div>PDF</div>
|
|
||||||
}
|
|
|
@ -17,7 +17,6 @@ type TwoColumnMainContentProps = {
|
||||||
setLeftColumnIsOpen: (
|
setLeftColumnIsOpen: (
|
||||||
leftColumnIsOpen: TwoColumnMainContentProps['leftColumnIsOpen']
|
leftColumnIsOpen: TwoColumnMainContentProps['leftColumnIsOpen']
|
||||||
) => void
|
) => void
|
||||||
shouldPersistLayout?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TwoColumnMainContent({
|
export default function TwoColumnMainContent({
|
||||||
|
@ -28,7 +27,6 @@ export default function TwoColumnMainContent({
|
||||||
rightColumnContent,
|
rightColumnContent,
|
||||||
leftColumnIsOpen,
|
leftColumnIsOpen,
|
||||||
setLeftColumnIsOpen,
|
setLeftColumnIsOpen,
|
||||||
shouldPersistLayout = false,
|
|
||||||
}: TwoColumnMainContentProps) {
|
}: TwoColumnMainContentProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
@ -52,9 +50,7 @@ export default function TwoColumnMainContent({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelGroup
|
<PanelGroup
|
||||||
autoSaveId={
|
autoSaveId="ide-react-main-content-layout"
|
||||||
shouldPersistLayout ? 'ide-react-main-content-layout' : undefined
|
|
||||||
}
|
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
onLayout={handleLayout}
|
onLayout={handleLayout}
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
|
|
@ -6,14 +6,12 @@ export default function useCollapsiblePanel(
|
||||||
panelRef: RefObject<ImperativePanelHandle>
|
panelRef: RefObject<ImperativePanelHandle>
|
||||||
) {
|
) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const panel = panelRef.current
|
if (panelRef.current) {
|
||||||
if (!panel) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (panelIsOpen) {
|
if (panelIsOpen) {
|
||||||
panel.expand()
|
panelRef.current.expand()
|
||||||
} else {
|
} else {
|
||||||
panel.collapse()
|
panelRef.current.collapse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [panelIsOpen, panelRef])
|
}, [panelIsOpen, panelRef])
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||||
|
import { useModalsContext } from '@/features/ide-react/context/modals-context'
|
||||||
|
|
||||||
|
export const useConnectionState = () => {
|
||||||
|
const { connectionState } = useConnectionContext()
|
||||||
|
const { showLockEditorMessageModal } = useModalsContext()
|
||||||
|
|
||||||
|
// Show modal when editor is forcefully disconnected
|
||||||
|
useEffect(() => {
|
||||||
|
if (connectionState.forceDisconnected) {
|
||||||
|
showLockEditorMessageModal(connectionState.forcedDisconnectDelay)
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
connectionState.forceDisconnected,
|
||||||
|
connectionState.forcedDisconnectDelay,
|
||||||
|
showLockEditorMessageModal,
|
||||||
|
])
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ export default function useFixedSizeColumn(
|
||||||
return fixedPanelRef.current?.getSize('pixels') || 0
|
return fixedPanelRef.current?.getSize('pixels') || 0
|
||||||
}, [fixedPanelRef])
|
}, [fixedPanelRef])
|
||||||
|
|
||||||
const handleLayout = useCallback(
|
const handleLayout: PanelGroupOnLayout = useCallback(
|
||||||
sizes => {
|
sizes => {
|
||||||
// Measure the pixel width here because it's not always up to date in the
|
// Measure the pixel width here because it's not always up to date in the
|
||||||
// panel's onResize
|
// panel's onResize
|
||||||
|
@ -26,7 +26,7 @@ export default function useFixedSizeColumn(
|
||||||
setInitialLayoutDone(true)
|
setInitialLayoutDone(true)
|
||||||
},
|
},
|
||||||
[measureFixedPanelSizePixels]
|
[measureFixedPanelSizePixels]
|
||||||
) as PanelGroupOnLayout
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
|
|
|
@ -21,6 +21,4 @@ export function useOpenFile() {
|
||||||
// Expose BinaryFilesManager via ide object solely for the benefit of the file
|
// Expose BinaryFilesManager via ide object solely for the benefit of the file
|
||||||
// restore feature in history. This can be removed once Angular is gone.
|
// restore feature in history. This can be removed once Angular is gone.
|
||||||
ide.binaryFilesManager = { openFileWithId }
|
ide.binaryFilesManager = { openFileWithId }
|
||||||
|
|
||||||
return openFileWithId
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
import LayoutWithPlaceholders from '@/features/ide-react/components/layout/layout-with-placeholders'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Editor / Page Layout',
|
|
||||||
component: LayoutWithPlaceholders,
|
|
||||||
decorators: [
|
|
||||||
(Story: any) => (
|
|
||||||
<div
|
|
||||||
style={{ position: 'absolute', inset: '1em', border: 'solid #ccc 1px' }}
|
|
||||||
>
|
|
||||||
<Story />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Persisted = {
|
|
||||||
args: {
|
|
||||||
shouldPersistLayout: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Unpersisted = {
|
|
||||||
args: {
|
|
||||||
shouldPersistLayout: false,
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -128,6 +128,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ide-react-editor-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure an element with class "full-size", such as the binary file view, stays within the bounds of the panel
|
// Ensure an element with class "full-size", such as the binary file view, stays within the bounds of the panel
|
||||||
.ide-react-panel {
|
.ide-react-panel {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
Loading…
Reference in a new issue