JSFiddle - React, Tailwind, and code Playground
HTML
<div id="example"></div>
CSS
ul
{
display:inline-block; 0position: relative; float: left; clear: left;
margin:.25em;
padding:0;
background: pink;
}
ul:before
{
content:""; position: absolute; z-index: 1;
top:.25em; right:auto; bottom:0; left: 1.75em;
margin: auto;
border-right: dotted black .1em;
width: 0; height: auto;
0background: blue;
}
ul:after
{
content: "-"; position: absolute; z-index: 3;
top:0; left:-.5em;
margin:.65em; padding:0;
width:.8em; height: .8em;
text-align:center; line-height: .6em; font-size: 1em;
background: blue;
}
ul>li
{
display: block; position: relative; float: left; clear: both;
right:auto;
padding-left: 1em;
width:auto;
text-align: center; color:white;
background: gray;
}
ul>li>input
{
display:block; position: absolute; float: left; z-index: 4;
margin:0 0 0 -1em; padding:0;
width:1em; height: 2em;
font-size: 1em;
opacity: 0;
cursor: pointer;
}
ul>li>input:checked~ul:before
{
display: none;
}
ul>li>input:checked~ul:after
{
content: "+"
}
ul>li>input:checked~ul *
{
display: none;
}
ul>li>span
{
display: block; position: relative; float: left; z-index: 3;
margin:.25em; padding:.25em;
background: lightblue;
}
ul>li>span:after
{
content: ""; display: block; position: absolute;
left:-1em; top:0; bottom:0;
margin: auto .25em auto .25em;
border-top: dotted black .1em;
width: .75em; height: 0;
}
ul>li:last-child:before
{
content: ""; display: block; position: absolute; z-index: 2;
top:1em; left:0; bottom:-.25em;
width:.75em; height:auto;
background:lightblue;
}
#tree
{
position: relative; font-family: "Georgia";
}
#tree:before
{
left:.5em;
}
#tree:after
{
display: none;
}
/*decoration*/
ul,ul>li:last-child:before
{
background: white;
}
ul>li
{
background: transparent;
}
ul:after
{
background: white;
color: black;
border:solid gray 1px;
border-radius: .1em;
}
ul>li>span
{
border-radius: .25em;
color: black;
background: white;
}
ul>li>input~span:before
{
content:""; display: inline-block;
margin:...
JavaScript
const fileData = {
"files": ["index.html","panel.html"],
"directory1": {
"files": ["foo.html"],
"subdir1": {
"files": ["somefile.txt"]
},
"subdir2": {
"files": ["somefile.php","other.php"]
}
},
"directory2": {
"subdir1": {
"files": ["you_get_the_idea.txt"]
}
}
};
let html = '<ul id="tree">';
let iterations = 0;
const iterate = (fileData) => {
Object.keys(fileData).forEach(key => {
// It's a directory
if (typeof fileData[key] === 'object' && fileData[key] !== null && key != 'files') {
html += '<li><input type="checkbox"/><span>'+key+'</span><ul>';
iterations++;
iterate(fileData[key]);
last = false;
}
// It's a file
else
{
for(let i = 0; i < fileData[key].length; i++)
{
html += '<li><span>'+fileData[key][i]+'</span></li>';
}
for(let i = 0; i < iterations; i++)
{
html += '</ul></li>';
}
iterations--;
}
});
}
iterate(fileData);
html += '</ul>';
document.addEventListener("DOMContentLoaded", function(){
document.getElementById('example').innerHTML = html;
});