mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 22:53:25 +00:00
feat: modal enter & exit transitions
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { ReactNode } from "react";
|
||||
import { ReactNode, useId } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { GrClose } from "react-icons/gr";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import styles from "./modal.module.scss";
|
||||
|
||||
interface ModalProps {
|
||||
@@ -22,12 +23,25 @@ export default function Modal({
|
||||
noHeader = false,
|
||||
padding = "1em 1.5em",
|
||||
}: ModalProps) {
|
||||
const modalId = useId();
|
||||
const handleWrapperClick = (event) =>
|
||||
event.target.classList?.[0] === styles["modal-wrapper"] && close();
|
||||
|
||||
return createPortal(
|
||||
<div className={styles["modal-wrapper"]} onClick={handleWrapperClick}>
|
||||
<div className={styles["modal-container"]} style={{ padding }}>
|
||||
<motion.div
|
||||
className={styles["modal-wrapper"]}
|
||||
onClick={handleWrapperClick}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0, transition: { duration: 0.1 } }}
|
||||
>
|
||||
<motion.div
|
||||
className={styles["modal-container"]}
|
||||
style={{ padding }}
|
||||
initial={{ opacity: 0, y: -15 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -15, transition: { duration: 0.1 } }}
|
||||
>
|
||||
{!noHeader && (
|
||||
<div className={styles["modal-header"]}>
|
||||
<h3>{title}</h3>
|
||||
@@ -42,8 +56,8 @@ export default function Modal({
|
||||
</div>
|
||||
)}
|
||||
<div className={styles["modal-body"]}>{children}</div>
|
||||
</div>
|
||||
</div>,
|
||||
</motion.div>
|
||||
</motion.div>,
|
||||
document.body
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@import "styles/colors.scss";
|
||||
@import "styles/keyframes.scss";
|
||||
|
||||
.modal-wrapper {
|
||||
z-index: 9999;
|
||||
@@ -13,7 +12,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
animation: opacityin 0.3s both;
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
@@ -25,7 +23,6 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
animation: fadeintop 0.3s both;
|
||||
box-shadow: 0 0 1em 0px rgba($black, 0.25);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ export default function CategoryItem({
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
delay: index * 0.025,
|
||||
damping: 25,
|
||||
delay: index * 0.02,
|
||||
duration: 200,
|
||||
}}
|
||||
className={className}
|
||||
|
||||
@@ -9,7 +9,7 @@ import SearchModal from "components/SearchModal/SearchModal";
|
||||
import SideMenu from "components/SideMenu/SideMenu";
|
||||
|
||||
import * as Keys from "constants/keys";
|
||||
import { motion } from "framer-motion";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { Category, Link, SearchItem } from "types";
|
||||
import { prisma } from "utils/back";
|
||||
import { BuildCategory } from "utils/front";
|
||||
@@ -174,15 +174,17 @@ function Home(props: HomeProps) {
|
||||
openSearchModal={modal.open}
|
||||
/>
|
||||
<Links category={categoryActive} toggleFavorite={toggleFavorite} />
|
||||
{modal.isShowing && (
|
||||
<SearchModal
|
||||
close={modal.close}
|
||||
categories={categories}
|
||||
favorites={favorites}
|
||||
items={itemsSearch}
|
||||
handleSelectCategory={handleSelectCategory}
|
||||
/>
|
||||
)}
|
||||
<AnimatePresence>
|
||||
{modal.isShowing && (
|
||||
<SearchModal
|
||||
close={modal.close}
|
||||
categories={categories}
|
||||
favorites={favorites}
|
||||
items={itemsSearch}
|
||||
handleSelectCategory={handleSelectCategory}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user