Download apps/web/src/components/features/PluginCard.tsx from hunian003/message: direct link, hf CLI and curl.
- Browser
- Download file 3.07 kB
-
https://huggingface.co/spaces/hunian003/message/resolve/main/apps/web/src/components/features/PluginCard.tsx
- Command line
-
hf download hf://spaces/hunian003/message/apps/web/src/components/features/PluginCard.tsx
-
curl -L -o PluginCard.tsx https://huggingface.co/spaces/hunian003/message/resolve/main/apps/web/src/components/features/PluginCard.tsx
3.07 kB
| /** | |
| * 插件卡片组件 | |
| * | |
| * 使用 console 语义 token,与 PluginDetailPage 等页面保持一致 | |
| */ | |
| import { Link } from 'react-router-dom'; | |
| import { Play, Pause, LayoutGrid } from 'lucide-react'; | |
| import { PluginListItem, PluginStatus } from '@typings/plugin'; | |
| import { StatusPill } from '@components/console'; | |
| import { Button } from '@components/ui/button'; | |
| interface PluginCardProps { | |
| plugin: PluginListItem; | |
| onEnable: (name: string) => void; | |
| onDisable: (name: string) => void; | |
| } | |
| // 状态到 StatusPill 变体的映射 | |
| const statusVariantMap: Record<PluginStatus, 'enabled' | 'disabled' | 'error' | 'warning' | 'incomplete'> = { | |
| enabled: 'enabled', | |
| disabled: 'disabled', | |
| error: 'error', | |
| dependency_error: 'error', | |
| incomplete: 'incomplete', | |
| discovered: 'warning', | |
| loaded: 'warning', | |
| installed: 'disabled', | |
| installing: 'warning', | |
| uninstalling: 'warning', | |
| }; | |
| export function PluginCard({ plugin, onEnable, onDisable }: PluginCardProps) { | |
| const statusVariant = statusVariantMap[plugin.status] || 'disabled'; | |
| const hasUiPage = plugin.ui_entry?.type === 'static'; | |
| return ( | |
| <div className="py-3 px-4 bg-console-surface-raised rounded-console-md border border-console-border"> | |
| {/* 头部:名称 + 状态 */} | |
| <div className="flex items-start justify-between gap-2"> | |
| <div className="min-w-0"> | |
| <h3 className="font-semibold text-console-text-primary truncate"> | |
| {plugin.metadata.name} | |
| </h3> | |
| <div className="flex items-center gap-1.5 mt-1 text-xs text-console-text-secondary"> | |
| <span>v{plugin.metadata.version}</span> | |
| <span className="text-console-text-muted">•</span> | |
| <span>{plugin.metadata.author}</span> | |
| </div> | |
| </div> | |
| <StatusPill status={statusVariant} /> | |
| </div> | |
| {/* 描述 */} | |
| <p className="text-sm text-console-text-secondary mt-3 line-clamp-2"> | |
| {plugin.metadata.description} | |
| </p> | |
| {plugin.errors.length > 0 && ( | |
| <p className="text-sm text-console-status-error mt-2"> | |
| {plugin.errors[0].message} | |
| </p> | |
| )} | |
| {/* 操作按钮 */} | |
| <div className="flex items-center gap-2 mt-3 pt-3 border-t border-console-border"> | |
| {plugin.status === 'disabled' && ( | |
| <Button size="sm" onClick={() => onEnable(plugin.metadata.name)} className="h-7 text-xs"> | |
| <Play className="h-3 w-3 mr-1" /> | |
| 启用 | |
| </Button> | |
| )} | |
| {plugin.status === 'enabled' && ( | |
| <Button size="sm" variant="outline" onClick={() => onDisable(plugin.metadata.name)} className="h-7 text-xs"> | |
| <Pause className="h-3 w-3 mr-1" /> | |
| 禁用 | |
| </Button> | |
| )} | |
| {hasUiPage && ( | |
| <Link to={`/tool/${plugin.metadata.name}`}> | |
| <Button size="sm" variant="outline" className="h-7 text-xs"> | |
| <LayoutGrid className="h-3 w-3 mr-1" /> | |
| 访问页面 | |
| </Button> | |
| </Link> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |