mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 17:08:03 +08:00
feat: enhance carousel layout and search functionality in marketplace components
This commit is contained in:
@ -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',
|
||||
|
||||
@ -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<TItem>({
|
||||
renderCard,
|
||||
cardContainerClassName,
|
||||
}: CarouselCollectionProps<TItem>) {
|
||||
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 (
|
||||
<Carousel
|
||||
@ -92,7 +98,7 @@ export function CarouselCollection<TItem>({
|
||||
autoPlay={items.length > 8}
|
||||
autoPlayInterval={5000}
|
||||
>
|
||||
{rows.map((columnItems, idx) => (
|
||||
{columns.map((columnItems, idx) => (
|
||||
<div
|
||||
key={columnItems[0] ? getItemKey(columnItems[0]) : idx}
|
||||
className={CAROUSEL_COLUMN_CLASS}
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
import { cn } from '@/utils/classnames'
|
||||
import {
|
||||
searchModeAtom,
|
||||
useSearchTab,
|
||||
useSearchText,
|
||||
} from '../atoms'
|
||||
import { useMarketplaceUnifiedSearch } from '../query'
|
||||
@ -30,6 +31,7 @@ const SearchBoxWrapper = ({
|
||||
}: SearchBoxWrapperProps) => {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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 = () => {
|
||||
<h3 className="title-xl-semi-bold mb-3 text-text-primary">
|
||||
{t('templates', { ns: 'plugin' })}
|
||||
</h3>
|
||||
{renderTemplatesSection(templates, 6)}
|
||||
{renderTemplatesSection(templates, ALL_TAB_PREVIEW_SIZE)}
|
||||
</section>
|
||||
)}
|
||||
{plugins.length > 0 && (
|
||||
@ -180,7 +181,7 @@ const SearchPage = () => {
|
||||
<h3 className="title-xl-semi-bold mb-3 text-text-primary">
|
||||
{t('plugins', { ns: 'plugin' })}
|
||||
</h3>
|
||||
{renderPluginsSection(plugins, 6)}
|
||||
{renderPluginsSection(plugins, ALL_TAB_PREVIEW_SIZE)}
|
||||
</section>
|
||||
)}
|
||||
{creators.length > 0 && (
|
||||
@ -188,7 +189,7 @@ const SearchPage = () => {
|
||||
<h3 className="title-xl-semi-bold mb-3 text-text-primary">
|
||||
{t('marketplace.searchFilterCreators', { ns: 'plugin' })}
|
||||
</h3>
|
||||
{renderCreatorsSection(creators, 6)}
|
||||
{renderCreatorsSection(creators, ALL_TAB_PREVIEW_SIZE)}
|
||||
</section>
|
||||
)}
|
||||
{!isLoading && plugins.length === 0 && templates.length === 0 && creators.length === 0 && (
|
||||
|
||||
Reference in New Issue
Block a user