<div id="app" v-cloak>
<div class="wrapper">
<div class="header layout-row">
<h5 class="time padding">Time</h5>
<h5 class="activity padding">Activity</h5>
</div>
<div class="content">
<div class="tracker">
<i class="material-icons">keyboard_arrow_left</i>
</div>
<div class="time-tracker">
<div v-for="interval in intervals" class="time-cell padding">
{{interval }}
</div>
</div>
<draggable @end="onDragEnd" :list="activityList" :options="{group:'people', animation: 150, handle: '.drag-handle'}" class="activities flex">
<div v-for="activity in activityList" class="activity-cell padding" v-bind:class="activity.color">
<a class="waves-effect waves-dark btn-flat drag-handle" @click=""><svg v-bind:class="{'white-fill': activity.color === 'white'}" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>
</a>
<span class="col s8" v-bind:class="{'white-text': activity.color !== 'white'}">{{activity.name }}</span>
<span class="flex"></span>
<a class="waves-effect waves-dark btn-flat" @click="edit(activity)"><i class="material-icons">edit</i></a>
</div>
</draggable>
</div>
</div>
<div id="edit-activity" class="modal">
<div class="modal-content">
<h4>Edit Activity</h4>
<div class="row">
<div class="input-field col s12">
<input id="modelActivityText" type="text" v-model="modalActivity.name" @keyup.enter="closeModal">
<label for="modelActivityText">Activity</label>
</div>
</div>
<div class="row">
<h5 class="col s8">Color Select</h5>
<div class="col s4 color-select" v-bind:class="modalActivity.color"></div>
</div>
<div class="row">
<div class="waves-effect red col s4 color-select" @click="changeModalActivityColor('red')"></div>
<div class="waves-effect purple col s4 color-select" @click="changeModalActivityColor('purple')"></div>
<div class="waves-effect deep-purple col s4 color-select" @click="changeModalActivityColor('deep-purple')"></div>
<div class="waves-effect indigo col s4 color-select" @click="changeModalActivityColor('indigo')"></div>
<div class="waves-effect blue col s4 color-select" @click="changeModalActivityColor('blue')"></div>
<div class="waves-effect light-blue col s4 color-select" @click="changeModalActivityColor('light-blue')"></div>
<div class="waves-effect teal col s4 color-select" @click="changeModalActivityColor('teal')"></div>
<div class="waves-effect green col s4 color-select" @click="changeModalActivityColor('green')"></div>
<div class="waves-effect orange col s4 color-select" @click="changeModalActivityColor('orange')"></div>
<div class="waves-effect brown col s4 color-select" @click="changeModalActivityColor('brown')"></div>
<div class="waves-effect grey col s4 color-select" @click="changeModalActivityColor('grey')"></div>
<div class="waves-effect blue-grey col s4 color-select" @click="changeModalActivityColor('blue-grey')"></div>
</div>
</div>
<div class="modal-footer">
<a class="waves-effect waves-dark btn-flat" @click="closeModal">Close</a>
</div>
</div>
</div>
$body-color: rgba(0,0,0,.8);
$app-color: #34495E;
$row-height: 2.5rem;
$borders-color: rgba(0,0,0,.4);
[v-cloak] { display:none; }
div {
position: relative;
box-sizing: border-box;
}
html {
width: 100%;
height: 100%;
font-family: Roboto,Lato,sans-serif;
}
body {
background-color: $body-color;
margin: 0;
}
#app {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
.content {
max-height: 90vh;
overflow: auto;
display: flex;
flex-direction: row;
}
.wrapper {
display: flex;
flex-direction: column;
background: white;
margin: auto;
max-width: 480px;
width: 100%;
border-radius: 0.25rem;
box-shadow: 0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12);
overflow: hidden;
}
}
.padding {
padding: 0.5rem;
}
.layout-row {
display: flex;
flex-direction: row;
}
.header {
color: white;
background: lighten($app-color, 10%);
flex-shrink: 0;
.time {
width: 100px;
text-align: center;
margin: 0;
border-right: solid 1px $borders-color;
border-bottom: solid 1px $borders-color;
}
.activity {
flex: 80;
margin: 0;
border-bottom: solid 1px $borders-color;
}
}
.time-tracker {
height: 100%;
}
.tracker {
color: black;
border-bottom: dotted 4px black;
position: absolute;
height: 2px;
width: 96%;
top: 70%;
right: 0;
z-index: 1;
i {
font-size: 40px;
position: absolute;
left: -28px;
transform: translateY(-18px);
}
}
.time-cell {
width: 100px;
color: white;
background: $app-color;
text-align: center;
height: $row-height;
}
.activity-cell {
.btn-flat {
padding: 0 0.5rem;
}
height: $row-height;
border: none;
border-bottom: solid 1px $borders-color;
display: flex;
align-items: center;
background: black;
a.drag-handle {
color: black;
cursor: grab;
margin-right: 0.5rem;
height: 24px;
width: 24px;
padding: 0;
svg {
height: 100%;
fill: white;
}
svg.white-fill {
fill: black;
}
}
}
.color-select {
height: 50px;
transform: scale3d(.95,.85,1);
box-shadow: 0 4px 5px 0 rgba(0,0,0,0.14),0 1px 10px 0 rgba(0,0,0,0.12),0 2px 4px -1px rgba(0,0,0,0.3);
}
.flex {
flex:1;
}
@media only screen and (max-width: 500px) {
#app {
margin: 0.5rem;
.wrapper {
height: 100vh;
}
.content {
flex: 1;
max-height: none;
}
}
}
View Compiled
$(document).ready(function() {
$('.modal').modal();
});
var save = function(data) {
window.localStorage.setItem('save', JSON.stringify(data));
};
var app = new Vue({
el: '#app',
data: {
modalActivity: {},
intervals:[ ],
activityList: []
},
watch: {
modalActivity: {
handler: function(val, oldVal) {
this.activityList.forEach(function(activity) {
if (activity.name === this.modalActivity.name) {
this.modalActivity.color = activity.color;
}
}, this);
save(this.activityList);
}, deep: true
}
},
methods: {
onDragEnd: function() {
save(this.activityList);
},
edit: function(activity, event) {
this.modalActivity = activity;
$('#edit-activity').modal('open');
$('#modelActivityText').get(0).focus();
$('.modal label').addClass('active');
},
closeModal: function() {
$('#edit-activity').modal('close');
},
changeModalActivityColor: function(color) {
this.modalActivity.color = color;
this.activityList.forEach(function(activity) {
if (activity.name === this.modalActivity.name) {
activity.color = color;
}
}, this);
}
},
created: function() {
window.setInterval(function() {
var currentTime = new Date();
var height = 0;
$('.time-tracker').children().each(function() {
height += $(this).outerHeight();
});
var heightPercent = ( currentTime.getHours()*60+currentTime.getMinutes() ) / (24*60);
$('.tracker').css('top', heightPercent*height + 'px');
console.log(height, heightPercent);
}, 1000);
var date = new Date();
for(var i = 0;i<24;i++) {
date.setHours(i);
date.setMinutes(0);
var text = date.toLocaleString('en-US', { minute: 'numeric', hour: 'numeric', hour12: true });
this.intervals.push(text);
}
try {
this.activityList = JSON.parse(window.localStorage.getItem('save')) || [];
} catch (e) {
console.error(e);
this.activityList = [];
}
if (this.activityList.length > 4) {
return;
}
for(var i = 0;i<24;i++) {
this.activityList.push({
name: 'Empty',
color: 'white'
})
}
}
});