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:

We'll structure the app using HTML. We'll style the app using CSS. We'll port the HTML to its equivalent in Elm. We'll refactor the Elm code. We'll make the "New quote" button work. 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

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> — <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>

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

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

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



<link rel= "stylesheet" href= "assets/styles.css" >

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 ; }

Style the background

<!-- Background --> <div class= "background" > <!-- Wraps the quotation box and attribution --> <div> <!-- ... --> </div> </div>

/* Background */ .background { height : 100vh ; display : flex ; align-items : center ; justify-content : center ; background-color : #333 ; }

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" > — <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>

/* 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 ; }

Style the attribution

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

/* Attribution */ .attribution { margin-top : 15px ; text-align : center ; font-size : 0.8rem ; color : #fff ; } .attribution__link { text-decoration : none ; font-weight : 500 ; color : #fff ; }

Here's how the app looks now:

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.