283 lines
8.2 KiB
TypeScript
283 lines
8.2 KiB
TypeScript
import { Template } from "interface/template";
|
||
import {
|
||
Container,
|
||
Heading,
|
||
Text,
|
||
Box,
|
||
Flex,
|
||
Card,
|
||
Button,
|
||
TextField,
|
||
DropdownMenu,
|
||
ScrollArea,
|
||
Dialog,
|
||
Tabs,
|
||
Switch,
|
||
IconButton
|
||
} from "@radix-ui/themes";
|
||
import {
|
||
PlusIcon,
|
||
MagnifyingGlassIcon,
|
||
DownloadIcon,
|
||
GearIcon,
|
||
CodeIcon,
|
||
Cross2Icon,
|
||
CheckIcon,
|
||
UpdateIcon,
|
||
TrashIcon,
|
||
ExclamationTriangleIcon
|
||
} from "@radix-ui/react-icons";
|
||
import { useState } from "react";
|
||
import type { PluginConfig } from "interface/plugin";
|
||
|
||
// 模拟插件数据
|
||
const mockPlugins: (PluginConfig & { id: number; preview?: string; installed?: boolean })[] = [
|
||
{
|
||
id: 1,
|
||
name: "comment-system",
|
||
displayName: "评论系统",
|
||
version: "1.0.0",
|
||
description: "支持多种评论系统集成,包括Disqus、Gitalk等",
|
||
author: "Admin",
|
||
enabled: true,
|
||
icon: "https://api.iconify.design/material-symbols:comment.svg",
|
||
preview: "https://images.unsplash.com/photo-1516116216624-53e697fedbea?w=500&auto=format",
|
||
managePath: "/dashboard/plugins/comment-system",
|
||
installed: true,
|
||
configuration: {
|
||
system: {
|
||
title: "评论系统配置",
|
||
description: "配置评论系统参数",
|
||
data: {
|
||
provider: "gitalk",
|
||
clientId: "",
|
||
clientSecret: ""
|
||
}
|
||
}
|
||
},
|
||
routes: new Set()
|
||
},
|
||
{
|
||
id: 2,
|
||
name: "image-optimization",
|
||
displayName: "图片优化",
|
||
version: "1.0.0",
|
||
description: "自动优化上传的图片,支持压缩、裁剪、水印等功能",
|
||
author: "ThirdParty",
|
||
enabled: false,
|
||
icon: "https://api.iconify.design/material-symbols:image.svg",
|
||
preview: "https://images.unsplash.com/photo-1618005198919-d3d4b5a92ead?w=500&auto=format",
|
||
installed: true,
|
||
configuration: {
|
||
system: {
|
||
title: "图片优化配置",
|
||
description: "配置图片优化参数",
|
||
data: {
|
||
quality: 80,
|
||
maxWidth: 1920,
|
||
watermark: false
|
||
}
|
||
}
|
||
},
|
||
routes: new Set()
|
||
}
|
||
];
|
||
|
||
// 模拟市场插件数据
|
||
interface MarketPlugin {
|
||
id: number;
|
||
name: string;
|
||
displayName: string;
|
||
version: string;
|
||
description: string;
|
||
author: string;
|
||
preview?: string;
|
||
downloads: number;
|
||
rating: number;
|
||
}
|
||
|
||
const marketPlugins: MarketPlugin[] = [
|
||
{
|
||
id: 4,
|
||
name: "image-optimization",
|
||
displayName: "图片优化",
|
||
version: "1.0.0",
|
||
description: "自动优化上传的图片,支持压缩、裁剪、水印等功能",
|
||
author: "ThirdParty",
|
||
preview: "https://images.unsplash.com/photo-1516116216624-53e697fedbea?w=500&auto=format",
|
||
downloads: 1200,
|
||
rating: 4.5
|
||
},
|
||
{
|
||
id: 5,
|
||
name: "markdown-plus",
|
||
displayName: "Markdown增强",
|
||
version: "2.0.0",
|
||
description: "增强的Markdown编辑器,支持更多扩展语法和实时预览",
|
||
author: "ThirdParty",
|
||
preview: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=500&auto=format",
|
||
downloads: 3500,
|
||
rating: 4.8
|
||
}
|
||
];
|
||
|
||
export default new Template({}, ({ http, args }) => {
|
||
const [searchTerm, setSearchTerm] = useState("");
|
||
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||
const [selectedPlugin, setSelectedPlugin] = useState<typeof mockPlugins[0] | null>(null);
|
||
|
||
// 处理插件启用/禁用
|
||
const handleTogglePlugin = (pluginId: number) => {
|
||
// 这里添加启用/禁用插件的逻辑
|
||
console.log('Toggle plugin:', pluginId);
|
||
};
|
||
|
||
return (
|
||
<Box>
|
||
{/* 页面标题和操作栏 */}
|
||
<Flex justify="between" align="center" className="mb-6">
|
||
<Box>
|
||
<Heading size="6" className="text-[--gray-12] mb-2">
|
||
插件管理
|
||
</Heading>
|
||
<Text className="text-[--gray-11]">
|
||
共 {mockPlugins.length} 个插件
|
||
</Text>
|
||
</Box>
|
||
<Button
|
||
className="bg-[--accent-9]"
|
||
onClick={() => setIsAddDialogOpen(true)}
|
||
>
|
||
<PlusIcon className="w-4 h-4" />
|
||
安装插件
|
||
</Button>
|
||
</Flex>
|
||
|
||
{/* 搜索栏 */}
|
||
<Box className="w-full sm:w-64 mb-6">
|
||
<TextField.Root
|
||
placeholder="搜索插件..."
|
||
value={searchTerm}
|
||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchTerm(e.target.value)}
|
||
>
|
||
<TextField.Slot>
|
||
<MagnifyingGlassIcon height="16" width="16" />
|
||
</TextField.Slot>
|
||
</TextField.Root>
|
||
</Box>
|
||
|
||
{/* 插件列表 */}
|
||
<Box className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{mockPlugins.map((plugin) => (
|
||
<Card key={plugin.id} className="p-4 border border-[--gray-6] hover-card">
|
||
{/* 插件预览图 */}
|
||
{plugin.preview && (
|
||
<Box className="aspect-video mb-4 rounded-lg overflow-hidden bg-[--gray-3]">
|
||
<img
|
||
src={plugin.preview}
|
||
alt={plugin.displayName}
|
||
className="w-full h-full object-cover"
|
||
/>
|
||
</Box>
|
||
)}
|
||
|
||
{/* 插件信息 */}
|
||
<Flex direction="column" gap="2">
|
||
<Flex justify="between" align="center">
|
||
<Heading size="3">{plugin.displayName}</Heading>
|
||
<Switch
|
||
checked={plugin.enabled}
|
||
onCheckedChange={() => handleTogglePlugin(plugin.id)}
|
||
/>
|
||
</Flex>
|
||
|
||
<Text size="1" className="text-[--gray-11]">
|
||
版本 {plugin.version} · 作者 {plugin.author}
|
||
</Text>
|
||
|
||
<Text size="2" className="text-[--gray-11] line-clamp-2">
|
||
{plugin.description}
|
||
</Text>
|
||
|
||
{/* 操作按钮 */}
|
||
<Flex gap="2" mt="2">
|
||
{plugin.managePath && plugin.enabled && (
|
||
<Button
|
||
variant="soft"
|
||
className="flex-1"
|
||
onClick={() => {
|
||
if(plugin.managePath) {
|
||
window.location.href = plugin.managePath;
|
||
}
|
||
}}
|
||
>
|
||
<GearIcon className="w-4 h-4" />
|
||
配置
|
||
</Button>
|
||
)}
|
||
<Button
|
||
variant="soft"
|
||
color="red"
|
||
className="flex-1"
|
||
>
|
||
<TrashIcon className="w-4 h-4" />
|
||
卸载
|
||
</Button>
|
||
</Flex>
|
||
</Flex>
|
||
</Card>
|
||
))}
|
||
</Box>
|
||
|
||
{/* 安装插件对话框 */}
|
||
<Dialog.Root open={isAddDialogOpen} onOpenChange={setIsAddDialogOpen}>
|
||
<Dialog.Content style={{ maxWidth: 500 }}>
|
||
<Dialog.Title>安装插件</Dialog.Title>
|
||
<Dialog.Description size="2" mb="4">
|
||
上传插件包进行安装
|
||
</Dialog.Description>
|
||
|
||
<Box className="mt-4">
|
||
<Box className="border-2 border-dashed border-[--gray-6] rounded-lg p-8 text-center">
|
||
<input
|
||
type="file"
|
||
className="hidden"
|
||
id="plugin-upload"
|
||
accept=".zip"
|
||
onChange={(e) => {
|
||
console.log(e.target.files);
|
||
}}
|
||
/>
|
||
<label
|
||
htmlFor="plugin-upload"
|
||
className="cursor-pointer"
|
||
>
|
||
<CodeIcon className="w-12 h-12 mx-auto mb-4 text-[--gray-9]" />
|
||
<Text className="text-[--gray-11] mb-2">
|
||
点击上传插件包或拖拽到此处
|
||
</Text>
|
||
<Text size="1" className="text-[--gray-10]">
|
||
支持 .zip 格式的插件包
|
||
</Text>
|
||
</label>
|
||
</Box>
|
||
</Box>
|
||
|
||
<Flex gap="3" mt="4" justify="end">
|
||
<Dialog.Close>
|
||
<Button variant="soft" color="gray">
|
||
取消
|
||
</Button>
|
||
</Dialog.Close>
|
||
<Dialog.Close>
|
||
<Button className="bg-[--accent-9]">
|
||
开始安装
|
||
</Button>
|
||
</Dialog.Close>
|
||
</Flex>
|
||
</Dialog.Content>
|
||
</Dialog.Root>
|
||
</Box>
|
||
);
|
||
}); |