From b187fac5c4ee5a2e9bef8a18cd8ad3de50d04023 Mon Sep 17 00:00:00 2001 From: Meera Date: Sun, 7 Jun 2026 19:09:20 +0530 Subject: [PATCH 1/3] feat: redesign dashboard layout and improve visual hierarchy --- src/app/dashboard/page.tsx | 31 +++++---- .../dashboard/CustomizableDashboard.tsx | 66 +++++++++++-------- .../dashboard/DashboardLayoutToolbar.tsx | 41 ++++++------ .../dashboard/SortableDashboardWidget.tsx | 16 ++--- 4 files changed, 84 insertions(+), 70 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 3c7a6a7d..3ee7eec7 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -21,19 +21,19 @@ export default async function DashboardPage() { {/* Quick actions */} -
+
{/* Left side actions */}
Year in Code Settings @@ -44,32 +44,35 @@ export default async function DashboardPage() {
-
+ {/* Info Banners */} +
-
+ {/* Today Focus Section */} +
-
-
-
+ {/* Featured Section */} +
+
+
- + New Feature - + AI Resume Generator
-

+

Generate an ATS-Friendly CV Backed by Your Real Code

-

+

Analyze your GitHub contributions, merged PRs, and lines of code changed to automatically generate professional bullet points for your target roles. @@ -78,10 +81,10 @@ export default async function DashboardPage() { Build Resume - +

diff --git a/src/components/dashboard/CustomizableDashboard.tsx b/src/components/dashboard/CustomizableDashboard.tsx index d294b629..803277d2 100644 --- a/src/components/dashboard/CustomizableDashboard.tsx +++ b/src/components/dashboard/CustomizableDashboard.tsx @@ -62,7 +62,7 @@ const SkeletonCard = () => ( role="status" aria-busy="true" aria-live="polite" - className="rounded-xl border border-[var(--border)] bg-[var(--card)] p-6 shadow-sm" + className="rounded-xl border border-[var(--border)] bg-[var(--card)] p-7 shadow-sm hover:shadow-md transition-shadow duration-200" >
@@ -70,20 +70,20 @@ const SkeletonCard = () => ( ); const ContributionGraphSkeleton = () => ( -
+

Your Commits

-
+
); const PRMetricsSkeleton = () => ( -
+

PR Analytics

-
+
); @@ -150,27 +150,27 @@ const SECTION_ANCHOR_IDS: Record = { }; const SECTION_ACCENT_CLASSES: Record = { - overview: "bg-[var(--accent)] shadow-[0_0_15px_var(--accent)]", - activity: "bg-emerald-500 shadow-[0_0_15px_rgba(16,185,129,0.5)]", - analytics: "bg-blue-500 shadow-[0_0_15px_rgba(59,130,246,0.5)]", - goals: "bg-purple-500 shadow-[0_0_15px_rgba(168,85,247,0.5)]", + overview: "h-1 bg-gradient-to-r from-[var(--accent)] to-[var(--accent)]/60 rounded-full shadow-md", + activity: "h-1 bg-gradient-to-r from-emerald-500 to-emerald-500/60 rounded-full shadow-md", + analytics: "h-1 bg-gradient-to-r from-blue-500 to-blue-500/60 rounded-full shadow-md", + goals: "h-1 bg-gradient-to-r from-purple-500 to-purple-500/60 rounded-full shadow-md", }; const SECTION_GRID_CLASSES: Record = { - overview: "grid grid-cols-1 xl:grid-cols-2 gap-6 w-full", - activity: "grid grid-cols-1 xl:grid-cols-3 gap-6 w-full", - analytics: "grid grid-cols-1 lg:grid-cols-2 gap-6 w-full", - goals: "grid grid-cols-1 xl:grid-cols-3 gap-6 w-full", + overview: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6 w-full", + activity: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full", + analytics: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-6 w-full", + goals: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full", }; const WIDGET_SPAN_CLASSES: Partial> = { - "weekly-summary": "xl:col-span-2", - "contribution-graph": "xl:col-span-2", - "repo-analytics": "lg:col-span-2", - "issue-metrics": "xl:col-span-2", - "goal-tracker": "xl:col-span-2", - "daily-note": "xl:col-span-2", - "recent-activity": "xl:col-span-2", + "weekly-summary": "md:col-span-2 lg:col-span-2", + "contribution-graph": "md:col-span-2 lg:col-span-2", + "repo-analytics": "md:col-span-2 lg:col-span-2", + "issue-metrics": "md:col-span-2 lg:col-span-2", + "goal-tracker": "md:col-span-2 lg:col-span-2", + "daily-note": "md:col-span-2 lg:col-span-2", + "recent-activity": "md:col-span-2 lg:col-span-2", }; const isDashboardWidgetId = ( @@ -522,7 +522,7 @@ export default function CustomizableDashboard() { }; return ( -
+
-
+
-

- {DASHBOARD_SECTION_LABELS[sectionId]} -

+
+

+ {DASHBOARD_SECTION_LABELS[sectionId]} +

+

+ {sectionId === "overview" && "Quick summary of your development profile"} + {sectionId === "activity" && "Your coding patterns and contributions"} + {sectionId === "analytics" && "In-depth analysis of your repositories and code"} + {sectionId === "goals" && "Track progress, milestones, and insights"} +

+
-
+
{sectionWidgets.map((widgetId) => ( -
-
-

- Dashboard Layout +
+
+
+

+

-

- Reorder widgets, hide unused cards, and reset the dashboard anytime. +

+ Reorder widgets by dragging, hide cards you don't need, and reset to default anytime.

-
+
{isEditing ? ( ) : null}
{isEditing ? ( -
-

- Hidden widgets +
+

+

{hiddenWidgets.length > 0 ? ( -
+
{hiddenWidgets.map((widgetId) => (
) : ( -

- No widgets are hidden. +

+ ✓ All widgets are visible. No hidden widgets to restore.

)}
diff --git a/src/components/dashboard/SortableDashboardWidget.tsx b/src/components/dashboard/SortableDashboardWidget.tsx index 8f4acb31..56bb74e4 100644 --- a/src/components/dashboard/SortableDashboardWidget.tsx +++ b/src/components/dashboard/SortableDashboardWidget.tsx @@ -46,16 +46,16 @@ export default function SortableDashboardWidget({ ref={setNodeRef} style={style} className={`relative min-w-0 ${className} ${ - isDragging ? "opacity-70" : "" - }`} + isDragging ? "opacity-60 scale-95" : "" + } transition-all duration-150`} > {isEditing ? ( -
+
@@ -77,8 +77,8 @@ export default function SortableDashboardWidget({
{children} From 40ba3e4919592e3e21591c294eccee7b2a9e4e77 Mon Sep 17 00:00:00 2001 From: Meera Date: Sun, 7 Jun 2026 19:14:03 +0530 Subject: [PATCH 2/3] feat: redesign dashboard layout and improve visual hierarchy --- src/components/dashboard/DashboardLayoutToolbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/DashboardLayoutToolbar.tsx b/src/components/dashboard/DashboardLayoutToolbar.tsx index 42c23171..a15465f8 100644 --- a/src/components/dashboard/DashboardLayoutToolbar.tsx +++ b/src/components/dashboard/DashboardLayoutToolbar.tsx @@ -30,7 +30,7 @@ export default function DashboardLayoutToolbar({ Customize Your Dashboard

- Reorder widgets by dragging, hide cards you don't need, and reset to default anytime. + Reorder widgets by dragging, hide cards you don't need, and reset to default anytime.

From 597a7394b521a92e691270d2de8522d2e109451d Mon Sep 17 00:00:00 2001 From: Meera Date: Mon, 8 Jun 2026 21:21:07 +0530 Subject: [PATCH 3/3] 'feat/dashboard-ui-refinement-1547' --- e2e/dashboard-widgets.spec.js | 23 ++++++++++++++++++++++- e2e/notifications.spec.js | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/e2e/dashboard-widgets.spec.js b/e2e/dashboard-widgets.spec.js index 8612d2e3..7ba431bc 100644 --- a/e2e/dashboard-widgets.spec.js +++ b/e2e/dashboard-widgets.spec.js @@ -179,6 +179,27 @@ test.beforeEach(async ({ page }) => { body: "data: {}\n\n", }); }); + + await page.route("**/api/user/dashboard-layout**", async (route) => { + if (route.request().method() === "GET") { + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ layout: null }), + }); + } else { + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ ok: true }), + }); + } + }); + + await page.route("**/api/daily-note**", async (route) => { + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ note: null }), + }); + }); }); test("dashboard widgets render with mocked metrics", async ({ page }) => { await page.goto("/dashboard", { waitUntil: "load" }); @@ -329,7 +350,7 @@ function mockMetricResponse(url) { }; } if (url.includes("/api/streak/freeze")) { - return { freezes: [] }; + return { hasFreeze: false, freezeDate: null }; } if (url.includes("/api/integrations/jira")) { return null; diff --git a/e2e/notifications.spec.js b/e2e/notifications.spec.js index be4320a0..a92717b4 100644 --- a/e2e/notifications.spec.js +++ b/e2e/notifications.spec.js @@ -153,6 +153,10 @@ test.beforeEach(async ({ page }) => { }); }); + await page.route("**/api/notifications**", async (route) => { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ notifications: [], unreadCount: 0 }) }); + }); + await page.route("**/api/user/github-accounts", async (route) => { await route.fulfill({ contentType: "application/json", @@ -255,6 +259,10 @@ test.beforeEach(async ({ page }) => { }); } + await page.route("**/api/streak/freeze**", async (route) => { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ hasFreeze: false, freezeDate: null }) }); + }); + await page.route("**/api/stream**", async (route) => { await route.fulfill({ status: 200, @@ -262,6 +270,18 @@ test.beforeEach(async ({ page }) => { body: "data: {}\n\n", }); }); + + await page.route("**/api/user/dashboard-layout**", async (route) => { + if (route.request().method() === "GET") { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ layout: null }) }); + } else { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ ok: true }) }); + } + }); + + await page.route("**/api/daily-note**", async (route) => { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ note: null }) }); + }); }); test("notification bell opens and closes drawer", async ({ page }) => {