My Fully-Animated Quote Machine

Hi Guys!
This is my random quote machine and my first ever app which I am very proud of. :sunglasses:
https://sahand-masoleh.github.io/project-quote-machine/
I had set a few goals for myself in addition to the project goals and it forced me to learn a ton over the past few days:

  1. I wanted to fully animate and randomize the background gradient, and since CSS does not do gradient transition, I had to learn about JavaScript animations and requestAnimationFrame.
  2. After I wrote the first version using React classes I learned about hooks and rewrote the whole thing using hooks.
  3. I wanted to host the app on github pages so I had to learn a bit of git.
  4. I wanted to animate the height change which is not animatable with CSS and this had me fiddle with life cycle events, useEffect and useRef for hours.
    So after a week of almost full-time trial and error, I got exactly what I wanted.
2 Likes

Hey, just wondering, is there a reason you are explicitly setting the height on the #text div each time you generate a new quote? If I increase the text size then the bottom of the quote disappears because the height is set with β€˜px’. Granted, after I change the text size, I can load a new quote and the height will be set properly again. But really, the page should be able to react gracefully to dynamic text size changes. This issue also applies for when I narrow the browser window.

Hi! I’m not (as far as I know! :laughing:), I was doing that as a workaround for a problem I was having in getting the div to shrink for a smaller quote. But I figured out what the problem was and deleted that.
May I ask which part of the code are you referring to?
This is the component now:


function Text(props) {
  const [fade, setFade] = useState(false);
  const [height, setHeight] = useState(null);
  const [scrollHeight, setScrollHeight] = useState(null);
  const textRef = useRef(null);
  useEffect(() => {
    fader();
    setScrollHeight(textRef.current.scrollHeight);
  }, [props.text]);
  useEffect(() => {
    if (height !== scrollHeight) {
      setHeight(scrollHeight);
    }
  }, [height, scrollHeight]);
  const fader = () => {
    setFade(!fade);
  };
  return (
    <div id="text" style={{ height: height }}>
      <p ref={textRef} className={fade ? "fade" : null} onAnimationEnd={fader}>
        {props.text}
      </p>
    </div>
  );
}

<div id="text" style={{ height: height }}>

This keeps the CSS height property in sync with the height state, which is tied to the scrollHeight using a useEffect.
Edit: I just realized I could just assign the scrollHeight to the CSS height property.

Another issue I just found is that if I make my browser shorter to cause a vertical scroll bar then the bottom of the page has a white background and I can’t scroll all the way up to the top of the page.

Yep, I should fix that. Thank you!