Skip to content

Commit ad3f7c8

Browse files
committed
refactor: simplify and reorganize panel components
- Extract GroupNodeRenderer and LeafNodeRenderer from PanelLayout - Add usePanelLayoutHooks for panel interactions - Simplify PanelLayout through component extraction - Remove DraggablePanel component - Update panel component exports
1 parent 6d0f15b commit ad3f7c8

File tree

12 files changed

+347
-251
lines changed

12 files changed

+347
-251
lines changed

src/renderer/features/panels/components/DraggablePanel.tsx

Lines changed: 0 additions & 64 deletions
This file was deleted.

src/renderer/features/panels/components/DraggableTab.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface DraggableTabProps {
99
label: string;
1010
isActive: boolean;
1111
index: number;
12+
draggable?: boolean;
1213
onSelect: () => void;
1314
onClose?: () => void;
1415
icon?: React.ReactNode;
@@ -20,6 +21,7 @@ export const DraggableTab: React.FC<DraggableTabProps> = ({
2021
label,
2122
isActive,
2223
index,
24+
draggable = true,
2325
onSelect,
2426
onClose,
2527
icon,
@@ -28,15 +30,19 @@ export const DraggableTab: React.FC<DraggableTabProps> = ({
2830
id: tabId,
2931
index,
3032
data: { tabId, panelId, type: "tab" },
33+
disabled: !draggable,
3134
});
3235

3336
return (
3437
<Flex
3538
ref={ref}
39+
role="tab"
40+
aria-label={label}
41+
data-active={isActive}
3642
align="center"
3743
gap="2"
3844
px="4"
39-
className="group relative cursor-grab select-none border-r border-b-2 transition-colors"
45+
className={`group relative select-none border-r border-b-2 transition-colors ${draggable ? "cursor-grab" : "cursor-default"}`}
4046
style={{
4147
backgroundColor: isActive ? "var(--accent-3)" : "transparent",
4248
borderRightColor: "var(--gray-6)",
@@ -75,6 +81,7 @@ export const DraggableTab: React.FC<DraggableTabProps> = ({
7581
variant="ghost"
7682
color={isActive ? undefined : "gray"}
7783
className="opacity-0 transition-opacity group-hover:opacity-100"
84+
aria-label="Close tab"
7885
onClick={(e) => {
7986
e.stopPropagation();
8087
onClose();
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from "react";
2+
import type { ImperativePanelGroupHandle } from "react-resizable-panels";
3+
import { PANEL_SIZES } from "../constants/panelConstants";
4+
import type { GroupPanel, PanelNode } from "../store/panelTypes";
5+
import { calculateDefaultSize } from "../utils/panelLayoutUtils";
6+
import { Panel } from "./Panel";
7+
import { PanelGroup } from "./PanelGroup";
8+
import { PanelResizeHandle } from "./PanelResizeHandle";
9+
10+
interface GroupNodeRendererProps {
11+
node: GroupPanel;
12+
setGroupRef: (
13+
groupId: string,
14+
ref: ImperativePanelGroupHandle | null,
15+
) => void;
16+
onLayout: (groupId: string, sizes: number[]) => void;
17+
renderNode: (node: PanelNode) => React.ReactNode;
18+
}
19+
20+
export const GroupNodeRenderer: React.FC<GroupNodeRendererProps> = ({
21+
node,
22+
setGroupRef,
23+
onLayout,
24+
renderNode,
25+
}) => {
26+
return (
27+
<PanelGroup
28+
ref={(ref) => setGroupRef(node.id, ref)}
29+
direction={node.direction}
30+
onLayout={(sizes) => onLayout(node.id, sizes)}
31+
>
32+
{node.children.map((child, index) => (
33+
<React.Fragment key={child.id}>
34+
<Panel
35+
id={child.id}
36+
order={index}
37+
defaultSize={calculateDefaultSize(node, index)}
38+
minSize={PANEL_SIZES.MIN_PANEL_SIZE}
39+
>
40+
{renderNode(child)}
41+
</Panel>
42+
{index < node.children.length - 1 && <PanelResizeHandle />}
43+
</React.Fragment>
44+
))}
45+
</PanelGroup>
46+
);
47+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { Task } from "@shared/types";
2+
import type React from "react";
3+
import { useTabInjection } from "../hooks/usePanelLayoutHooks";
4+
import type { LeafPanel } from "../store/panelTypes";
5+
import { TabbedPanel } from "./TabbedPanel";
6+
7+
interface LeafNodeRendererProps {
8+
node: LeafPanel;
9+
taskId: string;
10+
task: Task;
11+
closeTab: (taskId: string, panelId: string, tabId: string) => void;
12+
draggingTabId: string | null;
13+
draggingTabPanelId: string | null;
14+
onActiveTabChange: (panelId: string, tabId: string) => void;
15+
}
16+
17+
export const LeafNodeRenderer: React.FC<LeafNodeRendererProps> = ({
18+
node,
19+
taskId,
20+
task,
21+
closeTab,
22+
draggingTabId,
23+
draggingTabPanelId,
24+
onActiveTabChange,
25+
}) => {
26+
const tabs = useTabInjection(
27+
node.content.tabs,
28+
node.id,
29+
taskId,
30+
task,
31+
closeTab,
32+
);
33+
34+
const contentWithComponents = {
35+
...node.content,
36+
tabs,
37+
};
38+
39+
return (
40+
<TabbedPanel
41+
panelId={node.id}
42+
content={contentWithComponents}
43+
onActiveTabChange={onActiveTabChange}
44+
draggingTabId={draggingTabId}
45+
draggingTabPanelId={draggingTabPanelId}
46+
/>
47+
);
48+
};

src/renderer/features/panels/components/PanelDropZones.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type DropZoneType = SplitDirection | "center";
88
interface PanelDropZonesProps {
99
panelId: string;
1010
isDragging: boolean;
11+
allowSplit?: boolean; // Whether to show edge drop zones for splitting
1112
}
1213

1314
interface DropZoneProps {
@@ -25,13 +26,11 @@ const DropZone: React.FC<DropZoneProps> = ({ panelId, zone, style }) => {
2526
return (
2627
<Box
2728
ref={ref}
28-
className={`drop-zone drop-zone-${zone} pointer-events-auto absolute z-[100] transition-all duration-150 ${
29-
isDropTarget ? "border-2 opacity-50" : "border-0 opacity-10"
30-
}`}
29+
className={`drop-zone drop-zone-${zone} pointer-events-auto absolute z-[100] transition-all duration-150`}
3130
style={{
3231
...style,
33-
backgroundColor: isDropTarget ? "var(--accent-9)" : "var(--gray-5)",
34-
borderColor: isDropTarget ? "var(--accent-9)" : "transparent",
32+
backgroundColor: isDropTarget ? "var(--gray-8)" : "transparent",
33+
opacity: isDropTarget ? 0.3 : 0,
3534
}}
3635
/>
3736
);
@@ -71,9 +70,15 @@ const ZONE_CONFIGS: Array<{ zone: DropZoneType; style: React.CSSProperties }> =
7170
export const PanelDropZones: React.FC<PanelDropZonesProps> = ({
7271
panelId,
7372
isDragging,
73+
allowSplit = true,
7474
}) => {
7575
if (!isDragging) return null;
7676

77+
// Filter zones based on allowSplit
78+
const visibleZones = allowSplit
79+
? ZONE_CONFIGS
80+
: ZONE_CONFIGS.filter((config) => config.zone === "center");
81+
7782
return (
7883
<Box
7984
style={{
@@ -83,7 +88,7 @@ export const PanelDropZones: React.FC<PanelDropZonesProps> = ({
8388
zIndex: 100,
8489
}}
8590
>
86-
{ZONE_CONFIGS.map(({ zone, style }) => (
91+
{visibleZones.map(({ zone, style }) => (
8792
<DropZone key={zone} panelId={panelId} zone={zone} style={style} />
8893
))}
8994
</Box>

0 commit comments

Comments
 (0)