diff --git a/frontend/styles/main.css b/frontend/styles/main.css index 108c72a1..0ae71419 100644 --- a/frontend/styles/main.css +++ b/frontend/styles/main.css @@ -2861,7 +2861,8 @@ body::-webkit-scrollbar-thumb { .rank-change[data-tooltip]::before { content: attr(data-tooltip); position: absolute; - bottom: 140%; + bottom: 140%; /* Default position */ + top: auto; left: 50%; transform: translateX(-50%); background: var(--bg-raised); @@ -2879,6 +2880,11 @@ body::-webkit-scrollbar-thumb { transition: opacity 0.15s ease-in-out; box-shadow: 0 0 15px rgba(0, 255, 65, 0.2); } +/* Prevent tooltip from overlapping the sticky header */ +.leaderboard-row:nth-child(-n + 3) .rank-change[data-tooltip]::before { + top: 140%; + bottom: auto; +} .rank-change[data-tooltip]:hover::before { opacity: 1; diff --git a/scripts/fetch-user-info.js b/scripts/fetch-user-info.js index 76af9ca3..a27f390e 100644 --- a/scripts/fetch-user-info.js +++ b/scripts/fetch-user-info.js @@ -1,4 +1,5 @@ async function fetchUserInfo(username) { + let liveSolved = null; const usernameRegex = /^[a-zA-Z0-9_-]+$/; if (!username || !usernameRegex.test(username)) { throw new Error("Invalid username format"); @@ -50,23 +51,47 @@ async function fetchUserInfo(username) { } // 2. Fetch live profile ranking from the wrapper API - const livePromise = fetch(liveApiUrl).then(async (res) => { - if (res.ok) { - const apiData = await res.json(); - ranking = apiData.ranking || 0; - contest = apiData.contest || null; - } else { - throw new Error(`LeetCode API wrapper returned status ${res.status}`); - } - }); + const res = await fetch(liveApiUrl); + + if (!res.ok) { + throw new Error(`LeetCode API wrapper returned status ${res.status}`); + } + + const apiData = await res.json(); + + liveSolved = { + easy: apiData.easySolved, + medium: apiData.mediumSolved, + hard: apiData.hardSolved, + }; - // Wait for the live API task to complete - await livePromise; + ranking = apiData.ranking || 0; + contest = apiData.contest || null; // Ensure history is sorted chronologically // Guard against a corrupted history file (e.g. non-array `history` field) history = Array.isArray(history) ? history : []; history.sort((a, b) => new Date(a.date) - new Date(b.date)); + const today = new Date().toISOString().split("T")[0]; + let latestEntry = null; + + for (let i = history.length - 1; i >= 0; i--) { + const entry = history[i]; + + if ( + typeof entry.date === "string" && + entry.date.startsWith(today) + ) { + latestEntry = entry; + break; + } + } + + if (latestEntry && liveSolved) { + latestEntry.easy = liveSolved.easy; + latestEntry.medium = liveSolved.medium; + latestEntry.hard = liveSolved.hard; + } return { username,