Merge branch 'feat/add-search-params-to-url' into deploy/dev

This commit is contained in:
twwu 2025-04-10 10:55:11 +08:00
commit 4159310d1b
5 changed files with 49 additions and 31 deletions

View File

@ -2,19 +2,13 @@ import PluginPage from '@/app/components/plugins/plugin-page'
import PluginsPanel from '@/app/components/plugins/plugin-page/plugins-panel'
import Marketplace from '@/app/components/plugins/marketplace'
import { getLocaleOnServer } from '@/i18n/server'
import type { SearchParams } from '@/app/components/plugins/marketplace/types'
const PluginList = async (
props: {
searchParams: Promise<SearchParams>
},
) => {
const searchParams = await props.searchParams
const PluginList = async () => {
const locale = await getLocaleOnServer()
return (
<PluginPage
plugins={<PluginsPanel />}
marketplace={<Marketplace searchParams={searchParams} locale={locale} pluginTypeSwitchClassName='top-[60px]' searchBoxAutoAnimate={false} />}
marketplace={<Marketplace locale={locale} pluginTypeSwitchClassName='top-[60px]' searchBoxAutoAnimate={false} showSearchParams={false} />}
/>
)
}

View File

@ -97,6 +97,7 @@ type MarketplaceContextProviderProps = {
searchParams?: SearchParams
shouldExclude?: boolean
scrollContainerId?: string
showSearchParams?: boolean
}
export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) {
@ -108,6 +109,7 @@ export const MarketplaceContextProvider = ({
searchParams,
shouldExclude,
scrollContainerId,
showSearchParams,
}: MarketplaceContextProviderProps) => {
const { data, isSuccess } = useInstalledPluginList(!shouldExclude)
const exclude = useMemo(() => {
@ -164,11 +166,6 @@ export const MarketplaceContextProvider = ({
if (searchParams?.language)
url.searchParams.set('language', searchParams?.language)
history.replaceState({}, '', url)
updateSearchParams({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
})
}
else {
if (shouldExclude && isSuccess) {
@ -191,15 +188,19 @@ export const MarketplaceContextProvider = ({
resetPlugins()
}, [exclude, queryMarketplaceCollectionsAndPlugins, resetPlugins])
const handleSearchParamsChange = (debounced?: boolean) => {
const debouncedUpdateSearchParams = useMemo(() => debounce(() => {
updateSearchParams({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
})
}, 500), [])
const handleUpdateSearchParams = useCallback((debounced?: boolean) => {
if (!showSearchParams)
return
if (debounced) {
debounce(() => {
updateSearchParams({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
})
}, 500)()
debouncedUpdateSearchParams()
}
else {
updateSearchParams({
@ -208,10 +209,10 @@ export const MarketplaceContextProvider = ({
tags: filterPluginTagsRef.current,
})
}
}
}, [debouncedUpdateSearchParams, showSearchParams])
const handleQueryPlugins = useCallback((debounced?: boolean) => {
handleSearchParamsChange(debounced)
handleUpdateSearchParams(debounced)
if (debounced) {
queryPluginsWithDebounced({
query: searchPluginTextRef.current,
@ -236,18 +237,18 @@ export const MarketplaceContextProvider = ({
page: pageRef.current,
})
}
}, [exclude, queryPluginsWithDebounced, queryPlugins])
}, [exclude, queryPluginsWithDebounced, queryPlugins, handleUpdateSearchParams])
const handleQuery = useCallback((debounced?: boolean) => {
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
handleSearchParamsChange(debounced)
handleUpdateSearchParams(debounced)
cancelQueryPluginsWithDebounced()
handleQueryMarketplaceCollectionsAndPlugins()
return
}
handleQueryPlugins(debounced)
}, [handleQueryMarketplaceCollectionsAndPlugins, handleQueryPlugins, cancelQueryPluginsWithDebounced])
}, [handleQueryMarketplaceCollectionsAndPlugins, handleQueryPlugins, cancelQueryPluginsWithDebounced, handleUpdateSearchParams])
const handleSearchPluginTextChange = useCallback((text: string) => {
setSearchPluginText(text)

View File

@ -17,6 +17,7 @@ type MarketplaceProps = {
pluginTypeSwitchClassName?: string
intersectionContainerId?: string
scrollContainerId?: string
showSearchParams?: boolean
}
const Marketplace = async ({
locale,
@ -27,6 +28,7 @@ const Marketplace = async ({
pluginTypeSwitchClassName,
intersectionContainerId,
scrollContainerId,
showSearchParams = true,
}: MarketplaceProps) => {
let marketplaceCollections: any = []
let marketplaceCollectionPluginsMap = {}
@ -42,6 +44,7 @@ const Marketplace = async ({
searchParams={searchParams}
shouldExclude={shouldExclude}
scrollContainerId={scrollContainerId}
showSearchParams={showSearchParams}
>
<Description locale={locale} />
<IntersectionLine intersectionContainerId={intersectionContainerId} />
@ -53,6 +56,7 @@ const Marketplace = async ({
locale={locale}
className={pluginTypeSwitchClassName}
searchBoxAutoAnimate={searchBoxAutoAnimate}
showSearchParams={showSearchParams}
/>
<ListWrapper
locale={locale}

View File

@ -13,6 +13,7 @@ import {
useSearchBoxAutoAnimate,
} from './hooks'
import cn from '@/utils/classnames'
import { useCallback, useEffect } from 'react'
export const PLUGIN_TYPE_SEARCH_MAP = {
all: 'all',
@ -26,11 +27,13 @@ type PluginTypeSwitchProps = {
locale?: string
className?: string
searchBoxAutoAnimate?: boolean
showSearchParams?: boolean
}
const PluginTypeSwitch = ({
locale,
className,
searchBoxAutoAnimate,
showSearchParams,
}: PluginTypeSwitchProps) => {
const { t } = useMixedTranslation(locale)
const activePluginType = useMarketplaceContext(s => s.activePluginType)
@ -70,6 +73,23 @@ const PluginTypeSwitch = ({
},
]
const handlePopState = useCallback(() => {
if (!showSearchParams)
return
const url = new URL(window.location.href)
const category = url.searchParams.get('category') || PLUGIN_TYPE_SEARCH_MAP.all
handleActivePluginTypeChange(category)
}, [showSearchParams, handleActivePluginTypeChange])
useEffect(() => {
window.addEventListener('popstate', () => {
handlePopState()
})
return () => {
window.removeEventListener('popstate', handlePopState)
}
}, [handlePopState])
return (
<div className={cn(
'flex shrink-0 items-center justify-center space-x-2 bg-background-body py-3',

View File

@ -130,19 +130,18 @@ export const getMarketplaceListFilterType = (category: string) => {
export const updateSearchParams = (pluginsSearchParams: PluginsSearchParams) => {
const { query, category, tags } = pluginsSearchParams
const url = new URL(window.location.href)
const categoryChanged = url.searchParams.get('category') !== category
if (query)
url.searchParams.set('q', query)
else
url.searchParams.delete('q')
if (category && category !== PLUGIN_TYPE_SEARCH_MAP.all)
if (category)
url.searchParams.set('category', category)
else if (!category)
url.searchParams.delete('category')
else
url.searchParams.set('category', 'discover')
url.searchParams.delete('category')
if (tags && tags.length)
url.searchParams.set('tags', tags.join(','))
else
url.searchParams.delete('tags')
history.replaceState({}, '', url)
history[`${categoryChanged ? 'pushState' : 'replaceState'}`]({}, '', url)
}