+
Extensions
setTab(v as ExtTab)}>
diff --git a/src/components/layout/AppShell.tsx b/src/components/layout/AppShell.tsx
index fb0aae6..7d4d5e2 100644
--- a/src/components/layout/AppShell.tsx
+++ b/src/components/layout/AppShell.tsx
@@ -6,10 +6,16 @@ import { TooltipProvider } from "@/components/ui/tooltip";
import { NavRail } from "./NavRail";
import { ChatListPanel } from "./ChatListPanel";
import { RightPanel } from "./RightPanel";
+import { ResizeHandle } from "./ResizeHandle";
import { UpdateDialog } from "./UpdateDialog";
import { PanelContext, type PanelContent } from "@/hooks/usePanel";
import { UpdateContext, type UpdateInfo } from "@/hooks/useUpdate";
+const CHATLIST_MIN = 180;
+const CHATLIST_MAX = 400;
+const RIGHTPANEL_MIN = 200;
+const RIGHTPANEL_MAX = 480;
+
const LG_BREAKPOINT = 1024;
const CHECK_INTERVAL = 8 * 60 * 60 * 1000; // 8 hours
const DISMISSED_VERSION_KEY = "codepilot_dismissed_update_version";
@@ -19,6 +25,36 @@ export function AppShell({ children }: { children: React.ReactNode }) {
const [chatListOpen, setChatListOpenRaw] = useState(false);
+ // Panel width state with localStorage persistence
+ const [chatListWidth, setChatListWidth] = useState(() => {
+ if (typeof window === "undefined") return 240;
+ return parseInt(localStorage.getItem("codepilot_chatlist_width") || "240");
+ });
+ const [rightPanelWidth, setRightPanelWidth] = useState(() => {
+ if (typeof window === "undefined") return 288;
+ return parseInt(localStorage.getItem("codepilot_rightpanel_width") || "288");
+ });
+
+ const handleChatListResize = useCallback((delta: number) => {
+ setChatListWidth((w) => Math.min(CHATLIST_MAX, Math.max(CHATLIST_MIN, w + delta)));
+ }, []);
+ const handleChatListResizeEnd = useCallback(() => {
+ setChatListWidth((w) => {
+ localStorage.setItem("codepilot_chatlist_width", String(w));
+ return w;
+ });
+ }, []);
+
+ const handleRightPanelResize = useCallback((delta: number) => {
+ setRightPanelWidth((w) => Math.min(RIGHTPANEL_MAX, Math.max(RIGHTPANEL_MIN, w - delta)));
+ }, []);
+ const handleRightPanelResizeEnd = useCallback(() => {
+ setRightPanelWidth((w) => {
+ localStorage.setItem("codepilot_rightpanel_width", String(w));
+ return w;
+ });
+ }, []);
+
// Panel state
const isChatRoute = pathname.startsWith("/chat/") || pathname === "/chat";
const isChatDetailRoute = pathname.startsWith("/chat/");
@@ -165,7 +201,10 @@ export function AppShell({ children }: { children: React.ReactNode }) {
hasUpdate={updateInfo?.updateAvailable ?? false}
skipPermissionsActive={skipPermissionsActive}
/>
-
+
+ {chatListOpen && (
+
+ )}
{/* Electron draggable title bar region */}
{children}
- {isChatDetailRoute && }
+ {isChatDetailRoute && panelOpen && (
+
+ )}
+ {isChatDetailRoute && }
diff --git a/src/components/layout/ChatListPanel.tsx b/src/components/layout/ChatListPanel.tsx
index 35d36ea..314dc0a 100644
--- a/src/components/layout/ChatListPanel.tsx
+++ b/src/components/layout/ChatListPanel.tsx
@@ -21,6 +21,7 @@ import type { ChatSession } from "@/types";
interface ChatListPanelProps {
open: boolean;
+ width?: number;
}
function formatRelativeTime(dateStr: string): string {
@@ -69,7 +70,7 @@ const MODE_BADGE_CONFIG = {
ask: { label: "Ask", className: "bg-green-500/10 text-green-500" },
} as const;
-export function ChatListPanel({ open }: ChatListPanelProps) {
+export function ChatListPanel({ open, width }: ChatListPanelProps) {
const pathname = usePathname();
const router = useRouter();
const { streamingSessionId, pendingApprovalSessionId } = usePanel();
@@ -150,7 +151,7 @@ export function ChatListPanel({ open }: ChatListPanelProps) {
if (!open) return null;
return (
-