diff --git a/frontend/app/[locale]/market/MarketContent.css b/frontend/app/[locale]/market/MarketContent.css new file mode 100644 index 000000000..fb4b8e6ef --- /dev/null +++ b/frontend/app/[locale]/market/MarketContent.css @@ -0,0 +1,34 @@ +/* Custom styles for MarketContent component */ + +/* Hide scrollbars for featured row with subtle hover reveal */ +.noScrollbar { + /* Modern browsers: hide scrollbar but keep functionality */ + scrollbar-width: thin; + scrollbar-color: transparent transparent; + -ms-overflow-style: none; /* IE/Edge */ +} + +.noScrollbar::-webkit-scrollbar { + height: 4px; +} + +.noScrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.noScrollbar::-webkit-scrollbar-thumb { + background-color: transparent; + border-radius: 2px; + transition: background-color 0.2s ease; +} + +/* Show subtle scrollbar on hover for better UX */ +@media (hover: hover) { + .noScrollbar:hover::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.2); + } + + .noScrollbar:hover { + scrollbar-color: rgba(0, 0, 0, 0.2) transparent; + } +} diff --git a/frontend/app/[locale]/market/components/AgentMarketCard.tsx b/frontend/app/[locale]/market/components/AgentMarketCard.tsx index 3a0102adf..72ac5d624 100644 --- a/frontend/app/[locale]/market/components/AgentMarketCard.tsx +++ b/frontend/app/[locale]/market/components/AgentMarketCard.tsx @@ -12,6 +12,7 @@ interface AgentMarketCardProps { agent: MarketAgentListItem; onDownload: (agent: MarketAgentListItem) => void; onViewDetails: (agent: MarketAgentListItem) => void; + variant?: "featured" | "default"; } /** @@ -22,6 +23,7 @@ export function AgentMarketCard({ agent, onDownload, onViewDetails, + variant = "default", }: AgentMarketCardProps) { const { t, i18n } = useTranslation("common"); const isZh = i18n.language === "zh" || i18n.language === "zh-CN"; @@ -40,12 +42,29 @@ export function AgentMarketCard({ ? agent.category.icon || getCategoryIcon(agent.category.name) : "📦"; + return ( + {variant === "featured" && ( + // Full-card subtle purple gradient background overlay +
+ )} {/* Card header with category */}
@@ -70,56 +89,58 @@ export function AgentMarketCard({

{agent.display_name}

- {agent.author ? ( -

- {t("market.by", { defaultValue: "By {{author}}", author: agent.author })} -

- ) : ( -
- )} +
+ {agent.author ? ( +

+ {t("market.by", { defaultValue: "By {{author}}", author: agent.author })} +

+ ) : null} +
{/* Card body */} -
+
{/* Description */}

{agent.description}

- {/* Tags */} - {agent.tags && agent.tags.length > 0 && ( -
- {agent.tags.slice(0, 3).map((tag) => ( - - - {getGenericLabel(tag.display_name, t)} - - ))} - {agent.tags.length > 3 && ( - - +{agent.tags.length - 3} - - )} -
- )} + {/* Tags - always show container for consistent height */} +
+ {agent.tags && agent.tags.length > 0 && ( +
+ {agent.tags.slice(0, 3).map((tag) => ( + + + {getGenericLabel(tag.display_name, t)} + + ))} + {agent.tags.length > 3 && ( + + +{agent.tags.length - 3} + + )} +
+ )} +
{/* Tool count */}
- {agent.tool_count} {t("market.tools", "tools")} + {agent.tool_count || 0} {t("market.tools", "tools")}
- {/* Card footer */} -
+ {/* Card footer - pinned to bottom to keep all cards aligned */} +
+ +
+
+ +
+ )} + + {/* Separator between featured and main list (only when both exist) */} + {featuredItems.length > 0 && agents.length > 0 && ( +
+
+
+ )} + + {agents.length > 0 && ( + <> +
{agents.map((agent, index) => (
+ )} + )} )} diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index 9694b6ddf..92dd98457 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -1203,6 +1203,7 @@ "market.downloadSuccess": "Agent downloaded successfully!", "market.downloadFailed": "Failed to download agent", "market.tools": "tools", + "market.featuredTitle": "Featured Agents", "market.noAgents": "No agents found in this category", "market.totalAgents": "Total {{total}} agents", "market.error.loadCategories": "Failed to load categories", diff --git a/frontend/public/locales/zh/common.json b/frontend/public/locales/zh/common.json index 8b18c9b9a..b0e0d69e1 100644 --- a/frontend/public/locales/zh/common.json +++ b/frontend/public/locales/zh/common.json @@ -1182,6 +1182,7 @@ "market.downloadSuccess": "智能体下载成功!", "market.downloadFailed": "下载智能体失败", "market.tools": "工具", + "market.featuredTitle": "精选智能体", "market.noAgents": "此分类下未找到智能体", "market.totalAgents": "共 {{total}} 个智能体", "market.error.loadCategories": "加载分类失败", diff --git a/frontend/styles/globals.css b/frontend/styles/globals.css index 32715a2f0..019ad8380 100644 --- a/frontend/styles/globals.css +++ b/frontend/styles/globals.css @@ -167,6 +167,7 @@ scrollbar-color: rgba(0, 0, 0, 0.4) transparent; } + /* Tool Pool Tabs scroll fix */ .tool-pool-tabs .ant-tabs-content-holder { overflow: hidden; diff --git a/frontend/types/market.ts b/frontend/types/market.ts index 770e39520..d4005c0a4 100644 --- a/frontend/types/market.ts +++ b/frontend/types/market.ts @@ -29,11 +29,12 @@ export interface MarketAgentListItem { display_name: string; description: string; author?: string; - category: MarketCategory; + category?: MarketCategory; tags: MarketTag[]; download_count: number; created_at: string; - tool_count: number; + tool_count?: number; + is_featured: boolean; } export interface MarketAgentTool { @@ -90,6 +91,8 @@ export interface MarketPagination { export interface MarketAgentListResponse { items: MarketAgentListItem[]; pagination: MarketPagination; + // Optional featured items returned by the API when requested + featured_items?: MarketAgentListItem[]; } export interface MarketAgentListParams {