converting Markdown files into a website

how do you make a website that isnt tedious with all those <a href> and img tags and classes and blah blah?

-me
Table of Contents

    Intro

    I like coding websites with HTML and CSS and sometimes JavaScript. I don’t really know much about ‘modern frameworks’ like React or Angular.. I don’t even really understand what these do to be honest 😓.

    I’d love to learn about databases and MongoDB one day (I really want to add a freeform comment section like the one at the bottom of each of Gijs Gieskes‘ pages). I’ve tried learning some static site generators like Jekyll, I’ve gone down a long rabbit hole trying almost every ‘Documentation’ static site generator on this awesome-static-generators page. and I’ve even used one called Docnado to create a site about an installation I made called Harmonic Content. I will say my new favorite for this kind of documentation is now Material for MKdocs. I’ve also gone through a long process with my friend Jack Thompson to getting this self hosted wordpress site up-n-running! I say all that to say that after all that… i still wasnt satisfied with how to make my sites.

    I wanted something easy that took the tedium out of making sites. I like getting into the nerdy parts and getting experimental, but sometimes I just want a quick and easy way to write some stuff, show some pics and make the site have the same style as the rest of the pages. I’ve also been getting into using Markdown files by using this note-taking software called Obsidian. Markdown is cool cause you have simple headings using the pound-sign (#) you can make links easy by just pushing cntl+K and adding the link, you can add pictures by dragging and dropping.. thats pretty much all I need for a quick documentation site. Heres a quick rundown of Markdown syntax. Its so easy! I want a way to take those markdown files and add all the html syntax and headers and titles and everything and pop out a legit html website. I tried markdown to html converters inside VSCode, but didnt like any of them and felt confused by the options.

    Markdown to HTML

    I decided to make my own way of doing this. I used Pandoc, a universal document converter command line tool. Pandoc can take all the syntax of markdown and convert it easy peasy to html. Try it here!

    Once you install it via the command line (I have a Windows computer but am using Git Bash, a bash emulator, for all of this), you can easily invoke it by a simple command like this:

    pandoc index.md -o index.html

    Two things to note: 1. first argument is the input file 2. you have to be in the folder with the index.md file for this to work.

    This will output a simple html file. BOOM~ step 1 complete.

    What if we want the html file to have a header? And some ~style~ ?

    you can add the -s option. That is ‘standalone’ This will use the default styling template, which for html5 is this. Thats fine and dandy! And a ‘deployable’ website. BUT! its not MY website! I need to customize this. Lets tack on some stuff to the html like headers, navbars, and endings.

    Header

    This is where the general write options come in handy. To add our our header we can use the “-h FILE” option (Include contents of FILE, verbatim, at the end of the header) This will automatically add the -s option, which means the default style template will be added. More on that in a sec. Boom. Grab the header from your site and make a new file for that sucker. Mine has my favicon, the css, links to fonts, the meta tags, etc… for my site it looks like this:

    /code

    <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
    <link rel="manifest" href="/favicon/site.webmanifest">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="/css/bootstrap.min.css" rel="stylesheet" />
    <link href="/about/css/custom.css" rel="stylesheet" />
    <link
        href="https://fonts.googleapis.com/css?family=Cormorant+Unicase|Faster+One|Monoton|Nova+Square|Press+Start+2P|Raleway+Dots&display=swap"
        rel="stylesheet">
    <title> title </title>

    save that as header.html!

    Navigation / beginning of <body>

    I like for my site to have some navigation at the top, so lets add that! In my hand coded site that nav stuff is at the very beginning of the <body> of the site. to add that we can use “-B FILE” (Include contents of FILE, verbatim, at the beginning of the document body (e.g. after the <body> tag in HTML)). Copy and paste yours from some working page on your site. Heres mine. This is a basic bootstrap navbar. I also have a background gradient “grad1” that i add. We will close that div next 🙂

    <div id="grad1">
        <nav class="navbar navbar-inverse navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="/">freakylamps dot com</a>
                </div>
                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="/about/">about</a></li>
                        <li class="dropdown">
                            <a href="/lamps/" class="dropdown-toggle" data-toggle="dropdown" role="button"
                                aria-haspopup="true" aria-expanded="false">freaky lamps
                            </a>
                            <!-- <ul class="dropdown-menu">
                            <li><a href="#">Design</a></li>
                            <li><a href="#">Development</a></li>
                            <li><a href="#">Consulting</a></li>
                          </ul>
                        -->
                        </li>
                        <li><a href="https://soundcloud.com/imperceivable-shifts">music</a></li>
                    </ul>
                </div>
            </div>
        </nav>

    save that as nav.html!

    Ending (pre </body>)

    OK wow we are cooking with a gas here. need an ending to close that grad1 div tag! Luckily there is the ‘-a FILE’ option. This includes contents of FILE, verbatim, at the end of the document body (before the </body> tag in HTML). Grab the very bottom of some working page. Mine looks like this. I have this script down there because that’s what I got working a while ago. I cant remember exactly why there are two scripts and why they must be at the bottom, but i have to have em for the hamburger menu to unfurl when you are on mobile ¯\_(ツ)_/¯. heres mine:

    </div>
    <!-- these two js are needed for the hamburger menu to unfurl -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>

    save that as ending.html!

    Default template editing

    Final thing, we need to edit the default html style. This is the default html5 style. Copy and paste that sucker into the folder with the 3 files from above. The only thing I did was remove the lines:

      <style>
        $styles.html()$
      </style>
      $for(css)$
      <link rel="stylesheet" href="$css$" />
      $endfor$

    so that it doesn’t add a bunch of inline CSS into your document. I like for all my CSS to be in the seperate CSS file.

    Heres what my default template looks like:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$" $if(dir)$ dir="$dir$" $endif$>
    
    <head>
        <meta charset="utf-8" />
        <meta name="generator" content="pandoc" />
        $for(author-meta)$
        <meta name="author" content="$author-meta$" />
        $endfor$
        $if(date-meta)$
        <meta name="dcterms.date" content="$date-meta$" />
        $endif$
        $if(keywords)$
        <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
        $endif$
        $if(description-meta)$
        <meta name="description" content="$description-meta$" />
        $endif$
        <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
        $for(header-includes)$
        $header-includes$
        $endfor$
        $if(math)$
        $math$
        $endif$
        <!--[if lt IE 9]>
        <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
      <![endif]-->
    </head>
    
    <body>
        $for(include-before)$
        $include-before$
        $endfor$
        $if(title)$
        <header id="title-block-header">
            <h1 class="title">$title$</h1>
            $if(subtitle)$
            <p class="subtitle">$subtitle$</p>
            $endif$
            $for(author)$
            <p class="author">$author$</p>
            $endfor$
            $if(date)$
            <p class="date">$date$</p>
            $endif$
            $if(abstract)$
            <div class="abstract">
                <div class="abstract-title">$abstract-title$</div>
                $abstract$
            </div>
            $endif$
        </header>
        $endif$
        $if(toc)$
        <nav id="$idprefix$TOC" role="doc-toc">
            $if(toc-title)$
            <h2 id="$idprefix$toc-title">$toc-title$</h2>
            $endif$
            $table-of-contents$
        </nav>
        $endif$
        $body$
        $for(include-after)$
        $include-after$
        $endfor$
    </body>
    
    </html>

    save that as default.html. we are done with our files we tack onto the html!

    The script!

    Something to remember… these files are all in some folder on your computer. Mine is called “prototypes” The pandoc command inputs and outputs a file. Chances are you want to use that command somewhere else besides just that one folder. you dont want to copy and paste all that into the new folder with you markdown either. So lets create a command that can grab those files globally no matter where the script is being run from.

    Ok now we have 4 files we want pandoc to use to create the html file. In the interest of time I will show you my entire bash script:

    #!/bin/bash
    echo welcome to the markdown to html converter
    markdown_file="$1"
    echo file is "$markdown_file"
    
    if [[ -z "$markdown_file" ]]; then
      printf "Usage: %s <markdown_file>\n" "$0"
      exit 1
    fi
    
    # output_dir="$(dirname "$markdown_file")"
    # output_file="$output_dir/${markdown_file%%.*}.html"
    output_file="${markdown_file%%.*}.html"
    
    pandoc "$markdown_file" -f markdown+hard_line_breaks \
     -t html5 -H "c:/Users/moogtron 4k/Desktop/freakylamps website/httpdocs/prototypes/header.html" \
     -B "c:/Users/moogtron 4k/Desktop/freakylamps website/httpdocs/prototypes/nav.html" \
     -A "c:/Users/moogtron 4k/Desktop/freakylamps website/httpdocs/prototypes/ending.html" \
     --template="c:/Users/moogtron 4k/Desktop/freakylamps website/httpdocs/prototypes/default.html" \
     -o "$output_file" --verbose --highlight-style=breezedark
    
    
    printf "markdown_file: %s\n" "$markdown_file"
    printf "output_file: %s\n" "$output_file"
    
    echo we did it capitan, we converted to html
    

    pandoc command

    first the pandoc command… the first argrument is the input file. “-f markdown+hard_line_breaks” is ‘from’ option. We are converting from Markdown and using the ‘hard line breaks’ option which just means whenever there is a new line in markdown, there will be a new line in html. “-t html5” is the “to” option. We are going to html5. Then the header, before, after, and template with the long global file path. “-o” is the output option and that is going to the predefied ‘output_file’ variable. I added the verbose wording option which just shows you more info in the command line. I also left in the syntax highlighting for code snippets option. I liked the breezedark styling the best. It doesnt do anything tho, cause that modifies the inline CSS that would compile with the default template. We are using that default CSS, rather using our own. I copied and pasted the code snippet CSS into my custom.css so that if I did any code snippets they would be highlighted nicely.

    Small note: the backslash (\) allows you to break up a long command into a multi-line command. The compiler will not do anything with that slash, just ignores it and starts reading the next line.

    shell script snippets

    some kind soul named ‘Beef Broccoli’ on discord helped me with the input and output file snippets on the script. Thank you Beef Broccoli! $1 is the variable that is the first argument. Renamed that markdown_file. that -z line is looking for an empty variable. If someone uses the script and doesnt have an argument, the script will exit and tell the person how to use the script. this line:

    output_file="${markdown_file%%.*}.html"

    makes it so our output html file is going to be the same place as our input file (very convenient!…)

    usage

    I want to run the script from the default shell folder. Script is in a different folder, the file you want to convert is in another different folder. You need to have full path names. With windows and the way my folders are, I have spaces… that means everything needs to have quotes around it.

    $ "c:\Users\moogtron 4k\Desktop\freakylamps website\httpdocs\prototypes\build-html.sh" "c:\Users\moogtron 4k\Desktop\freakylamps website\httpdocs\testing\index.md"

    That is it! It took me wayyyy to long to figure out how to do all this. I hope this could benefit someone somewhere so they dont have to figure out all of this too. I feel like documentation of command line tools and developer tools in general is way to high level and jargony so I hope this brought things down a little bit. Seems like a big barrier to entry kinda thing and I dont like that! Leave a comment if you read this!!!

    Shortcut to use!

    make this a ‘task’ you can run in VScode… go to you task.json file in you .vscode folder.

    add this

        {
          "label": "markdown into website script",
          "type": "shell",
          "command": "bash",
          "args": ["c:/Users/moogtron 4k/Desktop/freakylamps website/httpdocs/prototypes/build-html.sh" "${file}"]
      }

    Im doing quotes around the script path and the file path because they contain spaces.

    TO USE:

    get into you markdown file. then: cntl+shift+P -> RUN TASKS –> select “markdown into website script”

    Hints for writing markdown files for web conversion — Bootstrap enabled!

    ok so I realized after i wrote this that I wanted more flexibility. The images wouldnt be responsive, I couldnt really do separate columns, movies were scaled all weird, pdfs look like trash, everything is all jumbled in mobile version. There is a way out!

    First things first though:

    Markdown Header

    you need a header for your file. here is a template:

    ---
    title: Nissan Ragnar Interactive Gateways
    date: Summer 2021
    tages: electronics, physical computing, fabrication, lighting design
    lang: en-US
    ---

    The template will use the title as your page title (the thing that shows up at the top of your web browser) and also the title will appear as your title at the top of the page. pretty nifty!

    Getting Bootstrappy – classes

    bootstrap is all about rows and columns. check out the grid system

    We can actually add classes to our elements in markdown!

    all you need to do is 3 colons and then the class name. here is an example of me starting off my page with a double column situation:

    :::container
    :::row
    :::col-md-6
    #overview
    this is my overview
    
    :::
    :::col-md-6
    ![](assets/gate.jpg)
    
    :::
    :::

    You have to start the whole thing out with a container tag. Then a row, then the columns in that row. here i have col-md-6 which means a column that takes up 6 out of 12 spaces. so its half of the screen. one of them is a header, the other a photo.

    SOMETIMES you need to have a line break and a new line after text! I hit my head against the desk for like an hour trying to figure out why pandoc wasn’t adding a <p></p> tags to my text, and it was because there was no line break. This might have something to do with the ‘hard_line_break” option from before but I dont know!

    close the divs with ::: and bam you are done!

    Attributes on photos and movies

    You also need to tell the website to make your shiz responsive.

    luckily pandoc allows for attribute setting! you use curly braces — { }

    Typically in bootstrap I put a “img-responsive” tag on all my photos so they will scale for mobile.

    Also you can actually add inline HTML to the markdown too and that will pass right through pandoc. So here I have added figure captions for my responsive image.

    ![](photos/IMG_7592.jpg){.img-responsive}<figcaption align = "center">final install of system (rev 2)</figcaption>

    you can also set height and width directly if you want. this helps for vertical movies…

    ![](assets/gateDemo.mp4){height=600px}

    Markdown Template

    ---
    title: catchy title
    date: Summer 2021
    tags: electronics, physical computing, fabrication, lighting design
    lang: en-US
    ---
    :::container
    
    :::row
    
    :::col-md-12
    
    # overview
    
    this spans the whole length of screen (12 section)
    
    :::
    
    :::
    
    :::row
    
    :::col-md-4
    ## picture
    all these "col-md-4" span 1/3 of screen
    :::
    
    :::col-md-4
    ![](assets/gates_night.jpg){.img-responsive}<figcaption align = "center">all gates setup at the Crystal Mountain, WA race</figcaption>
    :::
    
    :::col-md-4
    ![](assets/gatesRagnar.jpg){.img-responsive}<figcaption align = "center">render of one of the gates</figcaption>
    :::
    
    :::
    
    :::row
    
    :::col-md-6
    # technical 
    this spans half of the page
    
    ## LED Channels
    
    ![](assets/lightChannel.jpg){.img-responsive}<figcaption align = "center">lighting channel</figcaption>
    :::
    
    :::col-md-6
    ![](assets/led%20channel%20wiring%20.jpg){.img-responsive}<figcaption align = "center">LED channel wiring diagram</figcaption>
    
    ![](assets/shop_aaronChannel.jpg){.img-responsive}<figcaption align = "center">Aaron displaying a finished channel!</figcaption>
    :::
    
    :::
    

    Leave a Comment