/** * Shared macOS traffic-light geometry. * * Keep this as the single source of truth for both: * - main process native button positioning * - renderer process left padding reservation *//** IPC event channel emitted by main when zoom changes */export const WINDOW_ZOOM_FACTOR_CHANGED_CHANNEL = 'window:zoom-factor-changed';/** Base traffic-light origin at 100% zoom (native coordinates) */const MACOS_TRAFFIC_LIGHT_BASE_POSITION = { x: 12, y: 12 } as const;/** Header row height used by SidebarHeader and TabBar */export const HEADER_ROW1_HEIGHT = 40;/** Native button-group frame height (used to vertically center in header row) */const MACOS_TRAFFIC_LIGHT_GROUP_HEIGHT = 16;/** Approximate total width of the 3 traffic lights group in native px */const MACOS_TRAFFIC_LIGHT_GROUP_WIDTH = 52;/** Visual gap between traffic lights and first left-aligned content */const MACOS_TRAFFIC_LIGHT_CONTENT_GAP = 8;const MIN_ZOOM_FACTOR = 0.25;function sanitizeZoomFactor(zoomFactor: number): number { if (!Number.isFinite(zoomFactor) || zoomFactor <= 0) { return 1; } return Math.max(zoomFactor, MIN_ZOOM_FACTOR);}/** * Native traffic-light position for the given zoom. * Uses linear scaling to keep vertical alignment with zoomed title rows. */export function getTrafficLightPositionForZoom( zoomFactor: number): Readonly<{ x: number; y: number }> { const zoom = sanitizeZoomFactor(zoomFactor); return { x: Math.round(MACOS_TRAFFIC_LIGHT_BASE_POSITION.x * zoom), y: Math.round((HEADER_ROW1_HEIGHT * zoom - MACOS_TRAFFIC_LIGHT_GROUP_HEIGHT) / 2), };}/** * CSS left padding (in CSS px) needed to avoid overlap with native buttons. * Produces a stable physical gap between traffic lights and content at any zoom. */export function getTrafficLightPaddingForZoom(zoomFactor: number): number { const zoom = sanitizeZoomFactor(zoomFactor); return Math.ceil( MACOS_TRAFFIC_LIGHT_BASE_POSITION.x + (MACOS_TRAFFIC_LIGHT_GROUP_WIDTH + MACOS_TRAFFIC_LIGHT_CONTENT_GAP) / zoom );}
/**
* Shared macOS traffic-light geometry.
*
* Keep this as the single source of truth for both:
* - main process native button positioning
* - renderer process left padding reservation
*/
/** IPC event channel emitted by main when zoom changes */
export const WINDOW_ZOOM_FACTOR_CHANGED_CHANNEL = 'window:zoom-factor-changed';
/** Base traffic-light origin at 100% zoom (native coordinates) */
const MACOS_TRAFFIC_LIGHT_BASE_POSITION = { x: 12, y: 12 } as const;
/** Header row height used by SidebarHeader and TabBar */
export const HEADER_ROW1_HEIGHT = 40;
/** Native button-group frame height (used to vertically center in header row) */
const MACOS_TRAFFIC_LIGHT_GROUP_HEIGHT = 16;
/** Approximate total width of the 3 traffic lights group in native px */
const MACOS_TRAFFIC_LIGHT_GROUP_WIDTH = 52;
/** Visual gap between traffic lights and first left-aligned content */
const MACOS_TRAFFIC_LIGHT_CONTENT_GAP = 8;
const MIN_ZOOM_FACTOR = 0.25;
function sanitizeZoomFactor(zoomFactor: number): number {
if (!Number.isFinite(zoomFactor) || zoomFactor <= 0) {
return 1;
}
return Math.max(zoomFactor, MIN_ZOOM_FACTOR);
}
/**
* Native traffic-light position for the given zoom.
* Uses linear scaling to keep vertical alignment with zoomed title rows.
*/
export function getTrafficLightPositionForZoom(
zoomFactor: number
): Readonly<{ x: number; y: number }> {
const zoom = sanitizeZoomFactor(zoomFactor);
return {
x: Math.round(MACOS_TRAFFIC_LIGHT_BASE_POSITION.x * zoom),
y: Math.round((HEADER_ROW1_HEIGHT * zoom - MACOS_TRAFFIC_LIGHT_GROUP_HEIGHT) / 2),
};
}
/**
* CSS left padding (in CSS px) needed to avoid overlap with native buttons.
* Produces a stable physical gap between traffic lights and content at any zoom.
*/
export function getTrafficLightPaddingForZoom(zoomFactor: number): number {
const zoom = sanitizeZoomFactor(zoomFactor);
return Math.ceil(
MACOS_TRAFFIC_LIGHT_BASE_POSITION.x +
(MACOS_TRAFFIC_LIGHT_GROUP_WIDTH + MACOS_TRAFFIC_LIGHT_CONTENT_GAP) / zoom
);
}