-
-
Notifications
You must be signed in to change notification settings - Fork 656
Enhancing Social Media Icons with Hover Effects and Tooltips for Better UX #1199
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
Changes from 9 commits
3f05be8
f7dc308
0abf626
d08cec0
789d49a
abd92d6
ac838b9
a6fc158
cd40a70
7d4d2c9
492b733
fd1b5c3
8e22a08
4326543
07b1613
b287aa4
939d6d1
731cd67
68f3204
1e8dc6a
a3b9183
cca71a2
6f76ff9
ea6bb54
70af050
a867408
9bbb25d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,6 @@ import DisplayIcon from 'components/DisplayIcon' | |
| import Markdown from 'components/MarkdownWrapper' | ||
| import { Tooltip } from 'components/ui/tooltip' | ||
|
|
||
| // Initial check for mobile screen size | ||
| const isMobileInitial = typeof window !== 'undefined' && window.innerWidth < desktopViewMinWidth | ||
|
|
||
| const Card = ({ | ||
|
|
@@ -32,21 +31,16 @@ const Card = ({ | |
| }: CardProps) => { | ||
| const [isMobile, setIsMobile] = useState(isMobileInitial) | ||
|
|
||
| // Resize listener to adjust display based on screen width | ||
| useEffect(() => { | ||
| const checkMobile = () => { | ||
| const mobile = window.innerWidth < desktopViewMinWidth | ||
| setIsMobile(mobile) | ||
| } | ||
| const checkMobile = () => setIsMobile(window.innerWidth < desktopViewMinWidth) | ||
| window.addEventListener('resize', checkMobile) | ||
| return () => window.removeEventListener('resize', checkMobile) | ||
| }, []) | ||
|
|
||
| return ( | ||
| <div className="mx-auto mb-2 mt-4 flex w-full max-w-[95%] flex-col items-start rounded-md border border-border bg-white px-4 pb-4 pl-4 dark:bg-[#212529] md:max-w-6xl"> | ||
| <div className="mt-2 flex w-full flex-col items-start gap-4 pt-2 sm:flex-col sm:gap-4 md:pt-0"> | ||
| <div className="mx-auto mb-2 mt-4 w-full max-w-[95%] rounded-md border border-border bg-white px-4 pb-4 dark:bg-[#212529] md:max-w-6xl"> | ||
| <div className="mt-2 flex w-full flex-col gap-4 pt-2 sm:flex-col md:pt-0"> | ||
| <div className="flex items-center gap-3"> | ||
| {/* Display project level badge (if available) */} | ||
| {level && ( | ||
| <Tooltip | ||
| closeDelay={100} | ||
|
|
@@ -58,112 +52,105 @@ const Card = ({ | |
| showArrow | ||
| > | ||
| <span | ||
| className={cn( | ||
| 'flex h-8 w-8 items-center justify-center rounded-full text-xs shadow' | ||
| )} | ||
| className="flex h-8 w-8 items-center justify-center rounded-full shadow" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| style={{ backgroundColor: level.color }} | ||
| > | ||
| <FontAwesomeIconWrapper icon={level.icon} className="text-white" /> | ||
| </span> | ||
| </Tooltip> | ||
| )} | ||
| {/* Project title and link */} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can keep these as they separate logic blocks 👍🏼 |
||
|
|
||
| <Link href={url} target="_blank" rel="noopener noreferrer" className="flex-1"> | ||
| <h1 | ||
| className="max-w-full break-words text-base font-semibold dark:text-sky-600 sm:break-normal sm:text-lg lg:text-2xl" | ||
| style={{ | ||
| transition: 'color 0.3s ease', | ||
| }} | ||
| > | ||
| <h1 className="break-words text-base font-semibold dark:text-sky-600 sm:text-lg lg:text-2xl transition-colors hover:text-blue-500"> | ||
| {title} | ||
| </h1> | ||
| </Link> | ||
| </div> | ||
| {/* Icons associated with the project */} | ||
| {icons && Object.keys(Icons).some((key) => icons[key]) ? ( | ||
| <div className="-ml-1.5 flex flex-grow"> | ||
| {Object.keys(Icons).map((key, index) => | ||
| icons[key] ? ( | ||
| <DisplayIcon | ||
| key={`${key}-${index}`} | ||
| item={key} | ||
| icons={Object.fromEntries(Object.entries(icons).filter(([_, value]) => value))} | ||
| /> | ||
| ) : null | ||
|
|
||
| {icons && Object.keys(Icons).some((key) => icons[key]) && ( | ||
| <div className="flex flex-wrap items-center gap-2"> | ||
| {Object.keys(Icons).map( | ||
| (key, index) => | ||
| icons[key] && ( | ||
| <DisplayIcon | ||
| key={`${key}-${index}`} | ||
| item={key} | ||
| icons={Object.fromEntries(Object.entries(icons).filter(([_, value]) => value))} | ||
| /> | ||
| ) | ||
| )} | ||
| </div> | ||
| ) : null} | ||
| )} | ||
| </div> | ||
| {/* Link to project name if provided */} | ||
|
|
||
| {projectName && ( | ||
| <Link href={projectLink} rel="noopener noreferrer" className="mt-2 font-medium"> | ||
| <Link href={projectLink} rel="noopener noreferrer" className="mt-2 font-medium text-blue-600 hover:underline"> | ||
| {projectName} | ||
| </Link> | ||
| )} | ||
| {/* Render project summary using Markdown */} | ||
|
|
||
| <Markdown content={summary} className="py-2 pr-4 text-gray-600 dark:text-gray-300" /> | ||
| <div | ||
| className={ | ||
| social && social.length > 0 | ||
| ? 'flex w-full flex-col gap-2 pr-4' | ||
| : 'flex w-full items-center justify-between' | ||
| } | ||
| > | ||
| {/* Render top contributors as avatars */} | ||
| <div className="mt-3 flex w-full flex-wrap items-center gap-2"> | ||
| {topContributors?.map((contributor, index) => ( | ||
| <ContributorAvatar | ||
| key={contributor.login || `contributor-${index}`} | ||
| contributor={contributor} | ||
| uniqueKey={index.toString()} | ||
| /> | ||
| ))} | ||
| </div> | ||
|
|
||
| <div className={cn(social?.length ? 'flex w-full flex-col gap-2 pr-4' : 'flex w-full items-center justify-between')}> | ||
| {topContributors && topContributors.length > 0 && ( | ||
| <div className="mt-3 flex w-full flex-wrap items-center gap-2"> | ||
| {topContributors.map((contributor, index) => ( | ||
| <ContributorAvatar | ||
| key={contributor.login || `contributor-${index}`} | ||
| contributor={contributor} | ||
| uniqueKey={index.toString()} | ||
| /> | ||
| ))} | ||
| </div> | ||
| )} | ||
|
|
||
| {!social || social.length === 0 ? ( | ||
| <div | ||
| className={cn( | ||
| 'mt-3 flex items-center pr-4', | ||
| isMobile && 'mt-4 w-full justify-end pr-4' | ||
| )} | ||
| > | ||
| <div className={cn('mt-3 flex items-center pr-4', isMobile && 'mt-4 w-full justify-end')}> | ||
| <ActionButton tooltipLabel={tooltipLabel} url={button.url} onClick={button.onclick}> | ||
| {button.icon} | ||
| {button.label} | ||
| <FontAwesomeIconWrapper icon={button.icon} /> {button.label} | ||
| </ActionButton> | ||
| </div> | ||
| ) : ( | ||
| <div | ||
| className={cn( | ||
| 'flex w-full flex-wrap items-center justify-between gap-6', | ||
| isMobile && 'items-start' | ||
| )} | ||
| > | ||
| <div | ||
| className={cn('flex w-full items-center justify-between', isMobile && 'flex-wrap')} | ||
| > | ||
| {/* Render social links if available */} | ||
| <div className={cn('flex w-full flex-wrap items-center justify-between gap-6', isMobile && 'items-start')}> | ||
| <div className={cn('flex w-full items-center justify-between', isMobile && 'flex-wrap')}> | ||
| {social && social.length > 0 && ( | ||
| <HStack id="social" mt={2}> | ||
| {social.map((item) => ( | ||
| <Link | ||
| <Tooltip | ||
| key={`${item.title}-${item.url}`} | ||
| href={item.url} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| display="flex" | ||
| alignItems="center" | ||
| gap={2} | ||
| content={item.title} | ||
| recipe={TooltipRecipe} | ||
| openDelay={150} | ||
| closeDelay={100} | ||
| showArrow | ||
| positioning={{ placement: 'top' }} | ||
| > | ||
| <FontAwesomeIcon icon={getSocialIcon(item.url)} className="h-5 w-5" /> | ||
| </Link> | ||
| <Link | ||
| href={item.url} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="transition-transform duration-300 hover:scale-110" | ||
| > | ||
| <FontAwesomeIcon | ||
| icon={getSocialIcon(item.url)} | ||
| className={`h-5 w-5 transition-colors duration-300 ${ | ||
| { | ||
| discord: 'text-[#5865F2] hover:text-[#5865F2]', | ||
| instagram: 'text-[#E4405F] hover:text-[#E4405F]', | ||
| linkedin: 'text-[#0077B5] hover:text-[#0077B5]', | ||
| youtube: 'text-[#FF0000] hover:text-[#FF0000]', | ||
| }[item.title.toLowerCase()] || 'text-gray-500' | ||
| }`} | ||
| /> | ||
| </Link> | ||
| </Tooltip> | ||
| ))} | ||
| </HStack> | ||
| )} | ||
| {/* Action Button */} | ||
|
|
||
| <div className="flex items-center"> | ||
| <ActionButton tooltipLabel={tooltipLabel} url={button.url} onClick={button.onclick}> | ||
| {button.icon} | ||
| {button.label} | ||
| <FontAwesomeIconWrapper icon={button.icon} /> {button.label} | ||
| </ActionButton> | ||
| </div> | ||
| </div> | ||
|
|
@@ -173,5 +160,4 @@ const Card = ({ | |
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export default Card | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kasya can you clarify a little bit more on this issue, exactly would you like me to change the colours to their brand colurs, or let it be blue or grey?thank you!
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @srinjoy933 yes, I meant that we should show a single color - blue or grey, I'm fine with the grey one 👍🏼 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,17 @@ import FontAwesomeIconWrapper from 'wrappers/FontAwesomeIconWrapper' | |
| import { Tooltip } from 'components/ui/tooltip' | ||
|
|
||
| export default function DisplayIcon({ item, icons }: { item: string; icons: IconType }) { | ||
| // className for the container | ||
|
|
||
| const brandColors: Record<string, string> = { | ||
| discord: 'text-[#7289DA] hover:text-[#5b6eae]', | ||
| instagram: 'text-[#E4405F] hover:text-[#c13548]', | ||
| linkedin: 'text-[#0077B5] hover:text-[#005582]', | ||
| youtube: 'text-[#FF0000] hover:text-[#cc0000]', | ||
| } | ||
|
|
||
| const isSocialMedia = Object.keys(brandColors).includes(item.toLowerCase()) | ||
|
|
||
|
|
||
| const containerClassName = [ | ||
| 'flex flex-row-reverse items-center justify-center gap-1 px-4 pb-1 -ml-2', | ||
| item === 'stars_count' || item === 'starsCount' ? 'rotate-container' : '', | ||
|
|
@@ -20,9 +30,10 @@ export default function DisplayIcon({ item, icons }: { item: string; icons: Icon | |
| .filter(Boolean) | ||
| .join(' ') | ||
|
|
||
| // className for the FontAwesome icon | ||
|
|
||
| const iconClassName = [ | ||
| 'text-gray-600 dark:text-gray-300', | ||
| isSocialMedia ? brandColors[item.toLowerCase()] : 'text-gray-600 dark:text-gray-300', | ||
| 'transition-transform transform hover:scale-110', | ||
| item === 'stars_count' || item === 'starsCount' ? 'icon-rotate' : '', | ||
|
srinjoy933 marked this conversation as resolved.
|
||
| item === 'forks_count' || | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These don't have animation they had before. I'd prefer we keep it. |
||
| item === 'contributors_count' || | ||
|
|
@@ -47,16 +58,17 @@ export default function DisplayIcon({ item, icons }: { item: string; icons: Icon | |
| {/* Display formatted number if the value is a number */} | ||
| <span className="text-gray-600 dark:text-gray-300"> | ||
| {typeof icons[item] === 'number' | ||
| ? millify(icons[item], { precision: 1 }) // Format large numbers using 'millify' library | ||
| ? millify(icons[item], { precision: 1 }) | ||
| : icons[item]} | ||
| </span> | ||
| <span> | ||
| <FontAwesomeIconWrapper | ||
| className={iconClassName} | ||
| icon={Icons[item as IconKeys]?.icon} // Display corresponding icon | ||
| icon={Icons[item as IconKeys]?.icon} | ||
| /> | ||
| </span> | ||
| </div> | ||
| </Tooltip> | ||
| ) : null | ||
|
|
||
| } | ||



Uh oh!
There was an error while loading. Please reload this page.