JSFiddle - React, Tailwind, and code Playground
HTML
<div id="timesheet"></div>
CSS
.timesheet {
width: 720px;
height: 292px;
margin: 0 auto
}
.timesheet {
border-top: 1px solid rgba(250,250,250,0.5);
background-color: #333;
position: relative
}
.timesheet.color-scheme-default .bubble-default {
background-color: RGBA(252,70,74,1)
}
.timesheet.color-scheme-default .bubble-lorem {
background-color: RGBA(154,202,39,1)
}
.timesheet.color-scheme-default .bubble-ipsum {
background-color: RGBA(60,182,227,1)
}
.timesheet.color-scheme-default .bubble-dolor {
background-color: RGBA(244,207,48,1)
}
.timesheet.color-scheme-default .bubble-sit {
background-color: RGBA(169,105,202,1)
}
.timesheet.color-scheme-alternative .bubble-default {
background-color: #f3552e
}
.timesheet.color-scheme-alternative .bubble-lorem {
background-color: #88c33a
}
.timesheet.color-scheme-alternative .bubble-ipsum {
background-color: #436ae0
}
.timesheet.color-scheme-alternative .bubble-dolor {
background-color: #f4d234
}
.timesheet.color-scheme-alternative .bubble-sit {
background-color: #707d86
}
.timesheet .scale {
height: 100%;
position: absolute;
top: 0;
left: 0;
float: left
}
.timesheet .scale section {
float: left;
width: 59px;
text-align: center;
color: rgba(250,250,250,0.8);
font-family: "Signika Negative";
font-size: 13px;
line-height: 24px;
font-weight: lighter;
border-left: 1px dashed rgba(250,250,250,0.2);
height: 100%
}
.timesheet .data {
margin: 28px 0 0 0;
padding: 0;
text-align: left;
list-style-type: none;
color: rgba(250,250,250,0.8);
font-family: "Signika Negative";
font-size: 13px;
overflow: hidden
}
.timesheet .data li {
margin: 0 0 3px 0;
line-height: 22px;
height: 21px;
display: block;
clear: both;
position: relative;
white-space: nowrap
}
.timesheet .data li:hover .bubble {
opacity: 1
}
.timesheet .data li .date {
color: #b5b5b5;
font-size:...
JavaScript
! function() {
"use strict";
var Timesheet = function(container, min, max, data) {
this.data = [], this.year = {
min: min,
max: max
}, this.parse(data || []), "undefined" != typeof document && (this.container = "string" == typeof container ? document.querySelector("#" + container) : container, this.drawSections(), this.insertData())
};
Timesheet.prototype.insertData = function() {
for (var html = [], widthMonth = this.container.querySelector(".scale section").offsetWidth, n = 0, m = this.data.length; m > n; n++) {
var cur = this.data[n],
bubble = this.createBubble(widthMonth, this.year.min, cur.start, cur.end),
line = ['<span style="margin-left: ' + bubble.getStartOffset() + "px; width: " + bubble.getWidth() + 'px;" class="bubble bubble-' + (cur.type || "default") + '" data-duration="' + (cur.end ? Math.round((cur.end - cur.start) / 1e3 / 60 / 60 / 24 / 39) : "") + '"></span>', '<span class="date">' + bubble.getDateLabel() + "</span> ", '<span class="label">' + cur.label + "</span>"].join("");
html.push("<li>" + line + "</li>")
}
this.container.innerHTML += '<ul class="data">' + html.join("") + "</ul>"
}, Timesheet.prototype.drawSections = function() {
for (var html = [], c = this.year.min; c <= this.year.max; c++) html.push("<section>" + c + "</section>");
this.container.className = "timesheet color-scheme-default", this.container.innerHTML = '<div class="scale">' + html.join("") + "</div>"
}, Timesheet.prototype.parseDate = function(date) {
return -1 === date.indexOf("/") ? (date = new Date(parseInt(date, 10), 0, 1), date.hasMonth = !1) : (date = date.split("/"), date = new Date(parseInt(date[1], 10), parseInt(date[0], 10) - 1, 1), date.hasMonth = !0), date
}, Timesheet.prototype.parse = function(data) {
for (var n = 0, m = data.length; m > n; n++) {
var beg =...