diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx
index e8a2c3827e3..23f97e4c1ef 100644
--- a/apps/desktop/src/app/chat/sidebar/index.tsx
+++ b/apps/desktop/src/app/chat/sidebar/index.tsx
@@ -49,6 +49,7 @@ import {
$sidebarOpen,
$sidebarPinsOpen,
$sidebarRecentsOpen,
+ $sidebarRevealed,
pinSession,
reorderPinnedSession,
SESSION_SEARCH_FOCUS_EVENT,
@@ -247,6 +248,10 @@ export function ChatSidebar({
const { t } = useI18n()
const s = t.sidebar
const sidebarOpen = useStore($sidebarOpen)
+ // When collapsed but hover-revealed (floated over content), render the full
+ // sidebar — search field, pinned + recents — not just the nav rail.
+ const sidebarRevealed = useStore($sidebarRevealed)
+ const contentVisible = sidebarOpen || sidebarRevealed
const panesFlipped = useStore($panesFlipped)
const agentsGrouped = useStore($sidebarAgentsGrouped)
const pinnedSessionIds = useStore($pinnedSessionIds)
@@ -629,7 +634,7 @@ export function ChatSidebar({
type="button"
>
- {sidebarOpen && (
+ {contentVisible && (
<>
{s.nav[item.id] ?? item.label}
@@ -650,7 +655,7 @@ export function ChatSidebar({
- {sidebarOpen && showSessionSections && (
+ {contentVisible && showSessionSections && (
)}
- {sidebarOpen && showSessionSections && trimmedQuery && (
+ {contentVisible && showSessionSections && trimmedQuery && (
)}
- {sidebarOpen && showSessionSections && !trimmedQuery && (
+ {contentVisible && showSessionSections && !trimmedQuery && (
)}
- {sidebarOpen && showSessionSections && !trimmedQuery && (
+ {contentVisible && showSessionSections && !trimmedQuery && (
)}
- {sidebarOpen && !trimmedQuery && cronJobs.length > 0 && (
+ {contentVisible && !trimmedQuery && cronJobs.length > 0 && (
)}
- {sidebarOpen && !showSessionSections && }
+ {contentVisible && !showSessionSections && }
- {sidebarOpen && (
+ {contentVisible && (
diff --git a/apps/desktop/src/app/desktop-controller.tsx b/apps/desktop/src/app/desktop-controller.tsx
index c0a8d4809c0..27ce9a013c4 100644
--- a/apps/desktop/src/app/desktop-controller.tsx
+++ b/apps/desktop/src/app/desktop-controller.tsx
@@ -23,6 +23,7 @@ import {
FILE_BROWSER_MAX_WIDTH,
FILE_BROWSER_MIN_WIDTH,
pinSession,
+ setSidebarRevealed,
SIDEBAR_DEFAULT_WIDTH,
SIDEBAR_MAX_WIDTH,
SIDEBAR_SESSIONS_PAGE_SIZE,
@@ -300,6 +301,7 @@ export function DesktopController() {
// with few recent sessions isn't windowed out of the cross-profile
// recency page — the empty-history-on-profile-switch bug.
const sessionProfile = profileScope === ALL_PROFILES ? 'all' : profileScope
+
const result = await listAllProfileSessions(limit, 1, 'exclude', 'recent', sessionProfile, {
excludeSources: ['cron']
})
@@ -877,6 +879,7 @@ export function DesktopController() {
id="chat-sidebar"
maxWidth={SIDEBAR_MAX_WIDTH}
minWidth={SIDEBAR_DEFAULT_WIDTH}
+ onHoverRevealChange={setSidebarRevealed}
resizable
side={sidebarSide}
width={`${SIDEBAR_DEFAULT_WIDTH}px`}
diff --git a/apps/desktop/src/components/pane-shell/pane-shell.tsx b/apps/desktop/src/components/pane-shell/pane-shell.tsx
index 2a34638e49f..284c64476d0 100644
--- a/apps/desktop/src/components/pane-shell/pane-shell.tsx
+++ b/apps/desktop/src/components/pane-shell/pane-shell.tsx
@@ -39,6 +39,8 @@ export interface PaneProps {
* track stays at 0px.
*/
hoverReveal?: boolean
+ /** Called with the reveal state whenever a collapsed hoverReveal pane floats in/out. */
+ onHoverRevealChange?: (revealed: boolean) => void
id: string
maxWidth?: WidthValue
minWidth?: WidthValue
@@ -205,6 +207,7 @@ export function Pane({
id,
maxWidth,
minWidth,
+ onHoverRevealChange,
resizable = false,
width
}: PaneProps) {
@@ -248,6 +251,12 @@ export function Pane({
}
}, [overlayActive, hoverRevealed])
+ // Surface the effective reveal state to consumers (e.g. so the sidebar can
+ // render its full content while floated, not just while the track is open).
+ useEffect(() => {
+ onHoverRevealChange?.(overlayActive && hoverRevealed)
+ }, [onHoverRevealChange, overlayActive, hoverRevealed])
+
const startResize = useCallback(
(event: ReactPointerEvent) => {
const paneWidth = paneRef.current?.getBoundingClientRect().width ?? 0
diff --git a/apps/desktop/src/store/layout.ts b/apps/desktop/src/store/layout.ts
index c01d8b58bd3..ae279ec1728 100644
--- a/apps/desktop/src/store/layout.ts
+++ b/apps/desktop/src/store/layout.ts
@@ -54,6 +54,10 @@ export const $sidebarWidth: ReadableAtom = computed($paneStates, states
export const $pinnedSessionIds = atom(storedStringArray(SIDEBAR_PINNED_STORAGE_KEY))
export const $sidebarPinsOpen = atom(true)
+// Set by the PaneShell hover-reveal overlay while the collapsed sidebar is
+// floated over content. ChatSidebar treats `sidebarOpen || sidebarRevealed` as
+// "show my full self" so session rows render in the overlay too.
+export const $sidebarRevealed = atom(false)
export const $sidebarRecentsOpen = atom(true)
// Cron-job sessions live in their own section below recents, collapsed by
// default (it only renders at all when cron sessions exist) so the
@@ -116,6 +120,12 @@ export function setSidebarPinsOpen(open: boolean) {
$sidebarPinsOpen.set(open)
}
+export function setSidebarRevealed(revealed: boolean) {
+ if ($sidebarRevealed.get() !== revealed) {
+ $sidebarRevealed.set(revealed)
+ }
+}
+
export function setSidebarRecentsOpen(open: boolean) {
$sidebarRecentsOpen.set(open)
}