返回 oh-my-ppt
SaveTemplateDialog.tsx
根目录 / src / renderer / src / components / templates / SaveTemplateDialog.tsx
1 import { useEffect, useState } from 'react'
2 import { Button } from '../ui/Button'
3 import {
4 Dialog,
5 DialogContent,
6 DialogDescription,
7 DialogFooter,
8 DialogHeader,
9 DialogTitle
10 } from '../ui/Dialog'
11 import { Input } from '../ui/Input'
12 import { useT } from '@renderer/i18n'
13
14 export function SaveTemplateDialog({
15 open,
16 defaultName,
17 defaultDescription = '',
18 defaultTags,
19 mode = 'create',
20 saving,
21 onOpenChange,
22 onSubmit
23 }: {
24 open: boolean
25 defaultName: string
26 defaultDescription?: string
27 defaultTags?: string[]
28 mode?: 'create' | 'edit'
29 saving?: boolean
30 onOpenChange: (open: boolean) => void
31 onSubmit: (payload: { name: string; description: string; tags: string[] }) => void
32 }): React.JSX.Element {
33 const t = useT()
34 const [name, setName] = useState(defaultName)
35 const [description, setDescription] = useState('')
36 const [tags, setTags] = useState('')
37
38 useEffect(() => {
39 if (!open) return
40 setName(defaultName)
41 setDescription(defaultDescription)
42 setTags((defaultTags || []).join(','))
43 }, [defaultDescription, defaultName, defaultTags, open])
44
45 const submit = (): void => {
46 const cleanName = name.trim()
47 if (!cleanName || saving) return
48 onSubmit({
49 name: cleanName,
50 description: description.trim(),
51 tags: tags
52 .split(/[,,\n]/)
53 .map((tag) => tag.trim())
54 .filter(Boolean)
55 .slice(0, 12)
56 })
57 }
58
59 return (
60 <Dialog open={open} onOpenChange={(next) => !saving && onOpenChange(next)}>
61 <DialogContent>
62 <DialogHeader>
63 <DialogTitle>
64 {mode === 'edit' ? t('templateDialog.editTitle') : t('templateDialog.createTitle')}
65 </DialogTitle>
66 <DialogDescription className="text-xs leading-5">
67 {mode === 'edit'
68 ? t('templateDialog.editDescription')
69 : t('templateDialog.createDescription')}
70 </DialogDescription>
71 </DialogHeader>
72 <div className="space-y-3">
73 <div>
74 <label className="mb-1 block text-xs font-medium text-[#5f6b50]">
75 {t('templateDialog.nameLabel')}
76 </label>
77 <Input value={name} maxLength={120} onChange={(event) => setName(event.target.value)} />
78 </div>
79 <div>
80 <label className="mb-1 block text-xs font-medium text-[#5f6b50]">
81 {t('templateDialog.descriptionLabel')}
82 </label>
83 <textarea
84 value={description}
85 maxLength={240}
86 className="min-h-[74px] w-full rounded-lg border border-input bg-background px-3 py-2 text-sm outline-none transition-colors focus:border-ring"
87 placeholder={t('templateDialog.descriptionPlaceholder')}
88 onChange={(event) => setDescription(event.target.value)}
89 />
90 </div>
91 <div>
92 <label className="mb-1 block text-xs font-medium text-[#5f6b50]">
93 {t('templateDialog.tagsLabel')}
94 </label>
95 <Input
96 value={tags}
97 placeholder={t('templateDialog.tagsPlaceholder')}
98 onChange={(event) => setTags(event.target.value)}
99 />
100 </div>
101 </div>
102 <DialogFooter>
103 <Button type="button" variant="outline" size="sm" onClick={() => onOpenChange(false)} disabled={saving}>
104 {t('common.cancel')}
105 </Button>
106 <Button type="button" size="sm" onClick={submit} disabled={saving || !name.trim()}>
107 {saving
108 ? t('common.saving')
109 : mode === 'edit'
110 ? t('templateDialog.update')
111 : t('common.save')}
112 </Button>
113 </DialogFooter>
114 </DialogContent>
115 </Dialog>
116 )
117 }
118
118 lines Plain Text