Skip to content

Commit a6fdba6

Browse files
Zeff01claude
andcommitted
fix: redesign service card layout to ensure team members always visible
- Create scrollable content area for main content (description + tech stack) - Add fixed bottom section with border separator for team members - Reduce tech stack display from 4 to 3 items for better space management - Make team leader avatar smaller (40px) and team members even smaller (32px) - Remove margin gaps and use flex gap for better spacing - Ensure team section is always visible regardless of content length 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 81062f5 commit a6fdba6

1 file changed

Lines changed: 67 additions & 65 deletions

File tree

‎apps/codebility/app/(marketing)/services/_components/ServicesServiceCard.tsx‎

Lines changed: 67 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -118,92 +118,94 @@ function ServiceCard({ service }: Props) {
118118
<div className="absolute inset-0 bg-gradient-to-br from-transparent via-transparent to-blue-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
119119
</div>
120120

121-
<div className="flex flex-1 flex-col p-4 text-white transition-all duration-500 group-hover:translate-z-4">
122-
{/* Main Content */}
123-
<div className="space-y-3">
124-
<h3 className="line-clamp-1 text-lg font-bold group-hover:text-blue-300 transition-colors lg:text-xl">
125-
{name}
126-
</h3>
121+
<div className="flex flex-1 flex-col text-white transition-all duration-500 group-hover:translate-z-4">
122+
{/* Scrollable Content Area */}
123+
<div className="flex-1 overflow-y-auto p-4 pb-2">
124+
<div className="space-y-3">
125+
<h3 className="line-clamp-1 text-lg font-bold group-hover:text-blue-300 transition-colors lg:text-xl">
126+
{name}
127+
</h3>
127128

128-
<div className="min-h-[3rem] max-h-[6rem] overflow-y-auto">
129-
<p
130-
className={`text-gray-300 text-sm leading-relaxed ${!isDescriptionExpanded ? "line-clamp-3" : ""}`}
131-
>
132-
{description || "No description available."}
133-
</p>
134-
{isDescriptionLong && (
135-
<button
136-
onClick={() => setIsDescriptionExpanded(!isDescriptionExpanded)}
137-
className="mt-1 text-xs text-blue-400 hover:text-blue-300 transition-colors"
129+
<div>
130+
<p
131+
className={`text-gray-300 text-sm leading-relaxed ${!isDescriptionExpanded ? "line-clamp-3" : ""}`}
138132
>
139-
{isDescriptionExpanded ? "Show less" : "Read more"}
140-
</button>
141-
)}
142-
</div>
133+
{description || "No description available."}
134+
</p>
135+
{isDescriptionLong && (
136+
<button
137+
onClick={() => setIsDescriptionExpanded(!isDescriptionExpanded)}
138+
className="mt-1 text-xs text-blue-400 hover:text-blue-300 transition-colors"
139+
>
140+
{isDescriptionExpanded ? "Show less" : "Read more"}
141+
</button>
142+
)}
143+
</div>
143144

144-
{/* Tech Stack */}
145-
{tech_stack && tech_stack.length > 0 && (
146-
<div className="space-y-2">
147-
<h4 className="text-xs font-semibold text-gray-400 uppercase tracking-wide">
148-
Tech Stack
149-
</h4>
150-
<div className="flex flex-wrap gap-1.5">
151-
{tech_stack.slice(0, 4).map((tech, index) => (
152-
<span
153-
key={index}
154-
className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-gradient-to-r from-blue-500/20 to-indigo-500/20 text-blue-300 border border-blue-500/30 hover:shadow-sm hover:shadow-blue-500/20 transition-all duration-300 hover:scale-105 hover:bg-gradient-to-r hover:from-blue-500/30 hover:to-indigo-500/30 hover:border-blue-400/40 animate-fade-in-up group-hover:translate-y-[-1px]"
155-
style={{
156-
animationDelay: `${index * 100}ms`,
157-
animationFillMode: 'both'
158-
}}
159-
>
160-
{tech}
161-
</span>
162-
))}
163-
{tech_stack.length > 4 && (
164-
<span
165-
className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-gradient-to-r from-gray-600/20 to-gray-500/20 text-gray-300 border border-gray-500/30 hover:scale-110 transition-all duration-300 animate-fade-in-up"
166-
style={{
167-
animationDelay: `${4 * 100}ms`,
168-
animationFillMode: 'both'
169-
}}
170-
>
171-
+{tech_stack.length - 4} more
172-
</span>
173-
)}
145+
{/* Tech Stack */}
146+
{tech_stack && tech_stack.length > 0 && (
147+
<div className="space-y-2">
148+
<h4 className="text-xs font-semibold text-gray-400 uppercase tracking-wide">
149+
Tech Stack
150+
</h4>
151+
<div className="flex flex-wrap gap-1.5">
152+
{tech_stack.slice(0, 3).map((tech, index) => (
153+
<span
154+
key={index}
155+
className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-gradient-to-r from-blue-500/20 to-indigo-500/20 text-blue-300 border border-blue-500/30 hover:shadow-sm hover:shadow-blue-500/20 transition-all duration-300 hover:scale-105 hover:bg-gradient-to-r hover:from-blue-500/30 hover:to-indigo-500/30 hover:border-blue-400/40 animate-fade-in-up group-hover:translate-y-[-1px]"
156+
style={{
157+
animationDelay: `${index * 100}ms`,
158+
animationFillMode: 'both'
159+
}}
160+
>
161+
{tech}
162+
</span>
163+
))}
164+
{tech_stack.length > 3 && (
165+
<span
166+
className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-gradient-to-r from-gray-600/20 to-gray-500/20 text-gray-300 border border-gray-500/30 hover:scale-110 transition-all duration-300 animate-fade-in-up"
167+
style={{
168+
animationDelay: `${3 * 100}ms`,
169+
animationFillMode: 'both'
170+
}}
171+
>
172+
+{tech_stack.length - 3}
173+
</span>
174+
)}
175+
</div>
174176
</div>
175-
</div>
176-
)}
177+
)}
178+
</div>
177179
</div>
178180

179-
{/* Bottom Section with Website Button Absolute Positioned */}
180-
<div className="relative space-y-3 mt-auto flex-shrink-0">
181+
{/* Fixed Bottom Section - Always Visible */}
182+
<div className="relative px-4 pb-4 pt-2 flex-shrink-0 border-t border-white/10">
181183
{/* Team Section */}
182184
{members.length > 0 ? (
183185
<div>
184-
<p className="mb-2 text-xs font-semibold text-gray-400 uppercase tracking-wide">Team</p>
185-
<div className="flex flex-wrap items-end">
186+
<p className="mb-1.5 text-xs font-semibold text-gray-400 uppercase tracking-wide">Team</p>
187+
<div className="flex flex-wrap items-center gap-1">
186188
{teamLeader && (
187189
<Tooltip>
188190
<TooltipTrigger>
189-
<div className="relative mb-2 mr-2">
190-
<div className="relative h-14 w-14 overflow-hidden rounded-full border-2 border-customBlue-500">
191+
<div className="relative">
192+
<div className="relative h-10 w-10 overflow-hidden rounded-full border-2 border-customBlue-500">
191193
{teamLeader.image_url ? (
192194
<Image
193195
src={teamLeader.image_url}
194196
alt={`${teamLeader.first_name} ${teamLeader.last_name}`}
195197
fill
196-
sizes="56px"
198+
sizes="32px"
197199
className="object-cover"
198200
/>
199201
) : (
200202
<DefaultAvatar
201-
size={56}
203+
size={32}
202204
className="h-full w-full"
203205
/>
204206
)}
205207
</div>
206-
<Crown className="absolute -right-2 -top-2 h-4 w-6 rotate-45 text-yellow-400 drop-shadow-lg" />
208+
<Crown className="absolute -right-1 -top-1 h-3 w-3 rotate-45 text-yellow-400 drop-shadow-lg" />
207209
</div>
208210
</TooltipTrigger>
209211
<TooltipContent>
@@ -217,19 +219,19 @@ function ServiceCard({ service }: Props) {
217219
{teamMembers.map((member, index) => (
218220
<Tooltip key={`${member.id}${index}`}>
219221
<TooltipTrigger>
220-
<div className="mb-2 mr-1">
221-
<div className="relative h-10 w-10 overflow-hidden rounded-full border-2 border-gray-700">
222+
<div>
223+
<div className="relative h-8 w-8 overflow-hidden rounded-full border-2 border-gray-700">
222224
{member.image_url ? (
223225
<Image
224226
src={member.image_url}
225227
alt={`${member.first_name} ${member.last_name}`}
226228
fill
227-
sizes="40px"
229+
sizes="32px"
228230
className="object-cover"
229231
/>
230232
) : (
231233
<DefaultAvatar
232-
size={40}
234+
size={32}
233235
className="h-full w-full"
234236
/>
235237
)}

0 commit comments

Comments
 (0)