diff --git a/apps/sim/app/_styles/globals.css b/apps/sim/app/_styles/globals.css
index 14508122541..ae53a936065 100644
--- a/apps/sim/app/_styles/globals.css
+++ b/apps/sim/app/_styles/globals.css
@@ -11,7 +11,7 @@
*/
:root {
--sidebar-width: 0px; /* 0 outside workspace; blocking script always sets actual value on workspace pages */
- --sidebar-collapsed-width: 51px; /* icon rail on web; desktop overrides to 0 before first paint */
+ --sidebar-collapsed-width: 48px; /* icon rail on web; desktop overrides to 0 before first paint */
--sidebar-expanded-width: 238px; /* SIDEBAR_WIDTH.DEFAULT; the width to restore to, held even while collapsed */
--desktop-title-bar-height: 0px; /* macOS traffic-light lane; desktop overrides before first paint */
--workspace-content-title-bar-inset: 0px; /* lane the content pane must leave clear; only non-zero when the pane, not the sidebar, sits under it */
diff --git a/apps/sim/app/layout.tsx b/apps/sim/app/layout.tsx
index 6f5d5ff5705..21688e8470e 100644
--- a/apps/sim/app/layout.tsx
+++ b/apps/sim/app/layout.tsx
@@ -75,7 +75,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
// The macOS desktop shell overlays native traffic lights on the
// workspace. Mark it before first paint so the sidebar reserves
// its inset title-bar lane without a post-hydration layout shift.
- var collapsedSidebarWidth = 51;
+ var collapsedSidebarWidth = 48;
try {
if (window.simDesktop && /Mac/i.test(navigator.userAgent)) {
document.documentElement.setAttribute('data-sim-desktop-title-bar', 'inset');
diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-tabs/resource-tab-controls.ts b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-tabs/resource-tab-controls.ts
index cf8f02ac5ab..5d5697d7be9 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-tabs/resource-tab-controls.ts
+++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-tabs/resource-tab-controls.ts
@@ -7,13 +7,18 @@ export const RESOURCE_TAB_ICON_CLASS = 'size-[16px] text-[var(--text-icon)]'
/** Shared geometry for the resource header and controls positioned over it. */
export const RESOURCE_HEADER_CLASSES = {
layout:
- '[--resource-header-controls-height:43px] [--resource-header-end-inset:16px] [--resource-header-fixed-reserve:54px]',
+ '[--resource-header-controls-height:43px] [--resource-header-end-inset:16px] [--resource-header-fixed-reserve:54px] [--resource-header-toggle-size:30px]',
bar: 'h-[calc(var(--resource-header-controls-height)_+_1px)]',
- controls: 'h-[var(--resource-header-controls-height)]',
- contentTop: 'top-[8.5px]',
+ overlay: 'absolute top-0 flex h-[var(--resource-header-controls-height)] items-center',
startPadding: 'pl-[var(--resource-header-end-inset)]',
endPadding: 'pr-[var(--resource-header-fixed-reserve)]',
endPosition: 'right-[var(--resource-header-end-inset)]',
- adjacentEndPosition: 'right-[var(--resource-header-fixed-reserve)]',
+ /**
+ * Sits a control 1px clear of the overlaid 30px collapse toggle — the same
+ * chip-to-chip gap the sidebar header cluster uses (`gap-[1px]`), so the
+ * credits chip and the toggle read as one cluster across both surfaces.
+ */
+ adjacentEndPosition:
+ 'right-[calc(var(--resource-header-end-inset)_+_var(--resource-header-toggle-size)_+_1px)]',
emptyAddOffset: '-translate-x-1.5',
} as const
diff --git a/apps/sim/app/workspace/[workspaceId]/home/home.tsx b/apps/sim/app/workspace/[workspaceId]/home/home.tsx
index dd5d02da37d..eba97d8274e 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/home.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/home/home.tsx
@@ -283,21 +283,32 @@ export function Home({ chatId, userName, userId, tableViewsEnabled }: HomeProps)
setIsResourceCollapsed(true)
}, [clearWidth])
+ const clearResourceActivity = useCallback((resourceId: string) => {
+ setResourceActivityIds((current) => {
+ if (!current.has(resourceId)) return current
+ const next = new Set(current)
+ next.delete(resourceId)
+ return next
+ })
+ }, [])
+
+ const expandResource = () => {
+ userOwnsResourceViewRef.current = true
+ const activeResourceId = activeResourceParamRef.current
+ if (activeResourceId) clearResourceActivity(activeResourceId)
+ setIsResourceCollapsed(false)
+ }
+
const selectResourceFromUser = useCallback(
(resourceId: string) => {
userOwnsResourceViewRef.current = true
- setResourceActivityIds((current) => {
- if (!current.has(resourceId)) return current
- const next = new Set(current)
- next.delete(resourceId)
- return next
- })
+ clearResourceActivity(resourceId)
if (effectiveActiveResourceIdRef.current === resourceId) return
effectiveActiveResourceIdRef.current = resourceId
activeResourceParamRef.current = resourceId
setActiveResourceId(resourceId)
},
- [setActiveResourceId]
+ [setActiveResourceId, clearResourceActivity]
)
const addResourceFromUser = useCallback(
@@ -581,9 +592,17 @@ export function Home({ chatId, userName, userId, tableViewsEnabled }: HomeProps)
{showEmptyState && (
@@ -690,34 +709,14 @@ export function Home({ chatId, userName, userId, tableViewsEnabled }: HomeProps)