From e34edaed60c6eb3968fd7011f09daee83f4624cb Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 17:32:11 +0530 Subject: [PATCH 1/7] feat: add dashboard activity overview --- src/dashboard/DashboardPage.jsx | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index 5983c87..b40ef8d 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -88,6 +88,10 @@ export default function DashboardPage() { const totalProjects = stats?.totalProjects ?? projects.length; const totalStars = stats?.totalStars ?? sumNumber(projects, "stars"); const totalForks = stats?.totalForks ?? sumNumber(projects, "forks"); + const languagesUsed = uniqueValues([ + ...projects.map((project) => project.language), + ...problems.map((problem) => problem.language), + ]).length; const byPlatform = problems.reduce((acc, problem) => { const key = problem.platform || "Custom"; @@ -207,8 +211,9 @@ export default function DashboardPage() { { label: "Total Problems", value: totalProblems }, { label: "Verified Problems", value: verifiedProblems }, { label: "Total Projects", value: totalProjects }, - { label: "Total Stars", value: totalStars }, - { label: "Total Forks", value: totalForks }, + { label: "Languages Used", value: languagesUsed }, + { label: "GitHub Stars", value: totalStars }, + { label: "GitHub Forks", value: totalForks }, ], platformCards, languageCards, @@ -234,6 +239,23 @@ export default function DashboardPage() { align="left" /> + {!loading && !error ? ( + +
+ {analytics.overview.map((metric) => ( +
+ {metric.label} +

{metric.value}

+
+ ))} +
+
+ ) : null} + {loading ? ( From 7faca08c0a1c4a8421c33272e5f5dc99b3745a9b Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 17:37:30 +0530 Subject: [PATCH 2/7] feat: add dashboard coding process --- src/App.css | 56 ++++++++++++++++++++ src/dashboard/DashboardPage.jsx | 91 +++++++++++++++++++++++++++------ 2 files changed, 130 insertions(+), 17 deletions(-) diff --git a/src/App.css b/src/App.css index 3215c8f..f465e65 100644 --- a/src/App.css +++ b/src/App.css @@ -1324,6 +1324,62 @@ textarea:focus-visible { background: linear-gradient(90deg, var(--accent-color), color-mix(in srgb, var(--accent-color) 70%, #22c55e)); } +.dashboard-progress .progress-stack { + display: grid; + gap: 16px; +} + +.progress-row { + display: grid; + gap: 10px; +} + +.progress-label { + display: flex; + justify-content: space-between; + gap: 12px; + align-items: center; + color: var(--text-color); + font-weight: 700; +} + +.progress-bar { + height: 12px; + border-radius: 999px; + background: color-mix(in srgb, var(--accent-color) 14%, var(--card-bg)); + overflow: hidden; +} + +.progress-bar span { + display: block; + height: 100%; + border-radius: inherit; + background: linear-gradient(90deg, var(--accent-color), color-mix(in srgb, var(--accent-color) 70%, #22c55e)); +} + +.tag-chip-list { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 16px; +} + +.tag-chip { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 14px; + border-radius: 999px; + border: 1px solid color-mix(in srgb, var(--accent-color) 16%, transparent); + background: color-mix(in srgb, var(--accent-color) 8%, var(--card-bg)); + color: var(--text-color); + font-size: 0.92rem; +} + +.tag-chip strong { + font-weight: 700; +} + .timeline-list { display: grid; gap: 18px; margin-bottom: 28px; } .timeline-item { display: grid; diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index b40ef8d..cb2aeac 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -134,6 +134,7 @@ export default function DashboardPage() { const difficultyCards = difficultyOrder.map((name) => ({ name, count: byDifficulty[name] || 0, + percentage: percent(byDifficulty[name] || 0, totalProblems), })); const byTag = problems.reduce((acc, problem) => { @@ -143,10 +144,10 @@ export default function DashboardPage() { return acc; }, {}); - const tagCards = trackedTags.map((name) => ({ - name, - count: byTag[name] || 0, - })); + const tagCards = Object.entries(byTag) + .sort(([, countA], [, countB]) => countB - countA) + .slice(0, 6) + .map(([name, count]) => ({ name, count })); const problemsWithDate = problems.filter( (problem) => problem.addedAt || problem.createdAt || problem.updatedAt || problem.solvedAt @@ -240,21 +241,77 @@ export default function DashboardPage() { /> {!loading && !error ? ( - -
- {analytics.overview.map((metric) => ( -
- {metric.label} -

{metric.value}

-
- ))} + <> + +
+ {analytics.overview.map((metric) => ( +
+ {metric.label} +

{metric.value}

+
+ ))} +
+
+ + +
+
+

Difficulty Progress

+
+ {analytics.difficultyCards.map((item) => ( +
+
+ {item.name} + {item.count} +
+
+ +
+
+ ))} +
+
+ +
+

Platform Breakdown

+
+ {analytics.platformCards.map((item) => ( +
+
+ {item.name} + {item.count} +
+
+ +
+
+ ))} +
+
+ +
+

Top Topics

+
+ {analytics.tagCards.map((item) => ( + + {item.name} + {item.count} + + ))} +
+
- ) : null} + ) : null} {loading ? ( From 9860f5c69917b489f062007c8ef1fe8e9b16a95b Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 17:45:22 +0530 Subject: [PATCH 3/7] feat: add dashboard technology usage --- src/dashboard/DashboardPage.jsx | 89 ++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index cb2aeac..517a9a2 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -31,6 +31,26 @@ const languageOrder = [ const difficultyOrder = ["Easy", "Medium", "Hard"]; const trackedTags = ["Array", "Hash Map", "String", "Tree", "Graph", "DP"]; +const technologyAliases = { + js: "JavaScript", + javascript: "JavaScript", + ts: "TypeScript", + typescript: "TypeScript", + react: "React", + reactjs: "React", + node: "Node.js", + "node.js": "Node.js", + nodejs: "Node.js", + "c lang": "C", + c: "C", +}; + +function normalizeTechnology(value) { + if (!value || typeof value !== "string") return ""; + const normalized = value.trim().toLowerCase(); + return technologyAliases[normalized] || value.trim(); +} + function percent(value, total) { if (!total) return "0%"; return `${Math.round((value / total) * 100)}%`; @@ -149,6 +169,46 @@ export default function DashboardPage() { .slice(0, 6) .map(([name, count]) => ({ name, count })); + const technologyCandidates = []; + + projects.forEach((project) => { + const projectLanguage = normalizeTechnology(project.language); + if (projectLanguage) technologyCandidates.push(projectLanguage); + + (project.topics || []).forEach((topic) => { + const normalizedTopic = normalizeTechnology(topic); + if (normalizedTopic) technologyCandidates.push(normalizedTopic); + }); + }); + + problems.forEach((problem) => { + const solutionLanguages = Array.isArray(problem.solutions) + ? problem.solutions.map((solution) => normalizeTechnology(solution.language)).filter(Boolean) + : []; + + if (solutionLanguages.length) { + technologyCandidates.push(...solutionLanguages); + } else { + const fallbackLanguage = normalizeTechnology(problem.language); + if (fallbackLanguage) technologyCandidates.push(fallbackLanguage); + } + }); + + const technologyCounts = technologyCandidates.reduce((acc, tech) => { + if (!tech) return acc; + acc[tech] = (acc[tech] || 0) + 1; + return acc; + }, {}); + + const technologyCards = Object.entries(technologyCounts) + .sort(([, countA], [, countB]) => countB - countA) + .slice(0, 10) + .map(([name, count]) => ({ + name, + count, + percentage: percent(count, technologyCandidates.length), + })); + const problemsWithDate = problems.filter( (problem) => problem.addedAt || problem.createdAt || problem.updatedAt || problem.solvedAt ); @@ -220,6 +280,7 @@ export default function DashboardPage() { languageCards, difficultyCards, tagCards, + technologyCards, timelineCards, projectInsights: { byStars, @@ -263,7 +324,7 @@ export default function DashboardPage() { title="Coding Progress" description="Problem solving performance and platform, difficulty, and topic distributions from live coding-journal problem data." > -
+

Difficulty Progress

@@ -311,6 +372,32 @@ export default function DashboardPage() {
+ + +
+
+

Top Technologies

+
+ {analytics.technologyCards.map((item) => ( +
+
+ {item.name} + {item.count} +
+
+ +
+
+ ))} +
+
+
+
) : null} {loading ? ( From 66c8393b1540a7f8c3164199466650fa7487ae72 Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 17:57:58 +0530 Subject: [PATCH 4/7] feat: add dashboard career focus cards --- src/App.css | 16 ++++++++++++++ src/dashboard/DashboardPage.jsx | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/App.css b/src/App.css index f465e65..7681516 100644 --- a/src/App.css +++ b/src/App.css @@ -1380,6 +1380,22 @@ textarea:focus-visible { font-weight: 700; } +.career-list { + display: grid; + gap: 12px; + padding-left: 0; + margin: 18px 0 0; + list-style: none; +} + +.career-list li { + color: var(--text-secondary); + padding: 14px 16px; + border-radius: 16px; + background: color-mix(in srgb, var(--card-bg) 92%, transparent); + border: 1px solid color-mix(in srgb, var(--accent-color) 12%, transparent); +} + .timeline-list { display: grid; gap: 18px; margin-bottom: 28px; } .timeline-item { display: grid; diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index 517a9a2..7010323 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -398,6 +398,45 @@ export default function DashboardPage() {
+ + +
+
+

Current Focus

+
    +
  • MCA @ Bangalore University
  • +
  • React Development
  • +
  • Node.js APIs
  • +
  • DSA Problem Solving
  • +
  • Full Stack Projects
  • +
  • coding-journal
  • +
+
+ +
+

Open To Work

+
    +
  • Remote Internship
  • +
  • Part-Time Developer Roles
  • +
  • Freelance Projects
  • +
  • React Development
  • +
  • Full Stack Development
  • +
+
+ + Contact Me + + + View Projects + +
+
+
+
) : null} {loading ? ( From e1015ed71c165b3781b6038cb57211adc9420743 Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 18:20:39 +0530 Subject: [PATCH 5/7] feat: add dashboard recent activity --- src/dashboard/DashboardPage.jsx | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index 7010323..609f95f 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -5,6 +5,9 @@ import { getJournalProblems, getJournalProjects, getJournalStats, + getProblemLanguages, + toPlatformSegment, + toProjectSlug, sumNumber, uniqueValues, } from "../lib/codingJournal"; @@ -209,6 +212,44 @@ export default function DashboardPage() { percentage: percent(count, technologyCandidates.length), })); + const recentVerifiedProblems = [...problems] + .filter((problem) => problem.verified) + .sort((a, b) => { + const dateA = new Date(a.solvedAt || a.updatedAt || a.createdAt || 0).getTime(); + const dateB = new Date(b.solvedAt || b.updatedAt || b.createdAt || 0).getTime(); + const hasDateA = Boolean(dateA); + const hasDateB = Boolean(dateB); + + if (hasDateA && hasDateB) return dateB - dateA; + if (hasDateA) return -1; + if (hasDateB) return 1; + return 0; + }) + .slice(0, 6) + .map((problem) => ({ + ...problem, + languageCount: getProblemLanguages(problem).length, + platformSegment: toPlatformSegment(problem.platform), + })); + + const recentProjects = [...projects] + .sort((a, b) => { + const dateA = new Date(a.updatedAt || 0).getTime(); + const dateB = new Date(b.updatedAt || 0).getTime(); + const hasDateA = Boolean(dateA); + const hasDateB = Boolean(dateB); + + if (hasDateA && hasDateB) return dateB - dateA; + if (hasDateA) return -1; + if (hasDateB) return 1; + return 0; + }) + .slice(0, 6) + .map((project) => ({ + ...project, + slug: toProjectSlug(project.name), + })); + const problemsWithDate = problems.filter( (problem) => problem.addedAt || problem.createdAt || problem.updatedAt || problem.solvedAt ); @@ -281,6 +322,8 @@ export default function DashboardPage() { difficultyCards, tagCards, technologyCards, + recentVerifiedProblems, + recentProjects, timelineCards, projectInsights: { byStars, @@ -437,6 +480,53 @@ export default function DashboardPage() {
+ + +
+ {analytics.recentVerifiedProblems.map((problem) => ( +
+
+ {problem.platform} + {problem.difficulty || "Unknown"} +
+

{problem.title}

+

{problem.languageCount} solution language{problem.languageCount === 1 ? "" : "s"}

+
+ Verified + + View Problem + +
+
+ ))} +
+
+ + +
+ {analytics.recentProjects.map((project) => ( +
+
+ {project.language || "Unknown"} + ⭐ {project.stars || 0} +
+

{project.name}

+

{project.forks || 0} forks • Updated {formatDate(project.updatedAt) || "Unknown"}

+ + View Project + +
+ ))} +
+
) : null} {loading ? ( From 7328e325b30b8a22c4cd07609fea8731f2a001b5 Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 18:35:59 +0530 Subject: [PATCH 6/7] feat: add dashboard build in public timeline --- src/dashboard/DashboardPage.jsx | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index 609f95f..9bc1fb1 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -250,6 +250,44 @@ export default function DashboardPage() { slug: toProjectSlug(project.name), })); + const timelineEvents = [ + ...projects + .filter((project) => project.updatedAt) + .map((project) => ({ + type: "Project Updated", + title: project.name, + date: new Date(project.updatedAt), + description: project.description + ? `Updated project ${project.name} on coding-journal.` + : `Updated project ${project.name}.`, + link: `/projects/${toProjectSlug(project.name)}`, + badge: project.language || "Project", + })), + ...problems + .filter((problem) => problem.solvedAt || problem.updatedAt) + .map((problem) => ({ + type: "Problem Solved", + title: problem.title, + date: new Date(problem.solvedAt || problem.updatedAt), + description: `Solved on ${problem.platform || "a platform"} with ${problem.difficulty || "unknown"} difficulty.`, + link: `/problems/${toPlatformSegment(problem.platform)}/${problem.slug}`, + badge: problem.platform || "Problem", + })), + ...problems + .filter((problem) => problem.verified && (problem.solvedAt || problem.updatedAt || problem.createdAt)) + .map((problem) => ({ + type: "Solution Verified", + title: problem.title, + date: new Date(problem.solvedAt || problem.updatedAt || problem.createdAt), + description: `Verified solution for ${problem.title} on ${problem.platform || "a platform"}.`, + link: `/problems/${toPlatformSegment(problem.platform)}/${problem.slug}`, + badge: "Verified", + })), + ] + .filter((event) => !Number.isNaN(event.date.getTime())) + .sort((a, b) => b.date.getTime() - a.date.getTime()) + .slice(0, 8); + const problemsWithDate = problems.filter( (problem) => problem.addedAt || problem.createdAt || problem.updatedAt || problem.solvedAt ); @@ -527,6 +565,37 @@ export default function DashboardPage() { ))}
+ + +
+ {analytics.timelineEvents.length ? ( + analytics.timelineEvents.map((event) => ( +
+ {formatDate(event.date)} +
+
+

{event.title}

+ {event.type} +
+

{event.description}

+ + View Details + +
+
+ )) + ) : ( +
+

No public build events available

+

There are currently not enough dated project or problem events in the live coding-journal feed to build a timeline.

+
+ )} +
+
) : null} {loading ? ( From 938852f2beb0a075a4365702ee6a11cf61c1bf7e Mon Sep 17 00:00:00 2001 From: SunilKumarKV Date: Tue, 16 Jun 2026 18:51:45 +0530 Subject: [PATCH 7/7] fix: guard dashboard timeline events --- src/dashboard/DashboardPage.jsx | 50 ++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/dashboard/DashboardPage.jsx b/src/dashboard/DashboardPage.jsx index 9bc1fb1..a3aafad 100644 --- a/src/dashboard/DashboardPage.jsx +++ b/src/dashboard/DashboardPage.jsx @@ -572,29 +572,35 @@ export default function DashboardPage() { description="Real timeline events generated from project updates, verified solutions, and solved problems in coding-journal." >
- {analytics.timelineEvents.length ? ( - analytics.timelineEvents.map((event) => ( -
- {formatDate(event.date)} -
-
-

{event.title}

- {event.type} -
-

{event.description}

- - View Details - -
-
- )) - ) : ( -
-

No public build events available

-

There are currently not enough dated project or problem events in the live coding-journal feed to build a timeline.

-
- )} + {(analytics.timelineEvents || []).length ? ( + (analytics.timelineEvents || []).map((event) => ( +
+ {formatDate(event.date) || "Unknown"} +
+
+

{event.title}

+ {event.type}
+

{event.description}

+ + View Details + +
+
+ )) + ) : ( +
+

No public build events available

+

+ There are currently not enough dated project or problem events in the live + coding-journal feed to build a timeline. +

+
+ )} +
) : null}