I took a shoot at writing a Github contribution clone using Vuej, tippy.js and tailwindcss.
Githubs looks like this: screenshot of Github contribution graph
My working clone looks like this: screenshot of working clone of Github contribution graph
It is not an exact look-a-like but I'm getting there. I have received some feedback on using the library date-fns to generate year, months and days; it seems that the data generation is scattered across the application.
At the moment I think my code is pretty readable but performance wise, I don't have a clue - I haven't tested it with a larger amount of data.
Here is the working example (and a stackblitz fiddle):
<template>
<div id="app">
<div v-for="(month, index) in all_months" v-bind:key="month">
<h1>{{ month }}, {{ getDaysInMonth(index) }}</h1>
<div class="flex">
<div v-for="day in getDaysInMonth(index)" v-bind:key="day" class="flex flex-col">
<div class="flex flex-row">
<div class="mr-1"></div>
<div class="w-4 h-4 rounded-sm mt-1 bg-gray-300 shadow"
:class="{'bg-green-300': test[whatDate(index, day, true)]}"
:data-tippy-content='`${whatDate(index, day)}`'></div>
</div>
</div>
</div>
</div>
<br>
whatDate: {{ whatDate(1, 22, true)}}
</div>
</template>
<script>
import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css'; // optional for styling
export default {
mounted(){
tippy('[data-tippy-content]')
},
// props: ['answers', 'correct_answer_count', 'wrong_answer_count'],
data(){
return{
days: [],
answers: {
"06-Nov-22": {
"total":24, "correct":17, "wrong":7},
"14-Jul-22": {
"total":26, "correct":24, "wrong":2},
"13-Jul-22": {
"total":21, "correct":14, "wrong":7},
"09-Jul-22": {
"total":30, "correct":23, "wrong":7},
"06-Jul-22": {
"total":4, "correct":3, "wrong":1},
"05-Jul-22": {
"total":13, "correct":11, "wrong":2},
"04-Jul-22": {
"total":164, "correct":148, "wrong":16},
"03-Jul-22": {
"total":7, "correct":4, "wrong":3},
"27-Jun-22": {
"total":1, "correct":1, "wrong":0},
"22-Jun-22": {
"total":10, "correct":9, "wrong":1}
},
}
},
computed:{
test(){
const tempArray = {}
const answers = this.answers
Object.keys(this.answers).forEach(function(element, key) {
tempArray[new Date(element).toLocaleDateString()] = answers[element]
})
return tempArray
},
all_months(){
const month = Array.from({length: 12}, (e,i) => {
return new Date(2022, i + 1, null).toLocaleDateString("sv", {month: 'long'})
})
return month
}
},
methods:{
getDaysInMonth(index){
return new Date(2022, index + 1, 0).getDate();
},
whatDay(index, day){
switch (new Date(2022, index , day).getDay()){
case 0:
day = "Sunday";
break;
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
case 5:
day = "Friday";
break;
case 6:
day = "Saturday";
}
return day
},
whatDate(index, day, standardDate = false){
if(!standardDate){
return new Date(2022, index, day).toLocaleDateString("sv", {weekday: "long", year: "numeric", month: "long", day: "numeric"}) //.toDateString()
}
return new Date(2022, index, day).toLocaleDateString()
}
},
}
</script>
1 Answer 1
General Feedback
It is interesting that Date methods like toLocaleDateString()
are used in method whatDate()
as well as for computed properties yet the method whatDay()
simply has a switch
statement to return string literals for the days of the week. One could replace the switch
statement with an array and fetch the day from the array based on the index, or use the toLocaleDateString()
method.
If performance does become an issue then one may want to consider converting functional loops (e.g. calling .forEach()
) to for
loops.
Suggestions
Attribute binding syntax can be more consistent
There are several elements in the markup using v-bind:
- e.g.
<div v-for="(month, index) in all_months" v-bind:key="month">
and
<div v-for="day in getDaysInMonth(index)" v-bind:key="day" class="flex flex-col">
Yet others simply use the v-bind
shorthand - e.g. :class
and :data-tippy-content
:class="{'bg-green-300': test[whatDate(index, day, true)]}" :data-tippy-content='`${whatDate(index, day)}`'
Arrow function can be used to eliminate local variable
The callback passed to the forEach
used in the test()
method can be switched to an arrow function, like that of the map function passed as the second argument to Array.from()
within the all_months()
computed function. Since arrow functions don't have their own bindings to this
1 the callback function can reference this.answers
instead of answers
and then that variable can be eliminated.
Variable name could be misleading
In the function for computed property all_months
the array is stored in a variable called month
. A more appropriate name would be months
, since it stores multiple months.
Explore related questions
See similar questions with these tags.