# Tutorial 1: Getting Started This tutorial walks you through our first Pencil website. At the end of this tutorial, you'll understand some of the core Pencil concepts and have the beginnings of a website built out. You may find it useful to also have [Pencil's Haddock page](https://hackage.haskell.org/package/pencil/docs/Pencil.html) open as a reference. We'll be using [stack](http://haskellstack.org) in this tutorial, so make sure you have it installed. Let's create our project: ```sh stack new my-website simple --resolver=lts-13.21 cd my-website ``` Open `my-website.cabal` and look for the `executable my-website-exe` section. Add `pencil` into the `build-depends` section. It should look something like this: ``` executable my-website hs-source-dirs: src main-is: Main.hs default-language: Haskell2010 build-depends: base >= 4.7 && < 5 , pencil ``` We'll also need to add `pencil` as as an `extra-deps` in `stack.yml`, since `pencil` is not in Stackage yet: ```yaml extra-deps: - pencil-1.0.1 ``` Now we're going to add some source files. First, let's make a new directory called `site/`, that will contain all of our website's HTML, Markdown and CSS files. ``` mkdir site ``` Our `my-website` folder should have a directory structure that looks something like this: ``` my-website.cabal src/ Main.hs site/ ``` Create a new file, `site/layout.html`. This will be our website's main template. Copy-and-paste this into `layout.html`: ```html $${title}
$${body}
``` Notice that `layout.html` contains the strings `$${title}` and `$${body}`. These are variables, and they allow us to dynamically inject content into this shared layout. Let's also create a stylesheet. Create a new file in `site/` called `stylesheet.scss`, with this content: ``` $bgColor: #ffffff; body { background-color: $bgColor; font-family: sans-serif; font-size: 18px; } .structure { margin-left: auto; margin-right: auto; width: 600px; } ``` Notice that we're using the `.scss` extension, and we have that weird `$bgColor` thing. This is because we're using [Sass/Scss](http://sass-lang.com) for our styling. I like Scss because it's a super set of CSS, so you can write plain-old CSS but "add on" the Scss parts (like variables) when you need it. The final source file we'll add is `index.markdown`. This will contain our index page's content in Markdown. You'll see how easy it is convert Markdown to HTML, and inject it into our HTML-based layout. `index.markdown` contains: ``` # My Awesome Website Welcome to my *awesome* [website](http://example.com)! ``` ## Writing some Haskell OK, let's write some Haskell! Fill `src/Main.hs` with this: ```haskell {-# LANGUAGE OverloadedStrings #-} module Main where import Pencil website :: PencilApp () website = do index <- load "index.markdown" render index main :: IO () main = run website defaultConfig ``` Let's build our project and try it out. ``` stack build stack exec my-website ``` This should create an `out/` directory with an `index.html` file, which contains our Markdown content rendered as HTML. It's basic stuff, but we're getting somewhere. ## Rendering Pages Let's look at what's happening inside the `website` function: ```haskell website :: PencilApp () website = do index <- load "index.markdown" render index ``` The first thing you see is `index <- load "index.markdown"`. This is the primary way we load source files in Pencil. `load` will open the given file and convert it if necessary. It's smart enough to know, based off the file extension, *how* to convert the files. So Markdown becomes HTML, and SCSS becomes CSS. This is done under the `IO` monad because it's not a pure function (it's reading a file). This is why we save the result to `index` using `<-` inside a `do` block. `index` is a `Page`. A `Page` holds a page's content (e.g. HTML tags) and variables (e.g. `$${title}` and `$${body}` as seen in `layout.html`). It's an important data type in Pencil. And finally we _render_ the page into an actual HTML file by calling `render index`. Underneath the hood, `render` replaces variables in the HTML with their values. ## Structuring our Pages Of course most websites are too complex for a single Markdown file. We want templates and CSS styling. Change the `website` function to this: ```haskell website :: PencilApp () website = do layout <- load "layout.html" index <- load "index.markdown" render (layout <|| index) loadAndRender "stylesheet.scss" ``` The call to `loadAndRender` loads and compiles our Scss file into `stylesheet.css` in our output directory. Look at the source code of [`loadAndRender`](https://hackage.haskell.org/package/pencil/docs/Pencil.html#v:loadAndRender). It's just a call to `load` with a `render` at the end. `layout <- load "layout.html"` is familiar—we load a layout file into a `Page`. But is `(layout <|| index)` about? It's common to share some common template across many pages. Specifically, we want the contents of a page to be injected into another page. In this case, we want the contents of `index.markdown` inside the `$${body}` position of `layout.html`. To do this, Pencil provides the concept of a `Structure`. A `Structure` is a list of `Page`s, defining a nesting order. Think [Russian nesting dolls](https://en.wikipedia.org/wiki/Matryoshka_doll). The first element defines the outer-most container, and subsequent elements are _inside_ the previous element.
Underneath the hood, a `Structure` is a `NonEmpty Page`, which is a list that cannot be empty. You can read more about `Structure`s [here](https://hackage.haskell.org/package/pencil/docs/Pencil.html#g:3).
When you have two Pages, you can combine them into a Structure using `(<||)` (pronounced "smash"). So `(layout <|| index)` tells Pencil to insert the contents of `index` into the `$${body}` variable of `layout`. There is also another method, `(<|)` (pronounced "push") that pushes a `Page` into an exiting `Structure`. For example, if we had a global layout and an _inner_ layout, we could do this: ```haskell layout <- load "layout.html" inner <- load "inner.html" index <- load "index.markdown" render (layout <|| inner <| index) ``` The `$${body}` variable in `inner.html` will be replaced with the contents of `index.markdown`. And that _combined_ content is what replaces the `$${body}` variable in `layout.html`. Back in our original example, we need to add the `title` variable into our `Config` for the layout's `$${title}` variable. So let's create our own called `config`, which is a modified version of `defaultConfig`: ```haskell config :: Config config = updateEnv (insertText "title" "My Awesome Website") defaultConfig main :: IO () main = run website config ``` Check out the [documentation](https://hackage.haskell.org/package/pencil/docs/Pencil.html) for more information on `updateEnv` and `insertText`.
`PencilApp` is Pencil's monad transformer. Don't worry if you aren't familiar with monad transformers. In simple terms, `PencilApp` is a function that takes a `Config` and does a bunch of stuff under the `IO` monad (e.g. reading source files, converting Markdown to HTML, and writing HTML files). This is why we have to "run" our `website` function inside `main`; we have to give the `PencilApp` function a `Config`. For now, we just pass in the default provided by Pencil, `defaultConfig`.
# Generating our website To generate and serve our website, run the following commands: ``` stack build stack exec my-website cd out && python -m SimpleHTTPServer 8000 ``` Go to [http://localhost:8000](http://localhost:8000). Note that we're using Python's HTTP server to serve our HTML files so that our relative URLs work correctly. And that's it! In this tutorial, you learned several important concepts: - `load` is the primary way we load source files into `Page`s. - A `Page` knows about our text content and template variables. - You can smash `Page`s together into a `Structure` using `(<||)`, and reference them using the `${body}` template variable. - You can set global variables in the `Config`. Next, we'll setup continuous integration with CircleCI and GitHub Pages for automatic deployments. Continue onward to [Tutorial 2: Deploying to GitHub Pages using Circle](/pencil/tutorials/02-deploying-to-github-pages-using-circle/)