diff --git a/client/src/components/Agents/Marketplace.tsx b/client/src/components/Agents/Marketplace.tsx index 8b7afc095..83aa453da 100644 --- a/client/src/components/Agents/Marketplace.tsx +++ b/client/src/components/Agents/Marketplace.tsx @@ -11,7 +11,6 @@ import { useDocumentTitle, useHasAccess, useLocalize, TranslationKeys } from '~/ import { useGetEndpointsQuery, useGetAgentCategoriesQuery } from '~/data-provider'; import MarketplaceAdminSettings from './MarketplaceAdminSettings'; import { SidePanelProvider, useChatContext } from '~/Providers'; -import { MarketplaceProvider } from './MarketplaceContext'; import { SidePanelGroup } from '~/components/SidePanel'; import { OpenSidebar } from '~/components/Chat/Menus'; import CategoryTabs from './CategoryTabs'; @@ -272,100 +271,176 @@ const AgentMarketplace: React.FC = ({ className = '' }) = } return (
- - - -
- {/* Scrollable container */} -
- {/* Simplified header for agents marketplace - only show nav controls when needed */} - {!isSmallScreen && ( -
-
- {!navVisible ? ( - <> - - - - - } - /> - - ) : ( - // Invisible placeholder to maintain height -
- )} -
-
- )} - {/* Hero Section - scrolls away */} - {!isSmallScreen && ( -
-
-

- {localize('com_agents_marketplace')} -

-

- {localize('com_agents_marketplace_subtitle')} -

-
-
- )} - {/* Sticky wrapper for search bar and categories */} -
-
- {/* Search bar */} -
- - {/* TODO: Remove this once we have a better way to handle admin settings */} - {/* Admin Settings */} - -
- - {/* Category tabs */} - + + +
+ {/* Scrollable container */} +
+ {/* Simplified header for agents marketplace - only show nav controls when needed */} + {!isSmallScreen && ( +
+
+ {!navVisible ? ( + <> + + + + + } + /> + + ) : ( + // Invisible placeholder to maintain height +
+ )}
- {/* Scrollable content area */} -
- {/* Two-pane animated container wrapping category header + grid */} -
- {/* Current content pane */} + )} + {/* Hero Section - scrolls away */} + {!isSmallScreen && ( +
+
+

+ {localize('com_agents_marketplace')} +

+

+ {localize('com_agents_marketplace_subtitle')} +

+
+
+ )} + {/* Sticky wrapper for search bar and categories */} +
+
+ {/* Search bar */} +
+ + {/* TODO: Remove this once we have a better way to handle admin settings */} + {/* Admin Settings */} + +
+ + {/* Category tabs */} + +
+
+ {/* Scrollable content area */} +
+ {/* Two-pane animated container wrapping category header + grid */} +
+ {/* Current content pane */} +
+ {/* Category header - only show when not searching */} + {!searchQuery && ( +
+ {(() => { + // Get category data for display + const getCategoryData = () => { + if (displayCategory === 'promoted') { + return { + name: localize('com_agents_top_picks'), + description: localize('com_agents_recommended'), + }; + } + if (displayCategory === 'all') { + return { + name: localize('com_agents_all'), + description: localize('com_agents_all_description'), + }; + } + + // Find the category in the API data + const categoryData = categoriesQuery.data?.find( + (cat) => cat.value === displayCategory, + ); + if (categoryData) { + return { + name: categoryData.label?.startsWith('com_') + ? localize(categoryData.label as TranslationKeys) + : categoryData.label, + description: categoryData.description?.startsWith('com_') + ? localize(categoryData.description as TranslationKeys) + : categoryData.description || '', + }; + } + + // Fallback for unknown categories + return { + name: + displayCategory.charAt(0).toUpperCase() + displayCategory.slice(1), + description: '', + }; + }; + + const { name, description } = getCategoryData(); + + return ( +
+

{name}

+ {description && ( +

{description}

+ )} +
+ ); + })()} +
+ )} + + {/* Agent grid */} + +
+ + {/* Next content pane, only during transition */} + {isTransitioning && nextCategory && (
{/* Category header - only show when not searching */} {!searchQuery && ( @@ -373,13 +448,13 @@ const AgentMarketplace: React.FC = ({ className = '' }) = {(() => { // Get category data for display const getCategoryData = () => { - if (displayCategory === 'promoted') { + if (nextCategory === 'promoted') { return { name: localize('com_agents_top_picks'), description: localize('com_agents_recommended'), }; } - if (displayCategory === 'all') { + if (nextCategory === 'all') { return { name: localize('com_agents_all'), description: localize('com_agents_all_description'), @@ -388,7 +463,7 @@ const AgentMarketplace: React.FC = ({ className = '' }) = // Find the category in the API data const categoryData = categoriesQuery.data?.find( - (cat) => cat.value === displayCategory, + (cat) => cat.value === nextCategory, ); if (categoryData) { return { @@ -396,7 +471,9 @@ const AgentMarketplace: React.FC = ({ className = '' }) = ? localize(categoryData.label as TranslationKeys) : categoryData.label, description: categoryData.description?.startsWith('com_') - ? localize(categoryData.description as TranslationKeys) + ? localize( + categoryData.description as Parameters[0], + ) : categoryData.description || '', }; } @@ -404,8 +481,8 @@ const AgentMarketplace: React.FC = ({ className = '' }) = // Fallback for unknown categories return { name: - displayCategory.charAt(0).toUpperCase() + - displayCategory.slice(1), + (nextCategory || '').charAt(0).toUpperCase() + + (nextCategory || '').slice(1), description: '', }; }; @@ -426,113 +503,30 @@ const AgentMarketplace: React.FC = ({ className = '' }) = {/* Agent grid */}
+ )} - {/* Next content pane, only during transition */} - {isTransitioning && nextCategory && ( -
- {/* Category header - only show when not searching */} - {!searchQuery && ( -
- {(() => { - // Get category data for display - const getCategoryData = () => { - if (nextCategory === 'promoted') { - return { - name: localize('com_agents_top_picks'), - description: localize('com_agents_recommended'), - }; - } - if (nextCategory === 'all') { - return { - name: localize('com_agents_all'), - description: localize('com_agents_all_description'), - }; - } - - // Find the category in the API data - const categoryData = categoriesQuery.data?.find( - (cat) => cat.value === nextCategory, - ); - if (categoryData) { - return { - name: categoryData.label?.startsWith('com_') - ? localize(categoryData.label as TranslationKeys) - : categoryData.label, - description: categoryData.description?.startsWith('com_') - ? localize( - categoryData.description as Parameters< - typeof localize - >[0], - ) - : categoryData.description || '', - }; - } - - // Fallback for unknown categories - return { - name: - (nextCategory || '').charAt(0).toUpperCase() + - (nextCategory || '').slice(1), - description: '', - }; - }; - - const { name, description } = getCategoryData(); - - return ( -
-

{name}

- {description && ( -

{description}

- )} -
- ); - })()} -
- )} - - {/* Agent grid */} - -
- )} - - {/* Note: Using Tailwind keyframes for slide in/out animations */} -
+ {/* Note: Using Tailwind keyframes for slide in/out animations */}
- {/* Agent detail dialog */} - {isDetailOpen && selectedAgent && ( - - )}
-
-
-
- + {/* Agent detail dialog */} + {isDetailOpen && selectedAgent && ( + + )} +
+
+
+
); }; diff --git a/client/src/components/Nav/Bookmarks/BookmarkNav.tsx b/client/src/components/Nav/Bookmarks/BookmarkNav.tsx index edff93a9e..27d558ba8 100644 --- a/client/src/components/Nav/Bookmarks/BookmarkNav.tsx +++ b/client/src/components/Nav/Bookmarks/BookmarkNav.tsx @@ -1,6 +1,5 @@ import { useMemo } from 'react'; import type { FC } from 'react'; -import { useRecoilValue } from 'recoil'; import { TooltipAnchor } from '@librechat/client'; import { Menu, MenuButton, MenuItems } from '@headlessui/react'; import { BookmarkFilledIcon, BookmarkIcon } from '@radix-ui/react-icons'; @@ -9,7 +8,6 @@ import { useGetConversationTags } from '~/data-provider'; import BookmarkNavItems from './BookmarkNavItems'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; -import store from '~/store'; type BookmarkNavProps = { tags: string[]; @@ -20,7 +18,6 @@ type BookmarkNavProps = { const BookmarkNav: FC = ({ tags, setTags, isSmallScreen }: BookmarkNavProps) => { const localize = useLocalize(); const { data } = useGetConversationTags(); - const conversation = useRecoilValue(store.conversationByIndex(0)); const label = useMemo( () => (tags.length > 0 ? tags.join(', ') : localize('com_ui_bookmarks')), [tags, localize], @@ -56,11 +53,9 @@ const BookmarkNav: FC = ({ tags, setTags, isSmallScreen }: Boo anchor="bottom" className="absolute left-0 top-full z-[100] mt-1 w-60 translate-y-0 overflow-hidden rounded-lg bg-surface-secondary p-1.5 shadow-lg outline-none" > - {data && conversation && ( + {data && ( tag.count > 0) }}> void; -}> = ({ conversation, tags = [], setTags }) => { - const [currentConversation, setCurrentConversation] = useState(); +}> = ({ tags = [], setTags }) => { const { bookmarks } = useBookmarkContext(); const localize = useLocalize(); - useEffect(() => { - if (!currentConversation) { - setCurrentConversation(conversation); - } - }, [conversation, currentConversation]); - const getUpdatedSelected = (tag: string) => { if (tags.some((selectedTag) => selectedTag === tag)) { return tags.filter((selectedTag) => selectedTag !== tag); diff --git a/client/src/routes/index.tsx b/client/src/routes/index.tsx index 2b3ab56db..871fd3ff8 100644 --- a/client/src/routes/index.tsx +++ b/client/src/routes/index.tsx @@ -8,6 +8,7 @@ import { TwoFactorScreen, RequestPasswordReset, } from '~/components/Auth'; +import { MarketplaceProvider } from '~/components/Agents/MarketplaceContext'; import AgentMarketplace from '~/components/Agents/Marketplace'; import { OAuthSuccess, OAuthError } from '~/components/OAuth'; import { AuthContextProvider } from '~/hooks/AuthContext'; @@ -112,11 +113,19 @@ export const router = createBrowserRouter( }, { path: 'agents', - element: , + element: ( + + + + ), }, { path: 'agents/:category', - element: , + element: ( + + + + ), }, ], },