diff --git a/web/app/src/components/ui/Icons/SidebarNavigationIcons.tsx b/web/app/src/components/ui/Icons/SidebarNavigationIcons.tsx
index 3d372539..eb4d322b 100644
--- a/web/app/src/components/ui/Icons/SidebarNavigationIcons.tsx
+++ b/web/app/src/components/ui/Icons/SidebarNavigationIcons.tsx
@@ -166,6 +166,32 @@ export function SidebarPuzzlePiece02Icon({ size, ...props }: SidebarNavigationIc
);
}
+export function SidebarMcpIcon({ size, ...props }: SidebarNavigationIconProps) {
+ const resolvedSize = iconSize(size, 16);
+ return (
+
+ );
+}
+
export function SidebarBoxIcon({ size, ...props }: SidebarNavigationIconProps) {
const resolvedSize = iconSize(size, 24);
return (
diff --git a/web/app/src/pages/WorkspacePage/components/ProfilePreviewPopover/ProfilePreviewPopover.tsx b/web/app/src/pages/WorkspacePage/components/ProfilePreviewPopover/ProfilePreviewPopover.tsx
index efea21dd..f2eb65fb 100644
--- a/web/app/src/pages/WorkspacePage/components/ProfilePreviewPopover/ProfilePreviewPopover.tsx
+++ b/web/app/src/pages/WorkspacePage/components/ProfilePreviewPopover/ProfilePreviewPopover.tsx
@@ -23,35 +23,27 @@ function clamp(value: number, min: number, max: number): number {
return Math.min(max, Math.max(min, value));
}
-function rootZoomScale(): number {
- const zoom = Number.parseFloat(window.getComputedStyle(document.documentElement).zoom);
- return Number.isFinite(zoom) && zoom > 0 ? zoom : 1;
-}
-
function profilePreviewStyle(anchorRect: ProfilePreviewAnchorRect | null | undefined, cardHeight?: number | null) {
- const scale = rootZoomScale();
const offset = 12;
const viewportPadding = 16;
- const width = Math.min(360, (window.innerWidth - viewportPadding * 2) / scale);
- const visualWidth = width * scale;
- const maxLeft = Math.max(viewportPadding, window.innerWidth - viewportPadding - visualWidth);
- const visualCardHeight = cardHeight ?? 420 * scale;
- const visibleHeight = Math.min(visualCardHeight, window.innerHeight - viewportPadding * 2);
+ const width = Math.min(360, window.innerWidth - viewportPadding * 2);
+ const maxLeft = Math.max(viewportPadding, window.innerWidth - viewportPadding - width);
+ const visibleHeight = Math.min(cardHeight ?? 420, window.innerHeight - viewportPadding * 2);
const maxTop = Math.max(viewportPadding, window.innerHeight - viewportPadding - visibleHeight);
if (!anchorRect) {
return {
- top: `${viewportPadding / scale}px`,
- left: `${viewportPadding / scale}px`,
+ top: `${viewportPadding}px`,
+ left: `${viewportPadding}px`,
width: `${width}px`,
};
}
- const hasRoomRight = anchorRect.right + offset + visualWidth <= window.innerWidth - viewportPadding;
- const preferredLeft = hasRoomRight ? anchorRect.right + offset : anchorRect.left - visualWidth - offset;
+ const hasRoomRight = anchorRect.right + offset + width <= window.innerWidth - viewportPadding;
+ const preferredLeft = hasRoomRight ? anchorRect.right + offset : anchorRect.left - width - offset;
const left = clamp(preferredLeft, viewportPadding, maxLeft);
const top = clamp(anchorRect.top - 12, viewportPadding, maxTop);
- return { top: `${top / scale}px`, left: `${left / scale}px`, width: `${width}px` };
+ return { top: `${top}px`, left: `${left}px`, width: `${width}px` };
}
export function ProfilePreviewPopover({
diff --git a/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspacePrimaryNavigation.tsx b/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspacePrimaryNavigation.tsx
index d89fa9ca..6d548952 100644
--- a/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspacePrimaryNavigation.tsx
+++ b/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspacePrimaryNavigation.tsx
@@ -1,6 +1,7 @@
import { classNames } from "@/shared/lib/classNames";
import styles from "./WorkspaceSidebar.module.css";
import { useCallback, useId, useRef, useState } from "react";
+import { createPortal } from "react-dom";
import type { CSSProperties, ReactNode } from "react";
import type { WorkspaceContextSectionId } from "./types";
@@ -101,11 +102,14 @@ function PrimaryNavigationButton({
{typeof item.badge === "number" ? (
{formatBadge(item.badge)}
) : null}
- {collapsed && tooltipStyle ? (
-
- {item.label}
-
- ) : null}
+ {collapsed && tooltipStyle
+ ? createPortal(
+
+ {item.label}
+ ,
+ document.body,
+ )
+ : null}
);
}
diff --git a/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspaceSidebar.tsx b/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspaceSidebar.tsx
index 392e79e5..d5bb89a1 100644
--- a/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspaceSidebar.tsx
+++ b/web/app/src/pages/WorkspacePage/components/WorkspaceSidebar/WorkspaceSidebar.tsx
@@ -1,11 +1,12 @@
import { useEffect, useMemo, useRef, useState } from "react";
-import { PanelLeftOpen, Plus, Search, Server } from "lucide-react";
+import { PanelLeftOpen, Plus, Search } from "lucide-react";
import {
SidebarAlertTriangleIcon,
SidebarBoxIcon,
SidebarGrid07Icon,
SidebarLaptopIcon,
SidebarListUnordered4Icon,
+ SidebarMcpIcon,
SidebarMessageIcon,
SidebarPuzzlePiece02Icon,
SidebarRobotIcon,
@@ -304,7 +305,7 @@ export function WorkspaceSidebar({
active: activeContextSectionId === WorkspaceContextSectionIds.mcpServers,
badge: badgeCount(hub?.mcpServers?.length),
groupId: WorkspaceContextSectionIds.mcpServers,
- icon: navigationIcon(Server),
+ icon: navigationIcon(SidebarMcpIcon),
id: "mcp-servers",
label: t("resourcesMCPLabel"),
onSelect: () => {
diff --git a/web/app/src/shared/styles/globals.css b/web/app/src/shared/styles/globals.css
index 8a320e87..f8cbd922 100644
--- a/web/app/src/shared/styles/globals.css
+++ b/web/app/src/shared/styles/globals.css
@@ -10,35 +10,9 @@
}
:root {
- --app-ui-floating-layer-scale: 1;
--app-ui-viewport-height: 100dvh;
}
-@supports (zoom: 80%) {
- :root {
- --app-ui-floating-layer-scale: 125%;
- --app-ui-viewport-height: 125dvh;
- --text-xs-size: 13px;
- --text-sm-size: 15px;
- --text-md-size: 17px;
- --text-lg-size: 19px;
- --text-xl-size: 21px;
- --text-2xl-size: 25px;
- --text-3xl-size: 31px;
- --text-4xl-size: 37px;
- --text-5xl-size: 49px;
- --text-6xl-size: 61px;
- --text-7xl-size: 73px;
- font-size-adjust: 0.65;
- zoom: 80%;
- }
-}
-
-/* Radix positions poppers in visual viewport coordinates, so cancel the root zoom on its positioning wrapper. */
-[data-radix-popper-content-wrapper] {
- zoom: var(--app-ui-floating-layer-scale);
-}
-
html,
body,
#root {
diff --git a/web/app/tests/components/ProfilePreviewPopover.test.tsx b/web/app/tests/components/ProfilePreviewPopover.test.tsx
index b6136540..4c9e3f50 100644
--- a/web/app/tests/components/ProfilePreviewPopover.test.tsx
+++ b/web/app/tests/components/ProfilePreviewPopover.test.tsx
@@ -34,12 +34,10 @@ function t(key: string): string {
}
describe("ProfilePreviewPopover", () => {
- it("keeps the preview outside its anchor when the page is zoomed", () => {
- const previousZoom = document.documentElement.style.zoom;
- document.documentElement.style.zoom = "0.8";
+ it("keeps the preview outside its anchor in normal viewport coordinates", () => {
const anchorRect = { top: 120, right: 502, bottom: 152, left: 470 };
- const view = render(
+ render(
()}
agent={{ id: "agent-1", name: "Builder", role: "worker", status: "running" }}
@@ -52,19 +50,13 @@ describe("ProfilePreviewPopover", () => {
/>,
);
- try {
- const preview = screen.getByRole("dialog", { name: "Profile preview" });
- const scale = 0.8;
- const visualLeft = Number.parseFloat(preview.style.left) * scale;
- const visualTop = Number.parseFloat(preview.style.top) * scale;
+ const preview = screen.getByRole("dialog", { name: "Profile preview" });
+ const left = Number.parseFloat(preview.style.left);
+ const top = Number.parseFloat(preview.style.top);
- expect(visualLeft).toBe(anchorRect.right + 12);
- expect(visualTop).toBe(anchorRect.top - 12);
- expect(visualLeft).toBeGreaterThan(anchorRect.right);
- } finally {
- view.unmount();
- document.documentElement.style.zoom = previousZoom;
- }
+ expect(left).toBe(anchorRect.right + 12);
+ expect(top).toBe(anchorRect.top - 12);
+ expect(left).toBeGreaterThan(anchorRect.right);
});
it("shows compact agent runtime/provider/model fields with reasoning in model", () => {
diff --git a/web/app/tests/shared/appScale.test.ts b/web/app/tests/shared/appScale.test.ts
index 5677f5ed..f4458465 100644
--- a/web/app/tests/shared/appScale.test.ts
+++ b/web/app/tests/shared/appScale.test.ts
@@ -6,22 +6,19 @@ function readSource(path: string): string {
}
describe("default app scale", () => {
- it("renders the full UI at 80 percent while preserving the scaled viewport height", () => {
+ it("renders the full UI at normal viewport scale", () => {
const globals = readSource("src/shared/styles/globals.css");
const workspace = readSource("src/pages/WorkspacePage/components/WorkspaceComponents.css");
const workspaceLayout = readSource("src/pages/WorkspacePage/components/WorkspaceLayout/WorkspaceLayout.module.css");
const settings = readSource("src/pages/SettingsPage/SettingsPage.module.css");
- expect(globals).toContain("@supports (zoom: 80%)");
- expect(globals).toContain("--app-ui-floating-layer-scale: 125%;");
- expect(globals).toContain("--app-ui-viewport-height: 125dvh;");
- expect(globals).toContain("--text-xs-size: 13px;");
- expect(globals).toContain("--text-sm-size: 15px;");
- expect(globals).toContain("--text-md-size: 17px;");
- expect(globals).toContain("font-size-adjust: 0.65;");
- expect(globals).toContain("zoom: 80%;");
- expect(globals).toContain("[data-radix-popper-content-wrapper]");
- expect(globals).toContain("zoom: var(--app-ui-floating-layer-scale);");
+ expect(globals).toContain("--app-ui-viewport-height: 100dvh;");
+ expect(globals).not.toContain("--app-ui-floating-layer-scale");
+ expect(globals).not.toContain("@supports (zoom: 80%)");
+ expect(globals).not.toContain("--app-ui-viewport-height: 125dvh;");
+ expect(globals).not.toContain("font-size-adjust: 0.65;");
+ expect(globals).not.toContain("zoom: 80%;");
+ expect(globals).not.toContain("[data-radix-popper-content-wrapper]");
expect(globals).toContain("font-size: var(--text-md-size);");
expect(globals).toContain("font-family: var(--font-sans);");
expect(workspace).toContain("height: var(--app-ui-viewport-height);");