I took a shoot at writing a Github contribution clone using Vuej, tippy.js and tailwindcss.
My working clone looks like this:

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>
