Canyi Chen's Homepage

Recent Posts List in Franklin.jl

On my main page, I have a ticker that lists my recent posts. This list is generated by a key feature of Franklin.jl, hfun[1]. In short, an hfun is a Julia function that is run at site-generation time and produces HTML to be plugged into the page. These functions are defined in the utils.jl file in your site repo and can be called by including {{ func }} in your markdown file (when the function is named hfun_func). For example, the following hfun will produce the italicized, reversed title of the page wherever {{ reverse_title }} is called, like so: .

function hfun_reverse_title()
  return "<i>" * reverse(locvar(:title)) * "</i>"
end

Rather than writing HTML directly, arbitrary markdown code can be converted to HTML via the fd2html function. Furthermore, a string vector can be passed as parameters, as in: {{ func param1 param2 param3 }}.

In the Franklin docs, the following hfun is provided as an example of listing all posts chronologically:

function hfun_recentblogposts()
    list = readdir("blog")
    filter!(f -> endswith(f, ".md"), list)
    dates = [stat(joinpath("blog", f)).mtime for f in list]
    perm = sortperm(dates, rev=true)
    idxs = perm[1:min(3, length(perm))]
    io = IOBuffer()
    write(io, "<ul>")
    for (k, i) in enumerate(idxs)
        fi = "/blog/" * splitext(list[i])[1] * "/"
        write(io, """<li><a href="$fi">Post $k</a></li>\n""")
    end
    write(io, "</ul>")
    return String(take!(io))
end

This function works quite well, except that it uses stats(file).mtime to extract the most recently modified time of the file which is then used for sorting. This does not accurately convey the posts' chronological order as one may write a post and fix a typo in it many years later causing the mtime to be much more recent than posts written after it. It also does not allow for limiting the number of posts that are given. In my utils.jl, I have a simple hfun that uses the posts' dates page variable[2] and accepts a parameter that limits the number of posts to output. It produces a list of the k most recent posts in reverse chronological order, which I include in my main page. The function requires that all posts are written as markdown files in the posts directory and that the dates are in mm/dd/yyyy format. When a negative number is passed in for k, all posts are listed, otherwise only k are given.

function hfun_recent_posts(m::Vector{String})
  @assert length(m) == 1 "only one argument allowed for recent posts (the number of recent posts to pull)"
  n = parse(Int64, m[1])
  list = readdir("posts")
  filter!(f -> endswith(f, ".md") && f != "index.md" , list)
  markdown = ""
  posts = []
  df = DateFormat("mm/dd/yyyy")
  for (k, post) in enumerate(list)
      fi = "posts/" * splitext(post)[1]
      title = pagevar(fi, :title)
      datestr = pagevar(fi, :date)
      date = Date(pagevar(fi, :date), df)
      push!(posts, (title=title, link=fi, date=date))
  end

  # pull all posts if n <= 0
  n = n >= 0 ? n : length(posts)+1

  for ele in sort(posts, by=x->x.date, rev=true)[1:min(length(posts), n)]
    markdown *= "* [($(ele.date)) $(ele.title)](../$(ele.link))\n"
  end

  return fd2html(markdown, internal=true)
end

In my main index.md file, this is called as {{ recent_posts 3 }} to produce the list. I hope this function comes in handy for others that are using Franklin to implement their websites.

[1] https://franklinjl.org/syntax/utils/#html_functions_hfun_
[2] https://franklinjl.org/syntax/page-variables/#basic_settings