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
17 changes: 14 additions & 3 deletions apps/web/src/components/AppSidebarLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useAtomValue } from "@effect/atom-react";
import * as Schema from "effect/Schema";
import {
useEffect,
useLayoutEffect,
useState,
useSyncExternalStore,
type CSSProperties,
Expand Down Expand Up @@ -255,10 +256,20 @@ export function AppSidebarLayout({ children }: { children: ReactNode }) {
const sidebarProviderStyle = {
"--sidebar-width": `${clampThreadSidebarWidth(sidebarWidth, sidebarMinimumWidth, sidebarMaximumWidth)}px`,
"--panel-animation-duration": `${panelAnimationDurationMs}ms`,
...(isMacosDesktop && !isWindowFullscreen
? { "--workspace-controls-left": MACOS_TRAFFIC_LIGHTS_LEFT_INSET }
: {}),
} as CSSProperties;
// The traffic-light inset lives on the document root rather than on the
// provider: the zoomed-in sidebar renders as a sheet through a portal
// outside this subtree, and its header trigger has to see the same token
// as the floating control. Layout effect so the first paint already has it.
const reserveMacosWindowControls = isMacosDesktop && !isWindowFullscreen;
useLayoutEffect(() => {
if (!reserveMacosWindowControls) return;
const root = document.documentElement;
root.style.setProperty("--workspace-controls-left", MACOS_TRAFFIC_LIGHTS_LEFT_INSET);
return () => {
root.style.removeProperty("--workspace-controls-left");
};
}, [reserveMacosWindowControls]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

useEffect(() => {
if (!isMacosDesktop) return;
Expand Down
15 changes: 15 additions & 0 deletions apps/web/src/components/sidebar/SidebarChrome.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe, expect, it } from "vite-plus/test";

import { resolveSidebarSheetTriggerInsetClass } from "./SidebarChrome";

describe("resolveSidebarSheetTriggerInsetClass", () => {
it("aligns the sheet trigger with the floating control on desktop", () => {
expect(resolveSidebarSheetTriggerInsetClass(true)).toBe(
"ml-[calc(var(--workspace-controls-left)-0.75rem)]",
);
});

it("keeps the header padding on web and mobile", () => {
expect(resolveSidebarSheetTriggerInsetClass(false)).toBeNull();
});
});
24 changes: 19 additions & 5 deletions apps/web/src/components/sidebar/SidebarChrome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ import { SidebarProviderUpdatePill } from "./SidebarProviderUpdatePill";
import { SidebarUpdateArchitectureWarning, SidebarUpdatePill } from "./SidebarUpdatePill";
import { PullRequestGlyph } from "~/components/pullRequest/pullRequestIcons";

/**
* Left inset for the sheet-mode sidebar trigger. On macOS desktop the header
* sits under the native window buttons, so the trigger takes the same left
* edge as the floating `SidebarControl` (`--workspace-controls-left`, 90
* native points there, `0.75rem` elsewhere and in fullscreen) instead of the
* header's own `px-3`. Web and mobile keep the header padding.
*/
export function resolveSidebarSheetTriggerInsetClass(isElectron: boolean): string | null {
return isElectron ? "ml-[calc(var(--workspace-controls-left)-0.75rem)]" : null;
}

export const SidebarChromeHeader = memo(function SidebarChromeHeader({
isElectron,
}: {
Expand All @@ -55,11 +66,14 @@ export const SidebarChromeHeader = memo(function SidebarChromeHeader({
)}
>
{backdropVariant ? <SidebarStageBackdrop variant={backdropVariant} /> : null}
<SidebarTrigger
// Over the stage artwork: the media viewer's control-on-imagery treatment.
variant={backdropVariant ? "media-navigation" : "ghost"}
className="relative top-auto z-10 translate-y-0 md:hidden"
/>
{/* Placement belongs to the parent: the inset keeps the trigger clear of the window controls. */}
<span className={cn("md:hidden", resolveSidebarSheetTriggerInsetClass(isElectron))}>
<SidebarTrigger
// Over the stage artwork: the media viewer's control-on-imagery treatment.
variant={backdropVariant ? "media-navigation" : "ghost"}
className="relative top-auto z-10 translate-y-0 md:hidden"
/>
</span>
{/* One visible line: the pill wraps onto the clipped second line once it no longer fits.
The padding keeps the brand's focus ring inside the clip. */}
<div className="relative z-10 flex h-8 min-w-0 flex-1 flex-wrap content-start items-center gap-x-2 overflow-hidden py-0.5">
Expand Down
Loading