mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 09:50:15 +01:00
🖼️ style: Improve Marketplace & Sharing Dialog UI
feat: Enhance CategoryTabs and Marketplace components for better responsiveness and navigation feat: Refactor AgentCard and AgentGrid components for improved layout and accessibility feat: Implement animated category transitions in AgentMarketplace and update NewChat component layout feat: Refactor UI components for improved styling and accessibility in sharing dialogs refactor: remove GenericManagePermissionsDialog and GrantAccessDialog components - Deleted GenericManagePermissionsDialog and GrantAccessDialog components to streamline sharing functionality. - Updated ManagePermissionsDialog to utilize AccessRolesPicker directly. - Introduced UnifiedPeopleSearch for improved people selection experience. - Enhanced PublicSharingToggle with InfoHoverCard for better user guidance. - Adjusted AgentPanel to change error status to warning for duplicate agent versions. - Updated translations to include new keys for search and access management. feat: Add responsive design for SelectedPrincipalsList and improve layout in GenericGrantAccessDialog feat: Enhance styling in SelectedPrincipalsList and SearchPicker components for improved UI consistency feat: Improve PublicSharingToggle component with enhanced styling and accessibility features feat: Introduce InfoHoverCard component and refactor enums for better organization feat: Implement infinite scroll for agent grids and enhance performance - Added `useInfiniteScroll` hook to manage infinite scrolling behavior in agent grids. - Integrated infinite scroll functionality into `AgentGrid` and `VirtualizedAgentGrid` components. - Updated `AgentMarketplace` to pass the scroll container to the agent grid components. - Refactored loading indicators to show a spinner instead of a "Load More" button. - Created `VirtualizedAgentGrid` component for optimized rendering of agent cards using virtualization. - Added performance tests for `VirtualizedAgentGrid` to ensure efficient handling of large datasets. - Updated translations to include new messages for end-of-results scenarios. chore: Remove unused permission-related UI localization keys ci: Update Agent model tests to handle duplicate support_contact updates - Modified tests to ensure that updating an agent with the same support_contact does not create a new version and returns successfully. - Enhanced verification for partial changes in support_contact, confirming no new version is created when content remains the same. chore: Address ESLint, clean up unused imports and improve prop definitions in various components ci: fix tests ci: update tests chore: remove unused search localization keys
This commit is contained in:
parent
9585db14ba
commit
d82a63642d
51 changed files with 2074 additions and 1311 deletions
91
client/src/hooks/useInfiniteScroll.ts
Normal file
91
client/src/hooks/useInfiniteScroll.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { throttle } from 'lodash';
|
||||
|
||||
interface UseInfiniteScrollOptions {
|
||||
hasNextPage?: boolean;
|
||||
isFetchingNextPage?: boolean;
|
||||
fetchNextPage: () => void;
|
||||
threshold?: number; // Percentage of scroll position to trigger fetch (0-1)
|
||||
throttleMs?: number; // Throttle delay in milliseconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for implementing infinite scroll functionality
|
||||
* Detects when user scrolls near the bottom and triggers data fetching
|
||||
*/
|
||||
export const useInfiniteScroll = ({
|
||||
hasNextPage = false,
|
||||
isFetchingNextPage = false,
|
||||
fetchNextPage,
|
||||
threshold = 0.8, // Trigger when 80% scrolled
|
||||
throttleMs = 200,
|
||||
}: UseInfiniteScrollOptions) => {
|
||||
const scrollElementRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
// Throttled scroll handler to prevent excessive API calls
|
||||
const handleScroll = useCallback(
|
||||
throttle(() => {
|
||||
const element = scrollElementRef.current;
|
||||
if (!element) return;
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = element;
|
||||
|
||||
// Calculate scroll position as percentage
|
||||
const scrollPosition = (scrollTop + clientHeight) / scrollHeight;
|
||||
|
||||
// Check if we've scrolled past the threshold and conditions are met
|
||||
const shouldFetch = scrollPosition >= threshold && hasNextPage && !isFetchingNextPage;
|
||||
|
||||
if (shouldFetch) {
|
||||
fetchNextPage();
|
||||
}
|
||||
}, throttleMs),
|
||||
[hasNextPage, isFetchingNextPage, fetchNextPage, threshold, throttleMs],
|
||||
);
|
||||
|
||||
// Set up scroll listener
|
||||
useEffect(() => {
|
||||
const element = scrollElementRef.current;
|
||||
if (!element) return;
|
||||
|
||||
// Remove any existing listener first
|
||||
element.removeEventListener('scroll', handleScroll);
|
||||
|
||||
// Add the new listener
|
||||
element.addEventListener('scroll', handleScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
element.removeEventListener('scroll', handleScroll);
|
||||
// Clean up throttled function
|
||||
handleScroll.cancel?.();
|
||||
};
|
||||
}, [handleScroll]);
|
||||
|
||||
// Additional effect to re-setup listeners when scroll element changes
|
||||
useEffect(() => {
|
||||
const element = scrollElementRef.current;
|
||||
if (!element) return;
|
||||
// Remove any existing listener first
|
||||
element.removeEventListener('scroll', handleScroll);
|
||||
|
||||
// Add the new listener
|
||||
element.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => {
|
||||
element.removeEventListener('scroll', handleScroll);
|
||||
// Clean up throttled function
|
||||
handleScroll.cancel?.();
|
||||
};
|
||||
}, [scrollElementRef.current, handleScroll]);
|
||||
|
||||
// Function to manually set the scroll container
|
||||
const setScrollElement = useCallback((element: HTMLElement | null) => {
|
||||
scrollElementRef.current = element;
|
||||
}, []);
|
||||
|
||||
return {
|
||||
setScrollElement,
|
||||
scrollElementRef,
|
||||
};
|
||||
};
|
||||
|
||||
export default useInfiniteScroll;
|
||||
66
client/src/hooks/useVirtualGrid.ts
Normal file
66
client/src/hooks/useVirtualGrid.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
interface UseVirtualGridProps {
|
||||
itemCount: number;
|
||||
containerWidth: number;
|
||||
itemHeight: number;
|
||||
gapSize: number;
|
||||
mobileColumnsCount: number;
|
||||
desktopColumnsCount: number;
|
||||
mobileBreakpoint: number;
|
||||
}
|
||||
|
||||
interface UseVirtualGridReturn {
|
||||
cardsPerRow: number;
|
||||
rowCount: number;
|
||||
rowHeight: number;
|
||||
getRowItems: (rowIndex: number, items: any[]) => any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for virtual grid calculations
|
||||
* Handles responsive grid layout and item positioning for virtualized lists
|
||||
*/
|
||||
export const useVirtualGrid = ({
|
||||
itemCount,
|
||||
containerWidth,
|
||||
itemHeight,
|
||||
gapSize,
|
||||
mobileColumnsCount,
|
||||
desktopColumnsCount,
|
||||
mobileBreakpoint = 768,
|
||||
}: UseVirtualGridProps): UseVirtualGridReturn => {
|
||||
// Calculate cards per row based on container width
|
||||
const cardsPerRow = useMemo(() => {
|
||||
return containerWidth >= mobileBreakpoint ? desktopColumnsCount : mobileColumnsCount;
|
||||
}, [containerWidth, mobileBreakpoint, desktopColumnsCount, mobileColumnsCount]);
|
||||
|
||||
// Calculate total number of rows needed
|
||||
const rowCount = useMemo(() => {
|
||||
return Math.ceil(itemCount / cardsPerRow);
|
||||
}, [itemCount, cardsPerRow]);
|
||||
|
||||
// Calculate row height including gap
|
||||
const rowHeight = useMemo(() => {
|
||||
return itemHeight + gapSize;
|
||||
}, [itemHeight, gapSize]);
|
||||
|
||||
// Get items for a specific row
|
||||
const getRowItems = useCallback(
|
||||
(rowIndex: number, items: any[]) => {
|
||||
const startIndex = rowIndex * cardsPerRow;
|
||||
const endIndex = Math.min(startIndex + cardsPerRow, items.length);
|
||||
return items.slice(startIndex, endIndex);
|
||||
},
|
||||
[cardsPerRow],
|
||||
);
|
||||
|
||||
return {
|
||||
cardsPerRow,
|
||||
rowCount,
|
||||
rowHeight,
|
||||
getRowItems,
|
||||
};
|
||||
};
|
||||
|
||||
export default useVirtualGrid;
|
||||
Loading…
Add table
Add a link
Reference in a new issue