mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-11 08:42:11 +00:00
fix(desktop): render full sidebar content in hover-reveal overlay
The hover-reveal overlay showed only the nav rail — session rows, search, pinned/recents were gated behind `sidebarOpen` (false while collapsed), so they never mounted in the floated panel. Add a $sidebarRevealed store the PaneShell overlay drives via a new onHoverRevealChange callback, and gate ChatSidebar's content on `sidebarOpen || sidebarRevealed` (contentVisible) instead of raw open state. The overlay now shows the complete sidebar.
This commit is contained in:
parent
aa89205627
commit
3e455726eb
4 changed files with 35 additions and 8 deletions
|
|
@ -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"
|
||||
>
|
||||
<item.icon className="size-4 shrink-0 text-[color-mix(in_srgb,currentColor_72%,transparent)]" />
|
||||
{sidebarOpen && (
|
||||
{contentVisible && (
|
||||
<>
|
||||
<span className="min-w-0 flex-1 truncate max-[46.25rem]:hidden">
|
||||
{s.nav[item.id] ?? item.label}
|
||||
|
|
@ -650,7 +655,7 @@ export function ChatSidebar({
|
|||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
||||
{sidebarOpen && showSessionSections && (
|
||||
{contentVisible && showSessionSections && (
|
||||
<div className="shrink-0 px-2 pb-1 pt-1">
|
||||
<SearchField
|
||||
aria-label={s.searchAria}
|
||||
|
|
@ -662,7 +667,7 @@ export function ChatSidebar({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{sidebarOpen && showSessionSections && trimmedQuery && (
|
||||
{contentVisible && showSessionSections && trimmedQuery && (
|
||||
<SidebarSessionsSection
|
||||
activeSessionId={activeSidebarSessionId}
|
||||
contentClassName="flex min-h-0 flex-1 flex-col gap-px overflow-y-auto overscroll-contain pb-1.75"
|
||||
|
|
@ -686,7 +691,7 @@ export function ChatSidebar({
|
|||
/>
|
||||
)}
|
||||
|
||||
{sidebarOpen && showSessionSections && !trimmedQuery && (
|
||||
{contentVisible && showSessionSections && !trimmedQuery && (
|
||||
<SidebarSessionsSection
|
||||
activeSessionId={activeSidebarSessionId}
|
||||
contentClassName="flex min-h-10 shrink-0 flex-col gap-px rounded-lg pb-2 pt-1"
|
||||
|
|
@ -708,7 +713,7 @@ export function ChatSidebar({
|
|||
/>
|
||||
)}
|
||||
|
||||
{sidebarOpen && showSessionSections && !trimmedQuery && (
|
||||
{contentVisible && showSessionSections && !trimmedQuery && (
|
||||
<SidebarSessionsSection
|
||||
activeSessionId={activeSidebarSessionId}
|
||||
contentClassName={cn(
|
||||
|
|
@ -781,7 +786,7 @@ export function ChatSidebar({
|
|||
/>
|
||||
)}
|
||||
|
||||
{sidebarOpen && !trimmedQuery && cronJobs.length > 0 && (
|
||||
{contentVisible && !trimmedQuery && cronJobs.length > 0 && (
|
||||
<SidebarCronJobsSection
|
||||
jobs={cronJobs}
|
||||
label={s.cronJobs}
|
||||
|
|
@ -793,9 +798,9 @@ export function ChatSidebar({
|
|||
/>
|
||||
)}
|
||||
|
||||
{sidebarOpen && !showSessionSections && <div className="min-h-0 flex-1" />}
|
||||
{contentVisible && !showSessionSections && <div className="min-h-0 flex-1" />}
|
||||
|
||||
{sidebarOpen && (
|
||||
{contentVisible && (
|
||||
<div className="shrink-0 px-0.5 pb-1 pt-0.5">
|
||||
<ProfileRail />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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`}
|
||||
|
|
|
|||
|
|
@ -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<HTMLDivElement>) => {
|
||||
const paneWidth = paneRef.current?.getBoundingClientRect().width ?? 0
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ export const $sidebarWidth: ReadableAtom<number> = 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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue