Franklin.jl


Creation date: 2020-06-09

Tags: julia, blog

I was waiting for this moment for a long long time. If you aren't new to my blog you can see that the layout is completely different now.

Maybe just try it out a bit.

Yeah go I'll wait here ;)

What do you think about it? Hope you enjoy it as much as I do. In this post I want to roughly explain how it's done. Unfortunately my code is not open source for this blog at the moment as some of you, my patrons, pay such that they can see posts like this earlier. They also have experienced the new layout for quite a while now before I moved all posts and finalized the last things in the last couple of days.

Quick overview of Franklin.jl

As you might have seen in the title of this post: The new post is made using Franklin.jl a static site generator written in Julia by Thibaut Lienart.

Franklin.jl is a static site generator specifically for technical blogging but that's not the main selling point for me.

I wanted to:

The last point is probably the most relevant one and Franklin is the only package that offers it. That isn't a bad thing as it's really good and Thibaut responds fast when one has problems or feature suggestions. This does of course not mean that he implements all the features you want but guides you through it :)

What didn't change?

Ohm that is a good question :D Hopefully the content or I messed something up if so please comment.

What did change?

Where do I even begin?

One can easily navigate using the hamburger menu on the left. It includes:

I missed it so much to search my own posts. Well I can open my file explorer or my code editor but you have no other chance than to use a search engine and I can't allow that you leave my site just like that. For that I use Lunr.js which is integrated nicely into Franklin as well as quite extendible.

The frontend of the search looks like this on my side:

@def title = "Search ⋅ OpenSourc.ES"

Number of results found: ~~~<span id="resultCount"></span>~~~

~~~
<div id="searchResults"></div>
~~~

and I can change what is shown in the search results in _libs/lunr/lunrclient.js:

// Parse search results into HTML
function parseLunrResults(results) {
    var html = [];
    for (var i = 0; i < results.length; i++) {
        var id = results[i]["ref"];
        var item = PREVIEW_LOOKUP[id];
        var title = item["t"];
        var preview = item["p"];
        var desc = item["d"];
        var link = item["l"].replace("__site/", "");

        var result = ('<h3><u><a href="'+link+'">'+ title +'</a></u></h3>' + 
                     '<p class="post-list-desc">'+ desc +'</p>');            
        html.push(result);
    }
    if (html.length) {
        html = html.join("");
        return '<div>'+html+'</div>'
    }
    else {
        return "";
    }
}

In the old blog I would have needed to install some kind of plugin and check where I should change something and I had so many folders I always had no clue how to navigate internals of the blog.

Okay you might want to try out Franklin.jl yourself and try to read here how to get started but I think you should better do that at the official website.

In this post you will see some ways to customize your own blog with some features which you might easily see that they exist or are not yet documented on the main page. This is due to the fact that developers sometimes are so into coding that they don't have time to document it. As mentioned before the main developer is very responsive so whenever I asked him I found out by myself how to implement what I want.

These features will all be available in the docs later and maybe I can help to bring them there. Currently it's just easier to write an informal blog about them :D

Page variables

Let's have a look at the top of the markdown file I write my blog in:

@def title = "Franklin.jl"
@def date = Date(2020, 06, 09)
@def desc = "Using Franklin for the new blog layout. A static site generator written for Julians."
@def rss = "Using Franklin for the new blog layout. A static site generator written for Julians."
@def tags = ["julia", "blog"]
@def categories = ["blog"]
@def mintoclevel=2
@def maxtoclevel=3

Each post should have a title, date and some description.

I also use tags which is an undocumented feature and is still a bit work in progress but works good enough for me to use it ;)

For example you can see all posts which have the Julia tags.

One needs a to write a _layout/tag.html for that which includes something like:

{{ insert head.html }}
  <div class="{{div_content}} tagpage">
    {{taglist}}
  </div>
{{ insert foot.html }}

The {{}} either fill a variable, insert a html file or call a function. In this case taglist calls the function hfun_taglist which is defined in Franklin.jl.

If you want to change the output of the list you just change it to {{list_tags}} and implement your own hfun_list_tags function inside utils.jl.

i.e I actually have changed it:

function hfun_pages_with_tag()::String
    tag = locvar(:fd_tag)

    c = IOBuffer()
    write(c, "<ul>")

    rpaths = globvar("fd_tag_pages")[tag]
    sorter(p) = begin
        pvd = pagevar(p, "date")
        if isnothing(pvd)
            return Date(Dates.unix2datetime(stat(p * ".md").ctime))
        end
        return pvd
    end
    sort!(rpaths, by=sorter, rev=true)

    for rpath in rpaths
        !pagevar(rpath, "published") && continue
        title = pagevar(rpath, "title")
        if isnothing(title)
            title = "/$rpath/"
        end
        url = get_url(rpath)
        url = replace(url, r"blog/\d{4}-\d{2}-\d{2}-" => "blog/")
        write(c, "<li><a href=\"$url\">$title</a></li>")
    end
    write(c, "</ul>")

    return String(take!(c))
end

It's mostly copied from Franklin but I need the url = replace(url, r"blog/\d{4}-\d{2}-\d{2}-" => "blog/") as my internal structure is blog/2020-06-09-Franklin.jl but the output structure is just blog/Franklin.jl.

Categories

The next thing is the categories you can see in the menu.

If I write a series like the current constraint-solver series it is much either to navigate in a categories panel like that instead of scrolling through the main page as one had to do with my old "design". On my side this just looks like that in my _layout/head.html file:

{{navbar constraint-solver}}
{{navbar kaggle-santa}}
{{navbar blog}}
{{navbar simplex}}
{{navbar visualization}}
{{navbar neuro}}
{{navbar mnist}}
{{navbar machine-learning}}

where I still write which categories I want to display and in which order but you know it's clean. I just had to write a hfun_navbar which takes in a parameter this time and return the <li></li> or whatever I want.

LaTeX

Then there are the other kind of functions defined in config.md:

\newcommand{\R}{\mathbb R}
\newcommand{\scal}[1]{\langle #1 \rangle}
\newcommand{\note}[1]{@@note @@title ⚠ Note@@ @@content #1 @@ @@}
\newcommand{\sidebyside}[2]{@@sidebyside @@sidebyside-right #2 @@ @@sidebyside-left #1 @@ @@}

Such that $\R$ gives \(\mathbb R\) throughout my posts. Or I can write \note{This is a note}

⚠ Note
This is a note

where the html looks like this:

<div class="note">
    <div class="title">⚠ Note</div>
    <div class="content">This is a note</div>
</div>

For two arguments like in sidebyside:

\sidebyside{The explanation to `\sidebyside` can be here and the code on the side}
           {`\newcommand{\sidebyside}[2]{@@sidebyside @@sidebyside-right #2 @@ @@sidebyside-left #1 @@ @@}`}

creates:

\newcommand{\sidebyside}[2]{@@sidebyside @@sidebyside-right #2 @@ @@sidebyside-left #1 @@ @@}
The explanation to \sidebyside can be here and the code on the side.

If one wants to create longer latex functions which need some julia code one can define lx_FUNNAME like this:

function lx_showdiff(com, _)
    # keep this first line
    brace_content = Franklin.content(com.braces[1]) # input string
    before, after = strip.(split(brace_content, ','))
    GitDiff.show_diff(before, after)
end

where GitDiff is a module I wrote which is not open source as well :/

I just write:

\showdiff{https://github.com/Wikunia/ConstraintSolver.jl/blob/4598e63634efd6a92abf8efa30c117b74e722e49/src/types.jl#L26-L33, 
          https://github.com/Wikunia/ConstraintSolver.jl/blob/c4fda2c469aea1019a8db1ef91c68c56cc7b86c2/src/types.jl#L26-33

and get:

Before Now
        
 mutable struct NumberConstraintTypes
     equality::Int
     inequality::Int
     notequal::Int
     alldifferent::Int
     table::Int
-end



        
    
    
        
 mutable struct NumberConstraintTypes
     equality::Int
     inequality::Int
     notequal::Int
     alldifferent::Int
     table::Int

+    indicator::Int
+end

        
    
    

which might come in handy at a later time. I just wanted to test what's possible ;)

Currently the lx functions only support one argument such that I can't write \showdiff{url1}{url2} but you can't have everything :D

Speed

Hopefully the website is faster now as everything is just html/css/js and the "heavy" rendering is done once on my laptop.

Conclusion

I'm quite happy with the outcome and I love that I have full control now and can do whatever I want quite easily.

Thanks for reading and special thanks to my six patrons!

List of patrons paying more than 4$ per month:

Currently I get 19$ per Month using Patreon and PayPal.

For a donation of a single dollar per month you get early access to the posts. Try it out at the start of a month and if you don't enjoy it just cancel your subscription before pay day (end of month).

I'll keep you updated on Twitter OpenSourcES as well as my more personal one: Twitter Wikunia_de



Blog Comments powered by Disqus.
Subscribe to RSS