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: lj.nilknarF ni tsiL stsoP tneceR.
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 |