Skip to content

Instantly share code, notes, and snippets.

@mandy13511
Last active August 1, 2019 07:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mandy13511/989766b224cdb03423e18a5f2ea7d729 to your computer and use it in GitHub Desktop.
Save mandy13511/989766b224cdb03423e18a5f2ea7d729 to your computer and use it in GitHub Desktop.
Pomodoro
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
</head>
<body>
<div class = "container">
<div id = "panel">
<transition name = "fade">
<div class = "panel" v-if = "showPanel">
<div class = "panel-header-rect" v-bind:class="{ right: tabIsRight }"></div>
<div class = "panel-header-button" v-on:click = "changeTab('to_do_list')" v-bind:class="{ active: tabIsLeft }">
To-do list
</div>
<div class = "panel-header-button right" v-on:click = "changeTab('dashboard')" v-bind:class="{ active: tabIsRight }">
Dashboard
</div>
<div id = "panel-to-do" class = "panel-content" v-show = "showTODOLIST">
<div class = "panel-week-content">
<div class = "panel-date-button" v-on:click = "changeActiveDate(0)" v-bind:class="{ active: activeDay == '0'}" >
<div class = "button-content">
{{historyData[0].date}}<br>SUN
</div>
</div>
<div class = "panel-date-button" v-on:click = "changeActiveDate(1)" v-bind:class="{ active: activeDay == '1'}">
<div class = "button-content">
{{historyData[1].date}}<br>MON
</div>
</div>
<div class = "panel-date-button" v-on:click = "changeActiveDate(2)" v-bind:class="{ active: activeDay == '2'}">
<div class = "button-content">
{{historyData[2].date}}<br>TUE
</div>
</div>
<div class = "panel-date-button" v-on:click = "changeActiveDate(3)" v-bind:class="{ active: activeDay == '3'}">
<div class = "button-content">
{{historyData[3].date}}<br>WED
</div>
</div>
<div class = "panel-date-button" v-on:click = "changeActiveDate(4)" v-bind:class="{ active: activeDay == '4'}">
<div class = "button-content">
{{historyData[4].date}}<br>THU
</div>
</div>
<div class = "panel-date-button" v-on:click = "changeActiveDate(5)" v-bind:class="{ active: activeDay == '5'}">
<div class = "button-content">
{{historyData[5].date}}<br>FRI
</div>
</div>
<div class = "panel-date-button" v-on:click = "changeActiveDate(6)" v-bind:class="{ active: activeDay == '6'}">
<div class = "button-content">
{{historyData[6].date}}<br>SAT
</div>
</div>
</div>
<div class = "panel-todo-content">
<ul>
<li v-for="item in historyData[activeDay].task" v-bind:class="{ active: isSelected == item}" @click = "isSelected = item">
<button v-bind:class="{ active: item.complete }" @click = "changeTaskStatus(item.taskName)"></button>
<a v-if = "item.complete" class = "line-through">{{ item.taskName }}</a>
<a v-else>{{ item.taskName }}</a>
</li>
<li><button class = "add">+</button><input type = "text" placeholder = "Add new task" v-model="taskName" v-on:keyup.enter = "addTask"></input></li>
</ul>
</div>
</div>
<div id = "panel-dash-board" class = "panel-content" v-show = "showDASHBOARD">
<div class = "panel-calculate-content">
<div class = "left">
<div class = "font-bold up" v-cloak>{{tomatoSum[activeDay]}}</div>
<div class = "down">TODAY</div>
</div>
<div class = "right">
<div class = "font-bold up" v-cloak>{{weekTomatoSum}}</div>
<div class = "down" v-cloak>{{historyData[0].date}}~{{historyData[6].date}}</div>
</div>
</div>
<div class = "panel-statistic-content">
<div id = "day1" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[0]*180/15+ 'px'}" v-cloak>{{tomatoSum[0]}}</div>
</div>
</transition>
</div>
<div id = "day2" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[1]*180/15+ 'px'}" v-cloak>{{tomatoSum[1]}}</div>
</div>
</transition>
</div>
<div id = "day3" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[2]*180/15+ 'px'}" v-cloak>{{tomatoSum[2]}}</div>
</div>
</transition>
</div>
<div id = "day4" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[3]*180/15+ 'px'}" v-cloak>{{tomatoSum[3]}}</div>
</div>
</transition>
</div>
<div id = "day5" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[4]*180/15+ 'px'}" v-cloak>{{tomatoSum[4]}}</div>
</div>
</transition>
</div>
<div id = "day6" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[5]*180/15+ 'px'}" v-cloak>{{tomatoSum[5]}}</div>
</div>
</transition>
</div>
<div id = "day7" class = "statistic-flex">
<transition name="up">
<div v-show = "tabIsRight" class = "straight">
<div class = "font-bold" v-bind:style="{ height: 31 + 150 -tomatoSum[6]*180/15+ 'px'}" v-cloak>{{tomatoSum[6]}}</div>
</div>
</transition>
</div>
</div>
<div class = "panel-statistic-date">
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[0].date}}</div>
<div>MON</div>
</div>
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[1].date}}</div>
<div>TUE</div>
</div>
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[2].date}}</div>
<div>WED</div>
</div>
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[3].date}}</div>
<div>THU</div>
</div>
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[4].date}}</div>
<div>FRI</div>
</div>
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[5].date}}</div>
<div>SAT</div>
</div>
<div class = "panel-statistic-date-detail">
<div v-cloak>{{historyData[6].date}}</div>
<div>SUN</div>
</div>
</div>
</div>
<div class = "finish-text">Finished</div>
<div class = "finish-area">
<i v-for = "n in tomatoSum[activeDay]" class="material-icons">favorite</i>
</div>
</div>
</transition>
</div>
<div id = "clock">
<div class = "circle">
<div class = "timer" v-cloak>{{countMinutes}}:{{countSeconds}}</div>
</div>
<button class = "button above-circle" @click = "changeAlarmStatus">
<i class="material-icons" v-cloak>{{alarm}}</i>
</button>
<button v-if = "isPlaying == true" class = "button left-circle" v-on:click = "stopCounDown">
<i class="material-icons">pause</i>
</button>
<button v-else class = "button left-circle" v-on:click = "timeCountDown">
<i class="material-icons">play_arrow</i>
</button>
<button class = "button under-circle" v-on:click = "reset">
<i class="material-icons">replay</i>
</button>
<transition name = "rotate">
<div v-if = "showClock" class = "minute-rect">
<div class = "line-rect minute-30" @click = "changeTargetMinutes('30')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '30' }">30</div>
<div class = "line"></div>
</div>
<div class = "line-rect minute-25" @click = "changeTargetMinutes('25')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '25' }">25</div>
<div class = "line"></div>
</div>
<div class = "line-rect minute-20" @click = "changeTargetMinutes('20')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '20' }">20</div>
<div class = "line"></div>
</div>
<div class = "line-rect minute-15" @click = "changeTargetMinutes('15')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '15' }">15</div>
<div class = "line"></div>
</div>
<div class = "line-rect minute-10" @click = "changeTargetMinutes('10')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '10' }">10</div>
<div class = "line"></div>
</div>
<div class = "line-rect minute-5" @click = "changeTargetMinutes('05')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '05' }">5</div>
<div class = "line"></div>
</div>
<div class = "line-rect minute-0" @click = "changeTargetMinutes('00')">
<div class = "minute" v-bind:class="{ active: targetMinutes == '00' }">0</div>
<div class = "line"></div>
</div>
</div>
</transition>
</div>
<div class = "license">UI Designed By
<a href="https://challenge.thef2e.com/user/1875?schedule=2512#works-2512">杯杯</a>
</div>
</div>
</body>
var vuePanel = new Vue({
el: '#panel',
data: {
showTODOLIST : true,
showDASHBOARD : false,
showPanel: false,
tabIsRight: false,
tabIsLeft: true,
isSelected: '',
activeDay : '',
currentDay: '',
currentDate: '',
currentMonthe: '',
currentYear: '',
taskName:'',
tomatoSum: [],
weekTomatoSum: 0,
historyData: []
},
mounted:function(){
this.showPanel = true;
var today = new Date();
this.currentYear = today.getFullYear();
this.currentMonth = today.getMonth()+1;
this.currentDate = today.getDate();
this.currentDay = today.getDay();
this.activeDay = this.currentDay;
//get the date og the first day of this week
var date = new Date();
date.setDate(date.getDate() - this.currentDay); //get the date of Sunday of current week
var startDay = date.getDate();
var startMonth = date.getMonth()+1;
backup = JSON.parse(localStorage.getItem('historyData'));
if (backup != null && backup[0].date == startMonth +'/' + startDay){
this.historyData = JSON.parse(JSON.stringify(backup));
}
else{
for (var i = 0; i < 7; i++) {
var tempMonth = date.getMonth()+1;
var tempDate = date.getDate();
this.historyData.push({date: tempMonth +'/' + tempDate, task: []});
date.setDate(date.getDate() + 1);
}
}
this.updateTomatoSum();
},
methods:{
changeTab: function(pTarget){
if (pTarget == "to_do_list"){
this.showTODOLIST = true;
this.showDASHBOARD = false;
this.tabIsRight = false;
this.tabIsLeft = true;
}
else{
this.showTODOLIST = false;
this.showDASHBOARD = true;
this.tabIsRight = true;
this.tabIsLeft = false;
}
},
changeActiveDate: function(pDate){
this.isSelected = '';
this.activeDay = pDate;
this.updateTomatoSum();
},
updateTomatoSum(){
let weekSum = 0
for(var i = 0; i < 7; i++){
this.tomatoSum[i] = this.historyData[i].task.reduce(function(sum,element){
if ("tomatoNum" in element){
return sum + element.tomatoNum
}
else{
return sum;
}
},0);
weekSum += this.tomatoSum[i];
}
this.weekTomatoSum = weekSum;
},
addTask(){
this.historyData[this.activeDay].task.push({taskName: this.taskName, complete: false, tomatoNum: 0});
localStorage.setItem('historyData', JSON.stringify(this.historyData));
this.taskName = '';
},
changeTaskStatus: function(pTaskName){
var selectedIndex = this.historyData[this.activeDay].task.map(function(e) { return e.taskName; }).indexOf(pTaskName);
if (this.historyData[this.activeDay].task[selectedIndex].complete == true){
this.historyData[this.activeDay].task[selectedIndex].complete = false;
}
else{
this.historyData[this.activeDay].task[selectedIndex].complete = true;
}
localStorage.setItem('historyData', JSON.stringify(this.historyData));
}
}
});
var vueClock = new Vue({
el: '#clock',
data:{
showClock: false,
targetMinutes: '15',
countMinutes: '15',
countSeconds: '00',
isPlaying: false,
alarm: 'notifications',
timer: null,
},
mounted:function(){
this.showClock = true;
},
methods:{
changeAlarmStatus(){
this.alarm == 'notifications'?this.alarm = 'notifications_off':this.alarm = 'notifications';
},
changeTargetMinutes: function(pTargetMinutes){
this.targetMinutes = pTargetMinutes;
this.countMinutes = pTargetMinutes;
this.countSeconds = '00';
},
reset(){
this.countMinutes = this.targetMinutes;
this.countSeconds = '00';
},
timeCountDown(){
if (vuePanel.isSelected != ''){
let my = this;
this.isPlaying = true;
this.timer = setInterval(function() {
var m = Number(my.countMinutes);
var s = Number(my.countSeconds);
var snd = new Audio("https://www.freespecialeffects.co.uk/soundfx/various/forest.wav");
if (m != 0 && s == 0){
m--;
s = 59;
}
else if (m == 0 && s==0){
my.stopCounDown();
if (this.alarm == 'notifications'){
snd.play();
}
else{
alert('Stop timing');
}
var selectedIndex = vuePanel.historyData[vuePanel.activeDay].task.map(function(e) { return e.taskName; }).indexOf(vuePanel.isSelected.taskName);
vuePanel.historyData[vuePanel.activeDay].task[selectedIndex].tomatoNum += 1
localStorage.setItem('historyData', JSON.stringify(vuePanel.historyData));
vuePanel.updateTomatoSum();
}
else{
s--;
}
m < 10 ? my.countMinutes = '0' + m : my.countMinutes = '' + m;
s < 10 ? my.countSeconds = '0' + s : my.countSeconds = '' + s;
},1000);
}
else{
alert('Please choose the task');
}
},
stopCounDown(){
clearInterval(this.timer);
this.isPlaying = false;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
$main-color: #FFF3F0;
$main-color-2: #FFD8CC;
$font-color: #9B9B9B;
$shadow-color: #bbbbbb;
$focus-color: #FF764C;
$font: Seravek;
@function pow($number, $exp) {
$value: 1;
@if $exp > 0 {
@for $i from 1 through $exp {
$value: $value * $number;
}
}
@else if $exp < 0 {
@for $i from 1 through -$exp {
$value: $value / $number;
}
}
@return $value;
}
@function fact($number) {
$value: 1;
@if $number > 0 {
@for $i from 1 through $number {
$value: $value * $i;
}
}
@return $value;
}
@function pi() {
@return 3.14159265359;
}
@function rad($angle) {
$unit: unit($angle);
$unitless: $angle / ($angle * 0 + 1);
// If the angle has 'deg' as unit, convert to radians.
@if $unit == deg {
$unitless: $unitless / 180 * pi();
}
@return $unitless;
}
@function sin($angle) {
$sin: 0;
$angle: rad($angle);
// Iterate a bunch of times.
@for $i from 0 through 10 {
$sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
}
@return $sin;
}
@function cos($angle) {
$cos: 0;
$angle: rad($angle);
// Iterate a bunch of times.
@for $i from 0 through 10 {
$cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i);
}
@return $cos;
}
@function tan($angle) {
@return sin($angle) / cos($angle);
}
*{
font-family: Seravek;
}
.material-icons {
color: $focus-color;
cursor: pointer;
}
body{
background-color: $main-color;
}
.container {
position: relative;
}
.panel {
position: absolute;
top: 63px;
left: 122px;
width: 504px;
height: 421px;
}
.panel-header-rect{
position:absolute;
border-radius: 10px 10px 0px 0px;
height: 55px;
width: 252px;
background-color: $main-color;
-webkit-box-shadow: 0 0 10px $shadow-color;
-moz-box-shadow: 0 0 10px $shadow-color;
box-shadow: 0 0 10px $shadow-color;
z-index: 1;
&.right{
left: 252px;
}
}
.panel-header-button{
position:absolute;
border-radius: 10px 10px 0px 0px;
height: 55px;
width: 252px;
padding-top: 16px;
text-align: center;
font-size: 20px;
color: #4A4A4A;
background-color: $main-color-2;
letter-spacing: 1.25px;
cursor: pointer;
&.right{
left: 252px;
z-index: 0;
}
&.active{
background-color: $main-color;
z-index: 3;
}
}
.panel-content{
position:absolute;
top: 55px;
height: 366px;
width: 504px;
background-color: $main-color;
border-radius: 0px 0px 10px 10px;
text-align: center;
-webkit-box-shadow: 0 0 10px $shadow-color;
-moz-box-shadow: 0 0 10px $shadow-color;
box-shadow: 0 0 10px $shadow-color;
z-index:2;
}
.panel-week-content{
display:flex;
justify-content: center;
margin: 19px 8px 16px 8px;
background-color: $main-color;
}
.panel-date-button{
height: 56px;
width: 56px;
margin: 0px 5px;
border: solid 1px;
border-radius: 5px;
border-color: rgba(151,151,151,0.2);
cursor: pointer;
&:active, &:hover, &:focus{
background-color: $main-color-2;
}
&.active{
border-color: $main-color-2;
background-color: $main-color-2;
.button-content{
color: black;
}
}
}
.button-content{
margin: 10px;
color: $font-color;
font-size: 16px;
letter-spacing: 1px;
text-align: center;
cursor: pointer;
}
.panel-todo-content{
height: 255px;
width: 464px;
margin:0px auto;
background-color: white;
border-radius: 5px;
text-align: left;
overflow:auto;
ul{
margin: 16px 16px 16px 16px;
padding: 0px;
list-style-type: none;
li{
margin-top: 10px;
line-height: 35px;
border-radius: 5px;
letter-spacing: 1.27px;
cursor: pointer;
&.active{
background-color: $focus-color;
color: white;
}
button{
width: 20px;
height: 20px;
margin-right: 16px;
margin-left: 5px;
padding-left: 1px;
border-radius: 50%;
border: solid 3px white;
vertical-align:middle;
background-color: white;
color: $focus-color;
font-size: 19px;
line-height: 15px;
cursor: pointer;
-webkit-box-shadow: 0 0 10px $shadow-color;
-moz-box-shadow: 0 0 10px $shadow-color;
box-shadow: 0 0 10px $shadow-color;
&.active{
background-color: $focus-color;
}
}
.line-through{
text-decoration:line-through;
}
input{
line-height: 24px;
width: 360px;
font-size: 14px;
letter-spacing: 1.27px;
border-top:solid 0px;
border-right: solid 0px;
border-left: solid 0px;
border-bottom: solid 1px #D8D8D8;
}
}
}
}
.panel-calculate-content{
position: absolute;
width: 464px;
height: 70px;
left: 20px;
top: 24px;
background-color: white;
border-radius: 5px;
.left{
width:232px;
height: 70px;
left: 0px;
}
.right{
position: absolute;
width:232px;
height: 70px;
left: 232px;
top: 0px;
}
}
.up{
margin-top: 7px;
color: #4A4A4A;
font-size: 30px;
}
.down{
font-size: 16px;
letter-spacing: 1px;
color: #4A4A4A;
}
.font-bold{
color: $focus-color;
}
.panel-statistic-content{
display: flex;
position:absolute;
width: 464px;
height: 181px;
left: 20px;
top: 118px;
align-items:flex-start;
background-color: white;
border-radius: 5px;
}
.panel-statistic-date{
display: flex;
position: absolute;
width: 464px;
height: 50px;
top: 307px;
left: 20px;
}
.panel-statistic-date-detail{
width: 464px;
font-size: 12px;
letter-spacing: 0.75px;
}
.straight{
width: 12px;
height: 181px;
background-color: #FFBBA6;
transition-duration: 0.5s;
.up{
margin-top: 0px;
background-color: white;
border: solid 1px black;
}
}
.statistic-flex{
margin-left: 47.5px;
.font-bold{
display: flex;
align-items:flex-end;
font-size: 24px;
background-color: white;
}
}
.circle{
position: absolute;
top: 262px;
left: 953px;
height: 123px;
width: 123px;
text-align: center;
border-radius: 50%;
border: 15px solid #FF9D80;
}
.button{
position: absolute;
display: block;
border-radius: 50%;
background-color: white;
height: 40px;
width: 40px;
cursor: pointer;
z-index: 1;
&:active, &:hover{
background-color: $main-color-2;
}
&.inside-circle{
margin-left: 41.5px;
margin-top: 41.5px;
}
&.above-circle{
top: 262px - 23px - 35px;
left: 953px + 41.5px + 15px;
}
&.left-circle{
top: 262px + 41.5px + 15px;
left: 953px - 41.5px - 15px;
}
&.under-circle{
top: 262px + 83px + 30px + 35px + 23px;
left: 953px + 41.5px + 15px;
}
}
.minute-rect{
position:absolute;
width: 700px;
height:700px;
left:680px;
z-index: 0;
}
.line-rect{
$half-long: (89.9px + 90px) /2 ;
position: absolute;
height: 89.9px + 90px;
width: 50px;
top: 262px - 33.4px + $half-long - 65px;
left: 322px;//953px + 41.5px + 15px + 18.9px - 25px;
cursor: pointer;
.line{
margin: 0px auto;
height: 89.9px;
width: 0px;
border: solid 1px #9B9B9B;
}
.minute{
font-size: 32px;
text-align: center;
color: #9B9B9B;
letter-spacing: 2px;
margin-bottom: 10px;
transform: rotate(90deg);
&.active, &:hover{
font-size: 32px;
color: #000000;
font-weight:bold;
transition-duration: 0.5s;
}
}
&.minute-30{
transform: translateY(-160px - $half-long + 40px);
}
&.minute-25{
$cos: cos(30deg) * -205px;
$sin: sin(30deg) * -205px;
transform: translate($sin, $cos) rotate(330deg);
}
&.minute-20{
$cos: cos(60deg) * -205px;
$sin: sin(60deg) * -205px;
transform: translate($sin, $cos) rotate(300deg);
}
&.minute-15{
$cos: cos(90deg) * -205px;
$sin: sin(90deg) * -205px;
transform: translate($sin, $cos) rotate(270deg);
}
&.minute-10{
$cos: cos(120deg) * -205px;
$sin: sin(120deg) * -205px;
transform: translate($sin, $cos) rotate(240deg);
}
&.minute-5{
$cos: cos(150deg) * -205px;
$sin: sin(150deg) * -205px;
transform: translate($sin, $cos) rotate(210deg);
}
&.minute-0{
$cos: cos(180deg) * -205px;
$sin: sin(180deg) * -205px;
transform: translate($sin, $cos) rotate(180deg);
}
}
.timer{
line-height: 123px;
font-size: 26px;
letter-spacing: 1.25px;
}
.finish-text{
position: absolute;
top: 450px;
opacity: 0.5;
font-size: 20px;
color: #000000;
letter-spacing: 1.25px;
text-align: center;
}
.finish-area{
position: absolute;
top: 450px + 30px;
}
.license{
letter-spacing: 1.25px;
opacity: 0.5;
}
button:focus {
outline: none;
}
/***Hide vue instance***/
[v-cloak] {
display: none;
}
/***transition***/
.up-enter-active, .up-leave-active {
transition: all .3s ease;
}
.up-enter, .up-leave-to /* .fade-leave-active below version 2.1.8 */ {
transform: translateY(10px);
opacity: 0;
}
.rotate-enter-active, .rotate-leave-active {
transition: all 1s ease;
//transform: rotate(-30deg);
}
.rotate-enter, .rotate-leave-to /* .fade-leave-active below version 2.1.8 */ {
transform: rotate(30deg) translateX(30px);
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 3s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment