-
Notifications
You must be signed in to change notification settings - Fork 73
Refined View Profile modal — wider layout, backdrop close support #136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
WalkthroughThe ViewProfileModal component received a comprehensive visual redesign, transitioning from a basic modal layout to a polished, full-overlay modal with enhanced typography, spacing, and responsive design. The profile display now features larger avatars, expanded social links sections, reworked match reasons styling, and improved stats grid presentation, while maintaining the existing public API. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Modal as ViewProfileModal
participant Overlay as Modal Overlay
User->>Modal: Open modal / render
Modal->>Overlay: Show with backdrop blur
Overlay-->>Modal: Rendered
alt User clicks Connect
User->>Modal: Click Connect button
Modal->>Modal: onConnect callback
else User clicks overlay/close
User->>Overlay: Click overlay area
Overlay->>Modal: handleOverlayClick
Modal->>Modal: Close modal
end
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
Frontend/src/components/collaboration-hub/ViewProfileModal.tsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/components/collaboration-hub/ViewProfileModal.tsx (1)
Frontend/src/components/collaboration-hub/mockProfileData.ts (2)
mockWhyMatch(46-59)mockProfileDetails(3-19)
🔇 Additional comments (7)
Frontend/src/components/collaboration-hub/ViewProfileModal.tsx (7)
6-6: LGTM!Using the X icon from lucide-react maintains consistency with the project's icon library.
33-35: LGTM!The overlay click handler correctly distinguishes between clicks on the backdrop versus clicks inside the modal content.
56-72: LGTM!The header section provides clear visual hierarchy with the match percentage badge, avatar, name, and profile details appropriately styled for emphasis.
75-77: LGTM!The bio and stats sections feature good responsive design with the grid adapting from 2 columns on mobile to 4 on larger screens, enhancing readability across devices.
Also applies to: 118-135
138-154: LGTM!The "Why You Match" section provides clear visual separation and hierarchy with bold points followed by detailed descriptions, making the match reasoning easy to scan and understand.
157-164: LGTM!The Connect button maintains consistent yellow accent theming and provides clear visual prominence as the primary call-to-action.
43-43: ****The animation classes (
animate-in,fade-in-0,zoom-in-95) are properly configured in this project. The codebase usestw-animate-css(a drop-in replacement fortailwindcss-animate), which is already installed as a dependency and provides these exact utilities. These animation classes are actively used and working in multiple UI components throughout the codebase (dialog, popover, select, dropdown-menu), confirming the animations are properly configured. No action needed.Likely an incorrect or invalid review comment.
| <div | ||
| className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm" | ||
| onClick={handleOverlayClick} | ||
| > | ||
| {/* Modal container */} | ||
| <div className="relative w-full max-w-3xl bg-white dark:bg-gray-900 rounded-3xl shadow-2xl overflow-y-auto max-h-[90vh] p-10 mx-4 animate-in fade-in-0 zoom-in-95 border border-gray-100 dark:border-gray-700"> | ||
|
|
||
| {/* Close button */} | ||
| <button | ||
| onClick={onClose} | ||
| aria-label="Close" | ||
| className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all" | ||
| > | ||
| <X className="h-6 w-6" /> | ||
| </button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add essential accessibility features for the modal dialog.
The modal is missing critical accessibility features:
- ARIA attributes: The modal lacks
role="dialog"andaria-modal="true"attributes required for screen readers - Escape key support: No keyboard event handler to close the modal with the Escape key (standard UX pattern)
- Focus management: No focus trap to prevent keyboard navigation from leaving the modal, and no focus restoration when closed
Apply these changes to improve accessibility:
1. Add ARIA attributes to the modal container:
- <div className="relative w-full max-w-3xl bg-white dark:bg-gray-900 rounded-3xl shadow-2xl overflow-y-auto max-h-[90vh] p-10 mx-4 animate-in fade-in-0 zoom-in-95 border border-gray-100 dark:border-gray-700">
+ <div
+ role="dialog"
+ aria-modal="true"
+ aria-labelledby="profile-modal-title"
+ className="relative w-full max-w-3xl bg-white dark:bg-gray-900 rounded-3xl shadow-2xl overflow-y-auto max-h-[90vh] p-10 mx-4 animate-in fade-in-0 zoom-in-95 border border-gray-100 dark:border-gray-700"
+ >2. Add Escape key handler (add after the component function opens, before the return):
if (!open) return null;
const profile = mockProfileDetails;
const handleOverlayClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === e.currentTarget) onClose();
};
+
+ React.useEffect(() => {
+ const handleEscape = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') onClose();
+ };
+ document.addEventListener('keydown', handleEscape);
+ return () => document.removeEventListener('keydown', handleEscape);
+ }, [onClose]);3. Add id to the heading for aria-labelledby:
- <h2 className="text-3xl font-extrabold text-gray-900 dark:text-white">
+ <h2 id="profile-modal-title" className="text-3xl font-extrabold text-gray-900 dark:text-white">Note: For focus trapping, consider using a library like focus-trap-react or implementing a custom focus trap to cycle focus within the modal.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div | |
| className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm" | |
| onClick={handleOverlayClick} | |
| > | |
| {/* Modal container */} | |
| <div className="relative w-full max-w-3xl bg-white dark:bg-gray-900 rounded-3xl shadow-2xl overflow-y-auto max-h-[90vh] p-10 mx-4 animate-in fade-in-0 zoom-in-95 border border-gray-100 dark:border-gray-700"> | |
| {/* Close button */} | |
| <button | |
| onClick={onClose} | |
| aria-label="Close" | |
| className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all" | |
| > | |
| <X className="h-6 w-6" /> | |
| </button> | |
| <div | |
| className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm" | |
| onClick={handleOverlayClick} | |
| > | |
| {/* Modal container */} | |
| <div | |
| role="dialog" | |
| aria-modal="true" | |
| aria-labelledby="profile-modal-title" | |
| className="relative w-full max-w-3xl bg-white dark:bg-gray-900 rounded-3xl shadow-2xl overflow-y-auto max-h-[90vh] p-10 mx-4 animate-in fade-in-0 zoom-in-95 border border-gray-100 dark:border-gray-700" | |
| > | |
| {/* Close button */} | |
| <button | |
| onClick={onClose} | |
| aria-label="Close" | |
| className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all" | |
| > | |
| <X className="h-6 w-6" /> | |
| </button> |
🤖 Prompt for AI Agents
Frontend/src/components/collaboration-hub/ViewProfileModal.tsx around lines 38
to 52: the modal lacks accessibility features; add role="dialog" and
aria-modal="true" to the modal container and set aria-labelledby pointing to the
modal heading (add an id to the heading), implement an Escape key handler by
adding a useEffect that listens for keydown and calls onClose when Escape is
pressed (with proper cleanup), and add focus management: either integrate
focus-trap-react around the modal content or implement a custom focus trap that
sets initial focus to the modal or first focusable element on open, cycles focus
within the modal, and restores focus to the previously focused element on close.
Ensure the Escape effect and focus management run only when the modal is open
and are cleaned up on unmount.
| <button | ||
| onClick={onClose} | ||
| aria-label="Close" | ||
| className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all" | ||
| > | ||
| <X className="h-6 w-6" /> | ||
| </button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add cursor pointer styling to the close button.
The close button lacks cursor-pointer styling, which may not clearly indicate it's interactive to users.
Apply this diff:
- className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all"
+ className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all cursor-pointer"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| onClick={onClose} | |
| aria-label="Close" | |
| className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all" | |
| > | |
| <X className="h-6 w-6" /> | |
| </button> | |
| <button | |
| onClick={onClose} | |
| aria-label="Close" | |
| className="absolute top-6 right-6 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-all cursor-pointer" | |
| > | |
| <X className="h-6 w-6" /> | |
| </button> |
🤖 Prompt for AI Agents
In Frontend/src/components/collaboration-hub/ViewProfileModal.tsx around lines
46 to 52, the close button is missing a cursor indicator; add the Tailwind class
cursor-pointer to the button's className so the pointer changes on hover, e.g.,
append " cursor-pointer" to the existing class string (preserve existing classes
and spacing).
| <div className="flex justify-center gap-5 mb-8"> | ||
| {profile.socialLinks.map((link, idx) => ( | ||
| <a key={idx} href={link.url} target="_blank" rel="noopener noreferrer" className="text-gray-500 hover:text-gray-900" title={link.platform}> | ||
| {/* icon rendering handled in parent */} | ||
| <a | ||
| key={idx} | ||
| href={link.url} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| title={link.platform} | ||
| className="text-gray-500 hover:text-yellow-500 transition-transform hover:scale-110" | ||
| > | ||
| {link.icon === "instagram" && ( | ||
| <svg className="w-5 h-5" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><rect width="20" height="20" x="2" y="2" rx="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" x2="17.51" y1="6.5" y2="6.5"/></svg> | ||
| <svg | ||
| className="w-6 h-6" | ||
| fill="none" | ||
| stroke="currentColor" | ||
| strokeWidth="2" | ||
| viewBox="0 0 24 24" | ||
| > | ||
| <rect width="20" height="20" x="2" y="2" rx="5" /> | ||
| <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" /> | ||
| <line x1="17.5" x2="17.51" y1="6.5" y2="6.5" /> | ||
| </svg> | ||
| )} | ||
| {link.icon === "youtube" && ( | ||
| <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M21.8 8.001a2.752 2.752 0 0 0-1.938-1.948C18.003 6 12 6 12 6s-6.003 0-7.862.053A2.752 2.752 0 0 0 2.2 8.001 28.934 28.934 0 0 0 2 12a28.934 28.934 0 0 0 .2 3.999 2.752 2.752 0 0 0 1.938 1.948C5.997 18 12 18 12 18s6.003 0 7.862-.053a2.752 2.752 0 0 0 1.938-1.948A28.934 28.934 0 0 0 22 12a28.934 28.934 0 0 0-.2-3.999zM10 15V9l5 3-5 3z"/></svg> | ||
| <svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> | ||
| <path d="M21.8 8.001a2.752 2.752 0 0 0-1.938-1.948C18.003 6 12 6 12 6s-6.003 0-7.862.053A2.752 2.752 0 0 0 2.2 8.001 28.934 28.934 0 0 0 2 12a28.934 28.934 0 0 0 .2 3.999 2.752 2.752 0 0 0 1.938 1.948C5.997 18 12 18 12 18s6.003 0 7.862-.053a2.752 2.752 0 0 0 1.938-1.948A28.934 28.934 0 0 0 22 12a28.934 28.934 0 0 0-.2-3.999zM10 15V9l5 3-5 3z" /> | ||
| </svg> | ||
| )} | ||
| {link.icon === "twitter" && ( | ||
| <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53A4.48 4.48 0 0 0 22.4.36a9.09 9.09 0 0 1-2.88 1.1A4.52 4.52 0 0 0 16.11 0c-2.5 0-4.52 2.02-4.52 4.52 0 .35.04.7.11 1.03C7.69 5.4 4.07 3.67 1.64.9c-.38.65-.6 1.4-.6 2.2 0 1.52.77 2.86 1.95 3.65A4.48 4.48 0 0 1 .96 6v.06c0 2.13 1.52 3.91 3.54 4.31-.37.1-.76.16-1.16.16-.28 0-.55-.03-.81-.08.55 1.7 2.16 2.94 4.07 2.97A9.06 9.06 0 0 1 0 20.29a12.8 12.8 0 0 0 6.95 2.04c8.34 0 12.9-6.91 12.9-12.9 0-.2 0-.39-.01-.58A9.22 9.22 0 0 0 23 3z"/></svg> | ||
| <svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> | ||
| <path d="M23 3a10.9 10.9 0 0 1-3.14 1.53A4.48 4.48 0 0 0 22.4.36a9.09 9.09 0 0 1-2.88 1.1A4.52 4.52 0 0 0 16.11 0c-2.5 0-4.52 2.02-4.52 4.52 0 .35.04.7.11 1.03C7.69 5.4 4.07 3.67 1.64.9c-.38.65-.6 1.4-.6 2.2 0 1.52.77 2.86 1.95 3.65A4.48 4.48 0 0 1 .96 6v.06c0 2.13 1.52 3.91 3.54 4.31-.37.1-.76.16-1.16.16-.28 0-.55-.03-.81-.08.55 1.7 2.16 2.94 4.07 2.97A9.06 9.06 0 0 1 0 20.29a12.8 12.8 0 0 0 6.95 2.04c8.34 0 12.9-6.91 12.9-12.9 0-.2 0-.39-.01-.58A9.22 9.22 0 0 0 23 3z" /> | ||
| </svg> | ||
| )} | ||
| </a> | ||
| ))} | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Replace inline SVGs with lucide-react icons for consistency.
The social links use inline SVG icons while the close button uses lucide-react. This creates inconsistency and increases code duplication.
Replace the inline SVGs with lucide-react icons. First, add the imports:
-import { X } from "lucide-react";
+import { X, Instagram, Youtube, Twitter } from "lucide-react";Then simplify the social links rendering:
{profile.socialLinks.map((link, idx) => (
<a
key={idx}
href={link.url}
target="_blank"
rel="noopener noreferrer"
title={link.platform}
className="text-gray-500 hover:text-yellow-500 transition-transform hover:scale-110"
>
- {link.icon === "instagram" && (
- <svg
- className="w-6 h-6"
- fill="none"
- stroke="currentColor"
- strokeWidth="2"
- viewBox="0 0 24 24"
- >
- <rect width="20" height="20" x="2" y="2" rx="5" />
- <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" />
- <line x1="17.5" x2="17.51" y1="6.5" y2="6.5" />
- </svg>
- )}
- {link.icon === "youtube" && (
- <svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
- <path d="M21.8 8.001a2.752 2.752 0 0 0-1.938-1.948C18.003 6 12 6 12 6s-6.003 0-7.862.053A2.752 2.752 0 0 0 2.2 8.001 28.934 28.934 0 0 0 2 12a28.934 28.934 0 0 0 .2 3.999 2.752 2.752 0 0 0 1.938 1.948C5.997 18 12 18 12 18s6.003 0 7.862-.053a2.752 2.752 0 0 0 1.938-1.948A28.934 28.934 0 0 0 22 12a28.934 28.934 0 0 0-.2-3.999zM10 15V9l5 3-5 3z" />
- </svg>
- )}
- {link.icon === "twitter" && (
- <svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
- <path d="M23 3a10.9 10.9 0 0 1-3.14 1.53A4.48 4.48 0 0 0 22.4.36a9.09 9.09 0 0 1-2.88 1.1A4.52 4.52 0 0 0 16.11 0c-2.5 0-4.52 2.02-4.52 4.52 0 .35.04.7.11 1.03C7.69 5.4 4.07 3.67 1.64.9c-.38.65-.6 1.4-.6 2.2 0 1.52.77 2.86 1.95 3.65A4.48 4.48 0 0 1 .96 6v.06c0 2.13 1.52 3.91 3.54 4.31-.37.1-.76.16-1.16.16-.28 0-.55-.03-.81-.08.55 1.7 2.16 2.94 4.07 2.97A9.06 9.06 0 0 1 0 20.29a12.8 12.8 0 0 0 6.95 2.04c8.34 0 12.9-6.91 12.9-12.9 0-.2 0-.39-.01-.58A9.22 9.22 0 0 0 23 3z" />
- </svg>
- )}
+ {link.icon === "instagram" && <Instagram className="w-6 h-6" />}
+ {link.icon === "youtube" && <Youtube className="w-6 h-6" />}
+ {link.icon === "twitter" && <Twitter className="w-6 h-6" />}
</a>
))}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
Frontend/src/components/collaboration-hub/ViewProfileModal.tsx lines 80-115: the
social links currently render inline SVGs for instagram/youtube/twitter; replace
them with lucide-react icons to match the rest of the component. Import the
corresponding icons from 'lucide-react' (e.g., Instagram, Youtube, Twitter) at
the top of the file, then in the map render use the matching icon component for
each platform (pass className="w-6 h-6" or equivalent) instead of the inline
<svg> blocks, keeping the surrounding <a> props unchanged.
…close behavior
Closes # (optional — add issue number if there’s one)
📝 Description
This PR enhances the View Profile modal for a better user experience.
The modal now opens in a full-screen responsive layout, includes a backdrop blur for depth,
and closes automatically when users click outside the popup.
🔧 Changes Made
ViewProfileModalcomponent for a wider, full-screen layout.📷 Screenshots or Visual Changes (if applicable)
Before:
before improvement.webm
After:
after.improvement.webm
🤝 Collaboration
Collaborated with:
@aniket866(optional)✅ Checklist
Summary by CodeRabbit
UX Improvements
Style