Revamping my website💻

Published: 2022-12-01

Background

Originally, this site was some free HTML/CSS template I found online and I put the few pages together editing the raw HTML alone. Worse yet, I wanted to share my work from some Jupyter Notebooks which I would export as HTML and just dump in the middle of the template -- which needless to say did not integrate well with the site and did not look good. It all sufficed for my original purpose of just hobbling something together but it was both a bit tedious and ugly.

And it sat that way for a few years until I

  1. Started getting a bit more interested in web development adjacent stuff and
  2. Decided it would be nice to scream my thoughts into the void write more. 📝

Really my only requirements were to be able to write Markdown posts and have Jupyter Notebooks (which can be converted to mostly Markdown) be able to be integrated nicely as well. I looked into some static site generators (even Frozen-Flask since I was doing a little bit of Flask at my last job) but everything felt like either overkill or was missing something. So I settled on the following, detailed in the next section.

Flow

  1. Start with a base template HTML file.
  2. Write Markdown files for posts - And Jupyter notebooks can be converted to Markdown!
  3. Run a Markdown to HTML script, looping over desired Markdown files.
  4. Plop the Markdown-converted HTML into the template HTML file and call it a day.

In case a single soul on the lonely internet ever wonders 🤔

On the off-chance it's ever helpful to someone else (or perhaps just for my own sake), I've compiled my notes a bit along the way and detailed it all below. You can also either skip to the TLDR section for a high level overview, or check out the repo directly.


Base HTML

Nothing too fancy is going on with the base HTML and you can skip me talking about it and view it directly here if you care to. I've only got two lines of classic HTML boilerplate up top:

<!DOCTYPE html>
<html lang="en">

And then some guts in my head and body tags that I'll get to in the following sections.

Bootstrap 👢

Bootstrap takes care of making everything look a bit nicer and giving me a nice Navigation Bar that scales down from desktop to mobile devices nicely. It makes up most of my boilerplate and there's probably some lighter weight solutions that would've sufficed but Bootstrap seems pretty popular which piqued my interest and if I ever am compelled to use more of its features it'll be easy to do so. That said, Bootstrap is very easy to set up -- in fact, you don't even have to download it! You can just link to it. Here's a (simplified) version of my head tag with the Bootstrap boilerplate:

<head>

    <!-- Required meta tags for Bootstrap -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link
        rel="stylesheet"
        href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
        integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
        crossorigin="anonymous"
    >

</head>

Now, inside the body tag, everything must additionally be in a container class div for Bootstrap to work properly. There's also a few JavaScript you must call for Bootstrap to work properly too. I've also got my Bootstrap Navigation Bar at the top of my body tag. So all the Bootstrap related elements in the body look like:

<body>

    <!-- Bootstrap needs to be in container to work properly -->
    <div class="container">

        <!-- Top Navigation Bar -->
        <nav class="navbar navbar-expand-md bg-dark navbar-dark">
            <!-- Brand -->
            <a class="navbar-brand" href="https://lukefeilberg.github.io">Luke Feilberg 🤠</a>
            <!-- Toggler/collapsibe Button -->
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
              <span class="navbar-toggler-icon"></span>
            </button>
            <!-- Navbar links -->
            <div class="collapse navbar-collapse" id="collapsibleNavbar">
              <ul class="navbar-nav">
                <li class="nav-item">
                  <a class="nav-link" href="https://lukefeilberg.github.io">Home</a>
                </li>
                <li class="nav-item">
                  <a class="nav-link" href="https://lukefeilberg.github.io/projects.html">Projects</a>
                </li>
                <li class="nav-item">
                  <a class="nav-link" href="https://lukefeilberg.github.io/blog.html">Blog</a>
                </li>
              </ul>
            </div>
          </nav>
          <!-- End Navigation Bar -->
          
    </div>

    <!-- Javascript libraries for Bootstrap -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

</body>

Pygments 🎨

I use Pygments for all my syntax highlighting. I like the Monokai theme so that's what I use. You can generate the CSS file (after downloading Pygments and adding it to your path) with a command like:

pygmentize -S monokai -f html -a .codehilite > monokai.css

Then you just need to reference this CSS stylesheet in the head tag (assuming you put the file in a css folder):

<!-- Pygment's code highlight -->
<link rel="stylesheet" type="text/css" href="css/monokai.css">

MathJax 🔢

In order to render LaTeX I use MathJax. This is super easy to plop right in with no downloads necessary! (Though I'm sure you could download and do it all yourself if you're inclined). In the head tag I simply have:

<!-- MathJax boilerplate -->
<script>
  MathJax = {
    tex: {
      inlineMath: [['$', '$'], ['\\(', '\\)']]
    },
    svg: {
      fontCache: 'global'
    }
  };
</script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async
        src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
</script>
<!-- End MathJax boilerplate -->

I like to use dollar signs for my inline math, hence that configuration above. I don't actually use the slash parentheses but haven't yet been compelled to take it out.

Other Custom CSS Rules 🖌

I have some miscellaneous rules defined in the (not so beautifully named) lukes_extra-dark.css. The only thing in there that might be of interest to others is my nice formatting of Pandas DataFrames. But I intend to cover that in more detail in a separate blog post -- keep an eye out!


convert.py

With the base HTML up and running, all I need is a little script to convert my Markdown files into HTML and plop the converted-HTML into the base template. I do this in my convert.py script, which I'll detail the guts of below.

Python-Markdown

The heavy lifter here is the Python-Markdown package. It's quite simple to use, with a little pip install markdown, you can simply pass your Markdown text to it and get back out your HTML. It also has many extensions you can optionally use. For example, I use Fenced Code Blocks because I personally strongly dislike the convention of using only indents to indicate code and greatly prefer the triple ticks! And I of course use CodeHilite which uses Pygment for syntax highlighting.

The relevant bit within convert.py is simply:

import markdown
from markdown.extensions.codehilite import CodeHiliteExtension

...

html_body = markdown.markdown(
    md_text, 
    extensions=['fenced_code', CodeHiliteExtension(pygments_style='monokai')],
    output_format='html5'
)

One thing to note that I perhaps didn't do super properly but haven't been compelled to perfect is use any of the MathJax Python Markdown extensions. I'm guessing these extensions solve some of the little pains I've faced, like Python Markdown interpreting two underscores on the same line as emphasis even if I'm inside a LaTeX block, but simply escaping one suffices -- and other little hiccups seem to always be solved with an extra escape character in the LaTeX.

Jinja

Jinja is a very powerful "template engine" for Python. You can do fancy stuff like for loops inside your HTML template to, say, loop over all blog posts and create a blog page without hardcoding every blog you've written.

Frankly though, I haven't yet used it for anything other than just plopping my HTML-converted Markdown into my base HTML page -- but it's nice to know I can beef up my blog and perhaps other pages in the future with some of Jinja's nice features.

Inside my base HTML body tag I have the following line:

<!-- Jinja fills in the body below -->
{{ html_body }}
<!-- End of Jinja filled in body -->

Then in my convert.py I have (simplified a bit):

from jinja2 import Environment, FileSystemLoader

# Setting up environment and base template
env = Environment(loader=FileSystemLoader('templates'))
template = env.get_template('base.html')

# Render HTML body into template (i.e. plop it in!)
full_html = template.render(html_body=html_body)

Other little things 🌼

I do a little bit of manual processing of the Markdown file myself, particularly I remove the indentation that Jupyter Notebooks add to the output of cells since Python Markdown interprets it as code (and instead I format this myself in my custom CSS file). I also add my own div class called "dataframe-dimensions" to the dimensions that are always output after DataFrames from Jupyter Notebooks, which I then, again, stylize in my custom CSS file so they look nicer. I currently just do this with regular expressions.

I also found it nice to use Python's webbrowser package in my script to (optionally) immediately open all the new files it generated. I also name the files differently if I'm testing new changes so that I can keep track of each version (I simply just append a datetime timestamp so files are ordered properly).

And that's pretty much it.


Was it worth it?

I'm much happier with the way my site looks now. It ended up taking more time than I anticipated to put it all together but it was quite fun getting a little bit exposed to all the tech out there in the web development type world.


Too Long; Didn't Read (TLDR)