๐Ÿšค ์„ฑ์žฅ์ผ์ง€ 7.0

์ฑ… ํ–‰๋ณตํ•œ ์ด๊ธฐ์ฃผ์˜์ž(์›จ์ธ ๋‹ค์ด์–ด)์˜ ๋‚ด์šฉ์— ์ž๊ทน๋ฐ›์•„ ์‹œ์ž‘ํ•˜๋Š” ์†Œ๋ฐ•ํ•œ ์„ฑ์žฅ๊ธฐ๋ก

์‚ด์•„์žˆ๋Š” ๊ฝƒ๊ณผ ์ฃฝ์€ ๊ฝƒ์€ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ณ„ํ•˜๋Š”๊ฐ€?
์„ฑ์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์‚ด์•„ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
์ƒ๋ช…์˜ ์œ ์ผํ•œ ์ฆ๊ฑฐ๋Š” ์„ฑ์žฅ์ด๋‹ค!

โš› (7.0)<์™„์ „ ๊ฐœํŽธ> ํŒŒ์ธ๋งŒ ํ•™์Šต๋ฒ•์„ ์•Œ๊ฒŒ ๋œ๋งŒํผ, ์„ฑ์žฅ์ผ์ง€๋Š” ์ •๋ง ๊ทธ ๋‚ ์˜ ํ‚ค์›Œ๋“œ ์ค‘์‹ฌ์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.

Toast ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ํ•˜๊ธฐ

์‚ด์ง ์• ๋งคํ•œ ๊ฐ์ด ์žˆ์ง€๋งŒ, tailwindcss๋ฅผ ์‚ฌ์šฉํ•ด์„œ Toast ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค. ์šฐ์„  ๋ธŒ๋ผ์šฐ์ € ํ•˜๋‹จ์—์„œ ์œ„๋กœ ํŠ€์–ด๋‚˜์˜ค๋Š” ํ† ์ŠคํŠธ์™€ ๊ทธ ๋ฐ˜๋Œ€๋กœ ์ด๋™ํ•˜๋Š” ํ† ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด tailwindcss config๋ฅผ ์„ค์ •ํ•˜์˜€๋‹ค.

import type { Config } from 'tailwindcss';

const config: Config = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    keyframes: {
      slideUpFadeOut: {
        '0%': { transform: 'translateY(0)', opacity: '100' },
        '90%': { transform: 'translateY(-90%)', opacity: '100' },
        '100%': { transform: 'translateY(-100%)', opacity: '0' },
      },
      slideDownFadeOut: {
        '0%': { transform: 'translateY(-100%)', opacity: '100' },
        '90%': { transform: 'translateY(-10%)', opacity: '100' },
        '100%': { transform: 'translateY(0)', opacity: '0' },
      },
    },
    animation: {
      slideUpFadeOut: 'slideUpFadeOut 1s ease-in-out forwards',
      slideDownFadeOut: 'slideDownFadeOut 1s ease-in-out forwards',
    },
  },
  plugins: [],
};

export default config;

์ด๋ ‡๊ฒŒ๋งŒ ํ•˜๋ฉด ์‚ฌ์‹ค ๊ฑฐ์˜ ๋์ด ๋‚ฌ๋‹ค. ์ด์ œ๋Š” ํ† ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค. ํ† ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

type Props = {
  children: React.ReactNode;
  direction: 'up' | 'down';
};

export default function Toast({ children, direction = 'up' }: Props) {
  if (direction === 'down') {
    return (
      <div className="fixed bottom-0 z-50 flex h-20 w-32 animate-slideDownFadeOut items-center justify-center rounded-lg bg-yellow">
        <span className="text-xl font-bold leading-xl text-black_100">{children}</span>
      </div>
    );
  }

  return (
    <div className="fixed bottom-0 z-50 flex h-20 w-32 animate-slideUpFadeOut items-center justify-center rounded-lg bg-blue">
      <span className="text-xl font-bold leading-xl text-white_100">{children}</span>
    </div>
  );
}

props๋กœ children๊ณผ direction์„ ๋ฐ›์•„์„œ ํ† ์ŠคํŠธ์˜ ๋‚ด์šฉ์€ children์œผ๋กœ ์ „๋‹ฌํ•˜๊ณ  ์œ„์—์„œ ๊ตฌํ˜„ํ–ˆ๋˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ค‘ ํ•˜๋‚˜๋ฅผ direction์— ๋”ฐ๋ผ์„œ ์ ์šฉํ•˜๋„๋ก ํ•˜์˜€๋‹ค. ์ด์ œ ํ† ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž.

export default function ToastMachine() {
  const [upToast, setUpToast] = useState(false);
  const [downToast, setDownToast] = useState(false);

  return (
    <>
      {upToast && <Toast direction="up">์Šคํฌ๋žฉ ์™„๋ฃŒ!</Toast>}
      {downToast && <Toast direction="down">์Šคํฌ๋žฉ ์ทจ์†Œ!</Toast>}
    </>
  );
}

์œ„์™€ ๊ฐ™์ด ๊ฐ๊ฐ์˜ ๋ฐฉํ–ฅ์— ๋งž๋Š” ์ƒํƒœ๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ด ๋•Œ, ๊ฐ ํ† ์ŠคํŠธ์˜ ์ƒํƒœ๋Š” ํŠน์ • ์ด๋ฒคํŠธ์— ๋”ฐ๋ผ์„œ ๋ณ€๊ฒฝ๋˜๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค. ex) ์–ด๋–ค ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, ํ† ์ŠคํŠธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” handler๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๋œ๋‹ค.

๐Ÿ“ ํšŒ๊ณ 

ํ›„์•„โ€ฆ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋Š” ๋™์•ˆ ์ฝ”๋“œ๋Š” ์—‰๋ง์ด์ง€๋งŒโ€ฆ ๊ทธ๋ž˜๋„ ์–ด์ง€์ €์ฐŒ ํ•„์ˆ˜ ๊ธฐ๋Šฅ๊ณผ ๋‚ด๊ฐ€ ์ข€๋” ์š•์‹ฌ ๋ƒˆ๋˜ ๋ถ€๋ถ„๋“ค๊นŒ์ง€ ๊ตฌํ˜„์„ ๋งˆ์น  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ƒ๊ฐ๋ณด๋‹ค ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„ ๋™์•ˆ ๋ฐ›๋Š” ์••๋ฐ•๊ฐ(?)์ด ์ž‘์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๋‹ค. ์ผ์ฃผ์ผ์„ ํœ˜๋ฆฌ๋ฆญ ๋ณด๋‚ธ๋งŒํผ ๋‹ค์‹œ ๊ณ„ํš๋ถ€ํ„ฐ ์žฌ์ •๋น„ํ•˜๊ณ  ๋‚ด์ผ๋ถ€ํ„ฐ ๋˜ ์—ด์‹ฌํžˆ ๋‹ฌ๋ ค๋ด์•ผ์ง€.

์ฐธ๊ณ