Spaces:
Running
Running
Download src/components/ConfirmModal.tsx from sitcod3/BRIDGE_Modul-S_prod: direct link, hf CLI and curl.
- Browser
- Download file 4.25 kB
-
https://huggingface.co/spaces/sitcod3/BRIDGE_Modul-S_prod/resolve/main/src/components/ConfirmModal.tsx
- Command line
-
hf download hf://spaces/sitcod3/BRIDGE_Modul-S_prod/src/components/ConfirmModal.tsx
-
curl -L -o ConfirmModal.tsx https://huggingface.co/spaces/sitcod3/BRIDGE_Modul-S_prod/resolve/main/src/components/ConfirmModal.tsx
4.25 kB
| import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from "@headlessui/react"; | |
| import { Fragment, ReactNode } from "react"; | |
| import { AlertTriangle, X } from "lucide-react"; | |
| interface ConfirmModalProps { | |
| isOpen: boolean; | |
| onClose: () => void; | |
| onConfirm: () => void; | |
| title: string; | |
| description: string | ReactNode; | |
| confirmText?: string; | |
| cancelText?: string; | |
| isDestructive?: boolean; | |
| isLoading?: boolean; | |
| } | |
| export default function ConfirmModal({ | |
| isOpen, | |
| onClose, | |
| onConfirm, | |
| title, | |
| description, | |
| confirmText = "Confirm", | |
| cancelText = "Cancel", | |
| isDestructive = true, | |
| isLoading = false, | |
| }: ConfirmModalProps) { | |
| return ( | |
| <Transition appear show={isOpen} as={Fragment}> | |
| <Dialog as="div" className="relative z-50" onClose={onClose}> | |
| <TransitionChild | |
| as={Fragment} | |
| enter="ease-out duration-200" | |
| enterFrom="opacity-0" | |
| enterTo="opacity-100" | |
| leave="ease-in duration-150" | |
| leaveFrom="opacity-100" | |
| leaveTo="opacity-0" | |
| > | |
| <div className="fixed inset-0 bg-black/70 backdrop-blur-xs" /> | |
| </TransitionChild> | |
| <div className="fixed inset-0 overflow-y-auto"> | |
| <div className="flex min-h-full items-center justify-center p-4 text-center"> | |
| <TransitionChild | |
| as={Fragment} | |
| enter="ease-out duration-200" | |
| enterFrom="opacity-0 scale-95" | |
| enterTo="opacity-100 scale-100" | |
| leave="ease-in duration-150" | |
| leaveFrom="opacity-100 scale-100" | |
| leaveTo="opacity-0 scale-95" | |
| > | |
| <DialogPanel className="w-full max-w-md transform overflow-hidden rounded-xl bg-zinc-900 border border-zinc-800 p-6 text-left align-middle shadow-2xl transition-all"> | |
| <div className="flex items-start gap-4"> | |
| <div | |
| className={`p-3 rounded-full shrink-0 ${ | |
| isDestructive ? "bg-rose-500/10 text-rose-400 border border-rose-500/20" : "bg-indigo-500/10 text-indigo-400 border border-indigo-500/20" | |
| }`} | |
| > | |
| <AlertTriangle className="w-6 h-6" /> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <DialogTitle as="h3" className="text-lg font-semibold text-zinc-100"> | |
| {title} | |
| </DialogTitle> | |
| <div className="mt-2 text-sm text-zinc-400"> | |
| {description} | |
| </div> | |
| </div> | |
| <button | |
| onClick={onClose} | |
| className="text-zinc-500 hover:text-zinc-300 transition-colors p-1 rounded-md" | |
| > | |
| <X className="w-5 h-5" /> | |
| </button> | |
| </div> | |
| <div className="mt-6 flex justify-end gap-3"> | |
| <button | |
| type="button" | |
| onClick={onClose} | |
| disabled={isLoading} | |
| className="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 text-sm font-medium rounded-lg transition-colors" | |
| > | |
| {cancelText} | |
| </button> | |
| <button | |
| type="button" | |
| onClick={() => { | |
| onConfirm(); | |
| }} | |
| disabled={isLoading} | |
| className={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors flex items-center gap-2 ${ | |
| isDestructive | |
| ? "bg-rose-600 hover:bg-rose-500" | |
| : "bg-indigo-600 hover:bg-indigo-500" | |
| } disabled:opacity-50`} | |
| > | |
| {isLoading && ( | |
| <div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" /> | |
| )} | |
| {confirmText} | |
| </button> | |
| </div> | |
| </DialogPanel> | |
| </TransitionChild> | |
| </div> | |
| </div> | |
| </Dialog> | |
| </Transition> | |
| ); | |
| } | |