fix: dark mode for plugins management page

This commit is contained in:
Junyan Qin
2025-08-26 22:40:32 +08:00
parent 56183867a7
commit e7fe41810e
10 changed files with 120 additions and 34 deletions

View File

@@ -2,6 +2,7 @@ import { PluginComponent } from '@/app/infra/entities/plugin';
export interface IPluginCardVO {
author: string;
label: string;
name: string;
description: string;
version: string;
@@ -16,6 +17,7 @@ export interface IPluginCardVO {
export class PluginCardVO implements IPluginCardVO {
author: string;
label: string;
name: string;
description: string;
version: string;
@@ -29,6 +31,7 @@ export class PluginCardVO implements IPluginCardVO {
constructor(prop: IPluginCardVO) {
this.author = prop.author;
this.label = prop.label;
this.description = prop.description;
this.enabled = prop.enabled;
this.components = prop.components;

View File

@@ -74,6 +74,7 @@ const PluginInstalledComponent = forwardRef<PluginInstalledComponentRef>(
value.plugins.map((plugin) => {
return new PluginCardVO({
author: plugin.manifest.manifest.metadata.author ?? '',
label: extractI18nObject(plugin.manifest.manifest.metadata.label),
description: extractI18nObject(
plugin.manifest.manifest.metadata.description ?? {
en_US: '',

View File

@@ -83,7 +83,7 @@ export default function PluginCardComponent({
return (
<>
<div
className="w-[100%] h-[10rem] bg-white rounded-[10px] shadow-[0px_2px_2px_0_rgba(0,0,0,0.2)] p-[1.2rem] cursor-pointer"
className="w-[100%] h-[10rem] bg-white rounded-[10px] shadow-[0px_2px_2px_0_rgba(0,0,0,0.2)] p-[1.2rem] cursor-pointer dark:bg-[#1f1f22]"
onClick={onCardClick}
>
<div className="w-full h-full flex flex-row items-start justify-start gap-[1.2rem]">
@@ -99,11 +99,13 @@ export default function PluginCardComponent({
<div className="w-full h-full flex flex-col items-start justify-between gap-[0.6rem]">
<div className="flex flex-col items-start justify-start">
<div className="flex flex-col items-start justify-start">
<div className="text-[0.7rem] text-[#666]">
{cardVO.author} /{' '}
<div className="text-[0.7rem] text-[#666] dark:text-[#999]">
{cardVO.author} / {cardVO.name}
</div>
<div className="flex flex-row items-center justify-start gap-[0.4rem]">
<div className="text-[1.2rem] text-black">{cardVO.name}</div>
<div className="text-[1.2rem] text-black dark:text-[#f0f0f0]">
{cardVO.label}
</div>
<Badge variant="outline" className="text-[0.7rem]">
v{cardVO.version}
</Badge>
@@ -166,7 +168,7 @@ export default function PluginCardComponent({
</div>
</div>
<div className="text-[0.8rem] text-[#666] line-clamp-2">
<div className="text-[0.8rem] text-[#666] line-clamp-2 dark:text-[#999]">
{cardVO.description}
</div>
</div>

View File

@@ -341,7 +341,7 @@ function MarketPageContent({
{isLoading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin" />
<span className="ml-2">{t('cloud.loading')}</span>
<span className="ml-2">{t('market.loading')}</span>
</div>
) : plugins.length === 0 ? (
<div className="flex items-center justify-center py-12">

View File

@@ -79,11 +79,11 @@ export default function PluginDetailDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="!min-w-[65vw] !min-h-[65vh] max-h-[85vh] overflow-hidden p-0">
<DialogContent className="!min-w-[65vw] !min-h-[65vh] max-h-[85vh] overflow-hidden p-0 dark:bg-[#1f1f22]">
{isLoading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin" />
<span className="ml-2">{t('cloud.loading')}</span>
<span className="ml-2">{t('market.loading')}</span>
</div>
) : plugin ? (
<div className="flex h-full">
@@ -97,20 +97,20 @@ export default function PluginDetailDialog({
pluginName!,
)}
alt={plugin.name}
className="w-16 h-16 rounded-xl border bg-gray-50 object-cover flex-shrink-0"
className="w-16 h-16 rounded-xl border bg-gray-50 object-cover flex-shrink-0 dark:bg-[#1f1f22]"
/>
<div className="flex-1 min-w-0">
<h2 className="text-2xl font-bold text-gray-900 mb-2">
<h2 className="text-2xl font-bold text-gray-900 mb-2 dark:text-[#f0f0f0]">
{extractI18nObject(plugin.label) || plugin.name}
</h2>
<div className="flex items-center gap-2 text-sm text-gray-600 mb-2">
<div className="flex items-center gap-2 text-sm text-gray-600 mb-2 dark:text-[#999]">
<Users className="w-4 h-4" />
<span>
{plugin.author} / {plugin.name}
</span>
</div>
<div className="flex flex-wrap items-center gap-2 text-sm text-gray-600 mb-2">
<div className="flex flex-wrap items-center gap-2 text-sm text-gray-600 mb-2 dark:text-[#999]">
<Badge variant="outline" className="text-sm">
v{plugin.latest_version}
</Badge>
@@ -128,7 +128,7 @@ export default function PluginDetailDialog({
{plugin.repository && (
<svg
className="w-[1.2rem] h-[1.2rem] text-black cursor-pointer hover:text-gray-600"
className="w-[1.2rem] h-[1.2rem] text-black cursor-pointer hover:text-gray-600 dark:text-[#f0f0f0]"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
@@ -146,10 +146,10 @@ export default function PluginDetailDialog({
{/* 插件描述 */}
<div className="mb-6">
<h3 className="text-lg font-semibold text-gray-900 mb-3">
<h3 className="text-lg font-semibold text-gray-900 mb-3 dark:text-[#f0f0f0]">
{t('market.description')}
</h3>
<p className="text-gray-700 leading-relaxed">
<p className="text-gray-700 leading-relaxed dark:text-[#999]">
{extractI18nObject(plugin.description) ||
t('market.noDescription')}
</p>
@@ -158,12 +158,16 @@ export default function PluginDetailDialog({
{/* 标签 */}
{plugin.tags && plugin.tags.length > 0 && (
<div className="mb-6">
<h3 className="text-lg font-semibold text-gray-900 mb-3">
<h3 className="text-lg font-semibold text-gray-900 mb-3 dark:text-[#f0f0f0]">
{t('market.tags')}
</h3>
<div className="flex flex-wrap gap-2">
{plugin.tags.map((tag) => (
<Badge key={tag} variant="secondary" className="text-sm">
<Badge
key={tag}
variant="secondary"
className="text-sm dark:bg-[#1f1f22]"
>
{tag}
</Badge>
))}
@@ -200,7 +204,7 @@ export default function PluginDetailDialog({
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin" />
<span className="ml-3 text-gray-600">
{t('cloud.loading')}
{t('market.loading')}
</span>
</div>
) : (
@@ -209,54 +213,56 @@ export default function PluginDetailDialog({
components={{
// 自定义样式
h1: ({ children }) => (
<h1 className="text-xl font-bold mb-4 text-gray-900 border-b border-gray-200 pb-2">
<h1 className="text-xl font-bold mb-4 text-gray-900 border-b border-gray-200 pb-2 dark:text-[#f0f0f0]">
{children}
</h1>
),
h2: ({ children }) => (
<h2 className="text-lg font-semibold mb-3 text-gray-900 mt-6">
<h2 className="text-lg font-semibold mb-3 text-gray-900 mt-6 dark:text-[#f0f0f0]">
{children}
</h2>
),
h3: ({ children }) => (
<h3 className="text-base font-medium mb-2 text-gray-900 mt-4">
<h3 className="text-base font-medium mb-2 text-gray-900 mt-4 dark:text-[#f0f0f0]">
{children}
</h3>
),
p: ({ children }) => (
<p className="mb-4 leading-relaxed text-gray-700">
<p className="mb-4 leading-relaxed text-gray-700 dark:text-[#999]">
{children}
</p>
),
ul: ({ children }) => (
<ul className="mb-4 pl-6 list-disc space-y-1">
<ul className="mb-4 pl-6 list-disc space-y-1 dark:text-[#999]">
{children}
</ul>
),
ol: ({ children }) => (
<ol className="mb-4 pl-6 list-decimal space-y-1">
<ol className="mb-4 pl-6 list-decimal space-y-1 dark:text-[#999]">
{children}
</ol>
),
li: ({ children }) => (
<li className="text-gray-700">{children}</li>
<li className="text-gray-700 dark:text-[#999]">
{children}
</li>
),
code: ({ children, node }) => {
const isInline =
node?.children?.length === 1 &&
node?.children[0]?.type === 'text';
return isInline ? (
<code className="bg-gray-200 p-1 rounded-md text-sm font-mono whitespace-pre-wrap border">
<code className="bg-gray-200 p-1 rounded-md text-sm font-mono whitespace-pre-wrap border dark:bg-[#1f1f22]">
{children}
</code>
) : (
<code className="block bg-gray-200 p-3 rounded-md text-sm font-mono whitespace-pre-wrap border">
<code className="block bg-gray-200 p-3 rounded-md text-sm font-mono whitespace-pre-wrap border dark:bg-[#1f1f22]">
{children}
</code>
);
},
blockquote: ({ children }) => (
<blockquote className="border-l-4 border-blue-300 pl-4 py-2 mb-4 italic bg-blue-50 text-gray-700 rounded-r-md">
<blockquote className="border-l-4 border-blue-300 pl-4 py-2 mb-4 italic bg-blue-50 text-gray-700 rounded-r-md dark:bg-[#1f1f22]">
{children}
</blockquote>
),
@@ -265,7 +271,7 @@ export default function PluginDetailDialog({
href={href}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:text-blue-800 underline"
className="text-blue-600 hover:text-blue-800 underline dark:text-[#29f]"
>
{children}
</a>

View File

@@ -15,7 +15,7 @@ export default function PluginMarketCardComponent({
return (
<div
className="w-[100%] h-[9rem] bg-white rounded-[10px] shadow-[0px_0px_4px_0_rgba(0,0,0,0.2)] p-[1rem] cursor-pointer hover:shadow-[0px_2px_8px_0_rgba(0,0,0,0.15)] transition-shadow duration-200"
className="w-[100%] h-[9rem] bg-white rounded-[10px] shadow-[0px_0px_4px_0_rgba(0,0,0,0.2)] p-[1rem] cursor-pointer hover:shadow-[0px_2px_8px_0_rgba(0,0,0,0.15)] transition-shadow duration-200 dark:bg-[#1f1f22]"
onClick={handleCardClick}
>
<div className="w-full h-full flex flex-col justify-between">
@@ -25,13 +25,17 @@ export default function PluginMarketCardComponent({
<div className="flex-1 flex flex-col items-start justify-start gap-[0.6rem]">
<div className="flex flex-col items-start justify-start">
<div className="text-[0.7rem] text-[#666]">{cardVO.pluginId}</div>
<div className="text-[0.7rem] text-[#666] dark:text-[#999]">
{cardVO.pluginId}
</div>
<div className="flex flex-row items-center justify-start gap-[0.4rem]">
<div className="text-[1.2rem] text-black">{cardVO.label}</div>
<div className="text-[1.2rem] text-black dark:text-[#f0f0f0]">
{cardVO.label}
</div>
</div>
</div>
<div className="text-[0.8rem] text-[#666] dark:text-[#888888] line-clamp-2">
<div className="text-[0.8rem] text-[#666] dark:text-[#999] line-clamp-2">
{cardVO.description}
</div>
</div>
@@ -39,7 +43,7 @@ export default function PluginMarketCardComponent({
<div className="flex h-full flex-row items-start justify-center gap-[0.4rem]">
{cardVO.githubURL && (
<svg
className="w-[1.4rem] h-[1.4rem] text-black cursor-pointer hover:text-gray-600"
className="w-[1.4rem] h-[1.4rem] text-black cursor-pointer hover:text-gray-600 dark:text-[#f0f0f0]"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"

View File

@@ -235,6 +235,7 @@ const enUS = {
noPlugins: 'No plugins available',
noResults: 'No relevant plugins found',
loadingMore: 'Loading more...',
loading: 'Loading...',
allLoaded: 'All plugins displayed',
install: 'Install',
installConfirm:

View File

@@ -236,6 +236,7 @@ const jaJP = {
noPlugins: '利用可能なプラグインがありません',
noResults: '関連するプラグインが見つかりません',
loadingMore: 'さらに読み込み中...',
loading: '読み込み中...',
allLoaded: 'すべてのプラグインが表示されました',
install: 'インストール',
installConfirm:

View File

@@ -228,6 +228,7 @@ const zhHans = {
noPlugins: '暂无插件',
noResults: '未找到相关插件',
loadingMore: '加载更多...',
loading: '加载中...',
allLoaded: '已显示全部插件',
install: '安装',
installConfirm: '确定要安装插件 "{{name}}" ({{version}}) 吗?',

View File

@@ -192,6 +192,73 @@ const zhHant = {
eventCount: '事件:{{count}}',
toolCount: '工具:{{count}}',
starCount: '星標:{{count}}',
uploadLocal: '本地上傳',
debugging: '調試中',
uploadLocalPlugin: '上傳本地插件',
dragToUpload: '拖拽文件到此處上傳',
unsupportedFileType: '不支持的文件類型,僅支持 .lbpkg 和 .zip 文件',
uploadingPlugin: '正在上傳插件...',
uploadSuccess: '上傳成功',
uploadFailed: '上傳失敗',
selectFileToUpload: '選擇要上傳的插件文件',
askConfirm: '確定要安裝插件 "{{name}}" ({{version}}) 嗎?',
fromGithub: '來自 GitHub',
fromLocal: '本地安裝',
fromMarketplace: '來自市場',
componentsList: '組件: ',
noComponents: '無組件',
delete: '刪除插件',
update: '更新插件',
updateConfirm: '更新確認',
confirmUpdatePlugin: '您確定要更新插件({{author}}/{{name}})嗎?',
confirmUpdate: '確認更新',
updating: '更新中...',
updateSuccess: '插件更新成功',
updateError: '更新失敗:',
saveConfigSuccessNormal: '儲存配置成功',
saveConfigSuccessDebugPlugin: '儲存配置成功,請手動重啟插件',
saveConfigError: '儲存配置失敗:',
},
market: {
searchPlaceholder: '搜尋插件...',
searchResults: '搜尋到 {{count}} 個插件',
totalPlugins: '共 {{count}} 個插件',
noPlugins: '暫無插件',
noResults: '未找到相關插件',
loadingMore: '載入更多...',
loading: '載入中...',
allLoaded: '已顯示全部插件',
install: '安裝',
installConfirm: '確定要安裝插件 "{{name}}" ({{version}}) 嗎?',
downloadComplete: '插件 "{{name}}" 下載完成',
installFailed: '安裝失敗,請稍後重試',
loadFailed: '取得插件列表失敗,請稍後重試',
noDescription: '暫無描述',
notFound: '插件資訊未找到',
sortBy: '排序方式',
sort: {
recentlyAdded: '最近新增',
recentlyUpdated: '最近更新',
mostDownloads: '最多下載',
leastDownloads: '最少下載',
},
downloads: '次下載',
download: '下載',
repository: '代碼倉庫',
downloadFailed: '下載失敗',
noReadme: '該插件沒有提供 README 文件',
description: '描述',
tags: '標籤',
submissionTitle: '您有插件提交正在審核中: {{name}}',
submissionApproved: '您的插件提交已通過審核: {{name}}',
submissionRejected: '您的插件提交已被拒絕: {{name}}',
clickToRevoke: '撤回',
revokeSuccess: '撤回成功',
revokeFailed: '撤回失敗',
submissionDetails: '插件提交詳情',
markAsRead: '已讀',
markAsReadSuccess: '已標記為已讀',
markAsReadFailed: '標記為已讀失敗',
},
pipelines: {
title: '流程線',