diff --git a/web_ui/package-lock.json b/web_ui/package-lock.json index 269c3839..8279ebd0 100644 --- a/web_ui/package-lock.json +++ b/web_ui/package-lock.json @@ -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", diff --git a/web_ui/package.json b/web_ui/package.json index 9e7c20f7..e01e5464 100644 --- a/web_ui/package.json +++ b/web_ui/package.json @@ -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", diff --git a/web_ui/src/app/home/plugins/plugin-installed/PluginCardVO.ts b/web_ui/src/app/home/plugins/plugin-installed/PluginCardVO.ts index e83bd75c..768624d7 100644 --- a/web_ui/src/app/home/plugins/plugin-installed/PluginCardVO.ts +++ b/web_ui/src/app/home/plugins/plugin-installed/PluginCardVO.ts @@ -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; diff --git a/web_ui/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx b/web_ui/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx index be137ded..1c4511c7 100644 --- a/web_ui/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx +++ b/web_ui/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx @@ -17,7 +17,7 @@ export default function PluginCardComponent({ {/* right icon & version */}
v{cardVO.version} diff --git a/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx b/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx index c6b7b540..90487cd5 100644 --- a/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx +++ b/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx @@ -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([]) + 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 { + // 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 { + return [ + new PluginMarketCardVO({ + pluginId: "aaa", + description: "一般的描述", + name: "插件AAA", + author: "/hana", + version: "0.1", + githubURL: "", + starCount: 23 + }), + ] + } + return ( -
- plugin-market +
+ onInputSearchKeyword(e.target.value)} + /> + { + marketPluginList.map((vo, index) => { + return
+ +
+ }) + }
) } diff --git a/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent.tsx b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent.tsx index b2a94b74..5d96c57f 100644 --- a/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent.tsx +++ b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent.tsx @@ -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 ( -
- plugin market card +
+ {/* header */} +
+ {/* left author */} +
{cardVO.author}
+ {/* right icon */} + +
+ {/* content */} +
+
{cardVO.name}
+
{cardVO.description}
+
+ {/* footer */} +
+
+
+ + {cardVO.starCount} +
+
+ +
- ) + ); } diff --git a/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts new file mode 100644 index 00000000..4a806ec4 --- /dev/null +++ b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts @@ -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 + } + + +} diff --git a/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/pluginMarketCard.module.css b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/pluginMarketCard.module.css new file mode 100644 index 00000000..f611f335 --- /dev/null +++ b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/pluginMarketCard.module.css @@ -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; + } +}