Skip to content

Commit

Permalink
✨ feat : added about section
Browse files Browse the repository at this point in the history
🎨 chore : improve structure of about section code
  • Loading branch information
dev-madhurendra authored Dec 28, 2023
2 parents 9cbfe19 + 4bfbafb commit 9e2ba89
Show file tree
Hide file tree
Showing 20 changed files with 518 additions and 31 deletions.
3 changes: 2 additions & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Madhurendra's Tech Odyssey</title>
<link rel="shortcut icon" href="public/gif/Logo.gif" type="image/x-icon">
<title>👋 | Madhurendra's Tech Odyssey</title>
</head>
<body>
<div id="root"></div>
Expand Down
Binary file added frontend/public/jpeg/About-Image.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import HomeSection from './pages/Home';
import './App.css';
import { DarkModeProvider } from './services/context/DarkMode';
import { useDarkMode } from './services/customhook/useDarkMode';
import About from './pages/About';

function App() {
return (
Expand All @@ -18,13 +19,15 @@ const AppContent: React.FC = () => {
const { isDark } = useDarkMode();

const AppContainer = styled('div')({
color:isDark ? '#fff' : 'inherit',
color: isDark ? '#fff' : '#000',
backgroundColor: isDark ? "#1f1d27" : "inherit"
});

return (
<AppContainer>
<Navbar />
<HomeSection />
<About />
</AppContainer>
);
};
Expand Down
35 changes: 35 additions & 0 deletions frontend/src/components/atoms/Chip/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import MyChip from '.';
import "@testing-library/jest-dom"
import { IChipProp } from '../../../interfaces/types';

const mockProps: IChipProp = {
size: 'small',
label: 'Test Label',
variant: 'outlined',
onClick: jest.fn(),
color: 'primary',
style: {},
};


describe('MyChip Component', () => {
it('renders MyChip component with given props', () => {
render(<MyChip {...mockProps} />);

const chipElement = screen.getByTestId('mui-chip');
expect(chipElement).toBeInTheDocument();
expect(chipElement).toHaveTextContent('Test Label');
expect(chipElement).toHaveClass('MuiChip-outlined');
expect(chipElement).toHaveClass('MuiChip-sizeSmall');
});

it('calls onClick when chip is clicked', () => {
const mockFunction = jest.fn()
render(<MyChip {...mockProps} onClick={mockFunction} />);
const chipElement = screen.getByTestId('mui-chip');
chipElement.click()
expect(mockFunction).toHaveBeenCalledTimes(1);
});
});
20 changes: 20 additions & 0 deletions frontend/src/components/atoms/Chip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { Chip } from '@mui/material';
import { MUI_CHIP } from '../../../utils/constants';
import { IChipProp } from '../../../interfaces/types';
import { getRandomLightColor } from '../../../services/functions/functions';



const MyChip = (props: IChipProp) =>
<Chip
size={props.size}
label={props.label}
variant={props.variant}
onClick={props.onClick}
color={props.color}
style={{ ...props.style, backgroundColor: getRandomLightColor() }}
data-testid={MUI_CHIP}
/>

export default MyChip;
16 changes: 16 additions & 0 deletions frontend/src/components/molecules/AnimatedName/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { render } from '@testing-library/react';
import AnimatedName from '.';
import "@testing-library/jest-dom"
import { NAME_ANIMATION } from '../../../utils/constants';

test('renders the AnimatedName component', () => {
const { getByText, getAllByTestId } = render(<AnimatedName />);

const imText = getByText("I'm");
expect(imText).toBeInTheDocument();

const nameLetters = getAllByTestId(NAME_ANIMATION);
expect(nameLetters.length).toBeGreaterThan(0);

});
30 changes: 30 additions & 0 deletions frontend/src/components/molecules/AnimatedName/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'
import { myname } from '../../../services/mocks/mocks'
import { FlexDiv } from '../../../utils/styled'
import { NAME_ANIMATION } from '../../../utils/constants'
import './style.css'


const AnimatedName = () => {
return (
<FlexDiv>
<div>I'm</div>
<div className='name'>
&lt;
{myname.split('').map((ch, index) =>
<span
className={`name-${index}`}
data-testid={NAME_ANIMATION}
key={index}
>
{ch}
</span>
)}
{'/'}
&gt;
</div>
</FlexDiv>
)
}

export default AnimatedName
152 changes: 152 additions & 0 deletions frontend/src/components/molecules/AnimatedName/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
@keyframes gelatine {
from, to { transform: scale(1, 1); }
25% { transform: scale(0.9, 1.1); }
50% { transform: scale(1.1, 0.9); }
75% { transform: scale(0.95, 1.05); }
}

@keyframes bounce {
0%, 20%, 50%, 80%, 100% {transform: translateY(0);}
40% {transform: translateY(-20px);}
60% {transform: translateY(-15px);}
}
@keyframes flip {
0% {
transform: perspective(400px) rotateY(0);
animation-timing-function: ease-out;
}
40% {
transform: perspective(400px) translateZ(150px) rotateY(170deg);
animation-timing-function: ease-out;
}
50% {
transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
animation-timing-function: ease-in;
}
80% {
transform: perspective(400px) rotateY(360deg) scale(.95);
animation-timing-function: ease-in;
}
100% {
transform: perspective(400px) scale(1);
animation-timing-function: ease-in;
}
}

@keyframes swing {
20% { transform: rotate(15deg); }
40% { transform: rotate(-10deg); }
60% { transform: rotate(5deg); }
80% { transform: rotate(-5deg); }
100% { transform: rotate(0deg); }
}

@keyframes wobble {
0% { transform: translateX(0%); }
15% { transform: translateX(-25%) rotate(-5deg); }
30% { transform: translateX(20%) rotate(3deg); }
45% { transform: translateX(-15%) rotate(-3deg); }
60% { transform: translateX(10%) rotate(2deg); }
75% { transform: translateX(-5%) rotate(-1deg); }
100% { transform: translateX(0%); }
}

@keyframes bounce-in-right {
0% {
opacity: 0;
transform: translateX(2000px);
}
60% {
opacity: 1;
transform: translateX(-30px);
}
80% { transform: translateX(10px); }
100% { transform: translateX(0); }
}

@keyframes hinge {
0% { transform: rotate(0); transform-origin: top left; animation-timing-function: ease-in-out; }
20%, 60% { transform: rotate(80deg); transform-origin: top left; animation-timing-function: ease-in-out; }
40% { transform: rotate(60deg); transform-origin: top left; animation-timing-function: ease-in-out; }
80% { transform: rotate(60deg) translateY(0); opacity: 1; transform-origin: top left; animation-timing-function: ease-in-out; }
100% { transform: translateY(700px); opacity: 0; }
}

@keyframes rotate-in-up-left {
0% {
transform-origin: left bottom;
transform: rotate(90deg);
opacity: 0;
}
100% {
transform-origin: left bottom;
transform: rotate(0);
opacity: 1;
}
}

@keyframes rotate-in-down-left {
0% {
transform-origin: left bottom;
transform: rotate(-90deg);
opacity: 0;
}
100% {
transform-origin: left bottom;
transform: rotate(0);
opacity: 1;
}
}

@keyframes hithere {
30% { transform: scale(1.2); }
40%, 60% { transform: rotate(-20deg) scale(1.2); }
50% { transform: rotate(20deg) scale(1.2); }
70% { transform: rotate(0deg) scale(1.2); }
100% { transform: scale(1); }
}

.name {
color: #f4b039;
}

.name-0 {
display: inline-block;
animation: hinge 1.5s infinite 0.1s;
}
.name-1 {
display: inline-block;
animation: bounce 1.5s infinite 0.1s;
}
.name-2, .name-10 {
display: inline-block;
animation: flip 1.5s infinite 0.1s;
}

.name-3 {
display: inline-block;
animation: swing 1.5s infinite 0.1s;
}

.name-4, .name-8 {
display: inline-block;
animation: wobble 1.5s infinite 0.1s;
}
.name-5 {
display: inline-block;
animation: gelatine 1.5s infinite 0.1s;
}
.name-9 {
display: inline-block;
animation: rotate-in-up-left 1.5s infinite 0.1s;
}

.name-7 {
display: inline-block;
animation: rotate-in-down-left 1.5s infinite 0.1s;
}

.name-6 {
display: inline-block;
animation: hithere 1.5s infinite 0.1s;
}
7 changes: 3 additions & 4 deletions frontend/src/components/molecules/IconList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBriefcase, faCode, faEnvelope, faHouse, faLaptopCode, faRightToBracket, faUserGraduate } from '@fortawesome/free-solid-svg-icons';
import { faBriefcase, faCode, faEnvelope, faHouse, faInfo, faLaptopCode, faRightToBracket, faUserGraduate } from '@fortawesome/free-solid-svg-icons';
import DarkModeToggle from '../../atoms/Toggle';
import { IconContainer, LeftDiv, MiddleDiv, RightDiv, StyledAboutIcon, StyledNavIcon } from '../../../utils/styled';
import { IconContainer, LeftDiv, MiddleDiv, RightDiv, StyledNavIcon } from '../../../utils/styled';
import Icon from '../../atoms/Icon';
import LogoGif from '../../../../public/gif/Logo.gif';
import About from '../../../../public/svg/About.svg';
import { useDarkMode } from '../../../services/customhook/useDarkMode';
import { ICON_COMPONENT_HOME } from '../../../utils/constants';

Expand All @@ -19,7 +18,7 @@ const HomeIconsList = () => {
</LeftDiv>
<MiddleDiv>
<FontAwesomeIcon icon={faHouse} />
<Icon src={About} sx={StyledAboutIcon} />
<FontAwesomeIcon icon={faInfo} />
<FontAwesomeIcon icon={faUserGraduate} />
<FontAwesomeIcon icon={faCode} />
<FontAwesomeIcon icon={faLaptopCode} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const SocialMediaIcons = () => {
<IconDiv data-testid = {SOCIAL_MEDIA_COMPONENT}>
{socialMediaData.map(({ platform, icon, color, link }) => (
<a key={platform} href={link} target="_blank" rel="noopener noreferrer">
<FontAwesomeIcon icon={icon} style={{ color }} />
<FontAwesomeIcon icon={icon} style={{ color }} className='wave' />
</a>
))}
</IconDiv>
Expand Down
13 changes: 12 additions & 1 deletion frontend/src/interfaces/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ButtonProps, TypographyProps } from "@mui/material";
import { CSSProperties } from "react";
import { CSSProperties, ReactElement } from "react";

export interface IButtonProps extends ButtonProps {}
export interface ITypgraphyProps extends TypographyProps {
Expand All @@ -21,4 +21,15 @@ export interface IDarkModeToggle {
export interface DarkModeContextProps {
isDark: boolean;
toggleMode: () => void;
}
export interface IChipProp {
label?: string
variant?: 'filled' | 'outlined',
size?: 'medium' | 'small',
color?: 'primary'| 'secondary'| 'warning'| 'error'| 'info'| 'default'| 'success',
text?: string
src?: string
avatar?: ReactElement
onClick?:() => void
style?:React.CSSProperties;
}
43 changes: 43 additions & 0 deletions frontend/src/pages/About/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import About from '.';
import { render, screen, cleanup } from '@testing-library/react';
import "@testing-library/jest-dom"
import { ABOUT_COMPONENT, ABOUT_DESC, ABOUT_SUB_DESC, ABOUT_SUB_FOOTER_DESC, ICON_ABOUT_ALT } from '../../utils/constants';

describe('About Component', () => {
beforeEach(() => {
render(<About />);
});

afterEach(cleanup);

it('renders the About component', () => {
const aboutElement = screen.getByTestId(ABOUT_COMPONENT);
expect(aboutElement).toBeInTheDocument();
});

it('renders the image', () => {
const imageElement = screen.getByAltText(ICON_ABOUT_ALT);
expect(imageElement).toBeInTheDocument();
});

it('renders the chip with label Software Engineer', () => {
const chipElement = screen.getByText('<Software Engineer />');
expect(chipElement).toBeInTheDocument();
});

it('renders the description', () => {
const descriptionElement = screen.getByText(ABOUT_DESC);
expect(descriptionElement).toBeInTheDocument();
});

it('renders the sub-description', () => {
const subDescriptionElement = screen.getByText(ABOUT_SUB_DESC);
expect(subDescriptionElement).toBeInTheDocument();
});

it('renders the skills', () => {
const skillElement = screen.getByText('🌐 Frontend Development');
expect(skillElement).toBeInTheDocument();
});
});
Loading

0 comments on commit 9e2ba89

Please sign in to comment.