JSFiddle - React, Tailwind, and code Playground

by brigand

HTML

<!DOCTYPE html>
<html lang="de">

  <head>
    <meta charset="UTF-8">
    <title>Fixxxx</title>
    <script type="text/javascript" src="main.js" defer></script>
    <link rel="stylesheet" href="normalize.css">
  </head>

  <body>
  </body>

</html>

CSS

@import url('https://fonts.googleapis.com/css?family=Josefin+Sans&display=swap');

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  list-style: none;
  text-decoration: none;
  font-family: 'Josefin Sans', sans-serif;
}

body {
  background-color: #f3f5f9;
}

.wrapper {
  display: flex;
  position: relative;
}

.wrapper .left {
  width: 200px;
  height: 100%;
  background: #4b4276;
  position: fixed;
}

.wrapper .left .title {
  color: #fff;
  text-transform: uppercase;
  text-align: center;
  margin: 30px 0 30px 0;
  font-size: 24px;
}

.wrapper .left a {
  color: #bdb8d7;
  padding: 15px 0 15px 15px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  outline: none;
  display: block;
}

.wrapper .left a:hover,
.wrapper .left a:active,
.wrapper .left a:focus {
  color: #fff;
  background: #594f8d;
}

.wrapper .right {
  width: 100%;
  margin-left: 200px;
}

.wrapper .right .title {
  padding: 20px;
  background: #fff;
  color: #717171;
  border-bottom: 1px solid #e0e4e8;
}

.wrapper .right .board {
  margin: 20px;
  color: #717171;
  line-height: 25px;
}

.wrapper .right .board div {
  margin-bottom: 20px;
}

JavaScript

class EventType {
  constructor() {
    this.listeners = new Set()
  }

  emit(data) {
    this.listeners.forEach(listener => {
      listener(data);
    });
  }

  on(handler) {
    const listener = data => handler(data);

    this.listeners.add(listener);

    return () => this.listeners.delete(listener);
  }
}

class node {
  constructor(_id) {
    this.id = _id
    this.events = {
      mount: new EventType(),
      click: new EventType(),
    };
  }

  description(_dc) {
    this.dc = _dc
    return this
  }

  children(..._ch) {
    this.ch = [..._ch]
    return this
  }

  element(_el) {
    this.el = _el
    return this
  }

}

const sketch = {
  entry: (node) => {
    let el = document.createElement("a")
    el.setAttribute("class", node.id)
    el.innerHTML = node.dc
    node.events.mount.emit({ el, node });
    return el
  },
  menu: (node) => {
    let el = document.createElement("div")
    el.setAttribute("class", node.id)
    node.ch.forEach(i => el.appendChild(i.el(i)))
    node.events.mount.emit({ el, node });
    return el
  },
  paragraph: (node) => {
    let el = document.createElement("div")
    el.setAttribute("class", node.id)
    el.innerHTML = node.dc
    node.events.mount.emit({ el, node });
    return el
  },
  hull: (node) => {
    return sketch.menu(node)
  }
}

let left_title = new node("title")
  .description("Fixxxxx")
  .element(sketch.paragraph)
let left_menu_admin = new node("entry")
  .description("Administration")
  .element(sketch.entry)
let left_menu_user = new node("entry")
  .description("Nutzer")
  .element(sketch.entry)
let left_menu_booking = new node("entry")
  .description("Buchen")
  .element(sketch.entry)
let left_menu_download = new node("entry")
  .description("Download")
  .element(sketch.entry)
let left_menu_upload = new node("entry")
  .description("Upload")
  .element(sketch.entry)
let left_menu_msg = new node("entry")
  .description("Nachrichten")
  .element(sketch.entry)
left_menu_msg.events.mount.on((el) =>...