From 4961242a8aea7f83dd3548e5a4d1e6611c1c0935 Mon Sep 17 00:00:00 2001 From: yessenia Date: Wed, 11 Feb 2026 04:31:55 +0800 Subject: [PATCH] feat: enhance carousel layout and search functionality in marketplace components --- .../marketplace/list/collection-constants.ts | 3 +++ .../plugins/marketplace/list/collection-list.tsx | 16 +++++++++++----- .../search-box/search-box-wrapper.tsx | 3 +++ .../plugins/marketplace/search-page/index.tsx | 13 +++++++------ 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/web/app/components/plugins/marketplace/list/collection-constants.ts b/web/app/components/plugins/marketplace/list/collection-constants.ts index 4421393394..742d5a7cb3 100644 --- a/web/app/components/plugins/marketplace/list/collection-constants.ts +++ b/web/app/components/plugins/marketplace/list/collection-constants.ts @@ -4,6 +4,9 @@ export const GRID_DISPLAY_LIMIT = 8 export const CAROUSEL_COLUMN_CLASS = 'flex w-[calc((100%-0px)/1)] shrink-0 flex-col gap-3 sm:w-[calc((100%-12px)/2)] lg:w-[calc((100%-24px)/3)] xl:w-[calc((100%-36px)/4)]' +/** Max visible columns at the widest (xl) breakpoint; used to decide 1-row vs 2-row carousel layout. */ +export const CAROUSEL_MAX_VISIBLE_COLUMNS = 4 + /** Collection name key that triggers carousel display (plugins: partners, templates: featured) */ export const CAROUSEL_COLLECTION_NAMES = { partners: 'partners', diff --git a/web/app/components/plugins/marketplace/list/collection-list.tsx b/web/app/components/plugins/marketplace/list/collection-list.tsx index 353000b5f6..76297960f9 100644 --- a/web/app/components/plugins/marketplace/list/collection-list.tsx +++ b/web/app/components/plugins/marketplace/list/collection-list.tsx @@ -12,7 +12,7 @@ import { useMarketplaceMoreClick } from '../atoms' import Empty from '../empty' import { getItemKeyByField } from '../utils' import Carousel from './carousel' -import { CAROUSEL_COLUMN_CLASS, GRID_CLASS, GRID_DISPLAY_LIMIT } from './collection-constants' +import { CAROUSEL_COLUMN_CLASS, CAROUSEL_MAX_VISIBLE_COLUMNS, GRID_CLASS, GRID_DISPLAY_LIMIT } from './collection-constants' type ViewMoreButtonProps = { searchParams?: SearchParamsFromCollection @@ -80,9 +80,15 @@ export function CarouselCollection({ renderCard, cardContainerClassName, }: CarouselCollectionProps) { - const rows: TItem[][] = [] - for (let i = 0; i < items.length; i += 2) - rows.push(items.slice(i, i + 2)) + const useDoubleRow = items.length > CAROUSEL_MAX_VISIBLE_COLUMNS + const numColumns = useDoubleRow ? Math.ceil(items.length / 2) : items.length + const columns: TItem[][] = [] + for (let i = 0; i < numColumns; i++) { + const column: TItem[] = [items[i]] + if (useDoubleRow && i + numColumns < items.length) + column.push(items[i + numColumns]) + columns.push(column) + } return ( ({ autoPlay={items.length > 8} autoPlayInterval={5000} > - {rows.map((columnItems, idx) => ( + {columns.map((columnItems, idx) => (
{ const { t } = useTranslation() const [searchText, handleSearchTextChange] = useSearchText() + const [, setSearchTab] = useSearchTab() const setSearchMode = useSetAtom(searchModeAtom) const committedSearch = searchText || '' const [draftSearch, setDraftSearch] = useState(committedSearch) @@ -67,6 +69,7 @@ const SearchBoxWrapper = ({ if (!trimmed) return handleSearchTextChange(trimmed) + setSearchTab('all') setSearchMode(true) setIsFocused(false) } diff --git a/web/app/components/plugins/marketplace/search-page/index.tsx b/web/app/components/plugins/marketplace/search-page/index.tsx index 5ac5580786..7d53864975 100644 --- a/web/app/components/plugins/marketplace/search-page/index.tsx +++ b/web/app/components/plugins/marketplace/search-page/index.tsx @@ -20,6 +20,7 @@ import { getPluginFilterType, mapTemplateDetailToTemplate } from '../utils' import CreatorCard from './creator-card' const PAGE_SIZE = 40 +const ALL_TAB_PREVIEW_SIZE = 8 const ZERO_WIDTH_SPACE = '\u200B' type SortValue = { sortBy: string, sortOrder: string } @@ -50,7 +51,7 @@ const SearchPage = () => { return undefined return { query, - page_size: searchTab === 'all' ? 6 : PAGE_SIZE, + page_size: searchTab === 'all' ? ALL_TAB_PREVIEW_SIZE : PAGE_SIZE, sort_by: sort.sortBy, sort_order: sort.sortOrder, type: getPluginFilterType(PLUGIN_TYPE_SEARCH_MAP.all), @@ -63,7 +64,7 @@ const SearchPage = () => { const { sort_by, sort_order } = mapSortForTemplates(sort) return { query, - page_size: searchTab === 'all' ? 6 : PAGE_SIZE, + page_size: searchTab === 'all' ? ALL_TAB_PREVIEW_SIZE : PAGE_SIZE, sort_by, sort_order, } @@ -75,7 +76,7 @@ const SearchPage = () => { const { sort_by, sort_order } = mapSortForCreators(sort) return { query, - page_size: searchTab === 'all' ? 6 : PAGE_SIZE, + page_size: searchTab === 'all' ? ALL_TAB_PREVIEW_SIZE : PAGE_SIZE, sort_by, sort_order, } @@ -172,7 +173,7 @@ const SearchPage = () => {

{t('templates', { ns: 'plugin' })}

- {renderTemplatesSection(templates, 6)} + {renderTemplatesSection(templates, ALL_TAB_PREVIEW_SIZE)} )} {plugins.length > 0 && ( @@ -180,7 +181,7 @@ const SearchPage = () => {

{t('plugins', { ns: 'plugin' })}

- {renderPluginsSection(plugins, 6)} + {renderPluginsSection(plugins, ALL_TAB_PREVIEW_SIZE)} )} {creators.length > 0 && ( @@ -188,7 +189,7 @@ const SearchPage = () => {

{t('marketplace.searchFilterCreators', { ns: 'plugin' })}

- {renderCreatorsSection(creators, 6)} + {renderCreatorsSection(creators, ALL_TAB_PREVIEW_SIZE)} )} {!isLoading && plugins.length === 0 && templates.length === 0 && creators.length === 0 && (