feat: Integrate Directus CMS, add i18n with next-intl, and configure project tooling with pnpm, husky, and commitlint.**
This commit is contained in:
104
components/StatusModal.tsx
Normal file
104
components/StatusModal.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { m, AnimatePresence, LazyMotion, domAnimation } from "framer-motion";
|
||||
import { CheckCircle, AlertCircle, X } from "lucide-react";
|
||||
import { Button } from "./Button";
|
||||
|
||||
interface StatusModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
type: "success" | "error";
|
||||
title: string;
|
||||
message: string;
|
||||
buttonText: string;
|
||||
}
|
||||
|
||||
export const StatusModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
type,
|
||||
title,
|
||||
message,
|
||||
buttonText,
|
||||
}: StatusModalProps) => {
|
||||
return (
|
||||
<LazyMotion features={domAnimation}>
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4 md:p-6">
|
||||
{/* Backdrop */}
|
||||
<m.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onClick={onClose}
|
||||
className="absolute inset-0 bg-slate-950/80 backdrop-blur-sm"
|
||||
/>
|
||||
|
||||
{/* Modal Content */}
|
||||
<m.div
|
||||
initial={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||
exit={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
transition={{ type: "spring", damping: 25, stiffness: 300 }}
|
||||
className="relative w-full max-w-lg bg-white rounded-[2.5rem] border border-slate-100 shadow-2xl overflow-hidden group"
|
||||
>
|
||||
{/* Tech Decoration */}
|
||||
<div className="absolute top-0 left-0 w-full h-2 bg-slate-100 overflow-hidden">
|
||||
<m.div
|
||||
initial={{ x: "-100%" }}
|
||||
animate={{ x: "100%" }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
|
||||
className={`absolute inset-0 w-1/2 ${type === "success" ? "bg-accent" : "bg-red-500"} opacity-30`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute top-6 right-6 p-2 text-slate-400 hover:text-primary transition-colors hover:bg-slate-50 rounded-xl"
|
||||
>
|
||||
<X size={20} />
|
||||
</button>
|
||||
|
||||
<div className="p-8 md:p-12 text-center">
|
||||
<div
|
||||
className={`w-20 h-20 rounded-full ${type === "success" ? "bg-accent/10 text-accent" : "bg-red-50 text-red-500"} flex items-center justify-center mx-auto mb-8 relative`}
|
||||
>
|
||||
<div
|
||||
className={`absolute inset-0 ${type === "success" ? "bg-accent/20" : "bg-red-500/20"} rounded-full animate-ping opacity-20`}
|
||||
/>
|
||||
{type === "success" ? (
|
||||
<CheckCircle size={40} />
|
||||
) : (
|
||||
<AlertCircle size={40} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h3 className="text-3xl font-extrabold text-primary mb-4 leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
<p className="text-slate-600 text-lg mb-10 leading-relaxed">
|
||||
{message}
|
||||
</p>
|
||||
|
||||
<Button
|
||||
onClick={onClose}
|
||||
variant={type === "success" ? "accent" : "primary"}
|
||||
className="w-full py-5 text-lg"
|
||||
showArrow
|
||||
>
|
||||
{buttonText}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Decorative Corners */}
|
||||
<div className="tech-corner top-4 left-4 border-t-2 border-l-2 opacity-20" />
|
||||
<div className="tech-corner bottom-4 right-4 border-b-2 border-r-2 opacity-20" />
|
||||
</m.div>
|
||||
</div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</LazyMotion>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user