Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions packages/ui/src/shell/HeaderRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useWorkspace } from "@posthog/ui/features/workspace/useWorkspace";
import { Tooltip } from "@posthog/ui/primitives/Tooltip";
import { useAppView } from "@posthog/ui/router/useAppView";
import { track } from "@posthog/ui/shell/analytics";
import { getHeaderSidebarPanelLayout } from "@posthog/ui/shell/headerSidebarPanel";
import { useHeaderStore } from "@posthog/ui/shell/headerStore";
import { isMac, isWindows } from "@posthog/ui/utils/platform";
import { Box, Flex } from "@radix-ui/themes";
Expand Down Expand Up @@ -162,9 +163,7 @@ function BluebirdButton() {
}

export const HEADER_HEIGHT = 36;
const COLLAPSED_WIDTH = 110;
const WINDOWS_TITLEBAR_INSET = 140;
const MACOS_TRAFFIC_LIGHT_INSET = 70;

export function HeaderRow() {
const content = useHeaderStore((state) => state.content);
Expand All @@ -174,6 +173,11 @@ export function HeaderRow() {
const sidebarWidth = useSidebarStore((state) => state.width);
const isResizing = useSidebarStore((state) => state.isResizing);
const setIsResizing = useSidebarStore((state) => state.setIsResizing);
const panel = getHeaderSidebarPanelLayout({
sidebarOpen,
sidebarWidth,
isMac,
});

const activeTaskId = view.type === "task-detail" ? view.taskId : undefined;
// Read the live task from the list cache instead of a stale snapshot off the
Expand Down Expand Up @@ -206,17 +210,20 @@ export function HeaderRow() {
>
<Flex
align="center"
justify="end"
justify={panel.justify}
px="2"
pr="3"
style={{
width: sidebarOpen
? `${sidebarWidth}px`
: `${COLLAPSED_WIDTH + (isMac ? MACOS_TRAFFIC_LIGHT_INSET : 0)}px`,
minWidth: `${COLLAPSED_WIDTH + (isMac ? MACOS_TRAFFIC_LIGHT_INSET : 0)}px`,
width: panel.width,
minWidth: panel.minWidth,
paddingLeft: panel.paddingLeft,
transition: isResizing ? "none" : "width 0.2s ease-in-out",
}}
className="relative h-full gap-2 border-r border-r-(--gray-6)"
className={
panel.showBorder
? "relative h-full gap-2 border-r border-r-(--gray-6)"
: "relative h-full gap-2"
}
>
<BluebirdButton />
<SidebarTrigger />
Expand Down
60 changes: 60 additions & 0 deletions packages/ui/src/shell/headerSidebarPanel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
getHeaderSidebarPanelLayout,
type HeaderSidebarPanelLayout,
} from "@posthog/ui/shell/headerSidebarPanel";
import { describe, expect, it } from "vitest";

describe("getHeaderSidebarPanelLayout", () => {
it.each<{
name: string;
input: { sidebarOpen: boolean; sidebarWidth: number; isMac: boolean };
expected: HeaderSidebarPanelLayout;
}>([
{
name: "open on macOS tracks the sidebar width and keeps the divider",
input: { sidebarOpen: true, sidebarWidth: 256, isMac: true },
expected: {
width: "256px",
minWidth: "180px",
paddingLeft: undefined,
justify: "end",
showBorder: true,
},
},
{
name: "open off macOS tracks the sidebar width",
input: { sidebarOpen: true, sidebarWidth: 300, isMac: false },
expected: {
width: "300px",
minWidth: "110px",
paddingLeft: undefined,
justify: "end",
showBorder: true,
},
},
{
name: "collapsed on macOS reserves the traffic-light strip as left padding and drops the divider",
input: { sidebarOpen: false, sidebarWidth: 256, isMac: true },
expected: {
width: "180px",
minWidth: "180px",
paddingLeft: "70px",
justify: "start",
showBorder: false,
},
},
{
name: "collapsed off macOS drops the divider and needs no traffic-light padding",
input: { sidebarOpen: false, sidebarWidth: 256, isMac: false },
expected: {
width: "110px",
minWidth: "110px",
paddingLeft: undefined,
justify: "start",
showBorder: false,
},
},
])("$name", ({ input, expected }) => {
expect(getHeaderSidebarPanelLayout(input)).toEqual(expected);
});
});
56 changes: 56 additions & 0 deletions packages/ui/src/shell/headerSidebarPanel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// The header's left region mirrors the sidebar: it holds the app-rail buttons
// (Bluebird) plus the sidebar toggle and lines up with the sidebar body below
// it. This helper derives its layout so the collapsed state stays clean — it
// clears the macOS traffic lights and drops the divider that would otherwise
// dangle as a stray edge over the page once the sidebar body has collapsed to
// zero width.

/** Width of the collapsed panel, sized to hold the app-rail + toggle buttons. */
const COLLAPSED_WIDTH = 110;
/**
* Width of the macOS traffic-light strip (close / minimize / zoom). Reserved as
* real left padding when collapsed so the buttons can never render underneath
* the window controls.
*/
const MACOS_TRAFFIC_LIGHT_INSET = 70;

export interface HeaderSidebarPanelLayout {
/** Inline width / minWidth for the panel (animates between the two states). */
width: string;
minWidth: string;
/**
* Left padding reserving the macOS traffic-light strip, or `undefined` when no
* reservation is needed (open, or non-macOS).
*/
paddingLeft: string | undefined;
/**
* Buttons hug the sidebar's right edge when open (matching the divider); when
* collapsed they hug the left, after the traffic-light inset, so a wide
* Bluebird label grows rightward into empty space rather than leftward under
* the window controls.
*/
justify: "start" | "end";
/** The divider only belongs while the sidebar body is visible beneath it. */
showBorder: boolean;
}

export function getHeaderSidebarPanelLayout({
sidebarOpen,
sidebarWidth,
isMac,
}: {
sidebarOpen: boolean;
sidebarWidth: number;
isMac: boolean;
}): HeaderSidebarPanelLayout {
const collapsedWidth =
COLLAPSED_WIDTH + (isMac ? MACOS_TRAFFIC_LIGHT_INSET : 0);
return {
width: sidebarOpen ? `${sidebarWidth}px` : `${collapsedWidth}px`,
minWidth: `${collapsedWidth}px`,
paddingLeft:
!sidebarOpen && isMac ? `${MACOS_TRAFFIC_LIGHT_INSET}px` : undefined,
justify: sidebarOpen ? "end" : "start",
showBorder: sidebarOpen,
};
}
Loading