refactor: seperate motion variants

This commit is contained in:
MAZE 2023-10-18 13:07:56 +03:30
parent b849b3aecd
commit 7fce9e1dff
5 changed files with 75 additions and 11 deletions

View File

@ -16,6 +16,7 @@ import { AnimatePresence, motion } from 'framer-motion';
import { useSoundStore } from '@/store';
import { cn } from '@/helpers/styles';
import { fade, mix, slideX } from '@/lib/motion';
import styles from './unselect.module.css';
@ -47,14 +48,17 @@ export function UnselectButton() {
const hasHistory = useSoundStore(state => !!state.history);
const unselectAll = useSoundStore(state => state.unselectAll);
const variants = mix(fade(), slideX(20));
return (
<>
<AnimatePresence mode="popLayout">
{(!noSelected || hasHistory) && (
<motion.div
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
initial={{ opacity: 0, x: 20 }}
animate="show"
exit="hidden"
initial="hidden"
variants={variants}
>
<button
disabled={noSelected && !hasHistory}

View File

@ -1,6 +1,7 @@
import { motion } from 'framer-motion';
import { Sounds } from '@/components/sounds';
import { fade } from '@/lib/motion';
import styles from './category.module.css';
@ -24,12 +25,15 @@ export function Category({
sounds,
title,
}: CategoryProps) {
const variants = fade();
return (
<motion.div
animate={{ opacity: 1 }}
animate="show"
className={styles.category}
initial={{ opacity: 0 }}
initial="hidden"
layout="position"
variants={variants}
>
<div className={styles.iconContainer}>
<div className={styles.tail} />

View File

@ -3,6 +3,7 @@ import { AnimatePresence, motion } from 'framer-motion';
import { useFavoriteStore } from '@/store/favorite';
import { cn } from '@/helpers/styles';
import { fade } from '@/lib/motion';
import styles from './like.module.css';
@ -14,6 +15,8 @@ export function Like({ id }: LikeProps) {
const isFavorite = useFavoriteStore(state => state.favorites.includes(id));
const toggleFavorite = useFavoriteStore(state => state.toggleFavorite);
const variants = fade();
return (
<AnimatePresence initial={false} mode="wait">
<button
@ -25,10 +28,11 @@ export function Like({ id }: LikeProps) {
}}
>
<motion.span
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
initial={{ opacity: 0 }}
animate="show"
exit="hidden"
initial="hidden"
key={isFavorite ? `${id}-is-favorite` : `${id}-not-favorite`}
variants={variants}
>
{isFavorite ? <BiSolidHeart /> : <BiHeart />}
</motion.span>

View File

@ -4,6 +4,7 @@ import { AnimatePresence, motion } from 'framer-motion';
import { Sound } from '@/components/sound';
import { useLocalStorage } from '@/hooks/use-local-storage';
import { cn } from '@/helpers/styles';
import { fade, scale, mix } from '@/lib/motion';
import styles from './sounds.module.css';
@ -45,6 +46,8 @@ export function Sounds({ functional, id, sounds }: SoundsProps) {
}));
}, []);
const variants = mix(fade(), scale(0.85));
return (
<div>
<div className={styles.sounds}>
@ -68,11 +71,12 @@ export function Sounds({ functional, id, sounds }: SoundsProps) {
{sounds.length > 6 && (
<AnimatePresence initial={false} mode="wait">
<motion.button
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.85 }}
initial={{ opacity: 0, scale: 0.85 }}
animate="show"
exit="hidden"
initial="hidden"
key={showAll ? `${id}-show-less` : `${id}-show-more`}
transition={{ duration: 0.2 }}
variants={variants}
className={cn(
styles.button,
hasHiddenSelection && !showAll && styles.active,

48
src/lib/motion.ts Normal file
View File

@ -0,0 +1,48 @@
type Motion = {
hidden: {
[key: string]: number | string;
};
show: {
[key: string]: number | string;
};
};
export function fade(): Motion {
return {
hidden: { opacity: 0 },
show: { opacity: 1 },
};
}
export function scale(from = 0.85, to = 1): Motion {
return {
hidden: { scale: from },
show: { scale: to },
};
}
export function slideX(from = -10, to = 0): Motion {
return {
hidden: { x: from },
show: { x: to },
};
}
export function slideY(from = -10, to = 0): Motion {
return {
hidden: { Y: from },
show: { Y: to },
};
}
export function mix(...motions: Array<Motion>): Motion {
let hidden = {};
let show = {};
motions.forEach(motion => {
if (motion.hidden) hidden = { ...hidden, ...motion.hidden };
if (motion.show) show = { ...show, ...motion.show };
});
return { hidden, show };
}