new-personal-site/components/pages/Home/(sections)/MySkillsSection.tsx

160 lines
6.7 KiB
TypeScript
Raw Normal View History

2024-12-09 15:36:17 +00:00
import Card from "@/components/lib/elements/Card";
import H2 from "@/components/lib/layout/H2";
import H3 from "@/components/lib/layout/H3";
import Section from "@/components/lib/layout/Section";
import Span from "@/components/lib/layout/Span";
import Stack from "@/components/lib/layout/Stack";
import { skills } from "../(data)/skills";
import React from "react";
import Row from "@/components/lib/layout/Row";
import { twMerge } from "tailwind-merge";
import Divider from "@/components/lib/layout/Divider";
type Props = {
noTitle?: boolean;
expand?: boolean;
};
export default function MySkillsSection({ noTitle, expand }: Props) {
const [category, setCategory] =
React.useState<keyof typeof skills>("Devops");
const categories = Object.keys(skills) as (keyof typeof skills)[];
if (expand) {
return (
<Section>
<Stack className="w-full">
{!noTitle && (
<React.Fragment>
<H2 className="leading-snug m-0">My Skills</H2>
<Span>
A summary of the vast array of tools I've
mastered over the years
</Span>
<Divider className="opacity-0 my-2" />
</React.Fragment>
)}
<Stack className="items-stretch gap-20 flex-row xl:flex-col flex-wrap md:flex-nowrap">
{categories.map((ctgr, i) => {
return (
<Stack key={i}>
<Stack className="gap-6">
<Stack className="gap-2">
<H3 className="m-0 text-lg">
{ctgr}
</H3>
<Span className="text-sm !leading-5">
{skills[ctgr].description}
</Span>
</Stack>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 w-full">
{skills[ctgr].portfolio.map(
(portfolio, index) => {
return (
<MySkillsCard
portfolio={
portfolio
}
key={index}
/>
);
}
)}
</div>
</Stack>
</Stack>
);
})}
</Stack>
</Stack>
</Section>
);
}
return (
<Section>
<Stack className="w-full">
{!noTitle && (
<React.Fragment>
<H2 className="leading-snug m-0">My Skills</H2>
<Span>
A summary of the vast array of tools I've mastered
over the years
</Span>
<Divider className="opacity-0 my-2" />
</React.Fragment>
)}
<Row className="flex-nowrap items-start gap-x-10 flex-col xl:flex-row gap-y-10">
<Stack className="xl:max-w-[200px] items-stretch gap-10 flex-row xl:flex-col flex-wrap md:flex-nowrap">
{categories.map((ctgr, i) => {
const isActive = category === ctgr;
return (
<Stack
key={i}
className={twMerge(
"cursor-pointer",
isActive
? ""
: "opacity-40 hover:opacity-70"
)}
onClick={() => setCategory(ctgr)}
>
<Stack className="gap-1">
<H3 className="m-0 text-lg">{ctgr}</H3>
<Span className="text-sm !leading-5">
{skills[ctgr].description}
</Span>
</Stack>
</Stack>
);
})}
</Stack>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 w-full">
{skills[category].portfolio.map((portfolio, index) => {
return (
<MySkillsCard
portfolio={portfolio}
key={index}
/>
);
})}
</div>
</Row>
</Stack>
</Section>
);
}
export function MySkillsCard({
portfolio,
}: {
portfolio: (typeof skills.Devops.portfolio)[number];
}) {
return (
<Card className="grow w-full items-start">
<Stack className="gap-4">
<H3 className="m-0">{portfolio.title}</H3>
<Span>{portfolio.description}</Span>
{portfolio.technologies?.[0] && (
<Row className="gap-4">
{portfolio.technologies.map((tch, _i) => (
<React.Fragment key={_i}>
<Span className="text-sm dark:text-white/40">
{tch}
</Span>
{_i < portfolio.technologies.length - 1 && (
<Divider vertical />
)}
</React.Fragment>
))}
</Row>
)}
</Stack>
</Card>
);
}