返回 oh-my-ppt
UpdateAvailableDialog.tsx
根目录 / src / renderer / src / components / UpdateAvailableDialog.tsx
1 import type { UpdateAvailablePayload } from '@shared/app-update.js'
2 import { Download, FileText } from 'lucide-react'
3 import { useT } from '../i18n'
4 import { Button } from './ui/Button'
5 import {
6 Dialog,
7 DialogContent,
8 DialogDescription,
9 DialogFooter,
10 DialogHeader,
11 DialogTitle
12 } from './ui/Dialog'
13
14 function openExternalUrl(url: string | undefined): void {
15 if (!url) return
16 window.open(url, '_blank', 'noopener,noreferrer')
17 }
18
19 interface UpdateAvailableDialogProps {
20 update: UpdateAvailablePayload | null
21 onClose: () => void
22 }
23
24 export function UpdateAvailableDialog({
25 update,
26 onClose
27 }: UpdateAvailableDialogProps): React.JSX.Element {
28 const t = useT()
29 const primaryDownloadUrl = update?.downloadUrl
30
31 return (
32 <Dialog open={Boolean(update)} onOpenChange={(open) => !open && onClose()}>
33 <DialogContent className="max-w-lg">
34 <DialogHeader>
35 <DialogTitle>{update ? t('app.updateAvailableTitle', { version: update.latestVersion }) : ''}</DialogTitle>
36 <DialogDescription>
37 {update
38 ? t('app.updateAvailableDialogDescription', { currentVersion: update.currentVersion })
39 : ''}
40 </DialogDescription>
41 </DialogHeader>
42
43 {update && (
44 <div className="flex flex-wrap gap-2 rounded-lg border border-[#d8cfbc]/80 bg-[#f7f0e2]/55 p-4">
45 <span className="inline-flex h-7 items-center gap-1.5 rounded-full border border-[#d8cfbc] bg-[#fffaf0] px-3 text-xs font-medium text-[#6f6658]">
46 <span>{t('app.currentVersion')}</span>
47 <span className="text-[#3e4a32]">{update.currentVersion}</span>
48 </span>
49 <span className="inline-flex h-7 items-center gap-1.5 rounded-full border border-[#6f8159]/25 bg-[#eaf2df] px-3 text-xs font-semibold text-[#3e4a32]">
50 <span>{t('app.latestVersion')}</span>
51 <span>{update.latestVersion}</span>
52 </span>
53 </div>
54 )}
55
56 <DialogFooter className="flex-col-reverse gap-2 sm:flex-row sm:justify-between">
57 <Button type="button" variant="ghost" size="sm" className="h-8 px-3 text-xs" onClick={onClose}>
58 {t('app.later')}
59 </Button>
60 <div className="flex flex-col gap-2 sm:flex-row">
61 {update?.changeLog && (
62 <Button
63 type="button"
64 variant="outline"
65 size="sm"
66 className="h-8 px-3 text-xs"
67 onClick={() => openExternalUrl(update.changeLog)}
68 >
69 <FileText className="mr-1.5 h-3.5 w-3.5" />
70 {t('app.changeLog')}
71 </Button>
72 )}
73 {primaryDownloadUrl && (
74 <Button
75 type="button"
76 size="sm"
77 className="h-8 px-3 text-xs"
78 onClick={() => openExternalUrl(primaryDownloadUrl)}
79 >
80 <Download className="mr-1.5 h-3.5 w-3.5" />
81 {t('app.downloadHome')}
82 </Button>
83 )}
84 </div>
85 </DialogFooter>
86 </DialogContent>
87 </Dialog>
88 )
89 }
90
90 lines Plain Text