mirror of
https://github.com/geoffsee/open-gsio.git
synced 2025-09-08 22:56:46 +00:00
init
This commit is contained in:
62
src/components/resume/ResumeComponent.tsx
Normal file
62
src/components/resume/ResumeComponent.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { Box, Flex, useMediaQuery } from "@chakra-ui/react";
|
||||
import { resumeData } from "../../static-data/resume_data";
|
||||
import SectionContent from "./SectionContent";
|
||||
import SectionButton from "./SectionButton";
|
||||
|
||||
const sections = ["professionalSummary", "skills", "experience", "education"];
|
||||
|
||||
export default function ResumeComponent() {
|
||||
const [activeSection, setActiveSection] = React.useState(
|
||||
"professionalSummary",
|
||||
);
|
||||
const [isMobile] = useMediaQuery("(max-width: 1243px)");
|
||||
|
||||
const handleSectionClick = useCallback((section) => {
|
||||
setActiveSection(section);
|
||||
}, []);
|
||||
|
||||
const capitalizeFirstLetter = useCallback((word) => {
|
||||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||
}, []);
|
||||
|
||||
const sectionButtons = useMemo(
|
||||
() =>
|
||||
sections.map((section) => (
|
||||
<SectionButton
|
||||
key={section}
|
||||
onClick={() => handleSectionClick(section)}
|
||||
activeSection={activeSection}
|
||||
section={section}
|
||||
mobile={isMobile}
|
||||
callbackfn={capitalizeFirstLetter}
|
||||
/>
|
||||
)),
|
||||
[activeSection, isMobile, handleSectionClick, capitalizeFirstLetter],
|
||||
);
|
||||
|
||||
return (
|
||||
<Box p={"unset"}>
|
||||
<Flex
|
||||
direction={isMobile ? "column" : "row"}
|
||||
mb={8}
|
||||
wrap="nowrap"
|
||||
gap={isMobile ? 2 : 4}
|
||||
minWidth="0"
|
||||
>
|
||||
{sectionButtons}
|
||||
</Flex>
|
||||
<Box
|
||||
bg="background.secondary"
|
||||
color="text.primary"
|
||||
borderRadius="md"
|
||||
boxShadow="md"
|
||||
borderWidth={1}
|
||||
borderColor="brand.300"
|
||||
minHeight="300px"
|
||||
>
|
||||
<SectionContent activeSection={activeSection} resumeData={resumeData} />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
32
src/components/resume/SectionButton.tsx
Normal file
32
src/components/resume/SectionButton.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import { Button } from "@chakra-ui/react";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
|
||||
function SectionButton(props: {
|
||||
onClick: () => void;
|
||||
activeSection: string;
|
||||
section: string;
|
||||
mobile: boolean;
|
||||
callbackfn: (word) => string;
|
||||
}) {
|
||||
return (
|
||||
<Button
|
||||
mt={1}
|
||||
onClick={props.onClick}
|
||||
variant={props.activeSection === props.section ? "solid" : "outline"}
|
||||
colorScheme="brand"
|
||||
rightIcon={<ChevronRight size={16} />}
|
||||
size="md"
|
||||
width={props.mobile ? "100%" : "auto"}
|
||||
>
|
||||
{props.section
|
||||
.replace(/([A-Z])/g, " $1")
|
||||
.trim()
|
||||
.split(" ")
|
||||
.map(props.callbackfn)
|
||||
.join(" ")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default SectionButton;
|
98
src/components/resume/SectionContent.tsx
Normal file
98
src/components/resume/SectionContent.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
GridItem,
|
||||
Heading,
|
||||
ListItem,
|
||||
Text,
|
||||
UnorderedList,
|
||||
VStack,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
const fontSize = "md";
|
||||
|
||||
const ProfessionalSummary = ({ professionalSummary }) => (
|
||||
<Box>
|
||||
<Grid
|
||||
templateColumns="1fr"
|
||||
gap={4}
|
||||
maxW={["100%", "100%", "100%"]}
|
||||
mx="auto"
|
||||
className="about-container"
|
||||
>
|
||||
<GridItem
|
||||
colSpan={1}
|
||||
maxW={["100%", "100%", "container.md"]}
|
||||
justifySelf="center"
|
||||
minH={"100%"}
|
||||
>
|
||||
<Grid templateColumns="1fr" gap={4} overflowY={"auto"}>
|
||||
<GridItem>
|
||||
<Text fontSize="md">{professionalSummary}</Text>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const Skills = ({ skills }) => (
|
||||
<VStack align={"baseline"} spacing={6} mb={4}>
|
||||
<UnorderedList spacing={2} mb={0}>
|
||||
<Box>
|
||||
{skills?.map((skill, index) => (
|
||||
<ListItem p={1} key={index}>
|
||||
{skill}
|
||||
</ListItem>
|
||||
))}
|
||||
</Box>
|
||||
</UnorderedList>
|
||||
</VStack>
|
||||
);
|
||||
|
||||
const Experience = ({ experience }) => (
|
||||
<VStack align="start" spacing={6} mb={4}>
|
||||
{experience?.map((job, index) => (
|
||||
<Box key={index} width="100%">
|
||||
<Heading as="h3" size="md" mb={2}>
|
||||
{job.title}
|
||||
</Heading>
|
||||
<Text fontWeight="bold">{job.company}</Text>
|
||||
<Text color="gray.500" mb={2}>
|
||||
{job.timeline}
|
||||
</Text>
|
||||
<Text>{job.description}</Text>
|
||||
</Box>
|
||||
))}
|
||||
</VStack>
|
||||
);
|
||||
|
||||
const Education = ({ education }) => (
|
||||
<UnorderedList spacing={2} mb={4}>
|
||||
{education?.map((edu, index) => <ListItem key={index}>{edu}</ListItem>)}
|
||||
</UnorderedList>
|
||||
);
|
||||
|
||||
const SectionContent = ({ activeSection, resumeData }) => {
|
||||
const components = {
|
||||
professionalSummary: ProfessionalSummary,
|
||||
skills: Skills,
|
||||
experience: Experience,
|
||||
education: Education,
|
||||
};
|
||||
|
||||
const ActiveComponent = components[activeSection];
|
||||
|
||||
return (
|
||||
<Box p={4} minHeight="300px" width="100%">
|
||||
{ActiveComponent ? (
|
||||
<ActiveComponent {...resumeData} />
|
||||
) : (
|
||||
<Text>Select a section to view details.</Text>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SectionContent;
|
Reference in New Issue
Block a user