mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 19:37:36 +08:00
fix: dark mode for plugins management page
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -236,6 +236,7 @@ const jaJP = {
|
||||
noPlugins: '利用可能なプラグインがありません',
|
||||
noResults: '関連するプラグインが見つかりません',
|
||||
loadingMore: 'さらに読み込み中...',
|
||||
loading: '読み込み中...',
|
||||
allLoaded: 'すべてのプラグインが表示されました',
|
||||
install: 'インストール',
|
||||
installConfirm:
|
||||
|
||||
@@ -228,6 +228,7 @@ const zhHans = {
|
||||
noPlugins: '暂无插件',
|
||||
noResults: '未找到相关插件',
|
||||
loadingMore: '加载更多...',
|
||||
loading: '加载中...',
|
||||
allLoaded: '已显示全部插件',
|
||||
install: '安装',
|
||||
installConfirm: '确定要安装插件 "{{name}}" ({{version}}) 吗?',
|
||||
|
||||
@@ -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: '流程線',
|
||||
|
||||
Reference in New Issue
Block a user