persistence in panels
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useState, useCallback, useEffect, useRef, type ComponentRef } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from '@/components/ui/resizable';
|
||||
import type { LayoutNode, WorkspaceState, EphemeralPanels, PanelComponents } from './types';
|
||||
@@ -111,43 +111,22 @@ export const WorkspaceView = ({ workspace, cwd = '~', root, initialFilePath, def
|
||||
return () => window.removeEventListener('keydown', onKeyDown);
|
||||
}, [swapSourceId, dragSourceId, maximizedPanelId, setMaximizedAnimated]);
|
||||
|
||||
const ephemeralPanelRef = useRef<ComponentRef<typeof ResizablePanel>>(null);
|
||||
const isEphemeralOpen = !!ephemeral;
|
||||
|
||||
useEffect(() => {
|
||||
const panel = ephemeralPanelRef.current;
|
||||
if (!panel) return;
|
||||
|
||||
if (isEphemeralOpen) {
|
||||
panel.resize(100 - (ephemeral.defaultBaseSize ?? 40));
|
||||
} else {
|
||||
panel.collapse();
|
||||
}
|
||||
}, [isEphemeralOpen, ephemeral?.defaultBaseSize]);
|
||||
|
||||
if (!workspace.isLoaded) return null;
|
||||
|
||||
const baseRenderer = (
|
||||
<WorkspaceRenderer
|
||||
layout={layout}
|
||||
registry={registry}
|
||||
components={components}
|
||||
interactive
|
||||
onSetApp={handleSetApp}
|
||||
onSplit={handleSplit}
|
||||
onRemove={handleRemove}
|
||||
onResized={handleResized}
|
||||
/>
|
||||
);
|
||||
|
||||
const content = ephemeral ? (
|
||||
<ResizablePanelGroup direction="horizontal" className="h-full w-full">
|
||||
<ResizablePanel defaultSize={ephemeral.defaultBaseSize ?? 40} minSize={15}>
|
||||
{baseRenderer}
|
||||
</ResizablePanel>
|
||||
<ResizableHandle className="bg-transparent after:bg-transparent" />
|
||||
<ResizablePanel defaultSize={100 - (ephemeral.defaultBaseSize ?? 40)} minSize={15}>
|
||||
<WorkspaceRenderer
|
||||
layout={ephemeral.layout}
|
||||
registry={registry}
|
||||
components={ephemeral.components}
|
||||
onSetApp={noop}
|
||||
onSplit={noop}
|
||||
onRemove={noop}
|
||||
onResized={noop}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
) : (
|
||||
baseRenderer
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspaceProvider
|
||||
value={{
|
||||
@@ -167,7 +146,40 @@ export const WorkspaceView = ({ workspace, cwd = '~', root, initialFilePath, def
|
||||
transitioningPanelId,
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
<ResizablePanelGroup direction="horizontal" className="h-full w-full">
|
||||
<ResizablePanel defaultSize={100} minSize={15}>
|
||||
<WorkspaceRenderer
|
||||
layout={layout}
|
||||
registry={registry}
|
||||
components={components}
|
||||
interactive
|
||||
onSetApp={handleSetApp}
|
||||
onSplit={handleSplit}
|
||||
onRemove={handleRemove}
|
||||
onResized={handleResized}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle className="bg-transparent after:bg-transparent" disabled={!isEphemeralOpen} />
|
||||
<ResizablePanel
|
||||
ref={ephemeralPanelRef}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
defaultSize={0}
|
||||
minSize={15}
|
||||
>
|
||||
{isEphemeralOpen ? (
|
||||
<WorkspaceRenderer
|
||||
layout={ephemeral.layout}
|
||||
registry={registry}
|
||||
components={ephemeral.components}
|
||||
onSetApp={noop}
|
||||
onSplit={noop}
|
||||
onRemove={noop}
|
||||
onResized={noop}
|
||||
/>
|
||||
) : null}
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</WorkspaceProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
import type { EphemeralPanels } from '../../components/Workspace';
|
||||
import { FileViewerHeader, FileViewerBody } from '../../apps/FileViewer';
|
||||
@@ -17,42 +18,57 @@ export const useFileViewerPanels = (): EphemeralPanels | null => {
|
||||
? viewerWithEphemeralLayout
|
||||
: singleViewerLayout;
|
||||
|
||||
const components = {
|
||||
'files-viewer': {
|
||||
provider: ViewerProvider,
|
||||
header: FileViewerHeader,
|
||||
component: FileViewerBody,
|
||||
onClose: () => setSearchParams({}),
|
||||
},
|
||||
'files-ephemeral': {
|
||||
provider: EphemeralProvider,
|
||||
header: FileViewerHeader,
|
||||
component: FileViewerBody,
|
||||
onClose: () =>
|
||||
setSearchParams((prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
next.delete('ephemeral');
|
||||
next.delete('ephemeralRoot');
|
||||
next.delete('ephemeral2');
|
||||
next.delete('ephemeral2Root');
|
||||
next.delete('ephemeral2Auto');
|
||||
return next;
|
||||
}),
|
||||
},
|
||||
'files-ephemeral2': {
|
||||
provider: Ephemeral2Provider,
|
||||
header: FileViewerHeader,
|
||||
component: FileViewerBody,
|
||||
onClose: () =>
|
||||
setSearchParams((prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
next.delete('ephemeral2');
|
||||
next.delete('ephemeral2Root');
|
||||
next.delete('ephemeral2Auto');
|
||||
return next;
|
||||
}),
|
||||
},
|
||||
};
|
||||
const onCloseViewer = useCallback(() => setSearchParams({}), [setSearchParams]);
|
||||
|
||||
const onCloseEphemeral = useCallback(
|
||||
() =>
|
||||
setSearchParams((prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
next.delete('ephemeral');
|
||||
next.delete('ephemeralRoot');
|
||||
next.delete('ephemeral2');
|
||||
next.delete('ephemeral2Root');
|
||||
next.delete('ephemeral2Auto');
|
||||
return next;
|
||||
}),
|
||||
[setSearchParams],
|
||||
);
|
||||
|
||||
const onCloseEphemeral2 = useCallback(
|
||||
() =>
|
||||
setSearchParams((prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
next.delete('ephemeral2');
|
||||
next.delete('ephemeral2Root');
|
||||
next.delete('ephemeral2Auto');
|
||||
return next;
|
||||
}),
|
||||
[setSearchParams],
|
||||
);
|
||||
|
||||
const components = useMemo(
|
||||
() => ({
|
||||
'files-viewer': {
|
||||
provider: ViewerProvider,
|
||||
header: FileViewerHeader,
|
||||
component: FileViewerBody,
|
||||
onClose: onCloseViewer,
|
||||
},
|
||||
'files-ephemeral': {
|
||||
provider: EphemeralProvider,
|
||||
header: FileViewerHeader,
|
||||
component: FileViewerBody,
|
||||
onClose: onCloseEphemeral,
|
||||
},
|
||||
'files-ephemeral2': {
|
||||
provider: Ephemeral2Provider,
|
||||
header: FileViewerHeader,
|
||||
component: FileViewerBody,
|
||||
onClose: onCloseEphemeral2,
|
||||
},
|
||||
}),
|
||||
[onCloseViewer, onCloseEphemeral, onCloseEphemeral2],
|
||||
);
|
||||
|
||||
if (!viewPath) return null;
|
||||
return { layout, components, defaultBaseSize: 40 };
|
||||
|
||||
Reference in New Issue
Block a user