Skip to content

Commit d96b12a

Browse files
authored
feat: add panels ui (#118)
1 parent 8aa75fb commit d96b12a

19 files changed

+996
-26
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
},
6262
"dependencies": {
6363
"@ai-sdk/openai": "^2.0.52",
64+
"@dnd-kit/react": "^0.1.21",
6465
"@phosphor-icons/react": "^2.1.10",
6566
"@posthog/agent": "1.16.4",
6667
"@radix-ui/react-icons": "^1.3.2",
@@ -93,6 +94,7 @@
9394
"react-hook-form": "^7.64.0",
9495
"react-hotkeys-hook": "^4.4.4",
9596
"react-markdown": "^10.1.0",
97+
"react-resizable-panels": "^3.0.6",
9698
"sonner": "^2.0.7",
9799
"uuid": "^9.0.1",
98100
"zod": "^4.1.12",

pnpm-lock.yaml

Lines changed: 97 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/renderer/App.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { MainLayout } from "@components/MainLayout";
2+
import { DragDropProvider } from "@dnd-kit/react";
23
import { AuthScreen } from "@features/auth/components/AuthScreen";
34
import { useAuthStore } from "@features/auth/stores/authStore";
45
import { Flex, Spinner, Text } from "@radix-ui/themes";
56
import { initializePostHog } from "@renderer/lib/analytics";
67
import { useEffect, useState } from "react";
8+
import { useDragDropHandlers } from "@/renderer/hooks/useDragDropHandlers";
79
import { useRecordingQuerySync } from "@/renderer/hooks/useRecordingQuerySync";
810
import {
911
initializeRecordingService,
@@ -13,6 +15,7 @@ import {
1315
function App() {
1416
const { isAuthenticated, initializeOAuth } = useAuthStore();
1517
const [isLoading, setIsLoading] = useState(true);
18+
const dragDropHandlers = useDragDropHandlers();
1619

1720
useRecordingQuerySync();
1821

@@ -52,7 +55,9 @@ function App() {
5255
);
5356
}
5457

55-
return isAuthenticated ? <MainLayout /> : <AuthScreen />;
58+
const content = isAuthenticated ? <MainLayout /> : <AuthScreen />;
59+
60+
return <DragDropProvider {...dragDropHandlers}>{content}</DragDropProvider>;
5661
}
5762

5863
export default App;

src/renderer/components/MainLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export function MainLayout() {
132132
</Box>
133133
</Flex>
134134

135-
<StatusBar onOpenSettings={handleOpenSettings} />
135+
<StatusBar />
136136

137137
<CommandMenu open={commandMenuOpen} onOpenChange={setCommandMenuOpen} />
138138
<UpdatePrompt />
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ThemeWrapper } from "@components/ThemeWrapper";
2+
import { queryClient } from "@renderer/lib/queryClient";
3+
import { QueryClientProvider } from "@tanstack/react-query";
4+
import type React from "react";
5+
6+
interface ProvidersProps {
7+
children: React.ReactNode;
8+
}
9+
10+
export const Providers: React.FC<ProvidersProps> = ({ children }) => {
11+
return (
12+
<QueryClientProvider client={queryClient}>
13+
<ThemeWrapper>{children}</ThemeWrapper>
14+
</QueryClientProvider>
15+
);
16+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { useDraggable, useDroppable } from "@dnd-kit/react";
2+
import { Box, Flex, Text } from "@radix-ui/themes";
3+
import { usePanelStore } from "@stores/panelStore";
4+
import type React from "react";
5+
6+
interface DraggablePanelProps {
7+
id: string;
8+
label: string;
9+
children: React.ReactNode;
10+
}
11+
12+
export const DraggablePanel: React.FC<DraggablePanelProps> = ({
13+
id,
14+
label,
15+
children,
16+
}) => {
17+
const { ref: draggableRef, isDragging } = useDraggable({
18+
id: `panel-${id}`,
19+
data: { panelId: id },
20+
});
21+
22+
const { ref: droppableRef, isDropTarget } = useDroppable({
23+
id: `drop-${id}`,
24+
data: { panelId: id },
25+
});
26+
27+
const draggingTabPanelId = usePanelStore((state) => state.draggingTabPanelId);
28+
29+
return (
30+
<Box
31+
ref={droppableRef}
32+
height="100%"
33+
className="flex flex-col transition-all duration-100 ease-in-out"
34+
style={{
35+
opacity: isDragging ? 0.5 : 1,
36+
border:
37+
isDropTarget && draggingTabPanelId !== id
38+
? "2px solid var(--accent-9)"
39+
: "none",
40+
}}
41+
>
42+
<Flex
43+
ref={draggableRef}
44+
align="center"
45+
justify="between"
46+
px="3"
47+
py="2"
48+
className="cursor-grab select-none border-b"
49+
style={{
50+
backgroundColor: "var(--gray-3)",
51+
borderColor: "var(--gray-6)",
52+
}}
53+
>
54+
<Text size="2" weight="medium" color="gray">
55+
{label}
56+
</Text>
57+
</Flex>
58+
59+
<Box flexGrow="1" className="overflow-hidden">
60+
{children}
61+
</Box>
62+
</Box>
63+
);
64+
};

0 commit comments

Comments
 (0)