= ({ category, searchQuery, onSelectAg
variant="outline"
onClick={handleLoadMore}
className={cn(
- 'min-w-[160px] border-2 border-gray-300 bg-white px-6 py-3 font-medium text-gray-700',
- 'shadow-sm transition-all duration-200 hover:border-gray-400 hover:bg-gray-50',
- 'hover:shadow-md focus:ring-2 focus:ring-blue-500 focus:ring-offset-2',
- 'dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200',
- 'dark:hover:border-gray-500 dark:hover:bg-gray-700 dark:focus:ring-blue-400',
+ 'min-w-[160px] border-2 border-border-medium bg-surface-primary px-6 py-3 font-medium text-text-primary',
+ 'shadow-sm transition-all duration-200 hover:border-border-heavy hover:bg-surface-hover',
+ 'hover:shadow-md focus:ring-2 focus:ring-ring focus:ring-offset-2',
)}
aria-label={localize('com_agents_load_more_label', {
category: getCategoryDisplayName(category),
diff --git a/client/src/components/SidePanel/Agents/AgentMarketplace.tsx b/client/src/components/SidePanel/Agents/AgentMarketplace.tsx
index 339412d45..ed4088eac 100644
--- a/client/src/components/SidePanel/Agents/AgentMarketplace.tsx
+++ b/client/src/components/SidePanel/Agents/AgentMarketplace.tsx
@@ -1,9 +1,9 @@
import React, { useState, useEffect, useMemo } from 'react';
+import { useRecoilState } from 'recoil';
import { useOutletContext } from 'react-router-dom';
import { useQueryClient } from '@tanstack/react-query';
-import { useSetRecoilState, useRecoilValue } from 'recoil';
-import { TooltipAnchor, Button, NewChatIcon } from '@librechat/client';
import { useSearchParams, useParams, useNavigate } from 'react-router-dom';
+import { TooltipAnchor, Button, NewChatIcon, useMediaQuery } from '@librechat/client';
import { PermissionTypes, Permissions, QueryKeys, Constants } from 'librechat-data-provider';
import type t from 'librechat-data-provider';
import type { ContextType } from '~/common';
@@ -17,6 +17,7 @@ import CategoryTabs from './CategoryTabs';
import AgentDetail from './AgentDetail';
import SearchBar from './SearchBar';
import AgentGrid from './AgentGrid';
+import { cn } from '~/utils';
import store from '~/store';
interface AgentMarketplaceProps {
@@ -33,13 +34,14 @@ interface AgentMarketplaceProps {
const AgentMarketplace: React.FC
= ({ className = '' }) => {
const localize = useLocalize();
const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { conversation, newConversation } = useChatContext();
- const [searchParams, setSearchParams] = useSearchParams();
const { category } = useParams();
- const setHideSidePanel = useSetRecoilState(store.hideSidePanel);
- const hideSidePanel = useRecoilValue(store.hideSidePanel);
+ const queryClient = useQueryClient();
+ const [searchParams, setSearchParams] = useSearchParams();
+ const { conversation, newConversation } = useChatContext();
+
+ const isSmallScreen = useMediaQuery('(max-width: 768px)');
const { navVisible, setNavVisible } = useOutletContext();
+ const [hideSidePanel, setHideSidePanel] = useRecoilState(store.hideSidePanel);
// Get URL parameters (default to 'promoted' instead of 'all')
const activeTab = category || 'promoted';
@@ -203,123 +205,145 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
fullPanelCollapse={fullCollapse}
defaultCollapsed={defaultCollapsed}
>
-
- {/* Simplified header for agents marketplace - only show nav controls when needed */}
-
-
- {!navVisible && }
- {!navVisible && (
-
-
-
- }
- />
- )}
-
-
-
- {/* Hero Section - ChatGPT Style */}
-
-
- {localize('com_agents_marketplace')}
-
-
- {localize('com_agents_marketplace_subtitle')}
-
-
- {/* Search bar */}
-
-
-
-
-
- {/* Category tabs */}
-
-
- {/* Category header - only show when not searching */}
- {!searchQuery && (
-
- {(() => {
- // Get category data for display
- const getCategoryData = () => {
- if (activeTab === 'promoted') {
- return {
- name: localize('com_agents_top_picks'),
- description: localize('com_agents_recommended'),
- };
- }
- if (activeTab === 'all') {
- return {
- name: 'All Agents',
- description: 'Browse all shared agents across all categories',
- };
- }
-
- // Find the category in the API data
- const categoryData = categoriesQuery.data?.find(
- (cat) => cat.value === activeTab,
- );
- if (categoryData) {
- return {
- name: categoryData.label,
- description: categoryData.description || '',
- };
- }
-
- // Fallback for unknown categories
- return {
- name: activeTab.charAt(0).toUpperCase() + activeTab.slice(1),
- description: '',
- };
- };
-
- const { name, description } = getCategoryData();
-
- return (
-
-
- {name}
-
- {description && (
-
{description}
- )}
-
- );
- })()}
+
+ {/* Scrollable container */}
+
+ {/* Simplified header for agents marketplace - only show nav controls when needed */}
+ {!isSmallScreen && (
+
+
+ {!navVisible ? (
+ <>
+
+
+
+
+ }
+ />
+ >
+ ) : (
+ // Invisible placeholder to maintain height
+
+ )}
+
)}
- {/* Agent grid */}
-
-
+ {/* Hero Section - scrolls away */}
+
+
+
+ {localize('com_agents_marketplace')}
+
+
+ {localize('com_agents_marketplace_subtitle')}
+
+
+
- {/* Agent detail dialog */}
- {isDetailOpen && selectedAgent && (
-
- )}
+ {/* Sticky wrapper for search bar and categories */}
+
+
+ {/* Search bar */}
+
+
+
+
+ {/* Category tabs */}
+
+
+
+
+ {/* Scrollable content area */}
+
+ {/* Category header - only show when not searching */}
+ {!searchQuery && (
+
+ {(() => {
+ // Get category data for display
+ const getCategoryData = () => {
+ if (activeTab === 'promoted') {
+ return {
+ name: localize('com_agents_top_picks'),
+ description: localize('com_agents_recommended'),
+ };
+ }
+ if (activeTab === 'all') {
+ return {
+ name: 'All Agents',
+ description: 'Browse all shared agents across all categories',
+ };
+ }
+
+ // Find the category in the API data
+ const categoryData = categoriesQuery.data?.find(
+ (cat) => cat.value === activeTab,
+ );
+ if (categoryData) {
+ return {
+ name: categoryData.label,
+ description: categoryData.description || '',
+ };
+ }
+
+ // Fallback for unknown categories
+ return {
+ name: activeTab.charAt(0).toUpperCase() + activeTab.slice(1),
+ description: '',
+ };
+ };
+
+ const { name, description } = getCategoryData();
+
+ return (
+
+
{name}
+ {description && (
+
{description}
+ )}
+
+ );
+ })()}
+
+ )}
+
+ {/* Agent grid */}
+
+
+
+ {/* Agent detail dialog */}
+ {isDetailOpen && selectedAgent && (
+
+ )}
+
diff --git a/client/src/components/SidePanel/Agents/CategoryTabs.tsx b/client/src/components/SidePanel/Agents/CategoryTabs.tsx
index ef11472ef..f232c7ad0 100644
--- a/client/src/components/SidePanel/Agents/CategoryTabs.tsx
+++ b/client/src/components/SidePanel/Agents/CategoryTabs.tsx
@@ -1,7 +1,5 @@
import React from 'react';
-
import type t from 'librechat-data-provider';
-
import useLocalize from '~/hooks/useLocalize';
import { SmartLoader } from './SmartLoader';
import { cn } from '~/utils';
@@ -50,16 +48,14 @@ const CategoryTabs: React.FC
= ({
// Loading skeleton component
const loadingSkeleton = (
-
-
-
- {[...Array(6)].map((_, i) => (
-
- ))}
-
+
+
+ {[...Array(6)].map((_, i) => (
+
+ ))}
);
@@ -106,52 +102,54 @@ const CategoryTabs: React.FC
= ({
// Early return if no categories available
if (!isLoading && (!categories || categories.length === 0)) {
return (
- {localize('com_agents_no_categories')}
+ {localize('com_ui_no_categories')}
);
}
// Main tabs content
const tabsContent = (
-
-
- {/* Accessible tab navigation with proper ARIA attributes */}
-
- {categories.map((category, index) => (
-
- ))}
-
+
+
+ {categories.map((category, index) => (
+
+ ))}
);
diff --git a/client/src/components/SidePanel/Agents/SearchBar.tsx b/client/src/components/SidePanel/Agents/SearchBar.tsx
index 46c2cca0a..4c473b216 100644
--- a/client/src/components/SidePanel/Agents/SearchBar.tsx
+++ b/client/src/components/SidePanel/Agents/SearchBar.tsx
@@ -73,7 +73,7 @@ const SearchBar: React.FC
= ({ value, onSearch, className = '' }
value={searchTerm}
onChange={handleChange}
placeholder={localize('com_agents_search_placeholder')}
- className="h-14 rounded-2xl border-2 border-gray-200 bg-white pl-12 pr-12 text-lg text-gray-900 shadow-lg placeholder:text-gray-500 focus:border-gray-300 focus:ring-0 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:placeholder:text-gray-400 dark:focus:border-gray-500"
+ className="h-14 rounded-2xl border-2 border-border-medium bg-transparent pl-12 pr-12 text-lg text-text-primary shadow-lg placeholder:text-text-tertiary focus:border-border-heavy focus:ring-0"
aria-label={localize('com_agents_search_aria')}
aria-describedby="search-instructions search-results-count"
autoComplete="off"
@@ -82,7 +82,7 @@ const SearchBar: React.FC = ({ value, onSearch, className = '' }
{/* Search icon with proper accessibility */}
-
+
{/* Hidden instructions for screen readers */}
@@ -95,7 +95,7 @@ const SearchBar: React.FC = ({ value, onSearch, className = '' }