@nospt/plugin-dev-ai-hub 0.1.0 โ 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dev/index.tsx +17 -217
- package/dist/api/DevAiHubClient.esm.js +2 -0
- package/dist/api/DevAiHubClient.esm.js.map +1 -1
- package/dist/components/AssetCard/AssetCard.esm.js +60 -134
- package/dist/components/AssetCard/AssetCard.esm.js.map +1 -1
- package/dist/components/AssetCard/AssetCard.module.css.esm.js +8 -0
- package/dist/components/AssetCard/AssetCard.module.css.esm.js.map +1 -0
- package/dist/components/AssetDetailPanel/AssetDetailPanel.esm.js +175 -281
- package/dist/components/AssetDetailPanel/AssetDetailPanel.esm.js.map +1 -1
- package/dist/components/AssetDetailPanel/AssetDetailPanel.module.css.esm.js +8 -0
- package/dist/components/AssetDetailPanel/AssetDetailPanel.module.css.esm.js.map +1 -0
- package/dist/components/AssetFilters/AssetFilters.esm.js +94 -134
- package/dist/components/AssetFilters/AssetFilters.esm.js.map +1 -1
- package/dist/components/AssetFilters/AssetFilters.module.css.esm.js +8 -0
- package/dist/components/AssetFilters/AssetFilters.module.css.esm.js.map +1 -0
- package/dist/components/AssetInstallDialog/AssetInstallDialog.esm.js +70 -126
- package/dist/components/AssetInstallDialog/AssetInstallDialog.esm.js.map +1 -1
- package/dist/components/AssetInstallDialog/AssetInstallDialog.module.css.esm.js +8 -0
- package/dist/components/AssetInstallDialog/AssetInstallDialog.module.css.esm.js.map +1 -0
- package/dist/components/DevAiHubPage/DevAiHubPage.esm.js +64 -189
- package/dist/components/DevAiHubPage/DevAiHubPage.esm.js.map +1 -1
- package/dist/components/DevAiHubPage/DevAiHubPage.module.css.esm.js +8 -0
- package/dist/components/DevAiHubPage/DevAiHubPage.module.css.esm.js.map +1 -0
- package/dist/components/McpConfigPage/McpConfigPage.esm.js +200 -0
- package/dist/components/McpConfigPage/McpConfigPage.esm.js.map +1 -0
- package/dist/components/McpConfigPage/McpConfigPage.module.css.esm.js +8 -0
- package/dist/components/McpConfigPage/McpConfigPage.module.css.esm.js.map +1 -0
- package/dist/components/McpConfigPage/index.esm.js +6 -0
- package/dist/components/McpConfigPage/index.esm.js.map +1 -0
- package/dist/components/ToolIcon/ToolIcon.esm.js +25 -13
- package/dist/components/ToolIcon/ToolIcon.esm.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.esm.js +1 -1
- package/dist/node_modules_dist/style-inject/dist/style-inject.es.esm.js +29 -0
- package/dist/node_modules_dist/style-inject/dist/style-inject.es.esm.js.map +1 -0
- package/dist/plugin.esm.js +24 -6
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +2 -1
- package/dist/routes.esm.js.map +1 -1
- package/package.json +24 -14
- package/package.json-prepack +24 -14
- package/src/components/AssetCard/AssetCard.module.css +153 -0
- package/src/components/AssetCard/AssetCard.tsx +79 -148
- package/src/components/AssetDetailPanel/AssetDetailPanel.module.css +207 -0
- package/src/components/AssetDetailPanel/AssetDetailPanel.tsx +228 -292
- package/src/components/AssetFilters/AssetFilters.module.css +67 -0
- package/src/components/AssetFilters/AssetFilters.tsx +136 -178
- package/src/components/AssetInstallDialog/AssetInstallDialog.module.css +72 -0
- package/src/components/AssetInstallDialog/AssetInstallDialog.tsx +95 -135
- package/src/components/DevAiHubPage/DevAiHubPage.module.css +105 -0
- package/src/components/DevAiHubPage/DevAiHubPage.tsx +73 -222
- package/src/components/McpConfigDialog/McpConfigDialog.module.css +111 -0
- package/src/components/McpConfigDialog/McpConfigDialog.tsx +178 -208
- package/src/components/McpConfigPage/McpConfigPage.module.css +121 -0
- package/src/components/McpConfigPage/McpConfigPage.tsx +242 -0
- package/src/components/McpConfigPage/index.ts +1 -0
- package/src/components/ToolIcon/ToolIcon.tsx +31 -15
- package/src/css-modules.d.ts +4 -0
- package/src/index.ts +1 -1
- package/src/plugin.tsx +23 -3
- package/src/routes.ts +1 -0
- package/tests/e2e/.auth.json +14 -0
- package/tests/e2e/asset-detail.spec.ts +90 -0
- package/tests/e2e/asset-filtering.spec.ts +145 -0
- package/tests/e2e/asset-installation.spec.ts +74 -0
- package/tests/e2e/dev-ai-hub-page.spec.ts +89 -0
- package/tests/e2e/fixtures/base.ts +61 -0
- package/tests/e2e/fixtures/mock-api.ts +221 -0
- package/tests/e2e/mcp-config.spec.ts +88 -0
- package/dist/components/McpConfigDialog/McpConfigDialog.esm.js +0 -274
- package/dist/components/McpConfigDialog/McpConfigDialog.esm.js.map +0 -1
package/package.json-prepack
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nospt/plugin-dev-ai-hub",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Frontend plugin for Dev AI Hub",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"types": "src/index.ts",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/nosportugal/backstage-plugin-dev-ai-hub"
|
|
11
|
+
},
|
|
8
12
|
"publishConfig": {
|
|
9
13
|
"access": "public"
|
|
10
14
|
},
|
|
@@ -37,35 +41,41 @@
|
|
|
37
41
|
"lint": "backstage-cli package lint",
|
|
38
42
|
"prepack": "backstage-cli package prepack",
|
|
39
43
|
"postpack": "backstage-cli package postpack",
|
|
40
|
-
"test": "backstage-cli package test --passWithNoTests",
|
|
44
|
+
"test": "backstage-cli package test --passWithNoTests --watchAll=false",
|
|
45
|
+
"test:e2e": "playwright test",
|
|
46
|
+
"test:e2e:ui": "playwright test --ui",
|
|
47
|
+
"test:e2e:debug": "playwright test --debug",
|
|
41
48
|
"tsc": "tsc --noEmit"
|
|
42
49
|
},
|
|
43
50
|
"dependencies": {
|
|
44
|
-
"@backstage/core-components": "
|
|
45
|
-
"@backstage/core-plugin-api": "
|
|
46
|
-
"@backstage/frontend-plugin-api": "
|
|
51
|
+
"@backstage/core-components": "^0.18.9",
|
|
52
|
+
"@backstage/core-plugin-api": "^1.12.5",
|
|
53
|
+
"@backstage/frontend-plugin-api": "^0.16.2",
|
|
54
|
+
"@backstage/ui": "^0.14.3",
|
|
47
55
|
"@mui/icons-material": "^5.15.0",
|
|
48
56
|
"@mui/material": "^5.15.0",
|
|
49
|
-
"@nospt/plugin-dev-ai-hub-common": "
|
|
57
|
+
"@nospt/plugin-dev-ai-hub-common": "workspace:^",
|
|
58
|
+
"@remixicon/react": "^4.6.0",
|
|
50
59
|
"react-markdown": "^9.0.0",
|
|
51
60
|
"react-syntax-highlighter": "^16.1.1",
|
|
52
61
|
"remark-gfm": "^4.0.1",
|
|
53
62
|
"simple-icons": "^13.0.0"
|
|
54
63
|
},
|
|
55
64
|
"devDependencies": {
|
|
56
|
-
"@backstage/cli": "
|
|
57
|
-
"@backstage/dev-utils": "
|
|
58
|
-
"@
|
|
65
|
+
"@backstage/cli": "^0.36.1",
|
|
66
|
+
"@backstage/dev-utils": "^1.1.22",
|
|
67
|
+
"@playwright/test": "^1.60.0",
|
|
68
|
+
"@testing-library/dom": "^10.0.0",
|
|
59
69
|
"@testing-library/jest-dom": "^6.0.0",
|
|
60
|
-
"@testing-library/react": "^
|
|
61
|
-
"@types/jest": "^
|
|
70
|
+
"@testing-library/react": "^16.3.1",
|
|
71
|
+
"@types/jest": "^30.0.0",
|
|
62
72
|
"@types/react": "^18.0.0",
|
|
63
73
|
"@types/react-syntax-highlighter": "^15.0.0",
|
|
64
|
-
"jest": "^
|
|
65
|
-
"
|
|
74
|
+
"jest": "^30.2.0",
|
|
75
|
+
"jsdom": "^27.1.0",
|
|
66
76
|
"react": "^18.0.0",
|
|
67
77
|
"react-dom": "^18.0.0",
|
|
68
|
-
"react-router-dom": "^6.
|
|
78
|
+
"react-router-dom": "^6.30.2"
|
|
69
79
|
},
|
|
70
80
|
"peerDependencies": {
|
|
71
81
|
"react": "^18.0.0",
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.card {
|
|
3
|
+
height: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
border-radius: var(--bui-radius-2);
|
|
7
|
+
border: 1px solid var(--bui-border-1);
|
|
8
|
+
border-left: 3px solid var(--card-accent);
|
|
9
|
+
background-color: var(--bui-bg-neutral-1);
|
|
10
|
+
transition: all 0.18s ease;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.card:hover {
|
|
14
|
+
box-shadow: 0 6px 24px color-mix(in srgb, var(--card-accent) 19%, transparent);
|
|
15
|
+
border-color: var(--card-accent);
|
|
16
|
+
transform: translateY(-2px);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.cardContent {
|
|
20
|
+
padding: var(--bui-space-3);
|
|
21
|
+
padding-bottom: 0;
|
|
22
|
+
flex: 1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.header {
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: flex-start;
|
|
28
|
+
gap: var(--bui-space-2);
|
|
29
|
+
margin-bottom: var(--bui-space-2);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.iconBox {
|
|
33
|
+
width: 36px;
|
|
34
|
+
height: 36px;
|
|
35
|
+
border-radius: var(--bui-radius-2);
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
flex-shrink: 0;
|
|
40
|
+
box-shadow: 0 2px 8px color-mix(in srgb, var(--card-accent) 15%, transparent);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.iconImage {
|
|
44
|
+
width: 20px;
|
|
45
|
+
height: 20px;
|
|
46
|
+
object-fit: contain;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.headerInfo {
|
|
50
|
+
flex: 1;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.titleRow {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: var(--bui-space-1);
|
|
58
|
+
margin-bottom: 2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.title {
|
|
62
|
+
line-height: 1.2;
|
|
63
|
+
flex: 1;
|
|
64
|
+
overflow: hidden;
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
text-overflow: ellipsis;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.newBadge {
|
|
70
|
+
height: 16px;
|
|
71
|
+
flex-shrink: 0;
|
|
72
|
+
font-size: 0.58rem;
|
|
73
|
+
font-weight: 700;
|
|
74
|
+
background-color: #6AB04C;
|
|
75
|
+
color: #fff;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.description {
|
|
79
|
+
margin-bottom: var(--bui-space-2);
|
|
80
|
+
display: -webkit-box;
|
|
81
|
+
-webkit-line-clamp: 2;
|
|
82
|
+
-webkit-box-orient: vertical;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
line-height: 1.4;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.toolsRow :global(.bui-TagList) {
|
|
88
|
+
display: flex;
|
|
89
|
+
gap: var(--bui-space-1);
|
|
90
|
+
flex-wrap: wrap;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.toolsRowWithTags {
|
|
94
|
+
margin-bottom: 6px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.toolChip {
|
|
98
|
+
height: 18px;
|
|
99
|
+
font-size: 0.65rem;
|
|
100
|
+
font-weight: 600;
|
|
101
|
+
background-color: var(--bui-bg-neutral-1-hover);
|
|
102
|
+
color: var(--bui-fg-secondary);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.tagsRow :global(.bui-TagList) {
|
|
106
|
+
display: flex;
|
|
107
|
+
gap: var(--bui-space-1);
|
|
108
|
+
flex-wrap: wrap;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.tagChip {
|
|
112
|
+
height: 16px;
|
|
113
|
+
font-size: 0.6rem;
|
|
114
|
+
color: var(--bui-fg-secondary);
|
|
115
|
+
background-color: transparent;
|
|
116
|
+
border: 1px solid var(--bui-border-1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.cardActions {
|
|
120
|
+
padding: var(--bui-space-2) var(--bui-space-3);
|
|
121
|
+
display: flex;
|
|
122
|
+
justify-content: space-between;
|
|
123
|
+
align-items: center;
|
|
124
|
+
margin-top: auto;
|
|
125
|
+
border-top: 1px solid var(--bui-border-1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.metaRow {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
gap: var(--bui-space-2);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.metaText {
|
|
135
|
+
font-size: 0.65rem;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.installCountRow {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 2px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.installEmoji {
|
|
145
|
+
font-size: 0.65rem;
|
|
146
|
+
line-height: 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.actionsRow {
|
|
150
|
+
display: flex;
|
|
151
|
+
gap: 2px;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import type { ElementType } from 'react';
|
|
2
|
-
import Box from '@
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import CardContent from '@mui/material/CardContent';
|
|
6
|
-
import Chip from '@mui/material/Chip';
|
|
7
|
-
import IconButton from '@mui/material/IconButton';
|
|
8
|
-
import Tooltip from '@mui/material/Tooltip';
|
|
9
|
-
import Typography from '@mui/material/Typography';
|
|
10
|
-
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
|
11
|
-
import DownloadIcon from '@mui/icons-material/Download';
|
|
12
|
-
import ArticleIcon from '@mui/icons-material/Article';
|
|
13
|
-
import SmartToyIcon from '@mui/icons-material/SmartToy';
|
|
14
|
-
import BuildIcon from '@mui/icons-material/Build';
|
|
15
|
-
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
|
2
|
+
import { Box, Flex, Text, Card, CardBody, CardFooter, Tag, TagGroup, ButtonIcon, Tooltip, TooltipTrigger } from '@backstage/ui';
|
|
3
|
+
import { RiDownloadLine, RiExternalLinkLine } from '@remixicon/react';
|
|
4
|
+
import { RiArticleLine, RiRobot2Line, RiToolsLine, RiGitBranchLine } from '@remixicon/react';
|
|
16
5
|
import type { AiAssetSummary, AssetType, AiTool } from '@nospt/plugin-dev-ai-hub-common';
|
|
17
6
|
import { ToolIcon } from '../ToolIcon';
|
|
7
|
+
import styles from './AssetCard.module.css';
|
|
18
8
|
|
|
19
9
|
const POPULAR_THRESHOLD = 5;
|
|
20
10
|
const NEW_DAYS_MS = 14 * 24 * 60 * 60 * 1000;
|
|
@@ -28,10 +18,10 @@ const TOOL_LABELS: Record<AiTool, string> = {
|
|
|
28
18
|
};
|
|
29
19
|
|
|
30
20
|
const TYPE_CONFIG: Record<AssetType, { label: string; color: string; bg: string; Icon: ElementType }> = {
|
|
31
|
-
instruction: { label: 'Instruction', color: '#
|
|
32
|
-
agent: { label: 'Agent', color: '#
|
|
33
|
-
skill: { label: 'Skill', color: '#
|
|
34
|
-
workflow: { label: 'Workflow', color: '#
|
|
21
|
+
instruction: { label: 'Instruction', color: '#54A0FF', bg: 'rgba(84, 160, 255, 0.15)', Icon: RiArticleLine },
|
|
22
|
+
agent: { label: 'Agent', color: '#FF6B9D', bg: 'rgba(255, 107, 157, 0.15)', Icon: RiRobot2Line },
|
|
23
|
+
skill: { label: 'Skill', color: '#6AB04C', bg: 'rgba(106, 176, 76, 0.15)', Icon: RiToolsLine },
|
|
24
|
+
workflow: { label: 'Workflow', color: '#F9CA24', bg: 'rgba(249, 202, 36, 0.15)', Icon: RiGitBranchLine },
|
|
35
25
|
};
|
|
36
26
|
|
|
37
27
|
interface AssetCardProps {
|
|
@@ -48,174 +38,115 @@ export function AssetCard({ asset, onView, onInstall }: AssetCardProps) {
|
|
|
48
38
|
|
|
49
39
|
return (
|
|
50
40
|
<Card
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
height: '100%',
|
|
54
|
-
display: 'flex',
|
|
55
|
-
flexDirection: 'column',
|
|
56
|
-
borderRadius: 2,
|
|
57
|
-
border: '1px solid',
|
|
58
|
-
borderColor: 'divider',
|
|
59
|
-
borderLeft: `3px solid ${cfg.color}`,
|
|
60
|
-
transition: 'all 0.18s ease',
|
|
61
|
-
'&:hover': {
|
|
62
|
-
boxShadow: `0 6px 24px ${cfg.color}30`,
|
|
63
|
-
borderColor: cfg.color,
|
|
64
|
-
transform: 'translateY(-2px)',
|
|
65
|
-
},
|
|
66
|
-
}}
|
|
41
|
+
className={styles.card}
|
|
42
|
+
style={{ '--card-accent': cfg.color } as React.CSSProperties}
|
|
67
43
|
>
|
|
68
|
-
<
|
|
44
|
+
<CardBody className={styles.cardContent}>
|
|
69
45
|
{/* Header */}
|
|
70
|
-
<
|
|
46
|
+
<Flex className={styles.header}>
|
|
71
47
|
<Box
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
height: 36,
|
|
75
|
-
borderRadius: 1.5,
|
|
76
|
-
backgroundColor: cfg.bg,
|
|
77
|
-
display: 'flex',
|
|
78
|
-
alignItems: 'center',
|
|
79
|
-
justifyContent: 'center',
|
|
80
|
-
flexShrink: 0,
|
|
81
|
-
boxShadow: `0 2px 8px ${cfg.color}25`,
|
|
82
|
-
}}
|
|
48
|
+
className={styles.iconBox}
|
|
49
|
+
style={{ backgroundColor: cfg.bg }}
|
|
83
50
|
>
|
|
84
51
|
{asset.icon ? (
|
|
85
|
-
<
|
|
86
|
-
component="img"
|
|
52
|
+
<img
|
|
87
53
|
src={asset.icon}
|
|
88
54
|
alt={asset.label ?? asset.name}
|
|
89
|
-
|
|
55
|
+
className={styles.iconImage}
|
|
90
56
|
onError={e => { (e.target as HTMLImageElement).style.display = 'none'; }}
|
|
91
57
|
/>
|
|
92
58
|
) : (
|
|
93
|
-
<TypeIcon
|
|
59
|
+
<TypeIcon size={18} style={{ color: cfg.color }} />
|
|
94
60
|
)}
|
|
95
61
|
</Box>
|
|
96
62
|
|
|
97
|
-
<Box
|
|
98
|
-
<
|
|
99
|
-
<
|
|
63
|
+
<Box className={styles.headerInfo}>
|
|
64
|
+
<Flex className={styles.titleRow}>
|
|
65
|
+
<Text variant="body-medium" weight="bold" className={styles.title} title={asset.label ?? asset.name}>
|
|
100
66
|
{asset.label ?? asset.name}
|
|
101
|
-
</
|
|
67
|
+
</Text>
|
|
102
68
|
{isNew && (
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
sx={{
|
|
107
|
-
height: 16,
|
|
108
|
-
fontSize: '0.58rem',
|
|
109
|
-
fontWeight: 700,
|
|
110
|
-
backgroundColor: '#059669',
|
|
111
|
-
color: '#fff',
|
|
112
|
-
borderRadius: 1,
|
|
113
|
-
flexShrink: 0,
|
|
114
|
-
'& .MuiChip-label': { px: '5px' },
|
|
115
|
-
}}
|
|
116
|
-
/>
|
|
69
|
+
<TagGroup aria-label="Status">
|
|
70
|
+
<Tag id="new" size="small" className={styles.newBadge}>New</Tag>
|
|
71
|
+
</TagGroup>
|
|
117
72
|
)}
|
|
118
|
-
</
|
|
119
|
-
<
|
|
73
|
+
</Flex>
|
|
74
|
+
<Text variant="body-x-small" style={{ color: cfg.color, fontWeight: 600 }}>
|
|
120
75
|
{cfg.label}
|
|
121
|
-
</
|
|
76
|
+
</Text>
|
|
122
77
|
</Box>
|
|
123
|
-
</
|
|
78
|
+
</Flex>
|
|
124
79
|
|
|
125
80
|
{/* Description */}
|
|
126
|
-
<
|
|
127
|
-
variant="caption"
|
|
128
|
-
color="text.secondary"
|
|
129
|
-
sx={{
|
|
130
|
-
mb: 1,
|
|
131
|
-
display: '-webkit-box',
|
|
132
|
-
WebkitLineClamp: 2,
|
|
133
|
-
WebkitBoxOrient: 'vertical',
|
|
134
|
-
overflow: 'hidden',
|
|
135
|
-
lineHeight: 1.4,
|
|
136
|
-
}}
|
|
137
|
-
>
|
|
81
|
+
<Text variant="body-x-small" color="secondary" className={styles.description}>
|
|
138
82
|
{asset.description}
|
|
139
|
-
</
|
|
83
|
+
</Text>
|
|
140
84
|
|
|
141
85
|
{/* Tools */}
|
|
142
|
-
<
|
|
86
|
+
<TagGroup aria-label="Compatible tools" className={`${styles.toolsRow} ${asset.tags.length > 0 ? styles.toolsRowWithTags : ''}`}>
|
|
143
87
|
{asset.tools.map(tool => (
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
label={TOOL_LABELS[tool as AiTool] ?? tool}
|
|
148
|
-
size="small"
|
|
149
|
-
sx={{
|
|
150
|
-
height: 18,
|
|
151
|
-
fontSize: '0.65rem',
|
|
152
|
-
fontWeight: 600,
|
|
153
|
-
backgroundColor: 'action.hover',
|
|
154
|
-
color: 'text.secondary',
|
|
155
|
-
borderRadius: 1,
|
|
156
|
-
'& .MuiChip-icon': { ml: '4px' },
|
|
157
|
-
}}
|
|
158
|
-
/>
|
|
88
|
+
<Tag key={tool} id={tool} size="small" className={styles.toolChip} icon={<ToolIcon tool={tool as AiTool} size={12} />}>
|
|
89
|
+
{TOOL_LABELS[tool as AiTool] ?? tool}
|
|
90
|
+
</Tag>
|
|
159
91
|
))}
|
|
160
|
-
</
|
|
92
|
+
</TagGroup>
|
|
161
93
|
|
|
162
94
|
{/* Tags */}
|
|
163
95
|
{asset.tags.length > 0 && (
|
|
164
|
-
|
|
165
|
-
{
|
|
166
|
-
|
|
167
|
-
key={tag}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
fontSize: '0.6rem',
|
|
173
|
-
color: 'text.disabled',
|
|
174
|
-
backgroundColor: 'transparent',
|
|
175
|
-
border: '1px solid',
|
|
176
|
-
borderColor: 'divider',
|
|
177
|
-
borderRadius: 1,
|
|
178
|
-
}}
|
|
179
|
-
/>
|
|
180
|
-
))}
|
|
96
|
+
<>
|
|
97
|
+
<TagGroup aria-label="Tags" className={styles.tagsRow}>
|
|
98
|
+
{asset.tags.slice(0, 3).map(tag => (
|
|
99
|
+
<Tag key={tag} id={tag} size="small" className={styles.tagChip}>
|
|
100
|
+
#{tag}
|
|
101
|
+
</Tag>
|
|
102
|
+
))}
|
|
103
|
+
</TagGroup>
|
|
181
104
|
{asset.tags.length > 3 && (
|
|
182
|
-
<
|
|
105
|
+
<Text variant="body-x-small" color="secondary" style={{ alignSelf: 'center' }}>
|
|
183
106
|
+{asset.tags.length - 3}
|
|
184
|
-
</
|
|
107
|
+
</Text>
|
|
185
108
|
)}
|
|
186
|
-
|
|
109
|
+
</>
|
|
187
110
|
)}
|
|
188
|
-
</
|
|
111
|
+
</CardBody>
|
|
189
112
|
|
|
190
|
-
<
|
|
191
|
-
<
|
|
192
|
-
<
|
|
113
|
+
<CardFooter className={styles.cardActions}>
|
|
114
|
+
<Flex className={styles.metaRow}>
|
|
115
|
+
<Text variant="body-x-small" color="secondary" className={styles.metaText}>
|
|
193
116
|
v{asset.version} ยท {asset.author}
|
|
194
|
-
</
|
|
117
|
+
</Text>
|
|
195
118
|
{asset.installCount > 0 && (
|
|
196
|
-
<
|
|
197
|
-
<
|
|
119
|
+
<Flex className={styles.installCountRow}>
|
|
120
|
+
<Text className={styles.installEmoji}>
|
|
198
121
|
{isPopular ? '๐ฅ' : 'โ'}
|
|
199
|
-
</
|
|
200
|
-
<
|
|
122
|
+
</Text>
|
|
123
|
+
<Text variant="body-x-small" color="secondary" className={styles.metaText}>
|
|
201
124
|
{asset.installCount}
|
|
202
|
-
</
|
|
203
|
-
</
|
|
125
|
+
</Text>
|
|
126
|
+
</Flex>
|
|
204
127
|
)}
|
|
205
|
-
</
|
|
206
|
-
<
|
|
207
|
-
<
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
128
|
+
</Flex>
|
|
129
|
+
<Flex className={styles.actionsRow}>
|
|
130
|
+
<TooltipTrigger>
|
|
131
|
+
<ButtonIcon
|
|
132
|
+
aria-label="Install in editor"
|
|
133
|
+
icon={<RiDownloadLine size={16} />}
|
|
134
|
+
variant="tertiary"
|
|
135
|
+
onPress={() => onInstall(asset.id)}
|
|
136
|
+
/>
|
|
137
|
+
<Tooltip>Install in editor</Tooltip>
|
|
138
|
+
</TooltipTrigger>
|
|
139
|
+
<TooltipTrigger>
|
|
140
|
+
<ButtonIcon
|
|
141
|
+
aria-label="View details"
|
|
142
|
+
icon={<RiExternalLinkLine size={16} />}
|
|
143
|
+
variant="tertiary"
|
|
144
|
+
onPress={() => onView(asset.id)}
|
|
145
|
+
/>
|
|
146
|
+
<Tooltip>View details</Tooltip>
|
|
147
|
+
</TooltipTrigger>
|
|
148
|
+
</Flex>
|
|
149
|
+
</CardFooter>
|
|
219
150
|
</Card>
|
|
220
151
|
);
|
|
221
152
|
}
|