<div id="wrapper"></div>
<script src="https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js"></script>
* {
    box-sizing: border-box;
}

div, button, a {
    border-radius: 3px;
}

.same-color {
    background-color: var(--bg);
    color: white;
    text-decoration: none;
    transition: all calc(var(--trans-time) * 2);
}

.faded {
    background-color: white;
    color: var(--color);
    transition: all var(--trans-time);
}

body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    height: 100vh;
    margin: 0;
}

#wrapper {
    width: 35em;

    #quote-box {
        width: 100%;
        height: 100%;
        padding: 2em;

        background-color: white;

        display: flex;
        flex-direction: column;
        align-items: flex-end;
        justify-content: space-around;
    }
}

#text-container {
    align-self: center;
    font-family: 'Akshar', sans-serif;
    font-size: 2em;
}

#author-container {
    $margins: 1em;
    margin-top: $margins;
    margin-bottom: $margins;
    font-family: 'Open Sans', sans-serif;
    font-size: 1.2em;
}

.padded-button {
    padding: 0.5em;
    height: 100%;
    font-size: 1.2em;
}

#button-container {
    width: 100%;

    #tweet-quote {
        float: left;
    }

    #new-quote {
        float: right;
        font-family: 'Akshar', sans-serif;

        border: none;
    }
}
View Compiled
var body = document.body;
body.classList.add("same-color");

document.documentElement.style.setProperty("--trans-time", "0.5s");

class QuoteBox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            quote: "",
            author: "",
            tweetIntent: "https://twitter.com/intent/tweet"
        };

        this.handleNewQuote = this.handleNewQuote.bind(this);
    }

    handleNewQuote() {
        const this_func = this;
        const colorArray = ["#16A085", "#1974D2", "#27AE60", "#E74C3C", "#FFAA1D", "#FF007F"];
        let newColor = colorArray[Math.floor(Math.random() * colorArray.length)];

        document.documentElement.style.setProperty("--color", "white");
        document.documentElement.style.setProperty("--bg", newColor);

        async function getApi() {
            return fetch("https://api.quotable.io/random?tags=famous-quotes")
            .then(Response => Response.json())
            .then(data => ({
                quote: data.content,
                author: data.author,
                tweetIntent: `https://twitter.com/intent/tweet?text=${data.content}%0A-${data.author}`
            }));
        };

        async function updateQuote() {
            let responseData = await getApi();

            setTimeout(() => {
                this_func.setState(() => ({
                    quote: responseData.quote,
                    author: responseData.author,
                    tweetIntent: responseData.tweetIntent
                }));

                document.documentElement.style.setProperty("--color", newColor);
            }, 500);

        };

        updateQuote();
    }

    componentDidMount() {
        this.handleNewQuote();
    }

    render() {
        return (
            <div id="quote-box">
                <QuoteText quote={this.state.quote}/>
                <QuoteAuthor author={this.state.author}/>
                <ButtonContainer handleNewQuote={this.handleNewQuote} tweet={this.state.tweetIntent}/>
            </div>
        );
    }
};

class QuoteText extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div id="text-container">
                <span id="text" className="same-color faded">{this.props.quote}</span>
            </div>
        );
    }
};

class QuoteAuthor extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div id="author-container">
                <span id="author" className="same-color faded">{"-" + this.props.author}</span>
            </div>
        );
    }
};

class ButtonContainer extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div id="button-container">
                <a href={this.props.tweet} id="tweet-quote" className="same-color padded-button" target="_blank">
                    <i className="fa-brands fa-twitter"></i>
                </a>
                <button id="new-quote" className="same-color padded-button" onClick={this.props.handleNewQuote}>New Quote</button>
            </div>
        );
    }
};

// To render root element
const rootDiv = document.getElementById("wrapper")
const root = ReactDOM.createRoot(rootDiv);
document.body.onload = () => {
    root.render(<QuoteBox />);
};
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js