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

View File

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

View File

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

View File

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