From 6935ac33ac140c022828417e592966b7234d2c1b Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Fri, 9 May 2025 17:13:06 +0800 Subject: [PATCH] feat: implement sort in plugin market --- .../plugin-market/PluginMarketComponent.tsx | 132 ++++++++++++++---- web/src/app/infra/http/HttpClient.ts | 6 +- web/src/components/ui/pagination.tsx | 127 +++++++++++++++++ 3 files changed, 232 insertions(+), 33 deletions(-) create mode 100644 web/src/components/ui/pagination.tsx diff --git a/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx b/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx index 8a5f4555..84643c6e 100644 --- a/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx +++ b/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx @@ -4,8 +4,18 @@ import { useEffect, useState } from 'react'; import styles from '@/app/home/plugins/plugins.module.css'; import { PluginMarketCardVO } from '@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO'; import PluginMarketCardComponent from '@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent'; -import { Input, Pagination } from 'antd'; import { spaceClient } from '@/app/infra/http/HttpClient'; +import { Input } from '@/components/ui/input'; +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from "@/components/ui/pagination" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" export default function PluginMarketComponent({ askInstallPlugin, @@ -19,6 +29,8 @@ export default function PluginMarketComponent({ const [nowPage, setNowPage] = useState(1); const [searchKeyword, setSearchKeyword] = useState(''); const [loading, setLoading] = useState(false); + const [sortByValue, setSortByValue] = useState('stars'); + const [sortOrderValue, setSortOrderValue] = useState('DESC'); const pageSize = 10; useEffect(() => { @@ -40,10 +52,12 @@ export default function PluginMarketComponent({ function getPluginList( page: number = nowPage, keyword: string = searchKeyword, + sortBy: string = sortByValue, + sortOrder: string = sortOrderValue, ) { setLoading(true); spaceClient - .getMarketPlugins(page, pageSize, keyword) + .getMarketPlugins(page, pageSize, keyword, sortBy, sortOrder) .then((res) => { setMarketPluginList( res.plugins.map( @@ -89,23 +103,97 @@ export default function PluginMarketComponent({ getPluginList(page); } + function handleSortChange(value: string) { + const [newSortBy, newSortOrder] = value.split(',').map(s => s.trim()); + setSortByValue(newSortBy); + setSortOrderValue(newSortOrder); + setNowPage(1); + getPluginList(1, searchKeyword, newSortBy, newSortOrder); + } + return (
- onInputSearchKeyword(e.target.value)} - /> +
+ onInputSearchKeyword(e.target.value)} + /> + + + +
+ {totalCount > 0 && ( + + + + handlePageChange(nowPage - 1)} + className={nowPage <= 1 ? 'pointer-events-none opacity-50' : ''} + /> + + + {/* 如果总页数大于5,则只显示5页,如果总页数小于5,则显示所有页 */} + {(() => { + const totalPages = Math.ceil(totalCount / pageSize); + const maxVisiblePages = 5; + let startPage = Math.max(1, nowPage - Math.floor(maxVisiblePages / 2)); + let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); + + if (endPage - startPage + 1 < maxVisiblePages) { + startPage = Math.max(1, endPage - maxVisiblePages + 1); + } + + return Array.from({ length: endPage - startPage + 1 }, (_, i) => { + const pageNum = startPage + i; + return ( + + handlePageChange(pageNum)} + > + + {pageNum} + + + + ); + }); + })()} + + + + handlePageChange(nowPage + 1)} + className={nowPage >= Math.ceil(totalCount / pageSize) ? 'pointer-events-none opacity-50' : ''} + /> + + + + )} +
+
+
{loading ? ( -
加载中...
+
+ {/* 加载中... */} +
) : marketPluginList.length === 0 ? (
- 没有找到匹配的插件 + {/* 没有找到匹配的插件 */}
) : ( marketPluginList.map((vo, index) => ( @@ -117,24 +205,6 @@ export default function PluginMarketComponent({ )) )}
- {totalCount > 0 && ( -
- -
- )}
); } diff --git a/web/src/app/infra/http/HttpClient.ts b/web/src/app/infra/http/HttpClient.ts index d0f908cb..f7acb654 100644 --- a/web/src/app/infra/http/HttpClient.ts +++ b/web/src/app/infra/http/HttpClient.ts @@ -360,13 +360,15 @@ class HttpClient { page: number, page_size: number, query: string, + sort_by: string = 'stars', + sort_order: string = 'DESC', ): Promise { return this.post(`/api/v1/market/plugins`, { page, page_size, query, - sort_by: 'stars', - sort_order: 'DESC', + sort_by, + sort_order, }); } public installPluginFromGithub( diff --git a/web/src/components/ui/pagination.tsx b/web/src/components/ui/pagination.tsx new file mode 100644 index 00000000..d8cd7666 --- /dev/null +++ b/web/src/components/ui/pagination.tsx @@ -0,0 +1,127 @@ +import * as React from "react" +import { + ChevronLeftIcon, + ChevronRightIcon, + MoreHorizontalIcon, +} from "lucide-react" + +import { cn } from "@/lib/utils" +import { Button, buttonVariants } from "@/components/ui/button" + +function Pagination({ className, ...props }: React.ComponentProps<"nav">) { + return ( +