diff --git a/src/renderer/src/components/base/toast.tsx b/src/renderer/src/components/base/toast.tsx index f985bdb..cfcc85c 100644 --- a/src/renderer/src/components/base/toast.tsx +++ b/src/renderer/src/components/base/toast.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState, useCallback } from 'react' import { createPortal } from 'react-dom' -import { IoCheckmark, IoClose, IoAlertSharp, IoInformationSharp } from 'react-icons/io5' +import { IoCheckmark, IoClose, IoAlertSharp, IoInformationSharp, IoCopy } from 'react-icons/io5' type ToastType = 'success' | 'error' | 'warning' | 'info' @@ -11,6 +11,7 @@ interface ToastData { message: string duration?: number exiting?: boolean + detailed?: boolean } type ToastListener = (toasts: ToastData[]) => void @@ -38,11 +39,18 @@ const removeToast = (id: string): void => { notifyListeners() } +const addDetailedToast = (type: ToastType, message: string, title?: string): void => { + const id = `${Date.now()}-${Math.random().toString(36).slice(2)}` + toasts = [...toasts.slice(-4), { id, type, message, title, duration: 8000, detailed: true }] + notifyListeners() +} + export const toast = { success: (message: string, title?: string): void => addToast('success', message, title), error: (message: string, title?: string): void => addToast('error', message, title, 1800), warning: (message: string, title?: string): void => addToast('warning', message, title), - info: (message: string, title?: string): void => addToast('info', message, title) + info: (message: string, title?: string): void => addToast('info', message, title), + detailedError: (message: string, title?: string): void => addDetailedToast('error', message, title) } const ToastItem: React.FC<{ @@ -50,6 +58,7 @@ const ToastItem: React.FC<{ onRemove: (id: string) => void }> = ({ data, onRemove }) => { useEffect(() => { + if (data.detailed) return const duration = data.duration || 3500 const exitTimer = setTimeout(() => markExiting(data.id), duration - 200) const removeTimer = setTimeout(() => onRemove(data.id), duration) @@ -57,7 +66,7 @@ const ToastItem: React.FC<{ clearTimeout(exitTimer) clearTimeout(removeTimer) } - }, [data.id, data.duration, onRemove]) + }, [data.id, data.duration, data.detailed, onRemove]) const theme: Record = { success: { @@ -85,6 +94,66 @@ const ToastItem: React.FC<{ const { icon, iconBg } = theme[data.type] const duration = data.duration || 3500 + const handleClose = (): void => { + markExiting(data.id) + setTimeout(() => onRemove(data.id), 150) + } + + const [copied, setCopied] = useState(false) + const handleCopy = async (): Promise => { + await navigator.clipboard.writeText(data.message) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } + + if (data.detailed) { + return ( +
+
+
+
+ {icon} +
+

{data.title || '错误'}

+
+
+ +
+ 已复制 +
+
+
+
+
+            {data.message}
+          
+
+ +
+ ) + } + return (