fix(ui): back recent header only when stuck
This commit is contained in:
@@ -1705,9 +1705,10 @@ const SessionSidebarComponent: React.FC<SessionSidebarProps> = ({
|
||||
openSidebarMenuKey={openSidebarMenuKey}
|
||||
expansionState={recentExpandedParents}
|
||||
variant="section"
|
||||
isDesktopShellRuntime={isDesktopShellRuntime}
|
||||
/>
|
||||
) : null,
|
||||
[activitySections, editingId, hasSessionSearchQuery, isVSCode, openSidebarMenuKey, recentExpandedParents, renderSessionNode, showRecentSection],
|
||||
[activitySections, editingId, hasSessionSearchQuery, isDesktopShellRuntime, isVSCode, openSidebarMenuKey, recentExpandedParents, renderSessionNode, showRecentSection],
|
||||
);
|
||||
const isInlineEditing = Boolean(renamingFolderId || editingId || editingProjectDialogId);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
resolveMenuOpenSessionId,
|
||||
} from './sessionNodeItemUtils';
|
||||
import type { SessionNodeRenderExtras } from './sessionNodeItemUtils';
|
||||
import { useStickyHeader } from './hooks/useStickyProjectHeaders';
|
||||
|
||||
type ActivityItem = {
|
||||
node: SessionNode;
|
||||
@@ -45,6 +46,7 @@ type Props = {
|
||||
variant?: 'section' | 'flat';
|
||||
initialVisibleCount?: number;
|
||||
batchSize?: number;
|
||||
isDesktopShellRuntime: boolean;
|
||||
};
|
||||
|
||||
type RenderExtras = SessionNodeRenderExtras;
|
||||
@@ -60,12 +62,17 @@ export function SidebarActivitySections(props: Props): React.ReactNode {
|
||||
variant = 'section',
|
||||
initialVisibleCount = MAX_VISIBLE_RECENT_SESSIONS,
|
||||
batchSize = MAX_VISIBLE_RECENT_SESSIONS,
|
||||
isDesktopShellRuntime,
|
||||
} = props;
|
||||
const { t } = useI18n();
|
||||
const stickyZoneHeaders = useSessionDisplayStore((state) => state.stickyZoneHeaders);
|
||||
const [collapsed, setCollapsed] = React.useState<Set<string>>(new Set());
|
||||
const [visibleCountBySection, setVisibleCountBySection] = React.useState<Map<string, number>>(new Map());
|
||||
const flatVariant = variant === 'flat';
|
||||
const { isStuck: isRecentHeaderStuck, sentinelRef: recentHeaderSentinelRef } = useStickyHeader({
|
||||
enabled: stickyZoneHeaders && !flatVariant,
|
||||
isDesktopShellRuntime,
|
||||
});
|
||||
|
||||
const resetSectionLimit = React.useCallback((key: string) => {
|
||||
setVisibleCountBySection((prev) => {
|
||||
@@ -177,11 +184,17 @@ export function SidebarActivitySections(props: Props): React.ReactNode {
|
||||
|
||||
return (
|
||||
<div key={section.key} className="relative space-y-1">
|
||||
{/* Zone header styled like a project header band; sticky with a
|
||||
solid sidebar backing so rows never show through. */}
|
||||
{/* Zone header styled like a project header band; its solid
|
||||
backing applies only after the header is actually stuck. */}
|
||||
<div
|
||||
ref={recentHeaderSentinelRef}
|
||||
className="absolute top-0 h-px w-full pointer-events-none"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className={cn(
|
||||
'-ml-2.5 -mr-2',
|
||||
stickyZoneHeaders && 'oc-zone-header-backing sticky top-0 z-20 bg-sidebar',
|
||||
stickyZoneHeaders && 'sticky top-0 z-20 bg-sidebar',
|
||||
stickyZoneHeaders && isRecentHeaderStuck && 'oc-zone-header-backing',
|
||||
)}>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -7,6 +7,37 @@ type Args = {
|
||||
projectHeaderSentinelRefs: React.MutableRefObject<Map<string, HTMLDivElement | null>>;
|
||||
};
|
||||
|
||||
type StickyHeaderArgs = {
|
||||
enabled: boolean;
|
||||
isDesktopShellRuntime: boolean;
|
||||
};
|
||||
|
||||
export const useStickyHeader = (args: StickyHeaderArgs) => {
|
||||
const { enabled, isDesktopShellRuntime } = args;
|
||||
const [sentinel, setSentinel] = React.useState<HTMLDivElement | null>(null);
|
||||
const [isStuck, setIsStuck] = React.useState(false);
|
||||
|
||||
const sentinelRef = React.useCallback((node: HTMLDivElement | null) => {
|
||||
setSentinel(node);
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!enabled || !isDesktopShellRuntime || !sentinel) {
|
||||
setIsStuck(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(([entry]) => {
|
||||
setIsStuck(entry.intersectionRatio < 1);
|
||||
}, { threshold: 1 });
|
||||
|
||||
observer.observe(sentinel);
|
||||
return () => observer.disconnect();
|
||||
}, [enabled, isDesktopShellRuntime, sentinel]);
|
||||
|
||||
return { isStuck, sentinelRef };
|
||||
};
|
||||
|
||||
export const useStickyProjectHeaders = (args: Args): Set<string> => {
|
||||
const { enabled = true, isDesktopShellRuntime, projectSections, projectHeaderSentinelRefs } = args;
|
||||
const [stuckProjectHeaders, setStuckProjectHeaders] = React.useState<Set<string>>(new Set());
|
||||
|
||||
Reference in New Issue
Block a user