Skip to content

Commit 62e99f5

Browse files
Waleed Latifwaleedlatif1
authored andcommitted
feat(desktop): floating hover-peek sidebar
On the macOS desktop shell the collapsed sidebar has no width at all (`--sidebar-collapsed-width: 0`), so the only ways back were ⌘B and the title-bar toggle. Hovering that toggle now floats the sidebar in as a card over the content, inset from the window edge, and it retracts when the pointer leaves. Clicking the same control still docks it for good. The card is the existing `.sidebar-shell-outer` re-styled, not a second surface: `<Sidebar>` is never re-mounted, so its scroll position and expansion state survive a peek. One CSS rule re-points `--sidebar-width` at a new `--sidebar-expanded-width`, and the inner shell and aside follow with no per-element overrides. Chrome is all existing tokens — `--radius`, `--border`, `shadow-overlay`, `--z-modal` — and the fill is the sidebar's own `--surface-1`, so docked and floating are the same surface. Enter/exit use the popper idiom (`fade-in-0 zoom-in-95`) that emcn's Radix surfaces already use. Also migrates the search palette from raw `z-40`/`z-50` to `--z-modal`. It was the one overlay outranked by the new card, and the raw values also put it below `--z-toast`, inverting the order globals.css documents. Settings drive-bys, all pre-existing violations in files this touches: tokenize two literal pixel text sizes in passwords-view, route its cards through `SettingsResourceRow` instead of four re-derived chrome constants, and collapse three `{null}`-bodied `SettingsSection`s in browser settings into one section of real rows.
1 parent 18ddc22 commit 62e99f5

13 files changed

Lines changed: 993 additions & 126 deletions

File tree

apps/sim/app/_styles/globals.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
:root {
1313
--sidebar-width: 0px; /* 0 outside workspace; blocking script always sets actual value on workspace pages */
1414
--sidebar-collapsed-width: 51px; /* icon rail on web; desktop overrides to 0 before first paint */
15+
--sidebar-expanded-width: 248px; /* SIDEBAR_WIDTH.DEFAULT; the width to restore to, held even while collapsed */
1516
--desktop-title-bar-height: 0px; /* macOS traffic-light lane; desktop overrides before first paint */
1617
--desktop-title-bar-inset-x: 0px; /* clearance past the traffic lights; desktop overrides */
1718
--desktop-title-bar-control-offset: 0px; /* centres a lane control; desktop overrides */
@@ -154,6 +155,24 @@ html[data-sim-desktop-title-bar="inset"]
154155
--sidebar-width: var(--sidebar-collapsed-width);
155156
}
156157

158+
/**
159+
* Hover-peek: the shell floats out of flow as a card, so its subtree reads the restore
160+
* width instead of the collapsed one. Re-declaring the same variable the rule above
161+
* sets carries the inner shell and the aside along with no per-element overrides.
162+
*
163+
* Lives here rather than on the component because a Tailwind arbitrary property is one
164+
* class (0,1,0) and would lose to that rule's (0,2,0) selector.
165+
*/
166+
.sidebar-shell-outer[data-collapsed][data-peek] {
167+
--sidebar-width: var(--sidebar-expanded-width);
168+
}
169+
170+
/* The card appears at full width, so the aside's own width transition would animate
171+
0 -> expanded inside it. */
172+
.sidebar-shell-outer[data-peek] .sidebar-container {
173+
transition: none;
174+
}
175+
157176
.sidebar-container span,
158177
.sidebar-container .text-small {
159178
transition: opacity 120ms ease;

apps/sim/app/layout.tsx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,22 +112,26 @@ export default function RootLayout({ children }: { children: React.ReactNode })
112112
document.cookie = 'sidebar_collapsed=' + (collapsed ? '1' : '0') + '; path=/; max-age=31536000; samesite=lax';
113113
}
114114
115-
if (collapsed) {
116-
document.documentElement.style.setProperty(
117-
'--sidebar-width',
118-
collapsedSidebarWidth + 'px'
119-
);
120-
} else {
121-
var width = state && state.sidebarWidth;
122-
var maxSidebarWidth = Math.max(248, window.innerWidth * 0.3);
123-
var finalWidth =
124-
typeof width === 'number' && isFinite(width)
125-
? Math.min(Math.max(width, 248), maxSidebarWidth)
126-
: defaultSidebarWidth;
127-
document.documentElement.style.setProperty('--sidebar-width', finalWidth + 'px');
128-
}
115+
// The expanded width is published unconditionally, even while
116+
// collapsed, because the desktop hover-peek renders the sidebar at
117+
// its restore width while --sidebar-width still reads collapsed.
118+
var width = state && state.sidebarWidth;
119+
var maxSidebarWidth = Math.max(248, window.innerWidth * 0.3);
120+
var expandedWidth =
121+
typeof width === 'number' && isFinite(width)
122+
? Math.min(Math.max(width, 248), maxSidebarWidth)
123+
: defaultSidebarWidth;
124+
document.documentElement.style.setProperty(
125+
'--sidebar-expanded-width',
126+
expandedWidth + 'px'
127+
);
128+
document.documentElement.style.setProperty(
129+
'--sidebar-width',
130+
(collapsed ? collapsedSidebarWidth : expandedWidth) + 'px'
131+
);
129132
} catch (e) {
130133
document.documentElement.style.setProperty('--sidebar-width', defaultSidebarWidth + 'px');
134+
document.documentElement.style.setProperty('--sidebar-expanded-width', defaultSidebarWidth + 'px');
131135
}
132136
133137
// Panel width and active tab

0 commit comments

Comments
 (0)