|
| 1 | +import { useMediaQuery } from '@/hooks/useMediaQuery'; |
| 2 | +import { BaselineIcon, GalleryVerticalEndIcon } from 'lucide-react'; |
| 3 | +import { Fragment, FunctionComponent, useState } from 'react'; |
| 4 | +import { techIcons } from '@/utils/techIcons'; |
| 5 | + |
| 6 | +interface Props extends React.SVGProps<SVGElement> { |
| 7 | + size?: number | string; |
| 8 | +} |
| 9 | + |
| 10 | +type TechIconsDisplayProps = { |
| 11 | + heading: string |
| 12 | + techNames: string[] |
| 13 | +} |
| 14 | + |
| 15 | +function TechIconsDisplay({ heading, techNames }: TechIconsDisplayProps) { |
| 16 | + const hasRemainingIcons = (list: string[], startIndex: number, icons = techIcons): boolean => { |
| 17 | + for (let i = startIndex + 1; i < list.length; i++) { |
| 18 | + if (list[i] in icons) { |
| 19 | + return true; |
| 20 | + } |
| 21 | + } |
| 22 | + return false; |
| 23 | + } |
| 24 | + |
| 25 | + const isDesktop = useMediaQuery('(min-width: 768px)') |
| 26 | + const TechIcon: React.FunctionComponent<{ techName: string }> = ({techName}) => { |
| 27 | + // TODO: For techName = SQL, handle multiple SQL service like Postgres, MYSQL, MongoDB, etc. |
| 28 | + const IconComponent: React.FunctionComponent<Props> = techIcons[techName] |
| 29 | + return ( |
| 30 | + <div className="items-center justify-center"> |
| 31 | + <IconComponent size={isDesktop ? 50 : 35}/> |
| 32 | + </div> |
| 33 | + ) |
| 34 | + } |
| 35 | + const [showIcons, setShowIcons] = useState(false) |
| 36 | + const toggleView = () => setShowIcons(!showIcons) |
| 37 | + |
| 38 | + return ( |
| 39 | + <div className="px-4"> |
| 40 | + <div className="inline-flex items-center mb-2"> |
| 41 | + <h3 className="text-xl underline underline-offset-4 items-center"> |
| 42 | + <span className="font-bold">{heading}</span> |
| 43 | + </h3> |
| 44 | + <span> </span> |
| 45 | + {/* { |
| 46 | + showIcons |
| 47 | + ? <BaselineIcon onClick={toggleView} className="w-5 h-5 md:w-6 md:h-6"/> |
| 48 | + : <GalleryVerticalEndIcon onClick={toggleView} className="w-5 h-5 md:w-6 md:h-6"/> |
| 49 | + } */} |
| 50 | + </div> |
| 51 | + {techNames.length > 0 ? ( |
| 52 | + <div> |
| 53 | + {/* TODO: Make this compatible for mobile screens in the future */} |
| 54 | + {/* className="md:flex md:flex-row md:items-start md:justify-start grid grid-cols-2" */} |
| 55 | + {/* {techNames.map((lang, index) => ( |
| 56 | + (lang in techIcons) && <Fragment key={lang}> |
| 57 | + {showIcons ? ( |
| 58 | + <div className="inline-flex items-center justify-center" aria-label={lang}> |
| 59 | + <div className="bg-white p-1 rounded-md shadow-sm"> |
| 60 | + <TechIcon techName={lang} /> |
| 61 | + </div> |
| 62 | + </div> |
| 63 | + ) : ( |
| 64 | + <span className="inline-flex items-center"> |
| 65 | + {lang} |
| 66 | + {index < techNames.length - 1 && hasRemainingIcons(techNames, index) && ( |
| 67 | + <span className="mr-1">,</span> |
| 68 | + )} |
| 69 | + </span> |
| 70 | + )} |
| 71 | + </Fragment> |
| 72 | + ))} */} |
| 73 | + {techNames.map((lang, index) => ( |
| 74 | + <span className="inline-flex items-center"> |
| 75 | + {lang} |
| 76 | + {index < techNames.length - 1 && ( |
| 77 | + <span className="mr-1">,</span> |
| 78 | + )} |
| 79 | + </span> |
| 80 | + ))} |
| 81 | + </div> |
| 82 | + ) : ( |
| 83 | + <p className="text-gray-600">Nothing to display.</p> |
| 84 | + )} |
| 85 | + </div> |
| 86 | + ) |
| 87 | +} |
| 88 | + |
| 89 | +export function Skills() { |
| 90 | + return ( |
| 91 | + <section id="skills" className="mb-12"> |
| 92 | + <h2 className="text-2xl md:text-3xl lg:text-4xl font-section font-bold mb-4">Skills</h2> |
| 93 | + <div className="flex flex-col justify-around"> |
| 94 | + {/* TODO: Check if this fits in small screens & if this is good at all or not */} |
| 95 | + <TechIconsDisplay |
| 96 | + heading="Programming techNames:" |
| 97 | + techNames={["Python3", "HTML5", "CSS3", "JavaScript (ES6)", "TypeScript", "Go", "C", "C++20", "SQL"]} |
| 98 | + /> |
| 99 | + <TechIconsDisplay |
| 100 | + heading="Frameworks:" |
| 101 | + techNames={[ |
| 102 | + "Django", |
| 103 | + "Flask", |
| 104 | + "React", |
| 105 | + "Next.js", |
| 106 | + "Node.js", |
| 107 | + "Axios", |
| 108 | + "Socket.IO", |
| 109 | + "TailwindCSS", |
| 110 | + "D3.js", |
| 111 | + "Jest", |
| 112 | + "Cypress", |
| 113 | + "Pytest" |
| 114 | + ]} |
| 115 | + /> |
| 116 | + <TechIconsDisplay |
| 117 | + heading="Libraries:" |
| 118 | + techNames={[ |
| 119 | + "Pandas", |
| 120 | + "Matplotlib", |
| 121 | + "Plotly", |
| 122 | + "NumPy", |
| 123 | + "OpenCV", |
| 124 | + "Pillow", |
| 125 | + "NetworkX", |
| 126 | + ]} |
| 127 | + /> |
| 128 | + <TechIconsDisplay |
| 129 | + heading="Tools:" |
| 130 | + techNames={[ |
| 131 | + "Git", |
| 132 | + "Linux", |
| 133 | + "Bash", |
| 134 | + "Powershell", |
| 135 | + "Docker", |
| 136 | + "Postman", |
| 137 | + "GCP", |
| 138 | + "AWS", |
| 139 | + ]} |
| 140 | + /> |
| 141 | + </div> |
| 142 | + </section> |
| 143 | + ) |
| 144 | +} |
0 commit comments