feat: finish plugin market

This commit is contained in:
HYana
2025-04-27 15:35:26 +08:00
committed by Junyan Qin
parent 43d73bc493
commit b57186e894
8 changed files with 256 additions and 9 deletions

View File

@@ -11,6 +11,7 @@
"@ant-design/v5-patch-for-react-19": "^1.0.3",
"antd": "^5.24.6",
"axios": "^1.8.4",
"lodash": "^4.17.21",
"next": "15.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
@@ -18,6 +19,7 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@types/lodash": "^4.17.16",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
@@ -1094,6 +1096,12 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
"node_modules/@types/lodash": {
"version": "4.17.16",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz",
"integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==",
"dev": true
},
"node_modules/@types/node": {
"version": "20.17.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.27.tgz",
@@ -3837,6 +3845,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",

View File

@@ -12,6 +12,7 @@
"@ant-design/v5-patch-for-react-19": "^1.0.3",
"antd": "^5.24.6",
"axios": "^1.8.4",
"lodash": "^4.17.21",
"next": "15.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
@@ -19,6 +20,7 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@types/lodash": "^4.17.16",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",

View File

@@ -6,7 +6,7 @@ export interface IPluginCardVO {
handlerCount: number,
}
export class PluginCardVO implements IPluginCardVO{
export class PluginCardVO implements IPluginCardVO {
description: string;
handlerCount: number;
name: string;

View File

@@ -17,7 +17,7 @@ export default function PluginCardComponent({
{/* right icon & version */}
<div className={`${styles.iconVersionContainer}`}>
<GithubOutlined
style={{fontSize: '30px'}}
style={{fontSize: '26px'}}
type="setting"
/>
<Tag color="#108ee9">v{cardVO.version}</Tag>

View File

@@ -1,9 +1,84 @@
"use client"
export default function PluginMarketComponent () {
import {useCallback, 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} from "antd";
import {debounce} from "lodash"
export default function PluginInstalledComponent () {
const [marketPluginList, setMarketPluginList] = useState<PluginMarketCardVO[]>([])
const [searchKeyword, setSearchKeyword] = useState("")
useEffect(() => {
initData()
}, [])
function initData() {
getPluginList().then((value) => {
setMarketPluginList(value)
})
}
function onInputSearchKeyword(keyword: string) {
setSearchKeyword(keyword)
debounceSearch(keyword)
}
const debounceSearch = useCallback(
debounce((keyword: string) => {
console.log("debounce search", keyword)
searchPlugin(keyword).then(marketPluginList => {
setMarketPluginList(marketPluginList)
})
}, 500), []
)
async function searchPlugin(keyword: string): Promise<PluginMarketCardVO[]> {
// TODO 实现搜索
const demoResult: PluginMarketCardVO[] = []
for (let i = 0; i < keyword.length; i ++) {
demoResult.push(new PluginMarketCardVO({
author: "/hanahana",
description: "一个搜索测试的描述",
githubURL: "",
name: "搜索插件" + i,
pluginId: `${i}`,
starCount: 19 + i,
version: `0.${i}`,
}))
}
return demoResult
}
async function getPluginList(): Promise<PluginMarketCardVO[]> {
return [
new PluginMarketCardVO({
pluginId: "aaa",
description: "一般的描述",
name: "插件AAA",
author: "/hana",
version: "0.1",
githubURL: "",
starCount: 23
}),
]
}
return (
<div>
plugin-market
<div className={`${styles.pluginListContainer}`}>
<Input
value={searchKeyword}
onChange={(e) => onInputSearchKeyword(e.target.value)}
/>
{
marketPluginList.map((vo, index) => {
return <div key={index}>
<PluginMarketCardComponent cardVO={vo}/>
</div>
})
}
</div>
)
}

View File

@@ -1,7 +1,56 @@
export function PluginMarketCardComponent() {
import styles from "./pluginMarketCard.module.css"
import {GithubOutlined, StarOutlined} from '@ant-design/icons';
import {PluginMarketCardVO} from "@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO";
import {Button} from "antd";
export default function PluginMarketCardComponent({
cardVO
}: {
cardVO: PluginMarketCardVO
}) {
function handleInstallClick (pluginId: string) {
console.log("Install plugin: ", pluginId)
}
return (
<div>
plugin market card
<div className={`${styles.cardContainer}`}>
{/* header */}
<div className={`${styles.cardHeader}`}>
{/* left author */}
<div className={`${styles.fontGray}`}>{cardVO.author}</div>
{/* right icon */}
<GithubOutlined
style={{fontSize: '26px'}}
type="setting"
/>
</div>
{/* content */}
<div className={`${styles.cardContent}`}>
<div className={`${styles.boldFont}`}>{cardVO.name}</div>
<div className={`${styles.fontGray}`}>{cardVO.description}</div>
</div>
{/* footer */}
<div className={`${styles.cardFooter}`}>
<div className={`${styles.linkSettingContainer}`}>
<div className={`${styles.link}`}>
<StarOutlined
style={{fontSize: '22px'}}
/>
<span>{cardVO.starCount}</span>
</div>
</div>
<Button
type="primary"
size={"small"}
onClick={() => {
handleInstallClick(cardVO.pluginId)
}}
>
</Button>
</div>
</div>
)
);
}

View File

@@ -0,0 +1,31 @@
export interface IPluginMarketCardVO {
pluginId: string;
author: string,
version: string,
name: string,
description: string,
starCount: number,
githubURL: string,
}
export class PluginMarketCardVO implements IPluginMarketCardVO {
pluginId: string;
description: string;
name: string;
author: string;
version: string;
githubURL: string;
starCount: number;
constructor(prop: IPluginMarketCardVO) {
this.description = prop.description
this.name = prop.name
this.author = prop.author
this.version = prop.version
this.githubURL = prop.githubURL
this.starCount = prop.starCount
this.pluginId = prop.pluginId
}
}

View File

@@ -0,0 +1,77 @@
.cardContainer {
width: 360px;
height: 140px;
box-sizing: border-box;
background-color: #FFF;
border-radius: 9px;
padding-top: 10px;
padding-bottom: 10px;
box-shadow: rgba(0, 0, 0, 0.4) 0 1px 1px -1px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
}
.cardHeader {
width: 90%;
height: 30px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.iconVersionContainer {
width: 90px;
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
}
.cardContent {
width: 90%;
height: 70px;
}
.cardFooter {
width: 90%;
height: 30px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.fontGray {
color: #6C6C6C;
}
.boldFont {
font-size: 22px;
font-weight: bold;
}
.linkSettingContainer {
width: 80px;
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.link {
width: 32px;
cursor: pointer;
text-align: center;
display: flex;
flex-direction: row;
color: #6062E7;
align-self: center;
justify-content: space-between;
}
}