refactor: implement reusable Modal component

This commit is contained in:
ramvignesh-b
2026-04-28 22:52:06 +05:30
parent 8b28949d73
commit faee0b45d6
11 changed files with 316 additions and 323 deletions
+7 -14
View File
@@ -1,11 +1,12 @@
import { CampfireIcon, FlameIcon, XCircleIcon } from "@phosphor-icons/react";
import { CampfireIcon, FlameIcon } from "@phosphor-icons/react";
import { useEffect, useState } from "react";
import { Modal } from "../ui/Modal";
interface BurnModalProps {
burnLetter: () => void;
isBurning: boolean;
setShowBurnModal: (show: boolean) => void;
setRevealState: (state: "sealed" | "revealed" | "burning" | "burned") => void;
setRevealState: (state: "SEALED" | "REVEALED" | "BURNING" | "BURNED") => void;
}
export function BurnModal({
@@ -20,7 +21,7 @@ export function BurnModal({
useEffect(() => {
if (!burnClicked) return;
if (flameOn === 100) {
setRevealState("sealed");
setRevealState("SEALED");
burnLetter();
}
const interval = setInterval(() => {
@@ -33,23 +34,15 @@ export function BurnModal({
const burnStyle = flameOn < 30 ? "" : `contrast(${flameOn / 30})`;
return (
<div className="modal modal-open modal-middle bg-base-100/20 backdrop-blur-md">
<Modal isOpen={true} onClose={() => setShowBurnModal(false)}>
<div
className={`modal-box flex flex-col items-center gap-4 py-8 text-center transition-all duration-200 ease-in-out ${burnClicked ? "animate-[pulse_15s_linear_infinite]" : ""}`}
className={`flex flex-col items-center gap-4 text-center transition-all duration-200 ease-in-out ${burnClicked ? "animate-[pulse_15s_linear_infinite]" : ""}`}
style={
{
transform: `rotate(${rotate}deg)`,
} as React.CSSProperties
}
>
<button
type="button"
className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
onClick={() => setShowBurnModal(false)}
aria-label="Close"
>
<XCircleIcon size={18} weight="bold" />
</button>
<CampfireIcon
size={48}
weight="duotone"
@@ -101,6 +94,6 @@ export function BurnModal({
</button>
</div>
</div>
</div>
</Modal>
);
}
@@ -2,22 +2,22 @@ import { useNavigate } from "react-router-dom";
import { ROUTES } from "../../config/routes";
interface PostActionOverlayProps {
revealState: "sealed" | "revealed" | "burning" | "burned";
revealState: "SEALED" | "REVEALED" | "BURNING" | "BURNED";
}
export function PostActionOverlay({ revealState }: PostActionOverlayProps) {
const navigate = useNavigate();
return (
<div
className={`flex flex-col items-center justify-center min-h-screen bg-base-100 ${revealState === "burned" ? "opacity-100" : "opacity-0"} transition-all delay-300 duration-1000`}
className={`flex flex-col items-center justify-center min-h-screen bg-base-100 ${revealState === "BURNED" ? "opacity-100" : "opacity-0"} transition-all delay-1000 duration-1000`}
>
<h1
className={`text-6xl ${revealState === "burned" ? "opacity-100" : "opacity-0"} lg:text-9xl italic font-extralight text-base-content animate-[pulse_3s_ease-in-out_3]`}
className={`text-6xl ${revealState === "BURNED" ? "opacity-100" : "opacity-0"} lg:text-9xl italic font-extralight text-base-content animate-[pulse_3s_ease-in-out_3]`}
>
It is done
</h1>
<div
className={`text-xl ${revealState === "burned" ? "opacity-100" : "opacity-0"} lg:text-4xl text-center font-extralight text-base-content font-display mt-8 delay-3000 transition-all duration-2000 tracking-wide`}
className={`text-xl ${revealState === "BURNED" ? "opacity-100" : "opacity-0"} lg:text-4xl text-center font-extralight text-base-content font-display mt-8 delay-3000 transition-all duration-2000 tracking-wide`}
>
<p className="w-full">
May your <span className="italic text-primary">soul</span> find
+20 -21
View File
@@ -1,8 +1,6 @@
import {
EyeSlashIcon,
PaperPlaneTiltIcon,
XCircleIcon,
} from "@phosphor-icons/react";
import { EyeSlashIcon, PaperPlaneTiltIcon } from "@phosphor-icons/react";
import { Modal } from "../ui/Modal";
import Saajan from "../ui/Saajan";
interface ShareModalProps {
shareLink: string | null;
@@ -15,16 +13,8 @@ export function ShareModal({ shareLink, setShareLink }: ShareModalProps) {
await navigator.clipboard.writeText(shareLink);
};
return (
<div className="modal modal-open modal-middle bg-base-100/20 backdrop-blur-md z-100">
<div className="modal-box bg-base-100 border border-base-content/5 shadow-2xl relative">
<button
type="button"
className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
onClick={() => setShareLink(null)}
aria-label="Close"
>
<XCircleIcon size={18} weight="bold" />
</button>
<>
<Modal isOpen={!!shareLink} onClose={() => setShareLink(null)}>
<div className="flex flex-col items-center justify-center text-center gap-6 py-4">
<div className="space-y-2">
<PaperPlaneTiltIcon
@@ -34,14 +24,17 @@ export function ShareModal({ shareLink, setShareLink }: ShareModalProps) {
/>
<h3 className="font-serif text-3xl">Send this letter</h3>
<p className="text-base-content/80 text-sm font-sans mt-4">
You've carried these words long enough. Send your letter now, and
let the <span className="text-accent font-display">unsaid</span>{" "}
finally find its home.
You've carried these words long enough.
<br />
Send your letter now, and let the{" "}
<span className="text-accent font-display">unsaid</span> finally
find its home.
</p>
<div className="divider mx-auto" />
<blockquote className="text-sm info text-neutral-content/60 font-sans">
The recipient will have the same viewing experience like you do
now.
They'll receive it exactly as you're seeing it now.
<br />
Nothing more, nothing less.
</blockquote>
</div>
<div className="w-full flex items-center gap-2 bg-base-300 p-2 rounded-xl">
@@ -69,7 +62,13 @@ export function ShareModal({ shareLink, setShareLink }: ShareModalProps) {
</p>
</div>
</div>
</Modal>
<div className="absolute bottom-0 z-1000 font-sans w-full">
<Saajan
position="top"
message={`Someone once said,\n"To send a letter is a good way to go somewhere without moving anything but your heart."\nThey were not wrong.`}
/>
</div>
</div>
</>
);
}