From ed3ab770117111641caa8426558356cccc48ecdf Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 23 May 2026 07:39:51 +0000 Subject: [PATCH] Enhance Mastercard Dashboard with premium 1000px layout and more stats - Increased card width to 1000px for a "very very big" look. - Added user avatar, bio, followers, and following count. - Enlarged fonts, stats icons, and contribution heatmap. - Improved streak calculation logic and PR depth for lines changed. - Isolated all changes to Mastercard-related files. Co-authored-by: Chintanpatel24 <216989679+Chintanpatel24@users.noreply.github.com> --- api/master.js | 30 +++++++- src/svg-master.js | 180 +++++++++++++++++++++++++++------------------- 2 files changed, 133 insertions(+), 77 deletions(-) diff --git a/api/master.js b/api/master.js index 0c6f33c..0638ac1 100644 --- a/api/master.js +++ b/api/master.js @@ -74,7 +74,7 @@ module.exports = async (req, res) => { safe(fetchOpenPullRequests(username), 0) ]); - const linesChanged = await safe(fetchRecentPRLinesChanged(prs, 3), 0); + const linesChanged = await safe(fetchRecentPRLinesChanged(prs, 10), 0); const days = contributionData?.days || []; const sortedDays = [...days].sort((a, b) => a.date.localeCompare(b.date)); @@ -82,10 +82,28 @@ module.exports = async (req, res) => { let currentStreak = 0; let longestStreak = 0; let tempStreak = 0; + + // Corrected streak logic: find last day with activity and check if it's today/yesterday + const today = new Date().toISOString().split('T')[0]; + const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0]; + + let lastActiveIndex = -1; for (let i = sortedDays.length - 1; i >= 0; i--) { - if (sortedDays[i].count > 0) currentStreak++; - else if (i < sortedDays.length - 1) break; + if (sortedDays[i].count > 0) { + if (sortedDays[i].date === today || sortedDays[i].date === yesterday) { + lastActiveIndex = i; + } + break; + } } + + if (lastActiveIndex !== -1) { + for (let i = lastActiveIndex; i >= 0; i--) { + if (sortedDays[i].count > 0) currentStreak++; + else break; + } + } + for (const day of sortedDays) { if (day.count > 0) { tempStreak++; longestStreak = Math.max(longestStreak, tempStreak); } else tempStreak = 0; @@ -111,6 +129,12 @@ module.exports = async (req, res) => { data = { username: profile.login || username, name: profile.name || profile.login || username, + avatarUrl: profile.avatar_url || "", + bio: profile.bio || "", + location: profile.location || "", + company: profile.company || "", + followers: profile.followers || 0, + following: profile.following || 0, totalPRs: prs.length || 0, openPRs: openPRCount || 0, mergedPRs: mergedPRCount || 0, diff --git a/src/svg-master.js b/src/svg-master.js index b8eb19d..bdf4b98 100644 --- a/src/svg-master.js +++ b/src/svg-master.js @@ -1,5 +1,5 @@ /** - * Master Card SVG generation - Ultimate Profile Dashboard (830px). + * Master Card SVG generation - Ultimate Profile Dashboard (1000px). * Designed to cover the full width of a GitHub README with a high-end profile look. */ @@ -14,158 +14,190 @@ function escapeXml(s) { function generateMasterCardSVG(options) { const { - username, name, totalPRs = 0, openPRs = 0, mergedPRs = 0, repoCount = 0, + username, name, avatarUrl, bio, location, company, followers = 0, following = 0, + totalPRs = 0, openPRs = 0, mergedPRs = 0, repoCount = 0, languages = [], contributions = 0, totalCommits = 0, repoList = [], contributionDays = [], currentStreak = 0, longestStreak = 0, totalIssues = 0, openIssues = 0, closedIssues = 0, totalStars = 0, - linesChanged = 0, weekMap = {}, colors, hideBorder, cardWidth = 830 + linesChanged = 0, weekMap = {}, colors, hideBorder, cardWidth = 1000 } = options; - const pad = 32; + const pad = 40; const innerW = cardWidth - pad * 2; - const hba = hideBorder ? `rx="16"` : `rx="16" stroke="#30363d" stroke-width="2"`; + const hba = hideBorder ? `rx="20"` : `rx="20" stroke="#30363d" stroke-width="2"`; const accentColor = (colors && colors.accent_color) || "58a6ff"; const titleColor = (colors && colors.title_color) || "58a6ff"; const textColor = (colors && colors.text_color) || "c9d1d9"; + const bgColor = (colors && colors.bg_color) || "0d1117"; let y = 0; let content = ""; - // --- HEADER SECTION --- + // --- HEADER SECTION WITH AVATAR --- content += ` - - ${escapeXml(name || username)} - GitHub Profile @${escapeXml(username.toLowerCase())} - + + ${avatarUrl ? ` + + + + + + + ` : ``} + + + ${escapeXml(name || username)} + @${escapeXml(username.toLowerCase())} • ${repoCount} Repositories + ${bio ? `${escapeXml(bio.length > 80 ? bio.substring(0, 77) + '...' : bio)}` : ""} + + + + ${followers.toLocaleString()} + Followers + + ${following.toLocaleString()} + Following + `; - y = 135; + y = 180; + + content += ``; + y += 60; // --- MAIN STATS ROW --- const statW = Math.floor(innerW / 5); const heroStats = [ - { label: "Commits", value: totalCommits.toLocaleString(), color: accentColor }, - { label: "Stars", value: totalStars.toLocaleString(), color: "eab308" }, - { label: "PRs", value: totalPRs, color: "8b5cf6" }, - { label: "Issues", value: totalIssues, color: "f85149" }, + { label: "Total Commits", value: totalCommits.toLocaleString(), color: accentColor }, + { label: "Total Stars", value: totalStars.toLocaleString(), color: "eab308" }, + { label: "Pull Requests", value: totalPRs, color: "8b5cf6" }, + { label: "Issues Fixed", value: totalIssues, color: "f85149" }, { label: "Contributions", value: contributions.toLocaleString(), color: "39d353" }, ]; heroStats.forEach((s, i) => { content += ` - ${s.value} - ${s.label} + ${s.value} + ${s.label} `; }); - y += 90; + y += 100; - content += ``; - y += 45; + content += ``; + y += 60; - // --- MIDDLE GRID: Languages (Left) & Weekly Activity (Right) --- - const gridW = (innerW - 40) / 2; + // --- MIDDLE GRID --- + const gridW = (innerW - 60) / 2; - // Top Languages with bars + // Top Languages content += ` - Language Usage - `; + Language Dominance + `; const { getLanguageColor } = require("./languages"); - const topLangs = languages.slice(0, 7); + const topLangs = languages.slice(0, 8); topLangs.forEach((lang, i) => { - const ly = i * 28; - const barMax = gridW - 130; + const ly = i * 35; + const barMax = gridW - 150; const barW = (lang.percentage / 100) * barMax; content += ` - - ${escapeXml(lang.name)} - - - ${lang.percentage.toFixed(1)}% + + ${escapeXml(lang.name)} + + + ${lang.percentage.toFixed(1)}% `; }); content += ``; // Weekly Activity Chart - const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + const daysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; const maxWeekly = Math.max(...Object.values(weekMap), 1); - content += ` - Weekly Activity - `; + content += ` + Weekly Productivity + `; daysOfWeek.forEach((day, i) => { - const ly = i * 28; + const ly = i * 35; const count = weekMap[i] || 0; - const barW = (count / maxWeekly) * (gridW - 100); + const barW = (count / maxWeekly) * (gridW - 120); content += ` - ${day} - - - ${count.toLocaleString()} + ${day} + + + ${count.toLocaleString()} `; }); content += ``; - y += 240; - content += ``; - y += 45; + y += 330; + content += ``; + y += 60; - // --- LOWER GRID: PR Projects & Streaks --- + // --- LOWER GRID: Repos & Streaks --- content += ` - Top Active Repositories - `; - repoList.slice(0, 4).forEach((repo, i) => { - content += `• ${escapeXml(repo.name.length > 35 ? repo.name.substring(0, 32) + '...' : repo.name)} (${repo.count} PRs)`; + Top Contributions by Repository + `; + repoList.slice(0, 6).forEach((repo, i) => { + content += `• ${escapeXml(repo.name.length > 50 ? repo.name.substring(0, 47) + '...' : repo.name)} (${repo.count} PRs)`; }); content += ` - - Performance & Streaks - - - 🔥 Current Streak: ${currentStreak} Days - - - 🏆 All-time Best: ${longestStreak} Days + + Consistency & Momentum + + + 🔥 Current Streak: ${currentStreak} Days + + + 🏆 All-time Best: ${longestStreak} Days `; - y += 135; + y += 240; - content += ``; - y += 45; + content += ``; + y += 60; // --- FOOTER: CONTRIBUTION HEATMAP --- content += ` - Full Contribution History (Last 12 Months) - `; + Annual Contribution Heatmap + `; const sortedDays = [...contributionDays].sort((a, b) => String(a.date).localeCompare(String(b.date))); - const recent = sortedDays.slice(-371); - const cell = 11.5, gap = 3, step = cell + gap; + + // On 1000px width, we can fit more weeks. + // Standard GitHub heatmap is ~53 weeks. + // cell 14, gap 4 = 18 per week. 53 * 18 = 954. + const cell = 14, gap = 4, step = cell + gap; + const maxWeeks = Math.floor(innerW / step); + const recent = sortedDays.slice(-(maxWeeks * 7)); + recent.forEach((d, i) => { const col = Math.floor(i / 7); const row = i % 7; - content += ``; + content += ` + ${d.date}: ${d.count} contributions + `; }); content += ``; - y += 150; + y += 180; - const cardHeight = y + 45; + const cardHeight = y + 80; return ` - - + + - + - + ${content} - gitlyy full dashboard • updated every 30m + GITLYY ULTIMATE DASHBOARD • UPDATED EVERY 30M `; }