Skip to content

Commit b8d2499

Browse files
authored
feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage (#5190)
* feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage * feat: update random plugin selection logic to use pluginMarketData and refresh on relevant events
1 parent 8cb26d8 commit b8d2499

File tree

4 files changed

+385
-303
lines changed

4 files changed

+385
-303
lines changed
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
<script setup>
2+
import { useModuleI18n } from "@/i18n/composables";
3+
4+
const { tm } = useModuleI18n("features/extension");
5+
6+
defineProps({
7+
plugin: {
8+
type: Object,
9+
required: true,
10+
},
11+
defaultPluginIcon: {
12+
type: String,
13+
required: true,
14+
},
15+
showPluginFullName: {
16+
type: Boolean,
17+
default: false,
18+
},
19+
});
20+
21+
const emit = defineEmits(["install"]);
22+
23+
const handleInstall = (plugin) => {
24+
emit("install", plugin);
25+
};
26+
</script>
27+
28+
<template>
29+
<v-card
30+
class="rounded-lg d-flex flex-column plugin-card"
31+
elevation="0"
32+
style="height: 12rem; position: relative"
33+
>
34+
<v-chip
35+
v-if="plugin?.pinned"
36+
color="warning"
37+
size="x-small"
38+
label
39+
style="
40+
position: absolute;
41+
right: 8px;
42+
top: 8px;
43+
z-index: 10;
44+
height: 20px;
45+
font-weight: bold;
46+
"
47+
>
48+
{{ tm("market.recommended") }}
49+
</v-chip>
50+
51+
<v-card-text
52+
style="
53+
padding: 12px;
54+
padding-bottom: 8px;
55+
display: flex;
56+
gap: 12px;
57+
width: 100%;
58+
flex: 1;
59+
overflow: hidden;
60+
"
61+
>
62+
<div style="flex-shrink: 0">
63+
<img
64+
:src="plugin?.logo || defaultPluginIcon"
65+
:alt="plugin.name"
66+
style="
67+
height: 75px;
68+
width: 75px;
69+
border-radius: 8px;
70+
object-fit: cover;
71+
"
72+
/>
73+
</div>
74+
75+
<div
76+
style="
77+
flex: 1;
78+
overflow: hidden;
79+
display: flex;
80+
flex-direction: column;
81+
"
82+
>
83+
<div
84+
class="font-weight-bold"
85+
style="
86+
margin-bottom: 4px;
87+
line-height: 1.3;
88+
font-size: 1.2rem;
89+
white-space: nowrap;
90+
overflow: hidden;
91+
text-overflow: ellipsis;
92+
"
93+
>
94+
<span style="overflow: hidden; text-overflow: ellipsis">
95+
{{
96+
plugin.display_name?.length
97+
? plugin.display_name
98+
: showPluginFullName
99+
? plugin.name
100+
: plugin.trimmedName
101+
}}
102+
</span>
103+
</div>
104+
105+
<div class="d-flex align-center" style="gap: 4px; margin-bottom: 6px">
106+
<v-icon
107+
icon="mdi-account"
108+
size="x-small"
109+
style="color: rgba(var(--v-theme-on-surface), 0.5)"
110+
></v-icon>
111+
<a
112+
v-if="plugin?.social_link"
113+
:href="plugin.social_link"
114+
target="_blank"
115+
class="text-subtitle-2 font-weight-medium"
116+
style="
117+
text-decoration: none;
118+
color: rgb(var(--v-theme-primary));
119+
white-space: nowrap;
120+
overflow: hidden;
121+
text-overflow: ellipsis;
122+
"
123+
>
124+
{{ plugin.author }}
125+
</a>
126+
<span
127+
v-else
128+
class="text-subtitle-2 font-weight-medium"
129+
style="
130+
color: rgb(var(--v-theme-primary));
131+
white-space: nowrap;
132+
overflow: hidden;
133+
text-overflow: ellipsis;
134+
"
135+
>
136+
{{ plugin.author }}
137+
</span>
138+
<div
139+
class="d-flex align-center text-subtitle-2 ml-2"
140+
style="color: rgba(var(--v-theme-on-surface), 0.7)"
141+
>
142+
<v-icon
143+
icon="mdi-source-branch"
144+
size="x-small"
145+
style="margin-right: 2px"
146+
></v-icon>
147+
<span>{{ plugin.version }}</span>
148+
</div>
149+
</div>
150+
151+
<div class="text-caption plugin-description">
152+
{{ plugin.desc }}
153+
</div>
154+
155+
<div class="d-flex align-center" style="gap: 8px; margin-top: auto">
156+
<div
157+
v-if="plugin.stars !== undefined"
158+
class="d-flex align-center text-subtitle-2"
159+
style="color: rgba(var(--v-theme-on-surface), 0.7)"
160+
>
161+
<v-icon
162+
icon="mdi-star"
163+
size="x-small"
164+
style="margin-right: 2px"
165+
></v-icon>
166+
<span>{{ plugin.stars }}</span>
167+
</div>
168+
<div
169+
v-if="plugin.updated_at"
170+
class="d-flex align-center text-subtitle-2"
171+
style="color: rgba(var(--v-theme-on-surface), 0.7)"
172+
>
173+
<v-icon
174+
icon="mdi-clock-outline"
175+
size="x-small"
176+
style="margin-right: 2px"
177+
></v-icon>
178+
<span>{{ new Date(plugin.updated_at).toLocaleString() }}</span>
179+
</div>
180+
</div>
181+
</div>
182+
</v-card-text>
183+
184+
<v-card-actions style="gap: 6px; padding: 8px 12px; padding-top: 0">
185+
<v-chip
186+
v-for="tag in plugin.tags?.slice(0, 2)"
187+
:key="tag"
188+
:color="tag === 'danger' ? 'error' : 'primary'"
189+
label
190+
size="x-small"
191+
style="height: 20px"
192+
>
193+
{{ tag === "danger" ? tm("tags.danger") : tag }}
194+
</v-chip>
195+
<v-menu v-if="plugin.tags && plugin.tags.length > 2" open-on-hover offset-y>
196+
<template v-slot:activator="{ props: menuProps }">
197+
<v-chip
198+
v-bind="menuProps"
199+
color="grey"
200+
label
201+
size="x-small"
202+
style="height: 20px; cursor: pointer"
203+
>
204+
+{{ plugin.tags.length - 2 }}
205+
</v-chip>
206+
</template>
207+
<v-list density="compact">
208+
<v-list-item v-for="tag in plugin.tags.slice(2)" :key="tag">
209+
<v-chip :color="tag === 'danger' ? 'error' : 'primary'" label size="small">
210+
{{ tag === "danger" ? tm("tags.danger") : tag }}
211+
</v-chip>
212+
</v-list-item>
213+
</v-list>
214+
</v-menu>
215+
<v-spacer></v-spacer>
216+
<v-btn
217+
v-if="plugin?.repo"
218+
color="secondary"
219+
size="x-small"
220+
variant="tonal"
221+
:href="plugin.repo"
222+
target="_blank"
223+
style="height: 24px"
224+
>
225+
<v-icon icon="mdi-github" start size="x-small"></v-icon>
226+
{{ tm("buttons.viewRepo") }}
227+
</v-btn>
228+
<v-btn
229+
v-if="!plugin?.installed"
230+
color="primary"
231+
size="x-small"
232+
@click="handleInstall(plugin)"
233+
variant="flat"
234+
style="height: 24px"
235+
>
236+
{{ tm("buttons.install") }}
237+
</v-btn>
238+
<v-chip v-else color="success" size="x-small" label style="height: 20px">
239+
✓ {{ tm("status.installed") }}
240+
</v-chip>
241+
</v-card-actions>
242+
</v-card>
243+
</template>
244+
245+
<style scoped>
246+
.plugin-description {
247+
color: rgba(var(--v-theme-on-surface), 0.6);
248+
line-height: 1.3;
249+
margin-bottom: 6px;
250+
flex: 1;
251+
overflow-y: hidden;
252+
}
253+
254+
.plugin-card:hover .plugin-description {
255+
overflow-y: auto;
256+
}
257+
258+
.plugin-description::-webkit-scrollbar {
259+
width: 8px;
260+
height: 8px;
261+
}
262+
263+
.plugin-description::-webkit-scrollbar-track {
264+
background: transparent;
265+
}
266+
267+
.plugin-description::-webkit-scrollbar-thumb {
268+
background-color: rgba(var(--v-theme-primary-rgb), 0.4);
269+
border-radius: 4px;
270+
border: 2px solid transparent;
271+
background-clip: content-box;
272+
}
273+
274+
.plugin-description::-webkit-scrollbar-thumb:hover {
275+
background-color: rgba(var(--v-theme-primary-rgb), 0.6);
276+
}
277+
</style>

dashboard/src/i18n/locales/en-US/features/extension.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"selectFile": "Select File",
3939
"refresh": "Refresh",
4040
"updateAll": "Update All",
41-
"deleteSource": "Delete Source"
41+
"deleteSource": "Delete Source",
42+
"reshuffle": "Shuffle Again"
4243
},
4344
"status": {
4445
"enabled": "Enabled",
@@ -103,7 +104,9 @@
103104
"sourceUpdated": "Source updated successfully",
104105
"defaultOfficialSource": "Default Official Source",
105106
"sourceExists": "This source already exists",
106-
"installPlugin": "Install Plugin"
107+
"installPlugin": "Install Plugin",
108+
"randomPlugins": "🎲 Random Plugins",
109+
"sourceSafetyWarning": "Even with the default source, plugin stability and security cannot be fully guaranteed. Please verify carefully before use."
107110
},
108111
"sort": {
109112
"default": "Default",

dashboard/src/i18n/locales/zh-CN/features/extension.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"subtitle": "管理和配置系统插件",
44
"tabs": {
55
"installedPlugins": "AstrBot 插件",
6-
"market": "AstrBot 插件市场",
6+
"market": "AstrBot 插件市场",
77
"installedMcpServers": "MCP",
88
"skills": "Skills",
99
"handlersOperation": "管理行为"
@@ -38,7 +38,8 @@
3838
"selectFile": "选择文件",
3939
"refresh": "刷新",
4040
"updateAll": "更新全部插件",
41-
"deleteSource": "删除源"
41+
"deleteSource": "删除源",
42+
"reshuffle": "随机一发"
4243
},
4344
"status": {
4445
"enabled": "启用",
@@ -103,7 +104,9 @@
103104
"sourceUpdated": "插件源更新成功",
104105
"defaultOfficialSource": "默认官方源",
105106
"sourceExists": "该插件源已存在",
106-
"installPlugin": "安装插件"
107+
"installPlugin": "安装插件",
108+
"randomPlugins": "🎲 随机插件",
109+
"sourceSafetyWarning": "即使是默认插件源,我们也不能完全保证插件的稳定性和安全性,使用前请谨慎核查。"
107110
},
108111
"sort": {
109112
"default": "默认排序",

0 commit comments

Comments
 (0)