challenges

AI Style Generator: Part 5

Workshops in this series

  1. OpenAI Node SDK
  2. Prompt engineering: color
  3. Apply color response
  4. Prompt engineering: quote cleanup and font
  5. Apply font response
  6. Quote entry (coming October 17, 2024)

Prerequisites

Workshop context

Before this workshop

  • In the last workshop, we updated the response from the api/get-quote-styles route to include description and font.

This workshop

  • In this workshop, we’ll add the description and font to the UI.

After this workshop

  • In the next (and final) workshop in this series, we’ll allow the user to enter their own quote, instead of using a random quote.

Workshop goal

By the end of this workshop you will have:

  1. The quote displayed in the selected Google font.
    • the quote should not display with the default font before displaying with the selected font.
    • the selected font should use the weight 400.
    • the card should display the selected font at these sizes:
      • 1.5rem until the screen size is 50rem or wider
      • 1.75rem until the screen is 68.75rem or wider
      • 2rem if the screen is 68.75rem or wider
    • you may find the use-googlefonts package useful.
  2. The description, background color and font displayed beneath the quote, like this:
    UI with a button to generate a random quote. A quote with yellow-orange background and black text is shown beneath the button. Beneath the quote is a table with keys 'description', 'color' and 'font'.

Hints

Hint 1 To keep QuoteContent from being bogged down in too many details, you may want to make a new QuoteDetails comopnent. For a more accurate name, you might rename QuoteContent to QuoteDisplay (since it’s sometimes displaying quote content, and sometimes displaying a loading spinner or error).

Then, the QuoteDisplay component can return QuoteDetails when quoteProperties is truthy (where it used to return a Card containing the quote). The QuoteDetails component can take quoteProperties as a prop.

Because QuoteDetails will never be called from any component other than QuoteDisplay, QuoteDetails.tsx and QuoteDetails.module.css should be placed directly in the QuoteDisplay folder, and not given their own folder. For more details, check out Josh W. Comeau’s post on Delightful File Structure .

Hint 2 Use the use-googlefonts package to make the google font available to the page. This package does not come with the project, so you will need to install it:

npm install @flyyer/use-googlefonts

Since the spec asked for a weight of 400, the call in QuoteDetails looks like this:

const font = useGoogleFonts([
  {
    family: fontName,
    styles: [400],
  },
]);

Hint 3 QuoteDetails should display a Card containing the quote, like QuoteDisplay used to. For the font, you can pass a style prop to Card, and – thanks to our work in this workshop – the styles will be merged with the Card styles.

Since our use-googlefonts code has made the font available to the page, all you need to do is specify the fontName as the fontFamily value for the style.

For example:

const fontStyle = {
  fontFamily: fontName,
};
 
<Card
  textColor={colors.text}
  backgroundColor={colors.background}
  style={fontStyle}
>
  {quote}
</Card>

Hint 4 To avoid FOUT (Flash of Unstyled Text) before the font is ready, conditionally define the text color for the card to be:

  • the background color while the font.status value is GoogleFontsStatus.LOADING (note, you can import GoogleFontsStatus from “@flyyer/use-googlefonts”). If the text color is the same as the background color, the result will look like a blank card.
  • the actual text color if font.status is anything other than GoogleFontsStatus.LOADING

Hint 5 For the table of properties under the quote, I created a section within QuoteDisplay that had an h2 (“Quote Properties”) and a div that used display: grid for the properties themselves.

I created a new component: QuoteStyleItem to re-use for every row. This component takes a name prop (for example “description”) and a value prop (for example, “optimistic, hopeful, inspiring”). The files for this new component went into the QuoteDisplay folder since the component is only going to be used within QuoteDisplay.

The name in QuoteStyleItem is bold and right-aligned.

Resources