Simple shortcode for folder/document tree

I’m quite amazed that the first result Google gives for “markdown html folder tree” requires Node.js and npm, then the next uses d3.js The future of computer science seems to be bloatware at every level. How many kB do we need to place rectangles on a 2D screen in 2023 ? [/rant]

Anyway, I’m writing my fair share of software documentation and I believe in simple solutions to simple problems. Something we often do in software documentation is explaining how file structure should be ordered in a project. I found nothing clean and simple to do that, so I did it myself.

Prerequisites

You will need FontAwesome 5 (the following code can be adapted to FA 6 with little change, but since Mermaid.js still only support the v5 syntax, I didn’t bother).

How to use

Markdown sample:

{{< tree >}}
- home::folder
  - .config::folder
  - Documents::folder
    - index::file
    - resume.odt::file-word
  - Images::folder
    - pic1.jpg::file-image
    - pic2.jpg::file-image
  - Code::folder
    - home.php::file-code
{{</ tree >}}

Result:

The code

The shortcode tree.html

{{ $content := .Inner | markdownify }}
<div class="folder-tree">
{{ (replaceRE `<li>([^<>]+)::([^<> ]+)` "<li class='$2'><i class='fas fa-$2 fa-fw'></i><span class='$2'>$1</span>" $content) | safeHTML }}
</div>

Basically, the tree is a typical nested list. We let the Markdown parser do its thing, then we hack the HTML by extracting FILENAME::ICONNAME with regex in each <li> entry. ICONNAME can be any CSS class defined in FontAwesome as fa-ICONNAME, not limited to MIME/filesystem icons.

We embed the file/folder name into a <span> tag getting a class ICONNAME too. That can be used to set the font weight using .folder-tree li span.folder, for example.

The CSS

.folder-tree i {
  margin-right: 0.25em;
  font-size: 1em;
}

.folder-tree ul {
  border-left: 1px solid black;
  padding-left: 0;
  text-indent: 0;
  margin-left: calc(16px + 1.25em / 2 - 1px);
  list-style: none;
}

.folder-tree ul:first-child {
  margin-left: 0;
  border-left: 0;
}

.folder-tree li ul {
  margin-top: -0.30em;
}

.folder-tree li ul li:first-child {
  padding-top: 0.30em;
}

.folder-tree li:before {
  content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,1%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='1' d='m 0,8 16,0'/%3e%3c/svg%3e");
}

.folder-tree li.folder {
  margin-bottom: 4px;
}

.folder-tree li span.folder {
  font-weight: 600;
}

The npm package

Nope, just kidding. :slight_smile:


Hope that helps.

13 Likes

I’m wondering why the post has 12 likes but no reply yet.
This approach is simply brilliant and works like a charm.
Many thanks for sharing! :heart_decoration:

I want to share my adoptions:

  • monospace font
  • fa-regular (fas => far)

{{ $content := .Inner | markdownify }}
<div class="folder-tree">
{{ (replaceRE `<li>([^<>]+)::([^<> ]+)` "<li class='$2'><i class='far fa-$2 fa-fw'></i><span class='$2'>$1</span>" $content) | safeHTML }}
</div>
.folder-tree {
    font-family: 'Courier New', monospace;
}