import { HeaderSize, IconButton, SidebarLayout, SplitLayout, type SplitLayoutLayout, Toasts, } from "@yaakapp-internal/ui"; import classNames from "classnames"; import { useAtom, useAtomValue } from "jotai"; import { useState } from "react"; import { useLocalStorage } from "react-use"; import { flowLayoutAtom } from "../lib/atoms"; import { setupIncomplete } from "../lib/firstRun"; import { lockedAtom, noFlowsAtom, systemProxyEverOnAtom } from "../lib/store"; import { getOsType } from "../lib/tauri"; import { ClearFlowsButton } from "./ClearFlowsButton"; import { FirstRun } from "./FirstRun"; import { FlowDetail } from "./FlowDetail"; import { FlowList } from "./FlowList"; import { LockedState } from "./LockedState"; import { ProxyStatus, useProxySetup } from "./ProxyStatus"; import { HelperDialog } from "./HelperDialog"; import { SaveDialog } from "./SaveDialog"; import { SearchBar } from "./SearchBar"; import { SettingsWindow, useOpenSettings } from "./Settings"; import { Sidebar } from "./Sidebar"; import { TakeOverBanner } from "./TakeOverBanner"; export function ProxyLayout() { const os = getOsType(); const [flowLayout, setFlowLayout] = useAtom(flowLayoutAtom); const openSettings = useOpenSettings(); const [sidebarWidth, setSidebarWidth] = useLocalStorage("sidebar_width", 250); const [sidebarHidden, setSidebarHidden] = useLocalStorage("sidebar_hidden", false); const [floatingSidebarHidden, setFloatingSidebarHidden] = useLocalStorage( "floating_sidebar_hidden", true, ); const [floating, setFloating] = useState(false); const isHidden = floating ? (floatingSidebarHidden ?? true) : (sidebarHidden ?? false); return (
{/* Yaak's silhouette: the sidebar toggle and the state pill where Yaak has the toggle and the environment, the search where it names the request, then its icons. Only the controls take the pointer: everything around them, the traffic lights' corner included, falls through to the header, which drags the window. */}
{ if (floating) { setFloatingSidebarHidden(!floatingSidebarHidden); } else { setSidebarHidden(!sidebarHidden); } }} />
setFlowLayout((prev) => (prev === "horizontal" ? "vertical" : "horizontal")) } /> openSettings()} />
) : ( ) } >
); } /** * The flow list beside or above the detail pane, or, while setup is incomplete and there are no * flows, the first-run card across the whole area. Once setup is done an empty list says so * itself, after a Clear too. While captured traffic is locked, the locked state takes the whole * area, or the first-run card does, saying why, while setup is incomplete too. */ function FlowsOrFirstRun({ flowLayout }: { flowLayout: SplitLayoutLayout }) { const locked = useAtomValue(lockedAtom); const noFlows = useAtomValue(noFlowsAtom) || locked != null; const { caStatus, systemProxy } = useProxySetup(); const systemProxyEverOn = useAtomValue(systemProxyEverOnAtom); const incomplete = setupIncomplete({ trusted: caStatus.data?.trusted ?? null, systemProxySupported: systemProxy.data?.supported ?? null, systemProxyEverOn, }); if (noFlows && incomplete) return ; if (locked != null) return ; return ( } secondSlot={({ style, orientation }) => ( )} /> ); }