Workspaces
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from '../ui/resizable';
|
||||
import type { LayoutNode, WidgetRegistry } from './types';
|
||||
import { pruneEmptyPanels, countPanels } from './layout-utils';
|
||||
import { PanelSlot } from './PanelSlot';
|
||||
|
||||
type WorkspaceRendererProps = {
|
||||
layout: LayoutNode;
|
||||
registry: WidgetRegistry;
|
||||
editing: boolean;
|
||||
onSetWidget: (panelId: string, widgetType: string | null) => void;
|
||||
onSplit: (panelId: string, direction: 'horizontal' | 'vertical') => void;
|
||||
onRemove: (panelId: string) => void;
|
||||
onResized: (groupId: string, sizes: number[]) => void;
|
||||
};
|
||||
|
||||
export const WorkspaceRenderer = ({
|
||||
layout,
|
||||
registry,
|
||||
editing,
|
||||
onSetWidget,
|
||||
onSplit,
|
||||
onRemove,
|
||||
onResized,
|
||||
}: WorkspaceRendererProps) => {
|
||||
const displayLayout = editing ? layout : pruneEmptyPanels(layout);
|
||||
if (!displayLayout) {
|
||||
return <div className="flex h-full items-center justify-center text-sm text-muted-foreground">No widgets</div>;
|
||||
}
|
||||
|
||||
const totalPanels = countPanels(layout);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
<LayoutNodeRenderer
|
||||
node={displayLayout}
|
||||
registry={registry}
|
||||
editing={editing}
|
||||
totalPanels={totalPanels}
|
||||
onSetWidget={onSetWidget}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
onResized={onResized}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type LayoutNodeRendererProps = {
|
||||
node: LayoutNode;
|
||||
registry: WidgetRegistry;
|
||||
editing: boolean;
|
||||
totalPanels: number;
|
||||
onSetWidget: (panelId: string, widgetType: string | null) => void;
|
||||
onSplit: (panelId: string, direction: 'horizontal' | 'vertical') => void;
|
||||
onRemove: (panelId: string) => void;
|
||||
onResized: (groupId: string, sizes: number[]) => void;
|
||||
};
|
||||
|
||||
const LayoutNodeRenderer = ({
|
||||
node,
|
||||
registry,
|
||||
editing,
|
||||
totalPanels,
|
||||
onSetWidget,
|
||||
onSplit,
|
||||
onRemove,
|
||||
onResized,
|
||||
}: LayoutNodeRendererProps) => {
|
||||
const debounceRef = useRef<ReturnType<typeof setTimeout>>(null);
|
||||
|
||||
const handleLayout = useCallback(
|
||||
(sizes: number[]) => {
|
||||
if (node.type !== 'group') return;
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
debounceRef.current = setTimeout(() => {
|
||||
onResized(node.id, sizes);
|
||||
}, 500);
|
||||
},
|
||||
[node, onResized],
|
||||
);
|
||||
|
||||
if (node.type === 'panel') {
|
||||
return (
|
||||
<PanelSlot
|
||||
panel={node}
|
||||
registry={registry}
|
||||
editing={editing}
|
||||
isLastPanel={totalPanels <= 1}
|
||||
onSetWidget={onSetWidget}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ResizablePanelGroup direction={node.direction} onLayout={handleLayout} className="h-full w-full">
|
||||
{node.children.map((child, i) => (
|
||||
<ChildEntry key={child.node.id} index={i} total={node.children.length}>
|
||||
<ResizablePanel defaultSize={child.size} minSize={5}>
|
||||
<div className="h-full w-full p-1">
|
||||
<LayoutNodeRenderer
|
||||
node={child.node}
|
||||
registry={registry}
|
||||
editing={editing}
|
||||
totalPanels={totalPanels}
|
||||
onSetWidget={onSetWidget}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
onResized={onResized}
|
||||
/>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ChildEntry>
|
||||
))}
|
||||
</ResizablePanelGroup>
|
||||
);
|
||||
};
|
||||
|
||||
type ChildEntryProps = {
|
||||
index: number;
|
||||
total: number;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const ChildEntry = ({ index, total, children }: ChildEntryProps) => {
|
||||
if (index === 0) return <>{children}</>;
|
||||
return (
|
||||
<>
|
||||
<ResizableHandle className="bg-transparent after:bg-transparent" />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user