mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-09 07:03:25 +00:00
feat: add some animation
This commit is contained in:
39
package-lock.json
generated
39
package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"@prisma/client": "^4.14.0",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"axios": "^1.4.0",
|
||||
"framer-motion": "^10.12.12",
|
||||
"next": "^13.4.2",
|
||||
"next-auth": "^4.22.1",
|
||||
"next-seo": "^6.0.0",
|
||||
@@ -1763,6 +1764,21 @@
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz",
|
||||
"integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ=="
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
|
||||
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "0.7.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid/node_modules/@emotion/memoize": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
|
||||
@@ -4280,6 +4296,29 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/framer-motion": {
|
||||
"version": "10.12.12",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.12.12.tgz",
|
||||
"integrity": "sha512-DDCqp60U6hR7aUrXj/BXc/t0Sd/U4ep6w/NZQkw898K+u7s+Vv/P8yxq4WTNA86kU9QCsqOgn1Qhz2DpYK0Oag==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@emotion/is-prop-valid": "^0.8.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"@prisma/client": "^4.14.0",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"axios": "^1.4.0",
|
||||
"framer-motion": "^10.12.12",
|
||||
"next": "^13.4.2",
|
||||
"next-auth": "^4.22.1",
|
||||
"next-seo": "^6.0.0",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { motion } from "framer-motion";
|
||||
import LinkTag from "next/link";
|
||||
import { AiFillStar } from "react-icons/ai";
|
||||
|
||||
@@ -14,9 +15,11 @@ import styles from "./links.module.scss";
|
||||
export default function LinkItem({
|
||||
link,
|
||||
toggleFavorite,
|
||||
index,
|
||||
}: {
|
||||
link: Link;
|
||||
toggleFavorite: (linkId: Link["id"]) => void;
|
||||
index: number;
|
||||
}) {
|
||||
const { id, name, url, favorite } = link;
|
||||
const onFavorite = () => {
|
||||
@@ -33,7 +36,18 @@ export default function LinkItem({
|
||||
};
|
||||
|
||||
return (
|
||||
<li className={styles["link"]} key={id}>
|
||||
<motion.li
|
||||
className={styles["link"]}
|
||||
key={id}
|
||||
initial={{ x: -30, opacity: 0 }}
|
||||
animate={{ x: 0, opacity: 1 }}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
delay: index * 0.05,
|
||||
}}
|
||||
>
|
||||
<LinkFavicon url={url} />
|
||||
<LinkTag href={url} target={"_blank"} rel={"noreferrer"}>
|
||||
<span className={styles["link-name"]}>
|
||||
@@ -46,7 +60,7 @@ export default function LinkItem({
|
||||
<EditItem type="link" id={id} />
|
||||
<RemoveItem type="link" id={id} />
|
||||
</div>
|
||||
</li>
|
||||
</motion.li>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import EditItem from "components/QuickActions/EditItem";
|
||||
import RemoveItem from "components/QuickActions/RemoveItem";
|
||||
import LinkItem from "./LinkItem";
|
||||
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import styles from "./links.module.scss";
|
||||
|
||||
export default function Links({
|
||||
@@ -40,16 +41,32 @@ export default function Links({
|
||||
</span>
|
||||
</h2>
|
||||
{links.length !== 0 ? (
|
||||
<ul className={styles["links"]} key={Math.random()}>
|
||||
{links.map((link, key) => (
|
||||
<LinkItem key={key} link={link} toggleFavorite={toggleFavorite} />
|
||||
<ul className={styles["links"]}>
|
||||
{links.map((link, index) => (
|
||||
<LinkItem
|
||||
link={link}
|
||||
toggleFavorite={toggleFavorite}
|
||||
index={index}
|
||||
key={link.id}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<div className={styles["no-link"]}>
|
||||
<p>
|
||||
<AnimatePresence>
|
||||
<motion.p
|
||||
key={Math.random()}
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
}}
|
||||
>
|
||||
Aucun lien pour <b>{name}</b>
|
||||
</p>
|
||||
</motion.p>
|
||||
</AnimatePresence>
|
||||
<LinkTag href={`/link/create?categoryId=${id}`}>
|
||||
Créer un lien
|
||||
</LinkTag>
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
gap: 0.5em;
|
||||
padding: 3px;
|
||||
flex-direction: column;
|
||||
animation: fadein 0.3s both; // bug on drag start
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
@@ -89,7 +88,6 @@
|
||||
outline: 3px solid transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: 0.15s;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid transparent;
|
||||
|
||||
@@ -22,12 +22,13 @@ export default function Categories({
|
||||
<div className={styles["categories"]}>
|
||||
<h4>Catégories • {linksCount}</h4>
|
||||
<ul className={styles["items"]}>
|
||||
{categories.map((category, key) => (
|
||||
{categories.map((category, index) => (
|
||||
<CategoryItem
|
||||
category={category}
|
||||
categoryActive={categoryActive}
|
||||
handleSelectCategory={handleSelectCategory}
|
||||
key={key}
|
||||
key={category.id}
|
||||
index={index}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -3,18 +3,21 @@ import { AiFillFolderOpen, AiOutlineFolder } from "react-icons/ai";
|
||||
|
||||
import { Category } from "types";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import styles from "./categories.module.scss";
|
||||
|
||||
interface CategoryItemProps {
|
||||
category: Category;
|
||||
categoryActive: Category;
|
||||
handleSelectCategory: (category: Category) => void;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export default function CategoryItem({
|
||||
category,
|
||||
categoryActive,
|
||||
handleSelectCategory,
|
||||
index,
|
||||
}: CategoryItemProps): JSX.Element {
|
||||
const ref = useRef<HTMLLIElement>();
|
||||
const className = `${styles["item"]} ${
|
||||
@@ -29,11 +32,25 @@ export default function CategoryItem({
|
||||
}, [category.id, categoryActive.id]);
|
||||
|
||||
return (
|
||||
<li
|
||||
<motion.li
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
delay: index * 0.025,
|
||||
duration: 200,
|
||||
}}
|
||||
className={className}
|
||||
ref={ref}
|
||||
onClick={onClick}
|
||||
style={{ display: "flex", alignItems: "center", gap: ".25em" }}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: ".25em",
|
||||
transition: "none",
|
||||
}}
|
||||
>
|
||||
{category.id === categoryActive.id ? (
|
||||
<AiFillFolderOpen size={24} />
|
||||
@@ -45,6 +62,6 @@ export default function CategoryItem({
|
||||
<span className={styles["name"]}>{category.name}</span>
|
||||
<span className={styles["links-count"]}>— {category.links.length}</span>
|
||||
</div>
|
||||
</li>
|
||||
</motion.li>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,6 +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 { Category, Link, SearchItem } from "types";
|
||||
import { prisma } from "utils/back";
|
||||
import { BuildCategory } from "utils/front";
|
||||
@@ -155,7 +156,16 @@ function Home(props: HomeProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<motion.div
|
||||
className="App"
|
||||
initial={{ opacity: 0, scale: 0.85 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
}}
|
||||
>
|
||||
<SideMenu
|
||||
categories={categories}
|
||||
favorites={favorites}
|
||||
@@ -173,7 +183,7 @@ function Home(props: HomeProps) {
|
||||
handleSelectCategory={handleSelectCategory}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ body {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
animation: fadein 250ms both;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
Reference in New Issue
Block a user