Skip to content

Commit 0f4e66e

Browse files
committed
feat: added Skills section (with work to do for icons/text switch)
1 parent 0e8a2f7 commit 0f4e66e

File tree

4 files changed

+203
-0
lines changed

4 files changed

+203
-0
lines changed

package-lock.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"clsx": "^2.1.1",
14+
"devicons-react": "^1.3.0",
1415
"lucide-react": "^0.445.0",
1516
"next": "^14.2.14",
1617
"next-themes": "^0.3.0",

src/components/Skills.tsx

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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>&nbsp;&nbsp;&nbsp;</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+
}

src/utils/techIcons.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { FunctionComponent } from 'react';
2+
import {
3+
PythonOriginal,
4+
JavascriptOriginal,
5+
TypescriptOriginal,
6+
COriginal,
7+
CplusplusOriginal,
8+
GoOriginalWordmark,
9+
Html5OriginalWordmark,
10+
Css3OriginalWordmark,
11+
ROriginal,
12+
DjangoPlain,
13+
FlaskOriginalWordmark,
14+
ReactOriginal,
15+
NodejsOriginalWordmark,
16+
AxiosPlainWordmark,
17+
SocketioOriginalWordmark,
18+
TailwindcssOriginalWordmark,
19+
D3jsOriginal,
20+
JestPlain,
21+
CypressioOriginal,
22+
PytestOriginalWordmark,
23+
NextjsOriginal,
24+
} from 'devicons-react';
25+
26+
27+
export const techIcons: { [key: string]: FunctionComponent } = {
28+
"Python3": PythonOriginal,
29+
"JavaScript (ES6)": JavascriptOriginal,
30+
"TypeScript": TypescriptOriginal,
31+
"C": COriginal,
32+
"C++20": CplusplusOriginal,
33+
"Go": GoOriginalWordmark,
34+
"HTML5": Html5OriginalWordmark ,
35+
"CSS3": Css3OriginalWordmark,
36+
"R": ROriginal,
37+
"Django": DjangoPlain,
38+
"Flask": FlaskOriginalWordmark,
39+
"React": ReactOriginal,
40+
"Next.js": NextjsOriginal,
41+
"Node.js": NodejsOriginalWordmark,
42+
"Axios": AxiosPlainWordmark,
43+
"Socket.IO": SocketioOriginalWordmark,
44+
"TailwindCSS": TailwindcssOriginalWordmark,
45+
"D3.js": D3jsOriginal,
46+
"Jest": JestPlain,
47+
"Cypress": CypressioOriginal,
48+
"Pytest": PytestOriginalWordmark,
49+
}

0 commit comments

Comments
 (0)