mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
feat: marketplace cards
This commit is contained in:
@@ -86,7 +86,12 @@ export default function PluginConfigPage() {
|
||||
<PluginInstalledComponent ref={pluginInstalledRef} />
|
||||
</TabsContent>
|
||||
<TabsContent value="market">
|
||||
<PluginMarketComponent />
|
||||
<PluginMarketComponent askInstallPlugin={(githubURL) => {
|
||||
setGithubURL(githubURL);
|
||||
setModalOpen(true);
|
||||
setPluginInstallStatus(PluginInstallStatus.WAIT_INPUT);
|
||||
setInstallError(null);
|
||||
}} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
@@ -96,7 +101,7 @@ export default function PluginConfigPage() {
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-4">
|
||||
<GithubIcon className="size-6" />
|
||||
<span>从GitHub安装插件</span>
|
||||
<span>从 GitHub 安装插件</span>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
{pluginInstallStatus === PluginInstallStatus.WAIT_INPUT && (
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ import PluginMarketCardComponent from '@/app/home/plugins/plugin-market/plugin-m
|
||||
import { Input, Pagination } from 'antd';
|
||||
import { spaceClient } from '@/app/infra/http/HttpClient';
|
||||
|
||||
export default function PluginMarketComponent() {
|
||||
export default function PluginMarketComponent({
|
||||
askInstallPlugin,
|
||||
}: {
|
||||
askInstallPlugin: (githubURL: string) => void,
|
||||
}) {
|
||||
const [marketPluginList, setMarketPluginList] = useState<
|
||||
PluginMarketCardVO[]
|
||||
>([]);
|
||||
@@ -43,19 +47,31 @@ export default function PluginMarketComponent() {
|
||||
.then((res) => {
|
||||
setMarketPluginList(
|
||||
res.plugins.map(
|
||||
(marketPlugin) =>
|
||||
new PluginMarketCardVO({
|
||||
author: marketPlugin.author,
|
||||
(marketPlugin) => {
|
||||
let repository = marketPlugin.repository;
|
||||
if (repository.startsWith('https://github.com/')) {
|
||||
repository = repository.replace('https://github.com/', '');
|
||||
}
|
||||
|
||||
if (repository.startsWith('github.com/')) {
|
||||
repository = repository.replace('github.com/', '');
|
||||
}
|
||||
|
||||
const author = repository.split('/')[0];
|
||||
const name = repository.split('/')[1];
|
||||
return new PluginMarketCardVO({
|
||||
author: author,
|
||||
description: marketPlugin.description,
|
||||
githubURL: marketPlugin.repository,
|
||||
name: marketPlugin.name,
|
||||
githubURL: `https://github.com/${repository}`,
|
||||
name: name,
|
||||
pluginId: String(marketPlugin.ID),
|
||||
starCount: marketPlugin.stars,
|
||||
version:
|
||||
'version' in marketPlugin
|
||||
? String(marketPlugin.version)
|
||||
: '1.0.0', // Default version if not provided
|
||||
}),
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
setTotalCount(res.total);
|
||||
@@ -94,7 +110,9 @@ export default function PluginMarketComponent() {
|
||||
) : (
|
||||
marketPluginList.map((vo, index) => (
|
||||
<div key={`${vo.pluginId}-${index}`}>
|
||||
<PluginMarketCardComponent cardVO={vo} />
|
||||
<PluginMarketCardComponent cardVO={vo} installPlugin={(githubURL) => {
|
||||
askInstallPlugin(githubURL);
|
||||
}} />
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
|
||||
@@ -1,48 +1,58 @@
|
||||
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';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
export default function PluginMarketCardComponent({
|
||||
cardVO,
|
||||
installPlugin,
|
||||
}: {
|
||||
cardVO: PluginMarketCardVO;
|
||||
installPlugin: (pluginURL: string) => void;
|
||||
}) {
|
||||
function handleInstallClick(pluginId: string) {
|
||||
console.log('Install plugin: ', pluginId);
|
||||
function handleInstallClick(pluginURL: string) {
|
||||
installPlugin(pluginURL);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<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 style={{ paddingLeft: '5px' }}>{cardVO.starCount}</span>
|
||||
<div className={styles.contentContainer}>
|
||||
<svg className={styles.pluginIcon} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8 4C8 2.34315 9.34315 1 11 1C12.6569 1 14 2.34315 14 4C14 4.35064 13.9398 4.68722 13.8293 5H18C18.5523 5 19 5.44772 19 6V10.1707C19.3128 10.0602 19.6494 10 20 10C21.6569 10 23 11.3431 23 13C23 14.6569 21.6569 16 20 16C19.6494 16 19.3128 15.9398 19 15.8293V20C19 20.5523 18.5523 21 18 21H4C3.44772 21 3 20.5523 3 20V6C3 5.44772 3.44772 5 4 5H8.17071C8.06015 4.68722 8 4.35064 8 4Z"></path></svg>
|
||||
|
||||
<div className={styles.infoContainer}>
|
||||
|
||||
<div className={styles.basicInfoContainer}>
|
||||
|
||||
<div className={styles.nameContainer}>
|
||||
<div className={styles.author}>{cardVO.author} / </div>
|
||||
<div className={styles.nameAndVersionContainer}>
|
||||
<div className={styles.name}>{cardVO.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.description}>{cardVO.description}</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.componentContainer}>
|
||||
|
||||
<div className={styles.componentEntryContainer}>
|
||||
<svg className={styles.componentIcon} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12.0006 18.26L4.94715 22.2082L6.52248 14.2799L0.587891 8.7918L8.61493 7.84006L12.0006 0.5L15.3862 7.84006L23.4132 8.7918L17.4787 14.2799L19.054 22.2082L12.0006 18.26Z"></path></svg>
|
||||
<div className={styles.componentText}>星标 {cardVO.starCount}</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.componentEntryContainer}>
|
||||
<svg className={styles.githubIcon} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12.001 2C6.47598 2 2.00098 6.475 2.00098 12C2.00098 16.425 4.86348 20.1625 8.83848 21.4875C9.33848 21.575 9.52598 21.275 9.52598 21.0125C9.52598 20.775 9.51348 19.9875 9.51348 19.15C7.00098 19.6125 6.35098 18.5375 6.15098 17.975C6.03848 17.6875 5.55098 16.8 5.12598 16.5625C4.77598 16.375 4.27598 15.9125 5.11348 15.9C5.90098 15.8875 6.46348 16.625 6.65098 16.925C7.55098 18.4375 8.98848 18.0125 9.56348 17.75C9.65098 17.1 9.91348 16.6625 10.201 16.4125C7.97598 16.1625 5.65098 15.3 5.65098 11.475C5.65098 10.3875 6.03848 9.4875 6.67598 8.7875C6.57598 8.5375 6.22598 7.5125 6.77598 6.1375C6.77598 6.1375 7.61348 5.875 9.52598 7.1625C10.326 6.9375 11.176 6.825 12.026 6.825C12.876 6.825 13.726 6.9375 14.526 7.1625C16.4385 5.8625 17.276 6.1375 17.276 6.1375C17.826 7.5125 17.476 8.5375 17.376 8.7875C18.0135 9.4875 18.401 10.375 18.401 11.475C18.401 15.3125 16.0635 16.1625 13.8385 16.4125C14.201 16.725 14.5135 17.325 14.5135 18.2625C14.5135 19.6 14.501 20.675 14.501 21.0125C14.501 21.275 14.6885 21.5875 15.1885 21.4875C19.259 20.1133 21.9999 16.2963 22.001 12C22.001 6.475 17.526 2 12.001 2Z"></path></svg>
|
||||
<Button variant="default" size="sm"
|
||||
onClick={() => {
|
||||
handleInstallClick(cardVO.githubURL);
|
||||
}}
|
||||
>安装</Button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
size={'small'}
|
||||
onClick={() => {
|
||||
handleInstallClick(cardVO.pluginId);
|
||||
}}
|
||||
>
|
||||
安装
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,76 +1,115 @@
|
||||
.cardContainer {
|
||||
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;
|
||||
width: 26rem;
|
||||
height: 10rem;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 2px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
padding: 1.2rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
.contentContainer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
gap: 1.2rem;
|
||||
}
|
||||
|
||||
.link {
|
||||
width: 32px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
color: #6062E7;
|
||||
align-self: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.pluginIcon {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
color: #2288ee;
|
||||
}
|
||||
|
||||
.infoContainer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* background-color: aqua; */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.basicInfoContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
|
||||
.nameContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.author {
|
||||
font-size: 0.7rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.nameAndVersionContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 1.2rem;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.componentContainer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.componentEntryContainer {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.componentIcon {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
color: #ffcd27;
|
||||
}
|
||||
|
||||
|
||||
.componentText {
|
||||
font-size: 1rem;
|
||||
color: #ffcd27;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.githubIcon {
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
Reference in New Issue
Block a user