mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-26 23:44:19 +00:00
feat: finish plugin market
This commit is contained in:
Generated
+13
@@ -11,6 +11,7 @@
|
|||||||
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||||
"antd": "^5.24.6",
|
"antd": "^5.24.6",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"next": "15.2.4",
|
"next": "15.2.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
@@ -1094,6 +1096,12 @@
|
|||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.17.27",
|
"version": "20.17.27",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.27.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.27.tgz",
|
||||||
@@ -3837,6 +3845,11 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||||
"antd": "^5.24.6",
|
"antd": "^5.24.6",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"next": "15.2.4",
|
"next": "15.2.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export interface IPluginCardVO {
|
|||||||
handlerCount: number,
|
handlerCount: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PluginCardVO implements IPluginCardVO{
|
export class PluginCardVO implements IPluginCardVO {
|
||||||
description: string;
|
description: string;
|
||||||
handlerCount: number;
|
handlerCount: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function PluginCardComponent({
|
|||||||
{/* right icon & version */}
|
{/* right icon & version */}
|
||||||
<div className={`${styles.iconVersionContainer}`}>
|
<div className={`${styles.iconVersionContainer}`}>
|
||||||
<GithubOutlined
|
<GithubOutlined
|
||||||
style={{fontSize: '30px'}}
|
style={{fontSize: '26px'}}
|
||||||
type="setting"
|
type="setting"
|
||||||
/>
|
/>
|
||||||
<Tag color="#108ee9">v{cardVO.version}</Tag>
|
<Tag color="#108ee9">v{cardVO.version}</Tag>
|
||||||
|
|||||||
@@ -1,9 +1,84 @@
|
|||||||
"use client"
|
"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 (
|
return (
|
||||||
<div>
|
<div className={`${styles.pluginListContainer}`}>
|
||||||
plugin-market
|
<Input
|
||||||
|
value={searchKeyword}
|
||||||
|
onChange={(e) => onInputSearchKeyword(e.target.value)}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
marketPluginList.map((vo, index) => {
|
||||||
|
return <div key={index}>
|
||||||
|
<PluginMarketCardComponent cardVO={vo}/>
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-4
@@ -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 (
|
return (
|
||||||
<div>
|
<div className={`${styles.cardContainer}`}>
|
||||||
plugin market card
|
{/* 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>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+77
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user