From 62fa90e30ebc9bc08640c4f5d36809a842e2cf91 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Tue, 29 Oct 2024 18:13:47 +0800 Subject: [PATCH] feat: marketplace sort --- .../plugins/marketplace/constants.ts | 4 + .../plugins/marketplace/context.tsx | 17 +++- .../plugins/marketplace/list/list-wrapper.tsx | 6 ++ .../plugins/marketplace/search-box/index.tsx | 2 +- .../marketplace/sort-dropdown/index.tsx | 88 +++++++++++++++++++ .../components/plugins/marketplace/types.ts | 5 ++ .../components/plugins/marketplace/utils.ts | 2 +- 7 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 web/app/components/plugins/marketplace/constants.ts create mode 100644 web/app/components/plugins/marketplace/sort-dropdown/index.tsx diff --git a/web/app/components/plugins/marketplace/constants.ts b/web/app/components/plugins/marketplace/constants.ts new file mode 100644 index 0000000000..6bd4e29604 --- /dev/null +++ b/web/app/components/plugins/marketplace/constants.ts @@ -0,0 +1,4 @@ +export const DEFAULT_SORT = { + sortBy: 'install_count', + sortOrder: 'DESC', +} diff --git a/web/app/components/plugins/marketplace/context.tsx b/web/app/components/plugins/marketplace/context.tsx index 7b9712aeef..70e0b5f75a 100644 --- a/web/app/components/plugins/marketplace/context.tsx +++ b/web/app/components/plugins/marketplace/context.tsx @@ -12,8 +12,12 @@ import { import { useDebounceFn } from 'ahooks' import { PLUGIN_TYPE_SEARCH_MAP } from './plugin-type-switch' import type { Plugin } from '../types' -import type { PluginsSearchParams } from './types' +import type { + PluginsSearchParams, + PluginsSort, +} from './types' import { getMarketplacePlugins } from './utils' +import { DEFAULT_SORT } from './constants' export type MarketplaceContextValue = { intersected: boolean @@ -26,6 +30,8 @@ export type MarketplaceContextValue = { handleActivePluginTypeChange: (type: string) => void plugins?: Plugin[] setPlugins?: (plugins: Plugin[]) => void + sort: PluginsSort + handleSortChange: (sort: PluginsSort) => void } export const MarketplaceContext = createContext({ @@ -39,6 +45,8 @@ export const MarketplaceContext = createContext({ handleActivePluginTypeChange: () => {}, plugins: undefined, setPlugins: () => {}, + sort: DEFAULT_SORT, + handleSortChange: () => {}, }) type MarketplaceContextProviderProps = { @@ -57,6 +65,7 @@ export const MarketplaceContextProvider = ({ const [filterPluginTags, setFilterPluginTags] = useState([]) const [activePluginType, setActivePluginType] = useState(PLUGIN_TYPE_SEARCH_MAP.all) const [plugins, setPlugins] = useState() + const [sort, setSort] = useState(DEFAULT_SORT) const handleUpdatePlugins = useCallback(async (query: PluginsSearchParams) => { const { marketplacePlugins } = await getMarketplacePlugins(query) @@ -82,6 +91,10 @@ export const MarketplaceContextProvider = ({ setActivePluginType(type) }, []) + const handleSortChange = useCallback((sort: PluginsSort) => { + setSort(sort) + }, []) + return ( {children} diff --git a/web/app/components/plugins/marketplace/list/list-wrapper.tsx b/web/app/components/plugins/marketplace/list/list-wrapper.tsx index 68713ceb81..c4b5c854c7 100644 --- a/web/app/components/plugins/marketplace/list/list-wrapper.tsx +++ b/web/app/components/plugins/marketplace/list/list-wrapper.tsx @@ -3,6 +3,7 @@ import type { Plugin } from '../../types' import type { MarketplaceCollection } from '../types' import { useMarketplaceContext } from '../context' import List from './index' +import SortDropdown from '../sort-dropdown' type ListWrapperProps = { marketplaceCollections: MarketplaceCollection[] @@ -16,6 +17,11 @@ const ListWrapper = ({ return (
+
+
134 results
+
+ +
{ return (
diff --git a/web/app/components/plugins/marketplace/sort-dropdown/index.tsx b/web/app/components/plugins/marketplace/sort-dropdown/index.tsx new file mode 100644 index 0000000000..ed1d788b29 --- /dev/null +++ b/web/app/components/plugins/marketplace/sort-dropdown/index.tsx @@ -0,0 +1,88 @@ +'use client' +import { useState } from 'react' +import { + RiArrowDownSLine, + RiCheckLine, +} from '@remixicon/react' +import { useMarketplaceContext } from '../context' +import { + PortalToFollowElem, + PortalToFollowElemContent, + PortalToFollowElemTrigger, +} from '@/app/components/base/portal-to-follow-elem' + +const options = [ + { + value: 'install_count', + order: 'DESC', + text: 'Most Popular', + }, + { + value: 'version_updated_at', + order: 'DESC', + text: 'Recently Updated', + }, + { + value: 'created_at', + order: 'DESC', + text: 'Newly Released', + }, + { + value: 'created_at', + order: 'ASC', + text: 'First Released', + }, +] + +const SortDropdown = () => { + const sort = useMarketplaceContext(v => v.sort) + const handleSortChange = useMarketplaceContext(v => v.handleSortChange) + const [open, setOpen] = useState(false) + const selectedOption = options.find(option => option.value === sort.sortBy && option.order === sort.sortOrder)! + + return ( + + setOpen(v => !v)}> +
+ + Sort by + + + {selectedOption.text} + + +
+
+ +
+ { + options.map(option => ( +
handleSortChange({ sortBy: option.value, sortOrder: option.order })} + > + {option.text} + { + sort.sortBy === option.value && sort.sortOrder === option.order && ( + + ) + } +
+ )) + } +
+
+
+ ) +} + +export default SortDropdown diff --git a/web/app/components/plugins/marketplace/types.ts b/web/app/components/plugins/marketplace/types.ts index eea19b374c..f10db5c79a 100644 --- a/web/app/components/plugins/marketplace/types.ts +++ b/web/app/components/plugins/marketplace/types.ts @@ -27,3 +27,8 @@ export type PluginsSearchParams = { category?: string tag?: string } + +export type PluginsSort = { + sortBy: string + sortOrder: string +} diff --git a/web/app/components/plugins/marketplace/utils.ts b/web/app/components/plugins/marketplace/utils.ts index f4c9ec140d..558a07736f 100644 --- a/web/app/components/plugins/marketplace/utils.ts +++ b/web/app/components/plugins/marketplace/utils.ts @@ -36,7 +36,7 @@ export const getMarketplacePlugins = async (query: PluginsSearchParams) => { let marketplacePlugins = [] as Plugin[] try { const marketplacePluginsData = await globalThis.fetch( - `${MARKETPLACE_API_PREFIX}/plugins`, + `${MARKETPLACE_API_PREFIX}/plugins/search/basic`, { method: 'POST', headers: {