outputDir is a relative path from the site's directory.
copy is used to give aliases to pages. The scaffold specifies that /posts will also be available as the root level index page.
This aliasing is done as a postprocessing step, by copying files.
The object under the feed key specifies parameters for the RSS feed.
elm-package.json is a standard issue Elm file. If you need additional Elm packages in your code, add them here.
template.html is the HTML template used for every page:
It's an elm-css stylesheet. The generator looks specifically for the Styles.styles function.
It's needed to style Markdown (within nodes with the .markdown class) and any other external DOM nodes which you aren't able to style via Elm.
This stylesheet gets converted into /css/default.css which is linked in template.html.
The scaffold is set up with a couple of default tags which you can change as you see fit:
module Tags exposing (..)
import String exposing (toLower)
| UnknownTag -- This is required
fromString : String -> Tag
fromString s =
case toLower s of
Tags are applied to blog posts. Since tags are specified in Markdown files, there is no compile time enforcement. UnknownTag is there to catch any misspelled or nonexistent tags - and then you can go to the /tags/unknowntag page to check if there are any posts with invalid tags.
In retrospect, I'm not sure if I even need the union type - maybe just a list of valid tags would be sufficient.
For each tag that has posts, the generator creates a page with a list of the posts under /tags/.
Page.elm contains the bulk of the code which describes the layout and styling. It exports functions which are then used by specific pages. For example, this is the view function:
view : Header Variations m -> List (Element PageStyles Variations m) -> Html.Html m
view header contentElems =
viewport styleSheet <|
[ center, width (percent 100) ]
, column Main
[ width <| px 800, paddingTop 10, paddingBottom 50, spacingXY 0 10, alignLeft ]
And here is the view function from About.elm which uses functions from Page.elm:
You can write something about *yourself* here using `Markdown`.
view : a -> Html.Html msg
view _ =
[ Page.title "About the Author"
, Page.markdown pageContent
Each of the modules in the Pages directory gets converted into a corresponding HTML page by Elmstatic.
This is a plain page. You can add as many of them as you like. If you name the page file Index.elm, it will turn into an index page, both at the root level and at subsection level. For example, Pages/Index.elm becomes the page at /, in contrast to Pages/Projects.elm which becomes /projects. At subsection level, Pages/Elm/Index.elm becomes the page at /elm, while Pages/Elm/Projects.elm becomes /elm/projects.
Post.elm and Posts.elm
These functions provide templates for a single post and for a list of posts.
For example, the generator will take the Markdown from Posts/2018-01-01-using-elmstatic.md, pass it to the Pages.Post.view function and use its result to generate HTML.
Note that the Elm naming conventions for modules apply here, so each module name has to be prefixed with Pages, eg Pages.Post.
Everything in the Resources directory gets copied verbatim to the root level of the output directory. So, for example, Resources/img/logo.png becomes available as myblogdomain.com/img/logo.png on the published site. This is where you can add additional stylesheets, scripts and images.
Markdown files in the Posts directory
Posts are handled very similarly to Jekyll.
The post files have a particular naming scheme: YYYY-MM-DD-kebab-case-post-url-slug.md. Elmstatic extracts the date of the post and the URL for it from the file name.
Additionally, each post file starts with a preamble that looks like this:
title: "Introducing Elmstatic"
tags: software elm
The title has to be quoted. It appears both at the top of the post as well as on post list pages.
The post has to have one or more tags. For each tag which has associated posts, Elmstatic generates a post list page.
The body of the post is written in Markdown and appears after the preamble.
In addition to the root level pages like /contact and /about, this site has a couple of subsections: /postgres and /elm. These are defined via subdirectories of Pages, and Elmstatic handles them in a particular way.
The structure of Pages for this site looks like this:
Each subsection must have Post.elm and Posts.elm, everything else is optional. In my case, I set up different "About" pages at the root level and in each subsection (mainly because I wanted to have different headers in each subscection), so I have /about, /elm/about and /postgres/about.
Most of the special handling is to do with posts. /posts/elm only lists posts from the Posts/Elm directory, and /posts/postgres only lists posts from the Posts/Elm directory. However, /posts aggregates all of the posts into a single list, meaning it lists posts from the root level as well as posts from each subsection.
Further, /posts is generated using Pages/Posts.elm, and root level posts are generated using Pages/Post.elm. Each subsection has its own templates, so, for example, /posts/elm is generated using Pages/Elm/Posts.elm, and the posts under the Elm subsections are generated using Pages/Elm/Post.elm.
Each section is treated as an additional tag for posts in that section, so Elmstatic also generates /tags/elm and /tags/postgres pages.
Directory structure of the output
This structure is modelled on the output of Jekyll. For the scaffold described above, the output structure will look like this:
Looking for the nuts-and-bolts guide
to solving non-trivial, real problems
I'm writing "Practical Elm for a Busy Developer", a short book that skips the basics and gets right into explaining how to do practical stuff. Things like building out the UI, working with server APIs, parsing JSON, setting up a production build, structuring the application as it grows, and so on. You won't get lots of handholding but you will get plenty of examples and pointers for further research.
Pop in your email to get updates about the book.
You will also get notifications of new posts along with other mailing list only freebies.