Inspiration: @dzzgnr

Components

iphone-simulator.tsx

Key points

  • The reason that I used MotionConfig is because of sharing the same transition config for the whole app.
  • For that gradient effect, I used mask-image property.
    <motion.div
      ...
      className="... [mask-image:linear-gradient(to_bottom,transparent,black_20%)]"
    ></motion.div>

    If I used the div with linear-gradient background, the animation wouldn't work properly when changing theme.

  • Using these states are crucial for the animation to work.
    const [isOpen, setIsOpen] = useState(false);
    const [theme, setTheme] = useState<Theme>("light");
    const [toggleTheme, setToggleTheme] = useState<Theme>("light"); // For the toggle button
    const [isChangeTheme, setIsChangeTheme] = useState(false); // For scaling

Using spring transition makes it feel more natural but I was getting the following issue with theme component being flickering. So I decided to use cubic-bezier(0.85, 0, 0.15, 1) instead.