From 69ec0fa869f1259451c4224def503ba6ca643178 Mon Sep 17 00:00:00 2001
From: KanishkRanjan <68316017+KanishkRanjan@users.noreply.github.com>
Date: Tue, 3 Dec 2024 11:30:39 +0530
Subject: [PATCH 1/2] Fix some bug and improved fetcher
---
fetcher.js | 113 +++++++++++++-------------
index.js | 140 ++++++++++++++++----------------
public/images/profile.jpg | Bin 0 -> 4981 bytes
public/script.js | 36 +++++++++
public/styles.css | 165 ++++++++++++++++++++++++++++++++++++++
vercel.json | 16 +---
views/profile.ejs | 99 +++++++++++++++++++++++
7 files changed, 429 insertions(+), 140 deletions(-)
create mode 100644 public/images/profile.jpg
create mode 100644 public/script.js
create mode 100644 public/styles.css
create mode 100644 views/profile.ejs
diff --git a/fetcher.js b/fetcher.js
index 73ac28a..72fe660 100644
--- a/fetcher.js
+++ b/fetcher.js
@@ -2,6 +2,7 @@ const axios = require('axios');
const cheerio = require('cheerio');
const mongoose = require('mongoose');
const moment = require('moment');
+
require('dotenv').config();
// Function to extract users from HTML
@@ -60,92 +61,92 @@ async function fetchCSESData() {
// Function to update MongoDB
async function updateMongoDB(users) {
- if (!users || Object.keys(users).length === 0) {
+ if (!users) {
console.log('No user data to update');
return false;
}
- const session = await mongoose.startSession();
+ let client;
try {
- session.startTransaction();
-
+ const uri = process.env.MONGODB_URI;
+ if (!uri) {
+ throw new Error('MongoDB URI not found in environment variables');
+ }
+
+ if (!mongoose.connection.readyState) {
+ await mongoose.connect(uri, {
+ useNewUrlParser: true,
+ useUnifiedTopology: true
+ });
+ }
+
const collection = mongoose.connection.collection('CSES');
const todayDate = moment().format('DD/MM/YYYY');
const yesterdayDate = moment().subtract(1, 'days').format('DD/MM/YYYY');
- const operations = [];
for (const [user, tasks] of Object.entries(users)) {
- const document = await collection.findOne({ username: user }, { session });
+ const document = await collection.findOne({ username: user });
if (document) {
- const prevSolved = document.solved?.[yesterdayDate] || 0;
- const currentStreak = document.streak || 0;
-
- let newStreak = 0;
- if (tasks > prevSolved) {
- newStreak = currentStreak + 1;
+ let streak = parseInt(document.streak || 0);
+ const prevSolved = document.solved?.[yesterdayDate];
+ let currSolved = prevSolved;
+
+ if (prevSolved !== undefined && prevSolved < tasks) {
+ streak = document.prevStreak + 1;
+ currSolved = tasks;
+ } else {
+ streak = 0;
}
- operations.push({
- updateOne: {
- filter: { username: user },
- update: {
- $set: {
- [`solved.${todayDate}`]: tasks,
- streak: newStreak,
- questionSolved: tasks,
- lastUpdated: new Date()
- }
- }
- }
- });
- } else {
- operations.push({
- insertOne: {
- document: {
- username: user,
- solved: { [todayDate]: tasks },
- streak: 0,
+ document.solved = document.solved || {};
+ document.solved[todayDate] = currSolved;
+
+ await collection.updateOne(
+ { username: user },
+ {
+ $set: {
+ solved: document.solved,
+ streak: streak,
questionSolved: tasks,
- lastUpdated: new Date()
+ prevStreak: document.streak || 0
}
}
- });
+ );
+ } else {
+ const data = {
+ username: user,
+ solved: { [todayDate]: tasks },
+ streak: 0,
+ questionSolved: tasks,
+ prevStreak: 0
+ };
+ await collection.insertOne(data);
}
}
-
- if (operations.length > 0) {
- await collection.bulkWrite(operations, { session });
- console.log(`Updated ${operations.length} users`);
- }
-
- await session.commitTransaction();
return true;
} catch (error) {
- await session.abortTransaction();
- console.error('Error updating MongoDB:', error);
- throw error;
- } finally {
- await session.endSession();
+ console.error('Error updating MongoDB:', error.message);
+ return false;
}
}
// Main function to fetch and update data
async function updateLeaderboard() {
+ console.log('Starting leaderboard update:', new Date().toISOString());
try {
- console.log('Starting leaderboard update...');
const users = await fetchCSESData();
-
- if (!users || Object.keys(users).length === 0) {
- throw new Error('No user data received from CSES');
+ if (users) {
+ const success = await updateMongoDB(users);
+ console.log('Update completed:', success ? 'successful' : 'failed');
+ return success;
+ } else {
+ console.log('No user data fetched');
+ return false;
}
-
- await updateMongoDB(users);
- console.log('Leaderboard update completed successfully');
- return true;
} catch (error) {
- console.error('Error updating leaderboard:', error);
- throw error;
+ console.error('Error in updateLeaderboard:', error.message);
+ return false;
}
}
diff --git a/index.js b/index.js
index 0736056..47fe0bf 100644
--- a/index.js
+++ b/index.js
@@ -2,13 +2,15 @@ const express = require('express');
const mongoose = require("mongoose");
const moment = require('moment');
const path = require('path');
+const cron = require('node-cron');
const { updateLeaderboard } = require('./fetcher');
+
moment().format();
require('dotenv').config();
const app = express();
-const port = process.env.PORT || 3000;
+const port = 5000;
// Middleware
app.set('views', path.join(__dirname, 'views'));
@@ -20,34 +22,19 @@ app.use(express.json());
console.log('Current directory:', __dirname);
console.log('Views directory:', path.join(__dirname, 'views'));
-const mongoURI = process.env.MONGODB_URI;
-if (!mongoURI) {
- console.error('MONGODB_URI environment variable is not set');
- process.exit(1);
-}
+const mongoURI = process.env.MONGODB_URI ;
-// Connect to MongoDB with connection pooling
+// Connect to MongoDB
const connectDB = async () => {
try {
- if (mongoose.connection.readyState === 1) {
- console.log('MongoDB already connected');
- return mongoose.connection;
- }
-
- if (!global.mongoConnection) {
- global.mongoConnection = await mongoose.connect(mongoURI, {
- useNewUrlParser: true,
- useUnifiedTopology: true,
- serverSelectionTimeoutMS: 5000,
- bufferCommands: false,
- maxPoolSize: 10
- });
- console.log("Connected to MongoDB!");
- }
- return global.mongoConnection;
+ await mongoose.connect(mongoURI, {
+ useNewUrlParser: true,
+ useUnifiedTopology: true
+ });
+ console.log("Connected to MongoDB!");
} catch (error) {
console.error("MongoDB connection error:", error);
- throw error;
+ process.exit(1);
}
};
@@ -56,15 +43,13 @@ const User = mongoose.model("User", new mongoose.Schema({
username: String,
solved: Object,
streak: Number,
- questionSolved: Number,
- lastUpdated: Date
+ questionSolved: Number
}), "CSES");
// Routes
-app.get("/", async (req, res, next) => {
+app.get("/", async (req, res) => {
try {
- await connectDB();
- const users = await User.find().lean();
+ const users = await User.find();
const usersData = users.map(userData => {
const timeline = Array(7).fill(false);
const noOfDaysInWeek = 7;
@@ -72,16 +57,15 @@ app.get("/", async (req, res, next) => {
for (let index = 0; index < noOfDaysInWeek; index++) {
const reqDate = moment().subtract(index, 'days').format('DD/MM/YYYY');
const prevDate = moment().subtract(index + 1, 'days').format('DD/MM/YYYY');
-
- timeline[noOfDaysInWeek - index - 1] = parseInt(userData.solved?.[reqDate] || 0) > parseInt(userData.solved?.[prevDate] || 0);
+ if (userData.solved[prevDate])
+ timeline[noOfDaysInWeek - index - 1] = parseInt(userData.solved[reqDate] || 0) > parseInt(userData.solved[prevDate]);
}
return {
name: userData.username,
timeline: timeline,
streak: userData.streak || 0,
- questionSolved: userData.questionSolved || 0,
- lastUpdated: userData.lastUpdated
+ questionSolved: userData.questionSolved || 0
};
});
@@ -90,54 +74,72 @@ app.get("/", async (req, res, next) => {
res.render("index", { data: usersData });
} catch (error) {
- next(error);
+ console.error("Error fetching data:", error);
+ res.status(500).json({ error: "Error fetching data", details: error.message });
}
});
-// Manual update endpoint (protected)
-app.post("/update", async (req, res, next) => {
+
+app.get("/profile" , async (req , res) => {
try {
- const apiKey = req.headers['x-api-key'];
- if (apiKey !== process.env.API_KEY) {
- return res.status(401).json({ error: "Unauthorized" });
- }
+ res.render("profile")
- await connectDB();
+ }
+ catch (error) {
+ console.error("Error while loading page:", error);
+ res.status(500).json({ error: "Error while loading data", details: error.message });
+
+ }
+})
+
+
+// Manual update endpoint (protected)
+app.post("/update", async (req, res) => {
+ const apiKey = req.headers['x-api-key'];
+ if (apiKey !== process.env.API_KEY) {
+ return res.status(401).json({ error: "Unauthorized" });
+ }
+
+ try {
await updateLeaderboard();
res.json({ status: "success" });
} catch (error) {
- next(error);
+ console.error("Error in manual update:", error);
+ res.status(500).json({ error: "Update failed" });
}
});
-// Health check endpoint
-app.get("/health", (req, res) => {
- res.json({ status: "healthy" });
-});
-
// Error handling middleware
app.use((err, req, res, next) => {
- console.error('Error:', err);
- const statusCode = err.statusCode || 500;
- const message = err.message || 'Internal Server Error';
- res.status(statusCode).json({ error: message });
+ console.error(err.stack);
+ res.status(500).send('Something broke!');
});
-// For local development
-if (process.env.NODE_ENV !== 'production') {
- const startServer = async () => {
- try {
- await connectDB();
- app.listen(port, () => {
- console.log(`Server is running on port ${port}`);
- });
- } catch (error) {
- console.error('Failed to start server:', error);
- process.exit(1);
- }
- };
-
- startServer();
-}
-
-module.exports = app;
+// Schedule the update every 3 hours
+cron.schedule('0 */3 * * *', async () => {
+ console.log('Running scheduled update');
+ try {
+ await updateLeaderboard();
+ } catch (error) {
+ console.error('Scheduled update failed:', error);
+ }
+});
+
+// Start server
+const startServer = async () => {
+ await connectDB();
+
+ // Initial update on server start
+ try {
+ await updateLeaderboard();
+ console.log('Initial update completed');
+ } catch (error) {
+ console.error('Initial update failed:', error);
+ }
+
+ app.listen(port, () => {
+ console.log(`Server is running on port ${port}`);
+ });
+};
+// setInterval(updateLeaderboard, 3600000);
+startServer();
diff --git a/public/images/profile.jpg b/public/images/profile.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f99f0952b45b3808ec20119ff4a8c382b761ce20
GIT binary patch
literal 4981
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 {
+ graphContainer.appendChild(dayElement.cloneNode(true));
+ });
+
+ currentDate.setDate(currentDate.getDate() + 1);
+ }
+
\ No newline at end of file
diff --git a/public/styles.css b/public/styles.css
new file mode 100644
index 0000000..0884ee2
--- /dev/null
+++ b/public/styles.css
@@ -0,0 +1,165 @@
+/* Typography */
+.rubik-p {
+ font-family: "Rubik", sans-serif;
+ font-optical-sizing: auto;
+ font-weight: 300;
+ font-style: normal;
+ color: rgba(255, 255, 255, 0.8); /* Softer text for readability */
+ }
+
+ .rubik-h, .rubik-hmain, .rubik-hmain2, .rubik-hmain3 {
+ font-family: "Rubik", sans-serif;
+ font-optical-sizing: auto;
+ font-weight: 600;
+ font-style: normal;
+ }
+
+ .rubik-hmain {
+ font-size: xxx-large;
+ background: linear-gradient(90deg, #dfbac9, #cdc3ee);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ }
+
+ .rubik-hmain2 {
+ font-size: xx-large;
+ background: linear-gradient(90deg, #dfbac9, #cdc3ee);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ }
+
+ .rubik-hmain3 {
+ font-size: x-large;
+ background: linear-gradient(90deg, #dfbac9, #cdc3ee);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ margin-bottom: 15px;
+ }
+
+ /* Background */
+ body {
+ background-color: black;
+ margin: 0;
+ font-family: "Rubik", sans-serif;
+ }
+
+ /* Profile Card */
+ .profile_card {
+ background-color: rgb(22, 22, 22);
+ padding: 30px;
+ width: 300px;
+ border-radius: 35px;
+ border: 1px solid rgb(48, 48, 51);
+ color: #fff;
+ margin-left: 30px;
+ position: fixed;
+ left: 30px;
+ top: 50%;
+ transform: translateY(-50%);
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+ }
+
+ .avatar-img {
+ width: 100%;
+ border-radius: 35px;
+ border: 1px solid rgb(48, 48, 51);
+ }
+
+ /* Profile Bottom Section */
+ .profile_bot {
+ background: linear-gradient(to right, #e1b9c5, #d0c2e9);
+ border-radius: 25px;
+ width: 85%;
+ padding: 20px;
+ margin-top: 15px;
+ text-align: center;
+ color: #000;
+ margin-bottom: -60px;
+ }
+
+ /* Main Content */
+ .main {
+ margin-top: 40px;
+ margin-left: 460px;
+ color: rgba(255, 255, 255, 0.75);
+ }
+
+ /* Links */
+ a {
+ color: white;
+ text-decoration: none;
+ }
+
+ a:hover {
+ color: rgb(223, 185, 201);
+ }
+
+ a:active {
+ color: rgb(208, 193, 231);
+ }
+
+ /* Icons */
+ .icons {
+ display: inline;
+ height: 30px;
+ width: 30px;
+ margin-right: 5px;
+ }
+
+ .graph-container {
+ display: grid;
+ grid-template-rows: repeat(7, 15px); /* Days go from top to bottom */
+ grid-auto-flow: column; /* Columns represent weeks */
+ gap: 2px;
+ }
+ .day {
+ width: 15px;
+ height: 15px;
+ background-color: rgb(48,48,51);
+ border-radius: 2px;
+ position: relative;
+ }
+ .day[data-count="1"] { background-color: #0d4429 }
+ .day[data-count="2"] { background-color: #016c31 }
+ .day[data-count="3"] { background-color: #26a641 }
+ .day[data-count="4"] { background-color: #39d353; }
+ .tooltip {
+ display: none;
+ position: absolute;
+ background: #000;
+ color: #fff;
+ padding: 5px;
+ border-radius: 3px;
+ font-size: 10px;
+ white-space: nowrap;
+ z-index: 10;
+ pointer-events: none;
+ }
+ .day:hover .tooltip {
+ display: block;
+ top: -25px;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+ .month-labels {
+ display: flex;
+ justify-content: space-between;
+ padding: 0 5px;
+ }
+ .day-labels {
+ display: grid;
+ grid-template-rows: repeat(7, 15px);
+ gap: 2px;
+ }
+ .day-label {
+ font-size: 10px;
+ color: #666;
+ text-align: right;
+ margin-right: 5px;
+ }
+ .months {
+ margin-top: 20px;
+ }
\ No newline at end of file
diff --git a/vercel.json b/vercel.json
index 04f32b6..213cb53 100644
--- a/vercel.json
+++ b/vercel.json
@@ -7,14 +7,6 @@
}
],
"routes": [
- {
- "src": "/health",
- "dest": "index.js"
- },
- {
- "src": "/update",
- "dest": "index.js"
- },
{
"src": "/(.*)",
"dest": "index.js"
@@ -25,11 +17,5 @@
"path": "/update",
"schedule": "0 */3 * * *"
}
- ],
- "functions": {
- "index.js": {
- "memory": 1024,
- "maxDuration": 10
- }
- }
+ ]
}
diff --git a/views/profile.ejs b/views/profile.ejs
new file mode 100644
index 0000000..9f5cf51
--- /dev/null
+++ b/views/profile.ejs
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+ Portfolio
+
+
+
+
+
+
Neel Verma
+
![](./images/profile.jpg)
+
Role:
+
Executive
+
Skills:
+
Python, C++, Java
+
+
+
+
+
+
+
+
+
+
+
print("hello world!")
+
+
+
+
+
+
+
+
+
From 03b62f38bfe342472c39dd357ba1d76a8456ca08 Mon Sep 17 00:00:00 2001
From: KanishkRanjan <68316017+KanishkRanjan@users.noreply.github.com>
Date: Tue, 3 Dec 2024 20:04:03 +0530
Subject: [PATCH 2/2] Fixed null error and introduced profile page
---
fetcher.js | 6 +-
images/profile.jpg | Bin 0 -> 4981 bytes
index.ejs | 52 ++++++++++++++
index.js | 2 +-
profile.ejs | 99 +++++++++++++++++++++++++++
script.js | 36 ++++++++++
styles.css | 165 +++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 356 insertions(+), 4 deletions(-)
create mode 100644 images/profile.jpg
create mode 100644 index.ejs
create mode 100644 profile.ejs
create mode 100644 script.js
create mode 100644 styles.css
diff --git a/fetcher.js b/fetcher.js
index 72fe660..c5f3b57 100644
--- a/fetcher.js
+++ b/fetcher.js
@@ -90,7 +90,7 @@ async function updateMongoDB(users) {
if (document) {
let streak = parseInt(document.streak || 0);
const prevSolved = document.solved?.[yesterdayDate];
- let currSolved = prevSolved;
+ let currSolved = prevSolved ;
if (prevSolved !== undefined && prevSolved < tasks) {
streak = document.prevStreak + 1;
@@ -100,8 +100,8 @@ async function updateMongoDB(users) {
}
document.solved = document.solved || {};
- document.solved[todayDate] = currSolved;
-
+ document.solved[todayDate] = currSolved ?? tasks;
+
await collection.updateOne(
{ username: user },
{
diff --git a/images/profile.jpg b/images/profile.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f99f0952b45b3808ec20119ff4a8c382b761ce20
GIT binary patch
literal 4981
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
+
+
+
+
+
+
+
+ Leaderboard
+
+
+
+
+
Leaderboard
+
+
+
+ Rank |
+ Name |
+ Activity |
+ Streak |
+ Question Solved |
+
+
+
+
+
+ <% for (let index = 0; index < data.length; index++) { %>
+
+ #<%= index +1 %> |
+ <%= data[index].name %> |
+
+
+ <% data[index].timeline.forEach(element => { %>
+ <% if(element) { %>
+
+ <% } else { %>
+
+ <% } %>
+ <% }); %>
+
+ |
+ <%= data[index].streak %> |
+ <%= data[index].questionSolved %> |
+
+
+ <% } %>
+
+
+
+
+
\ No newline at end of file
diff --git a/index.js b/index.js
index 47fe0bf..1837778 100644
--- a/index.js
+++ b/index.js
@@ -138,7 +138,7 @@ const startServer = async () => {
}
app.listen(port, () => {
- console.log(`Server is running on port ${port}`);
+ console.log(`Server is 2 running on port ${port}`);
});
};
// setInterval(updateLeaderboard, 3600000);
diff --git a/profile.ejs b/profile.ejs
new file mode 100644
index 0000000..9f5cf51
--- /dev/null
+++ b/profile.ejs
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+ Portfolio
+
+
+
+
+
+
Neel Verma
+
![](./images/profile.jpg)
+
Role:
+
Executive
+
Skills:
+
Python, C++, Java
+
+
+
+
+
+
+
+
+
+
+
print("hello world!")
+
+
+
+
+
+
+
+
+
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..9cbc50f
--- /dev/null
+++ b/script.js
@@ -0,0 +1,36 @@
+// Get all the graph containers for CodeChef, Codeforces, and CSES
+const graphContainers = [
+ document.getElementById('codechef-graph-container'),
+ document.getElementById('codeforces-graph-container'),
+ document.getElementById('cses-graph-container')
+ ];
+
+ const startDate = new Date('2025-01-01');
+ const endDate = new Date('2025-12-31');
+
+ let currentDate = startDate;
+
+ while (currentDate <= endDate) {
+ const dayElement = document.createElement('div');
+ dayElement.className = 'day';
+ // Data regarding the day
+ const activityLevel = Math.floor(Math.random() * 5);
+
+
+
+
+ dayElement.setAttribute('data-count', activityLevel);
+
+ const tooltip = document.createElement('div');
+ tooltip.className = 'tooltip';
+ tooltip.innerText = currentDate.toDateString();
+ dayElement.appendChild(tooltip);
+
+ // Add the created day element to all graph containers
+ graphContainers.forEach(graphContainer => {
+ graphContainer.appendChild(dayElement.cloneNode(true));
+ });
+
+ currentDate.setDate(currentDate.getDate() + 1);
+ }
+
\ No newline at end of file
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..0884ee2
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,165 @@
+/* Typography */
+.rubik-p {
+ font-family: "Rubik", sans-serif;
+ font-optical-sizing: auto;
+ font-weight: 300;
+ font-style: normal;
+ color: rgba(255, 255, 255, 0.8); /* Softer text for readability */
+ }
+
+ .rubik-h, .rubik-hmain, .rubik-hmain2, .rubik-hmain3 {
+ font-family: "Rubik", sans-serif;
+ font-optical-sizing: auto;
+ font-weight: 600;
+ font-style: normal;
+ }
+
+ .rubik-hmain {
+ font-size: xxx-large;
+ background: linear-gradient(90deg, #dfbac9, #cdc3ee);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ }
+
+ .rubik-hmain2 {
+ font-size: xx-large;
+ background: linear-gradient(90deg, #dfbac9, #cdc3ee);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ }
+
+ .rubik-hmain3 {
+ font-size: x-large;
+ background: linear-gradient(90deg, #dfbac9, #cdc3ee);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ margin-bottom: 15px;
+ }
+
+ /* Background */
+ body {
+ background-color: black;
+ margin: 0;
+ font-family: "Rubik", sans-serif;
+ }
+
+ /* Profile Card */
+ .profile_card {
+ background-color: rgb(22, 22, 22);
+ padding: 30px;
+ width: 300px;
+ border-radius: 35px;
+ border: 1px solid rgb(48, 48, 51);
+ color: #fff;
+ margin-left: 30px;
+ position: fixed;
+ left: 30px;
+ top: 50%;
+ transform: translateY(-50%);
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+ }
+
+ .avatar-img {
+ width: 100%;
+ border-radius: 35px;
+ border: 1px solid rgb(48, 48, 51);
+ }
+
+ /* Profile Bottom Section */
+ .profile_bot {
+ background: linear-gradient(to right, #e1b9c5, #d0c2e9);
+ border-radius: 25px;
+ width: 85%;
+ padding: 20px;
+ margin-top: 15px;
+ text-align: center;
+ color: #000;
+ margin-bottom: -60px;
+ }
+
+ /* Main Content */
+ .main {
+ margin-top: 40px;
+ margin-left: 460px;
+ color: rgba(255, 255, 255, 0.75);
+ }
+
+ /* Links */
+ a {
+ color: white;
+ text-decoration: none;
+ }
+
+ a:hover {
+ color: rgb(223, 185, 201);
+ }
+
+ a:active {
+ color: rgb(208, 193, 231);
+ }
+
+ /* Icons */
+ .icons {
+ display: inline;
+ height: 30px;
+ width: 30px;
+ margin-right: 5px;
+ }
+
+ .graph-container {
+ display: grid;
+ grid-template-rows: repeat(7, 15px); /* Days go from top to bottom */
+ grid-auto-flow: column; /* Columns represent weeks */
+ gap: 2px;
+ }
+ .day {
+ width: 15px;
+ height: 15px;
+ background-color: rgb(48,48,51);
+ border-radius: 2px;
+ position: relative;
+ }
+ .day[data-count="1"] { background-color: #0d4429 }
+ .day[data-count="2"] { background-color: #016c31 }
+ .day[data-count="3"] { background-color: #26a641 }
+ .day[data-count="4"] { background-color: #39d353; }
+ .tooltip {
+ display: none;
+ position: absolute;
+ background: #000;
+ color: #fff;
+ padding: 5px;
+ border-radius: 3px;
+ font-size: 10px;
+ white-space: nowrap;
+ z-index: 10;
+ pointer-events: none;
+ }
+ .day:hover .tooltip {
+ display: block;
+ top: -25px;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+ .month-labels {
+ display: flex;
+ justify-content: space-between;
+ padding: 0 5px;
+ }
+ .day-labels {
+ display: grid;
+ grid-template-rows: repeat(7, 15px);
+ gap: 2px;
+ }
+ .day-label {
+ font-size: 10px;
+ color: #666;
+ text-align: right;
+ margin-right: 5px;
+ }
+ .months {
+ margin-top: 20px;
+ }
\ No newline at end of file