vitess.io/vitess@v0.16.2/web/vtadmin/src/components/Snackbar.tsx (about) 1 import React from 'react'; 2 import { Icon, Icons } from './Icon'; 3 import { Intent } from './intent'; 4 import { ToastContainer, toast, Slide, ToastOptions } from 'react-toastify'; 5 import 'react-toastify/dist/ReactToastify.css'; 6 7 interface SnackbarProps { 8 message: string; 9 icon?: Icons; 10 intent?: Intent; 11 closeToast?: () => void; 12 } 13 14 // Needed to choose lighter background color 15 const translateIntentColor = (intent: Intent) => { 16 switch (intent) { 17 case Intent.danger: 18 return 'red-50'; 19 case Intent.warning: 20 return 'yellow-50'; 21 case Intent.success: 22 return 'green-50'; 23 case Intent.none: 24 return 'gray-50'; 25 } 26 }; 27 28 const Snackbar: React.FC<SnackbarProps> = ({ closeToast, message, icon, intent = Intent.none, ...props }) => { 29 const intentColor = intent === Intent.none ? 'gray-900' : `${intent}`; 30 31 return ( 32 <div 33 className={`flex font-medium text-sm text-${intentColor} border border-${intentColor} items-center bg-gray-100 justify-between py-6 px-8 z-20 rounded-xl bg-${translateIntentColor( 34 intent 35 )}`} 36 > 37 <div className="flex items-center"> 38 {icon && ( 39 <div className="shrink-0"> 40 <Icon icon={icon} className={`shrink-0 mr-4 fill-current h-8 w-8 min-h-8 min-w-8`} /> 41 </div> 42 )} 43 <div className="grow-0 whitespace-normal">{message}</div> 44 </div> 45 <button onClick={closeToast}> 46 <Icon icon={Icons.delete} className="fill-current text-gray-900 h-6 w-6 ml-8" /> 47 </button> 48 </div> 49 ); 50 }; 51 52 interface SnackbarContextProps { 53 warn: (message: string) => void; 54 danger: (message: string) => void; 55 success: (message: string) => void; 56 info: (message: string) => void; 57 } 58 59 const defaultProps: SnackbarContextProps = { 60 warn: (message: string) => message, 61 danger: (message: string) => message, 62 success: (message: string) => message, 63 info: (message: string) => message, 64 }; 65 66 interface AddSnackbarParams { 67 message: string; 68 icon?: Icons; 69 intent?: Intent; 70 } 71 72 export const SnackbarContext = React.createContext<SnackbarContextProps>(defaultProps); 73 const addSnackbar = (props: AddSnackbarParams, options?: ToastOptions) => { 74 toast(({ closeToast }) => <Snackbar closeToast={closeToast} key={props.message} {...props} />, { 75 className: 'mb-2 rounded-2xl', 76 ...options, 77 }); 78 }; 79 80 export const warn = (message: string, options?: ToastOptions) => 81 addSnackbar({ message, intent: Intent.warning, icon: Icons.alertFail }, options); 82 export const danger = (message: string, options?: ToastOptions) => 83 addSnackbar({ message, intent: Intent.danger, icon: Icons.alertFail }, options); 84 export const success = (message: string, options?: ToastOptions) => 85 addSnackbar({ message, intent: Intent.success, icon: Icons.checkSuccess }, options); 86 export const info = (message: string, options?: ToastOptions) => 87 addSnackbar({ message, intent: Intent.none, icon: Icons.info }, options); 88 89 export const SnackbarContainer: React.FC = ({ children }) => { 90 return ( 91 <div className="fixed right-10 bottom-6" id="snackbar-container"> 92 <ToastContainer 93 toastClassName="mb-2" 94 autoClose={false} 95 position="bottom-right" 96 closeButton={false} 97 closeOnClick 98 hideProgressBar 99 pauseOnHover 100 transition={Slide} 101 /> 102 </div> 103 ); 104 }; 105 106 export default Snackbar;