src/shell/PaneHeader.tsx
import type { MouseEvent, ReactNode } from "react";
import { TrafficLights, drawsWindowControls } from "../ui/TrafficLights";
/**
* Which window controls a header carries: drawn lights on one side, room for
* macOS's own lights, or room for the system caption buttons at the right.
*/
export type Corner = "left" | "right" | "reserve" | "caption" | null;
// A frameless window gets no automatic maximize on its caption, so pane headers restore it.
export function captionDoubleClick(event: MouseEvent) {
if (!window.desktop || !drawsWindowControls) return;
if ((event.target as Element).closest("button, input, a, label")) return;
window.desktop.windowCommand("maximize");
}
/**
* The 52px header that starts every pane. Together the headers form the
* window's caption: they drag the window, and the one in each corner carries
* the window controls.
*/
export function PaneHeader({ className, corner, maximized, lead, children }: {
className?: string;
corner: Corner;
maximized: boolean;
// Sits in the corner before drawn window controls (the sidebar toggle).
lead?: ReactNode;
children?: ReactNode;
}) {
return (
<header className={`pane-head${className ? ` ${className}` : ""}${corner === "reserve" ? " reserve-lights" : corner === "caption" ? " reserve-caption" : ""}`}
onDoubleClick={captionDoubleClick}>
{lead}
{corner === "left" && <TrafficLights maximized={maximized} />}
{children}
{corner === "right" && <TrafficLights right maximized={maximized} />}
</header>
);
}