diff --git a/web/package.json b/web/package.json
index 8cce9538..26cb7ca7 100644
--- a/web/package.json
+++ b/web/package.json
@@ -58,6 +58,7 @@
"react-i18next": "^15.5.1",
"react-markdown": "^10.1.0",
"react-photo-view": "^1.2.7",
+ "remark-gfm": "^4.0.1",
"sonner": "^2.0.3",
"tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.5",
diff --git a/web/src/app/home/plugins/plugin-market/plugin-detail-dialog/PluginDetailDialog.tsx b/web/src/app/home/plugins/plugin-market/plugin-detail-dialog/PluginDetailDialog.tsx
index 83a3994b..2bb29f8d 100644
--- a/web/src/app/home/plugins/plugin-market/plugin-detail-dialog/PluginDetailDialog.tsx
+++ b/web/src/app/home/plugins/plugin-market/plugin-detail-dialog/PluginDetailDialog.tsx
@@ -6,11 +6,12 @@ import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Loader2, Download, Users } from 'lucide-react';
import ReactMarkdown from 'react-markdown';
-import { PluginV4 } from '@/app/infra/entities/plugin';
-import { extractI18nObject } from '@/i18n/I18nProvider';
+import remarkGfm from 'remark-gfm';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
+import { PluginV4 } from '@/app/infra/entities/plugin';
import { getCloudServiceClientSync } from '@/app/infra/http';
+import { extractI18nObject } from '@/i18n/I18nProvider';
interface PluginDetailDialogProps {
open: boolean;
@@ -50,7 +51,6 @@ export default function PluginDetailDialog({
author,
pluginName,
);
- console.log('detailResponse', detailResponse);
setPlugin(detailResponse.plugin);
// 获取README
@@ -58,7 +58,6 @@ export default function PluginDetailDialog({
try {
const readmeResponse =
await getCloudServiceClientSync().getPluginREADME(author, pluginName);
- console.log('readmeResponse', readmeResponse);
setReadme(readmeResponse.readme);
} catch (error) {
console.warn('Failed to load README:', error);
@@ -77,210 +76,212 @@ export default function PluginDetailDialog({
if (!open) return null;
+ const PluginHeader = () => (
+
+
.getPluginIconURL(author!,)
+
+
+ {extractI18nObject(plugin!.label) || plugin!.name}
+
+
+
+
+ {plugin!.author} / {plugin!.name}
+
+
+
+
v{plugin!.latest_version}
+
+
+ {plugin!.install_count.toLocaleString()} {t('market.downloads')}
+
+ {plugin!.repository && (
+
+ )}
+
+
+
+ );
+
+ const PluginDescription = () => (
+
+
+ {extractI18nObject(plugin!.description) || t('market.noDescription')}
+
+
+ );
+
+ const PluginOptions = () => (
+
+
+
+ );
+
+ const ReadmeContent = () => (
+
+
(
+
+ ),
+ thead: ({ ...props }) => ,
+ tbody: ({ ...props }) => (
+
+ ),
+ th: ({ ...props }) => (
+ |
+ ),
+ td: ({ ...props }) => (
+ |
+ ),
+ tr: ({ ...props }) => (
+
+ ),
+ // 删除线支持
+ del: ({ ...props }) => (
+
+ ),
+ // Todo 列表支持
+ input: ({ type, checked, ...props }) => {
+ if (type === 'checkbox') {
+ return (
+
+ );
+ }
+ return ;
+ },
+ ul: ({ ...props }) => ,
+ ol: ({ ...props }) =>
,
+ li: ({ ...props }) => ,
+ h1: ({ ...props }) => (
+
+ ),
+ h2: ({ ...props }) => (
+
+ ),
+ p: ({ ...props }) => ,
+ code: ({ className, children, ...props }) => {
+ const match = /language-(\w+)/.exec(className || '');
+ const isCodeBlock = match ? true : false;
+
+ // 如果是代码块(有语言标识),由 pre 标签处理样式,淡灰色底,黑色字
+ if (isCodeBlock) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ // 内联代码样式 - 淡灰色底
+ return (
+
+ {children}
+
+ );
+ },
+ pre: ({ ...props }) => (
+
+ ),
+ }}
+ >
+ {readme}
+
+
+ );
+
return (