Bundles in-progress working-tree UI work not authored this session (CoderPane ChatInput migration, AgentComposerBar/CoderMessageList/tab-bar/sidebar/pane refinements, provider icons) with this session's changes to the same files: MessageBubble renders a collapsible 'Thinking' block from reasoning_text/reasoning_parts (surfacing ACP agent_thought_chunk + native reasoning), and the DiffPanel approve/reject calls are repointed to the real /api/coder/pending/:id/apply and /reject routes (the old /sessions/:id/pending/:id/approve|reject paths did not exist).
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
import type { ReactNode } from 'react';
|
|
import { useLocation } from 'react-router-dom';
|
|
import { useViewport } from './useViewport';
|
|
|
|
interface SidebarDrawerState {
|
|
open: boolean;
|
|
setOpen: (open: boolean) => void;
|
|
toggle: () => void;
|
|
}
|
|
|
|
const Ctx = createContext<SidebarDrawerState | null>(null);
|
|
|
|
export function SidebarDrawerProvider({ children }: { children: ReactNode }) {
|
|
const [open, setOpen] = useState(false);
|
|
const location = useLocation();
|
|
const { isMobile } = useViewport();
|
|
|
|
useEffect(() => {
|
|
setOpen(false);
|
|
}, [location.pathname]);
|
|
|
|
// Close drawer on orientation change (landscape→portrait transition).
|
|
useEffect(() => {
|
|
setOpen(false);
|
|
}, [isMobile]);
|
|
|
|
const toggle = useCallback(() => setOpen((v) => !v), []);
|
|
|
|
return <Ctx.Provider value={{ open, setOpen, toggle }}>{children}</Ctx.Provider>;
|
|
}
|
|
|
|
export function useSidebarDrawer(): SidebarDrawerState {
|
|
const ctx = useContext(Ctx);
|
|
if (!ctx) {
|
|
// Soft fallback so consumers don't crash if rendered outside a provider.
|
|
// In practice all top-level routes are inside the provider.
|
|
return { open: false, setOpen: () => {}, toggle: () => {} };
|
|
}
|
|
return ctx;
|
|
}
|