Skip to content

Commit feb769b

Browse files
Zeff01claude
andcommitted
feat: enhance current projects UI on home page dashboard
- Improved visual structure with cleaner card design - Larger project images (48x48) for better visibility - Enhanced status badges with better colors for light/dark modes - Added hover effects with border transitions and accent bar - Better role display with formatting and visual indicators - Polished empty state with icon and helpful message - Maintained existing layout while improving polish and readability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d74bbe6 commit feb769b

1 file changed

Lines changed: 78 additions & 45 deletions

File tree

‎apps/codebility/app/home/(dashboard)/_components/DashboardCurrentProject.tsx‎

Lines changed: 78 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -130,74 +130,107 @@ const DashboardCurrentProject = () => {
130130
function getStatusClass(status: string | undefined) {
131131
switch (status) {
132132
case "pending":
133-
return "text-white bg-orange-500/80";
133+
return "bg-orange-100 text-orange-700 dark:bg-orange-900/20 dark:text-orange-400 border-orange-300 dark:border-orange-700";
134134
case "completed":
135-
return "text-white bg-blue-500/80";
135+
return "bg-blue-100 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400 border-blue-300 dark:border-blue-700";
136136
case "active":
137-
return "text-white bg-green-500/80";
137+
case "inprogress":
138+
return "bg-green-100 text-green-700 dark:bg-green-900/20 dark:text-green-400 border-green-300 dark:border-green-700";
138139
default:
139-
return "text-white bg-black-500/80";
140+
return "bg-gray-100 text-gray-700 dark:bg-gray-900/20 dark:text-gray-400 border-gray-300 dark:border-gray-700";
141+
}
142+
}
143+
144+
// Get role display text
145+
function getRoleDisplay(role: string) {
146+
switch (role) {
147+
case "team_leader":
148+
return "Team Leader";
149+
case "member":
150+
return "Member";
151+
case "developer":
152+
return "Developer";
153+
default:
154+
return role.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
140155
}
141156
}
142157

143158
return (
144-
<Box className="flex w-full flex-1 flex-col gap-4">
145-
<p className="text-2xl">Current Projects</p>
159+
<Box className="flex w-full flex-1 flex-col gap-5">
160+
<div className="flex items-center justify-between">
161+
<h2 className="text-2xl font-semibold">Current Projects</h2>
162+
<span className="text-sm text-muted-foreground">
163+
{projects.length} {projects.length === 1 ? 'project' : 'projects'}
164+
</span>
165+
</div>
166+
146167
{projects.length > 0 ? (
147-
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
168+
<div className="grid grid-cols-1 gap-3 md:grid-cols-2">
148169
{projects.map((involvement) => (
149170
<DashboardCurrentProjectButton
150171
key={involvement.project.id}
151172
projectId={involvement.project.id}
152173
>
153-
<div className="p-[1px] rounded-md bg-gradient-to-r from-purple-200 via-blue-50 to-sky-300 dark:from-purple-800 dark:via-blue-300 dark:to-sky-950 p-2 hover:shadow-lg hover:shadow-blue-500/50 dark:hover:shadow-blue-400/50">
154-
<div className="flex items-center gap-2">
155-
{/* Enhanced image handling with fallback */}
156-
<div className="relative h-8 w-8 flex-shrink-0">
157-
<Image
158-
src={getProjectImageSrc(involvement.project)}
159-
alt={`${involvement.project.name} project icon`}
160-
width={32}
161-
height={32}
162-
className="rounded object-cover"
163-
onError={() => handleImageError(involvement.project.id)}
164-
// Add unoptimized for external URLs
165-
unoptimized={getProjectImageSrc(involvement.project).includes('http')}
166-
/>
167-
</div>
174+
<div className="group relative overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 transition-all duration-200 hover:border-customBlue-400 dark:hover:border-customBlue-600 hover:shadow-md">
175+
<div className="p-4">
176+
<div className="flex items-center gap-3">
177+
{/* Project Image */}
178+
<div className="relative h-12 w-12 flex-shrink-0 overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-800">
179+
<Image
180+
src={getProjectImageSrc(involvement.project)}
181+
alt={`${involvement.project.name} project icon`}
182+
width={48}
183+
height={48}
184+
className="h-full w-full object-cover transition-transform duration-200 group-hover:scale-110"
185+
onError={() => handleImageError(involvement.project.id)}
186+
unoptimized={getProjectImageSrc(involvement.project).includes('http')}
187+
/>
188+
</div>
168189

169-
<div className="flex min-w-0 flex-1 items-center justify-between">
170-
<div className="flex min-w-0 flex-col">
171-
<p className="truncate text-sm font-medium">
172-
{involvement.project.name}
173-
</p>
174-
<p className="text-start text-xs text-muted-foreground">
175-
{involvement.role === "member"
176-
? "Member"
177-
: involvement.role}
190+
{/* Project Info */}
191+
<div className="flex min-w-0 flex-1 flex-col gap-1">
192+
<div className="flex items-start justify-between gap-2">
193+
<h3 className="truncate text-base font-semibold text-gray-900 dark:text-white">
194+
{involvement.project.name}
195+
</h3>
196+
<Badge
197+
variant="outline"
198+
className={`shrink-0 text-xs font-medium ${getStatusClass(involvement.project.status)}`}
199+
>
200+
{involvement.project.status === "inprogress"
201+
? "In Progress"
202+
: involvement.project.status
203+
? involvement.project.status.charAt(0).toUpperCase() +
204+
involvement.project.status.slice(1)
205+
: "Unknown"}
206+
</Badge>
207+
</div>
208+
<p className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400">
209+
<span className="inline-block h-1.5 w-1.5 rounded-full bg-customBlue-500"></span>
210+
{getRoleDisplay(involvement.role)}
178211
</p>
179212
</div>
180-
<Badge
181-
variant="outline"
182-
className={`ml-2 shrink-0 whitespace-nowrap text-xs ${getStatusClass(involvement.project.status)}`}
183-
>
184-
{involvement.project.status === "inprogress"
185-
? "In Progress"
186-
: involvement.project.status
187-
? involvement.project.status.charAt(0).toUpperCase() +
188-
involvement.project.status.slice(1)
189-
: "Unknown"}
190-
</Badge>
191213
</div>
192214
</div>
215+
216+
{/* Hover accent */}
217+
<div className="absolute bottom-0 left-0 h-1 w-full bg-gradient-to-r from-customBlue-500 to-purple-500 transform scale-x-0 transition-transform duration-200 group-hover:scale-x-100" />
193218
</div>
194219
</DashboardCurrentProjectButton>
195220
))}
196221
</div>
197222
) : (
198-
<p className="text-sm text-muted-foreground">
199-
No project involvements yet
200-
</p>
223+
<div className="flex flex-col items-center justify-center rounded-lg border border-dashed border-gray-300 dark:border-gray-700 bg-gray-50/50 dark:bg-gray-900/50 py-12 px-6 text-center">
224+
<div className="mb-3 rounded-full bg-gray-100 dark:bg-gray-800 p-3">
225+
<svg className="h-6 w-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
226+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
227+
</svg>
228+
</div>
229+
<p className="text-sm font-medium text-gray-900 dark:text-gray-100">No projects yet</p>
230+
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
231+
You'll see your active projects here once you're assigned to one
232+
</p>
233+
</div>
201234
)}
202235
</Box>
203236
);

0 commit comments

Comments
 (0)