返回 oh-my-ppt
ImageModelSettingsTab.tsx
根目录 / src / renderer / src / components / settings / ImageModelSettingsTab.tsx
1 import { CheckCircle2, Image as ImageIcon, Pencil, Plus, Trash2 } from 'lucide-react'
2 import type { ImageModelConfig } from '../../lib/ipc'
3 import { Button } from '../ui/Button'
4 import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
5 import { summarizeImageModelConfig } from './model-settings-utils'
6 import type { SettingsTranslate } from './types'
7
8 interface ImageModelSettingsTabProps {
9 activeImageModelConfig?: ImageModelConfig
10 activatingImageId: string | null
11 deletingImageId: string | null
12 imageModelConfigs: ImageModelConfig[]
13 t: SettingsTranslate
14 onActivate: (id: string) => void
15 onCreate: () => void
16 onDelete: (config: ImageModelConfig) => void
17 onEdit: (config: ImageModelConfig) => void
18 }
19
20 export function ImageModelSettingsTab({
21 activeImageModelConfig,
22 activatingImageId,
23 deletingImageId,
24 imageModelConfigs,
25 t,
26 onActivate,
27 onCreate,
28 onDelete,
29 onEdit
30 }: ImageModelSettingsTabProps): React.JSX.Element {
31 return (
32 <Card className="mb-4">
33 <CardHeader className="flex-row items-center justify-between p-5 pb-3">
34 <div>
35 <CardTitle className="flex items-center gap-1.5 text-base">
36 <ImageIcon className="h-4 w-4 text-[#5d7b4d]" />
37 {t('settings.imageModelAccess')}
38 </CardTitle>
39 <p className="mt-1 text-xs text-[#6f8f64]">
40 {t('settings.imageModelUsageHint')}
41 </p>
42 {activeImageModelConfig && (
43 <span className="mt-2 inline-flex max-w-full truncate rounded-full border border-[#96b77f]/55 bg-[#eef6e8] px-2.5 py-1 text-xs font-medium text-[#4f6b45]">
44 {t('settings.currentActiveImageModel', { name: activeImageModelConfig.name })}
45 </span>
46 )}
47 </div>
48 <Button size="sm" onClick={onCreate}>
49 <Plus className="mr-1.5 h-4 w-4" />
50 {t('settings.addImageModel')}
51 </Button>
52 </CardHeader>
53 <CardContent className="space-y-2.5 p-5 pt-0">
54 {imageModelConfigs.length === 0 ? (
55 <div className="rounded-lg border border-dashed border-[#d8ccb5]/85 bg-[#fff9ef]/70 p-6 text-sm text-muted-foreground">
56 {t('settings.noImageModels')}
57 </div>
58 ) : (
59 imageModelConfigs.map((config) => (
60 <div
61 key={config.id}
62 className={
63 config.active
64 ? 'flex flex-col gap-3 rounded-lg border border-[#96b77f]/80 bg-[#eef6e8] p-3 shadow-[inset_3px_0_0_#6f8f64] sm:flex-row sm:items-center sm:justify-between'
65 : 'flex flex-col gap-3 rounded-lg border border-[#d8ccb5]/80 bg-[#fffdf8]/78 p-3 sm:flex-row sm:items-center sm:justify-between'
66 }
67 >
68 <div className="min-w-0">
69 <div className="flex flex-wrap items-center gap-2">
70 {config.active && <CheckCircle2 className="h-4 w-4 text-[#5d7b4d]" />}
71 <p className="font-medium text-[#33402a]">{config.name}</p>
72 <span className="rounded-full bg-[#e9efde] px-2 py-0.5 text-[11px] uppercase text-[#506141]">
73 {config.provider}
74 </span>
75 </div>
76 <p className="mt-1 truncate text-xs text-muted-foreground">
77 {summarizeImageModelConfig(config.modelConfig)}
78 </p>
79 </div>
80 <div className="flex shrink-0 flex-wrap gap-2">
81 <Button
82 size="sm"
83 variant={config.active ? 'secondary' : 'outline'}
84 disabled={config.active || activatingImageId === config.id}
85 onClick={() => onActivate(config.id)}
86 >
87 {config.active
88 ? t('settings.activeImageModel')
89 : t('settings.activateImageModel')}
90 </Button>
91 <Button size="sm" variant="ghost" onClick={() => onEdit(config)}>
92 <Pencil className="h-4 w-4" />
93 </Button>
94 <Button
95 size="sm"
96 variant="ghost"
97 disabled={deletingImageId === config.id}
98 onClick={() => onDelete(config)}
99 >
100 <Trash2 className="h-4 w-4" />
101 </Button>
102 </div>
103 </div>
104 ))
105 )}
106 </CardContent>
107 </Card>
108 )
109 }
110
110 lines Plain Text