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.
Hope that helps.