JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

<div id='tab-btns'>
    <div class='tab-btn selected-tab' data-tab='story'>Story</div>
    <div class='tab-btn' data-tab='acts'>Acts</div>
    <div class='tab-btn' data-tab='povs'>Povs</div>
    <div class='tab-btn' data-tab='points'>Points</div>
    <div class='tab-btn' data-tab='about'>About</div>
</div>

<div id='tab-story' class='tab-content'>
    <!-- JS renders acts, povs and points in here. -->
    <div id='story-container'></div>
    
    <!-- Details about selected point. -->
    <div id='point-info'>
        <div id='dir-arrows'>
            <div class='dir-arrow' data-dir='l'> < </div>
            <div class='dir-arrow' data-dir='u'> ^ </div>
            <div class='dir-arrow' data-dir='d'> v </div>
            <div class='dir-arrow' data-dir='r'> > </div>
        </div>
        
        Act: <select id='select-act'></select><br>
        Pov: <select id='select-pov'></select><br>
        
        Name: <input type='text' id='select-name'><br>
        Desc:  <input type='text' id='select-desc'><br>
        Details: <textarea id='select-details'></textarea>
        
    </div>
</div>

<!-- Managing acts. Separate tab. -->
<div id='tab-acts' class='tab-content' style='display:none;'>
    <div id='act-list'></div>
    <div id='act-editor'></div>
</div>

<!-- Managing povs. Separate tab. -->
<div id='tab-povs' class='tab-content' style='display:none;'>
    <div id='pov-list'></div>
    <div id='pov-editor'></div>
</div>

<!-- Managing points. Separate tab. -->
<div id='tab-points' class='tab-content' style='display:none;'>
    <div id='point-list'></div>
    <div id='point-editor'></div>
</div>

<!-- How-to guide, import/export. -->
<div id='tab-about' class='tab-content' style='display:none;'>
    
    <p><b>JSON Import</b> - copy and paste JSON in here, then click button. Data will be parsed and loaded into tool.</p>
    
    <p><b>JSON Export</b> - click button, JSON will appear here. Copy and paste the datta into a text file or something, and save it on...

CSS

div, button, img, input, select, textarea, ul, li, p {
    box-sizing: border-box;
}


#tab-btns {
    display: flex;
    justify-content: center;
    background-image: linear-gradient(to bottom, #fff, silver);
    border-bottom: 1px solid grey;
    margin: 20px 0;
}
#tab-btns .tab-btn {
    position: relative;
    top: 1px;
    padding: 5px 15px;
    border: 1px solid grey;
    border-radius: 5px 5px 0 0;
    margin: 0 8px;
    background-color: #eee;
    transition: 0.2s;
}
#tab-btns .tab-btn:hover {
    cursor: pointer;
    background-color: #fff;
    transition: 0.2s;
}
#tab-btns .selected-tab {
    border-bottom: 1px solid #fff;
    background-color: #fff !important;
}


/* STORY */

table {
    width: 100%;
    border-collapse: collapse;
    margin: 20px 0;
    border: 1px solid grey;
}
table th {
    padding: 5px 10px;
    border: 1px solid grey;
    background-color: silver;
}
table td {
    padding: 5px 10px;
    /*border-left: 1px solid silver;
    border-right: 1px solid silver;*/
}

table .point-thumb {
    max-width: 400px;
    background-color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.3);
    border-radius: 10px;
    padding: 5px;
    text-align: center;
}
table .point-thumb:hover {
    cursor: pointer;
}
table .point-desc {
    font-size: 12px;
    margin-top: 5px;
}
table .selected-point {
    border: 1px solid black;
}

JavaScript

const db = {

    acts: [
        {
            id: 1, name: "Prologue",
            start: "", finish: "Timeskip of 11 years"
        },{
            id: 2, name: "January",
            start: "Lots of introductions!", finish: ""
        },{
            id: 3, name: "February",
            start: "", finish: ""
        },{
            id: 4, name: "March",
            start: "", finish: ""
        },{
            id: 5, name: "April",
            start: "", finish: ""
        },{
            id: 6, name: "May",
            start: "", finish: ""
        },{
            id: 7, name: "June",
            start: "", finish: ""
        }
    ],
    
    povs: [
        {
            id: 1, name: "Temple",
            start: 2, end: 7, colour: "EEEEEE",
            desc: "Siblings growing up at Wind Temple. Home."
        },{
            id: 2, name: "Prince",
            start: 2, end: 7, colour: "FFCC33",
            desc: "War, battles, drama. Shows off politics, a break from slow Temple life."
        },{
            id: 3, name: "Misc",
            start: 1, end: 7, colour: "CCCCCC",
            desc: "Various minor/side characters, isolated chapters showing things happening elsewhere.",
        },{
            id: 4, name: "PAV",
            start: 7, end: 7, colour: "CC33FF",
            desc: "Branch away from Temple siblings.",
        }
    ],
    
    points: [
        {
            id: 1, name: "one",
            act: 1, pov: 3, order: 0,
            desc: "16 eggs gathered in an old temple",
            details: ""
        },{
            id: 2, name: "two",
            act: 1, pov: 3, order: 1,
            desc: "celebration in ostoa",
            details: ""
        },{
            id: 3, name: "three",
            act: 1, pov: 3, order: 2,
            desc: "a hunter stumbles on strange scene in forest.",
            details: ""
        },{
            id: 4, name: "temple",
            act: 2, pov: 1, order: 1,
            desc: "first chapter, new...