DEV Community

Cover image for Let's build a Random Quote Machine in Elm - Part 1
Dwayne Crooks
Dwayne Crooks

Posted on • Updated on

Let's build a Random Quote Machine in Elm - Part 1

In this series I will teach you how to build the Random Quote Machine web app in Elm.

View the demo to see what we're trying to achieve.

We'll start from scratch and in 3 short posts we'll cover all the steps needed to complete the app.

Here's what we'll do:

  1. We'll structure the app using HTML.
  2. We'll style the app using CSS.
  3. We'll port the HTML to its equivalent in Elm.
  4. We'll refactor the Elm code.
  5. We'll make the "New quote" button work.
  6. We'll fetch quotations from a remote source.

You'll gain experience working with randomness, JSON decoders, HTTP and flags.

Let's get started.

Structure the app using HTML

Create a new directory named random-quote-machine and in it create an
index.html file.

$ mkdir random-quote-machine
$ cd random-quote-machine
$ touch index.html
Enter fullscreen mode Exit fullscreen mode

Open index.html in your favourite editor and write the following:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Random Quote Machine</title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
  </head>
  <body>
    <!-- Background -->
    <div>
      <!-- Wraps the quotation box and attribution -->
      <div>
        <!-- Quotation box -->
        <div>
          <!-- Quote and author -->
          <blockquote>
            <!-- Quote -->
            <p>
              <span><i class="fa fa-quote-left"></i></span>I am not a product of my circumstances. I am a product of my decisions.
            </p>
            <!-- Author -->
            <footer>
              &mdash; <cite>Stephen Covey</cite>
            </footer>
          </blockquote>

          <!-- Actions -->
          <div>
            <!-- Tweet it -->
            <div>
              <a href="https://twitter.com/intent/tweet?hashtags=quotes&text=%22I%20am%20not%20a%20product%20of%20my%20circumstances.%20I%20am%20a%20product%20of%20my%20decisions.%22%20%E2%80%94%20Stephen%20Covey" target="_blank"><i class="fa fa-twitter"></i></a>
            </div>
            <!-- Post it to Tumblr -->
            <div>
              <a href="https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes&content=I%20am%20not%20a%20product%20of%20my%20circumstances.%20I%20am%20a%20product%20of%20my%20decisions.&caption=Stephen%20Covey&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fdocs%2Fen%2Fshare_button" target="_blank"><i class="fa fa-tumblr"></i></a>
            </div>
            <!-- Get a new random quote -->
            <div>
              <button type="button" autofocus>New quote</button>
            </div>
          </div>
        </div>

        <!-- Attribution -->
        <footer>
          by <a href="https://github.com/dwayne/" target="_blank">dwayne</a>
        </footer>
      </div>
    </div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

When you view the HTML in a browser you'll see the following:

A screenshot of the app after step 1 is completed.

For more details, go here.

Style the app using CSS

Create a new directory named assets and in it create a styles.css file.

$ mkdir assets
$ touch assets/styles.css
Enter fullscreen mode Exit fullscreen mode

Open index.html and add a link to the stylesheet just after the Font Awesome link.

<link rel="stylesheet" href="assets/styles.css">
Enter fullscreen mode Exit fullscreen mode

Style the body

@import url("https://fonts.googleapis.com/css?family=Raleway:400,500");

/* General */

body {
  margin: 0;
  height: 100vh;

  font-family: Raleway, sans-serif;
  font-weight: 400;
}
Enter fullscreen mode Exit fullscreen mode

Style the background

<!-- Background -->
<div class="background">
  <!-- Wraps the quotation box and attribution -->
  <div>
    <!-- ... -->
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
/* Background */

.background {
  height: 100vh;

  display: flex;
  align-items: center;
  justify-content: center;

  background-color: #333;
}
Enter fullscreen mode Exit fullscreen mode

Style the quotation box

<!-- Quotation box -->
<div class="quote-box">
  <!-- Quote and author -->
  <blockquote class="quote-box__blockquote">
    <!-- Quote -->
    <p class="quote-box__quote-wrapper">
      <span class="quote-left"><i class="fa fa-quote-left"></i></span>...
    </p>
    <!-- Author -->
    <footer class="quote-box__author-wrapper">
      &#8212; <cite class="author">...</cite>
    </footer>
  </blockquote>

  <!-- Actions -->
  <div class="quote-box__actions">
    <!-- Tweet it -->
    <div>
      <a href="..." target="_blank" class="icon-button"><i class="fa fa-twitter"></i></a>
    </div>
    <!-- Post to Tumblr -->
    <div>
      <a href="..." target="_blank" class="icon-button"><i class="fa fa-tumblr"></i></a>
    </div>
    <!-- Get a new quote -->
    <div>
      <button type="button" autofocus class="button">New quote</button>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
/* Quote box */

.quote-box {
  width: 450px;
  padding: 40px 50px;

  border-radius: 3px;

  color: #333;
  background-color: #fff;
}

.quote-box__blockquote {
  margin: 0 0 30px 0;
}

.quote-box__quote-wrapper {
  margin-top: 0;

  text-align: center;
  font-size: 1.8rem;
}

.quote-box__quote-wrapper .quote-left {
  margin-right: 12px;
}

.quote-box__author-wrapper {
  text-align: right;
}

.quote-box__author-wrapper .author {
  font-style: italic;
}

.quote-box__actions {
  display: flex;
}

.quote-box__actions .button {
  height: 30px;

  padding-left: 15px;
  padding-right: 15px;

  border: 0;
  border-radius: 3px;

  cursor: pointer;

  color: #fff;
  background-color: #333;
}

.quote-box__actions .icon-button {
  display: flex;
  align-items: center;
  justify-content: center;

  width: 40px;
  height: 30px;

  border-radius: 3px;

  text-decoration: none;

  color: #fff;
  background-color: #333;
}

.quote-box__actions .button:hover,
.quote-box__actions .icon-button:hover {
  opacity: 0.9;
}

.quote-box__actions > div:first-child {
  margin-right: 10px;
}

.quote-box__actions > div:last-child {
  margin-left: auto;
}
Enter fullscreen mode Exit fullscreen mode

Style the attribution

<!-- Attribution -->
<footer class="attribution">
  by <a href="https://github.com/dwayne/" target="_blank" class="attribution__link">dwayne</a>
</footer>
Enter fullscreen mode Exit fullscreen mode
/* Attribution */

.attribution {
  margin-top: 15px;

  text-align: center;
  font-size: 0.8rem;

  color: #fff;
}

.attribution__link {
  text-decoration: none;
  font-weight: 500;

  color: #fff;
}
Enter fullscreen mode Exit fullscreen mode

Here's how the app looks now:

A screenshot of the app after step 2 is completed.

Tip: I've found that the earlier I get the majority of the HTML and CSS stuff out the way the easier it is to figure out how to structure the Elm code and to layer on the features. This isn't Elm specific though. That's how I do it in React and that's how I did it in Angular.

For more details, go here.

Tomorrow we'll port the HTML to Elm and do a little refactoring to organize the code and make it easier to add features in the later steps.

Latest comments (0)