how i made this site (from scratch)

New blog, new website, so here we go. I’ll start by describing how i built the website. From scratch. The site is built with zurb foundation , because i had read that it did everything that hugo could, but that final products were more lightweight and flexible. Plus i had no idea about it, and learning something new is always often sometimes worthwhile. I was also frustrated that standard hugo advice seemed to be, ‘’oh, just pick a template and off you go,’’ yet there is surprisingly little advice on how to modify any given template, let alone how to start from scratch. It turned out that foundation at least made starting from scratch fairly easy, and so this entry is about that process. Note that i consider myself a technically-oriented, back-end programmer more focussed on getting stuff in and processing it than on getting stuff out. So when i say ‘’starting from scratch,’’ i mean that most sincerely.

visual style

This is largely html-related ramblings, so if you’re interested in the code stuff, you might like to skip straight ahead to the next section. zurb provides a template (see here for details) which deposits a basic infrastructure on your local playground, along with the required foundation libraries. The basic system is fairly well documented , so there’s little point going into that here. The top of this site is a standard top bar , and most of the rest is built from standard callout containers or plain cells. This and all blog pages, for example, are full-width xy-grid containers with simple headers of

<div class="grid-x grid-padding-x">
    <div class="cell medium-12 large-12">

The entire site lives within the local src/ directory, with the remainder being stuff used by foundation to build the site. This src directory really is impressively lightweight.

The primary components of foundation are ‘’pages’’ and ‘’partials,’’ with the latter identical to most other systems for building websites. Crudely interpreted, ‘’pages’’ hold the actual content, while ‘’partials’’ define the styles, generally as html header and footer components inserted before and after the content of a page. foundation integrates directly with arbitrarily-structured yaml files, which made auto-generation of my main web page particularly easy. The files themselves live in the src/data directory, with the blog entries, for example, read straight from a src/data/blog.yaml file that looks like this:

-
    title: how i made this site
    description: < blah blah blah >
    created: 06 May 19
    modified: 06 May 19
    link: blog/blog001.html
- 
    title: C++ templates and Rcpp
    description: < blah blah blah >
    created: 07 May 19
    modified: 07 May 19
    link: blog/blog002.html

More on how that gets automatically generated below; for now, just pretend it’s a static file. This has two entries, each of which has a variety of components (such as title, description, and link). The ‘’blog’’ section on the main page is generated directly from these yaml meta-data, using the {{#each blog}} command to automatically loop over each of the above entries in the data/blog.yml file, using the same double-curly-bracket syntax from zurb’s panini to insert variables into the html code:

{{#each blog}}
    {{> blog_header}}
        <a href={{ link }}, style="color:#262626;">
            <div align="center">
                <h3>{{ title }}</h3>
            </div>
            <div align="center">
                <p>{{ description }}</p>
            </div>
        </a>
    {{> blog_footer}}
{{/each blog}}

The whole site is set up with a grid 12 squares across, so these are full-width containers with grid-padding-x, which by default reads values from the global /src/assets/scss/_settings.scss file. Yep, it’s an scss file, which is both great and … not so great. It means that almost all variables used to generate your site - this site - can be modified through directly modifying the values in src/assets/scss/_settings.scss. The not so great is that these are global variables which are translated during compilation into css variables which generally won’t share the same names. So if you want to change these values locally rather than globally, you can’t ‘just do it’, you are forced to revert to standard css (to define class structures) or html (to explicitly define elements). This blog page, for example, is defined by a simple entry in src/assets/scss/app.scss – the sole location needed to define all local classes - as:

.blogClass{
    margin-top: 0px;
    margin-left: 50px;
    margin-right: 50px;
}

The margin- elements are bog-standard css, and absent these custom definitions all inherit the global properties specified in src/assets/scss/_settings.scss (definining standard properties of foundation’s xy-grid):

$grid-margin-gutters: (
    small: 20px,
    medium: 30px
);
$grid-padding-gutters: $grid-margin-gutters;
$grid-container-padding: $grid-padding-gutters;

Examples of html modifications to the global default scss variables are the background colours for each component of the code and blog sections. Remember that everything on the main page is a ‘callout’, meaning that they all inherit the global variables defined in src/assets/scss/_settings.scss. I defined the global background as

$callout-backgroud: transparent;

so the background image would appear underneath everything by default. This required local changes to render the components semi-transparent white, which was achieved with a simple two-line src/partials/blog_header.html of:

<div class="large-4 medium-6 cell" style="background-color:#ffffffaa">

The code above with {{> blog_header }} simply inserts that header in its rightful place.

That is the very short version of how i got this site to look the way it does. It’s simple, but it was fairly easy, and most important to me was that i didn’t have to borrow somebody else’s arbitrary and way-more-difficult-to-modify-than-i-thought template for whatever other site/blog-generating system i may otherwise have chosen.

the content

The steps roughly described above yielded a static site largely as you see here. The only remaining step was automating the procedure of updating the site. Perhaps the easiest approach would be to do this manually, but as most of the content is contained within yaml files, this is a procedure ripe for automation. As the end product of most of my coding efforts is packaged in R-form, i opted to automate this procedure within R, although the same principles apply to any other language. What this section effectively describes is how easy foundation made the task of effectively recreating Yihui Xie ’s fabulous blogdown package. Subjective judgement here, but the blogdown package was first released to cran in August 2017, and a lot has changed in that short time. As often happens, the enormity of the task Yihui achieved with that package can now be recreated in foundation form much easier, and with much less code. In the case of this site, it effectively amounts to connecting some kind of blog_render() function to a simple update of a yaml text file, with a few more tricks for other included elements, notably graphics.

With the help of partials, the entire html formatting of a blog page is as simple as a header with these few lines:

{{> header}}
<div class="blogClass">
  <div class="grid-x grid-padding-x">
    <div class="cell medium-12 large-12">
      {{#markdown}}

and a footer simply closing each section with:

    {{/markdown}}
    </div>
  </div>
</div>

(plus just a couple of extra lines to add the navigation bar at the side – shown here in a navbar() function, if you’re interested). In between is ‘’standard’’ markdown (at least in a form I’ve yet to encounter any particular idosynracies with ..), which foundation interprets seamlessly. Converting an Rmarkdown (.Rmd) document to a blog entry is thus in essence as simple as rendering (via rmarkdown::render()) it to some kind of standard markdown, renaming that to .html, and inserting the 5 lines of header and four lines of footer shown above. The following function forms the basis of a blog_render() function:

blog_render <- function (fname) {
    rmarkdown::render(paste0 (fname, ".Rmd"), rmarkdown::md_document(variant='gfm'))
    file.rename (paste0 (fname, ".md"), paste0 (fname, ".html"))
    conn <- file (paste0 (fname, ".html"))
    md <- readLines (conn)

    header <- c (<... defined above ...>)
    footer <- c (<... defined above ...>)
    md <- c (header, md, footer)
    writeLines (md, conn)
    close (conn)
}

Simply calling blog_render ("this_page") will then render and transform this_page.Rmd into this_page.html formatted for this website. The full function used to generate these pages has a couple of other sub-functions, mostly to move images to locations accessible by foundation , and to replace a few character fields not otherwise interpretable in either standard html or foundation terms. Examples of the latter are the {{ breadcrumbs }} used by foundation’s panini interpreter, which are replaced by corresponding html encodings; or the Rmarkdown code chunk delimiter, ```{r}, from which the curly brackets must be removed to replace it with, ``` r.

images

While it is possible to specify an image directory in the yaml front-matter of an .Rmddocument, it was just as easy, and more explict, to add another function to my blog_render() function to move them to the appropriate place in the foundation directory, which is assets/img, and any arbitrary sub-directories thereof. The following lines achieve this

path <- file.path (paste0 (fname, "_files"), "figure-gfm")
flist <- list.files (path, full.names = TRUE)
newpath <- file.path ("..", "..", "assets", "img", fname)
if (!dir.exists (newpath))
    dir.create (newpath, recursive = TRUE)
file.rename (flist, file.path (newpath, list.files (path)))
unlink (paste0 (fname, "_files"), recursive = TRUE)

along with a simple replacement in the main file of the former with the latter path. A final parameter called center_images, when TRUE, inserts simple <center> and </center> lines before and after the standard markdown image insertion command (![](<path>/<to>/<image>)).

meta-data, yaml data, and the front page

The blog_render() function then worked, but I still needed to automatically update the front page to link directly to the latest entry. Another fairly straightforward yaml-processing task, this time stripping the yaml headers from all blog entries. This became the second, and only other, main function, update_main(). This function essentially just strips the yaml header data out of each .Rmd blog entry, and re-formats it slightly as the data/blog.yml file. This in turn relies on one main function, get_one_blog_dat() which, for example, converts the metadata for this entry of:

---
title: how i made this site
description: <blah blah blah>
date: 06/05/2019
link: blog/blog001.html
---

into the only slightly-modified version in data/blog.yml of

-
    title: how i made this site
    description: <blah blah blah>
    created: 06 May 19
    modified: 06 May 19
    link: blog/blog001.html

The “created” date is read from the original date field of the .Rmd metadata, while the “modified” date is the actual date of file modification. These two dates enable blog entries to be sorted by dates of either creation or modification with a simple binary parameter.

conclusion

That’s it. It took me a little while to construct this site, but most of the time was me learning how zurb foundation works. Most of the mechanics of site construction and updating are nevertheless done via the R code, which is really very short and efficient. If you’re interested, the two files that do the work are here, for rendering a blog entry and here, for updating the main page. The render_blog() function calls the main updating function anyway, so all I ever need to do is to call one simple function to render any new blog entry and update the website.

The site itself is housed on the master branch of mpadge.github.io, while the generating code behind the site is on the source branch. Deployment is controlled with a very simple bash script, called by a single makefile command, which builds the foundation site, copies everything across from the source to master branches, adds the changes to git, and creates a commit to update the site. That’s it.

Advantages of having done this my own way:

  • no borrowed templates!
  • no blogdown
  • full control over everything
    Originally posted: 06 May 19 Updated: 07 May 19

Copyright © 2019--22 mark padgham