JSFiddle - React, Tailwind, and code Playground

by dafastestfingers

HTML

<button>Create JSON</button>
<br/>
<ul class="root">
  <li class="toggle">--</li>
  <li><input type="text" placeholder="name"/></li>
  <li><input type="text" placeholder="description"/></li>
  <li class="children">
    <ul class="item">
      <li class="toggle">--</li>
      <li><input type="text" placeholder="title"/></li>
      <li><input type="text" placeholder="href"/></li>
      <li><input type="text" placeholder="image"/></li>
    </ul>
    <ul class="item">
      <li class="toggle">--</li>  
      <li><input type="text" placeholder="title"/></li>
      <li><input type="text" placeholder="href"/></li>
      <li><input type="text" placeholder="image"/></li>
      <li class="children">
        <ul class="item">
          <li class="toggle">--</li>
          <li><input type="text" placeholder="title"/></li>
          <li><input type="text" placeholder="href"/></li>
          <li><input type="text" placeholder="image"/></li>
        </ul>
      </li>
    </ul>
    <ul class="item">
      <li class="toggle">--</li>
      <li><input type="text" placeholder="title"/></li>
      <li><input type="text" placeholder="href"/></li>
      <li><input type="text" placeholder="image"/></li>
    </ul>
  </li>
</ul>
<textarea id="output"></textarea>

CSS

ul {
    list-style: none;
    margin: 2px;
    margin-left: 20px;
    padding: 0;
    position: relative;
}

li {
    display: table;
    padding: 1px;
}

.root > li:first-child + li {
    background: yellow;
    border: solid 1px black;
    border-bottom: none;
    margin-bottom: -3px;
}

.root li:first-child + li + li {
    background: yellow;
    border: solid 1px black;
    border-top: none;
}

.toggle {
    left: -20px;
    position: absolute;
}

.item li:first-child +li ,
.item li:first-child + li + li, 
.item li:first-child + li + li + li {
    background: yellow;
}

.item li:first-child + li {
    border: solid 1px black;
    border-bottom: none;
    margin-bottom: -3px;
}

.item li:first-child + li + li {
    border: solid 1px black;
    border-bottom: none;
    border-top: none;
    margin-bottom: -3px;
}

.item li:first-child + li + li + li {
    border: solid 1px black;
    border-top: none;
}

JavaScript

$('.toggle').click(function() {
    var $t = $(this);
    var $nxt = $t.next();
    var $siblings = $t.siblings().not($nxt);
    if ($t.text() === '+') {
        $t.text('--');
        $nxt.css('border-bottom', 'none');
        $siblings.show();
    } else {
        $t.text('+');
        $nxt.css('border-bottom', 'solid 1px black');
        $siblings.hide();
    }
});

$('button').click(function() {
    parseList($('.root')); 
})

function parseList(root) {
    var json = '';
    
    function parse(elm) {
        var arr = [];
        
        elm.children().not('.toggle').each(function(index) {
            var $t = $(this);
            var $c = $t.children();
            var key = $c.attr('placeholder');
            var val = $c.val();
            var str = '"' + key + '":"' + val + '"';
            if ($t.hasClass('children')) {
                arr[arr.length] = '"children": [' + parse($c) + ']}';
            } else {
                if (key === 'title') {
                    str = '{' + str;       
                } else if(key === 'image' && !$t.next().hasClass('children')) {
                    str = str + '}';
                }                    
                arr[arr.length] = str;
            }
        });
        return arr;
    }
    json = '{' + parse(root).join();
    $('#output').val(json);
    return json;
}