timeline
Milestones
import React from 'react';
import {
Box,
chakra,
Container,
Text,
HStack,
VStack,
Flex,
useColorModeValue,
useBreakpointValue
} from '@chakra-ui/react';
const milestones = [
{
id: 1,
date: 'MARCH 30, 2022',
title: 'Chakra Hackathon',
description: `Winner of first ever ChakraUI Hackathon. On sait depuis longtemps que travailler avec du texte lisible et contenant du sens.`
},
{
id: 2,
date: 'July 30, 2021',
title: 'Open Source, first contribution',
description: `Fixing a typo, to fix a bug, contributing to Open Source and collaborating to improve technology for everyone, Ahmad's world changed again!.`
},
{
id: 3,
date: 'July 30, 2018',
title: 'Freelancing, started working for myself',
description:
'Ahmad starts his own business consulting for companies as a fullstack developer. Clients include UK Government departments, UK banks, global fintechs and startups.'
}
];
const Milestones = () => {
const isMobile = useBreakpointValue({ base: true, md: false });
const isDesktop = useBreakpointValue({ base: false, md: true });
return (
<Container maxWidth="7xl" p={{ base: 2, sm: 10 }}>
<chakra.h3 fontSize="4xl" fontWeight="bold" mb={18} textAlign="center">
Milestones
</chakra.h3>
{milestones.map((milestone) => (
<Flex key={milestone.id} mb="10px">
{/* Desktop view(left card) */}
{isDesktop && milestone.id % 2 === 0 && (
<>
<EmptyCard />
<LineWithDot />
<Card {...milestone} />
</>
)}
{/* Mobile view */}
{isMobile && (
<>
<LineWithDot />
<Card {...milestone} />
</>
)}
{/* Desktop view(right card) */}
{isDesktop && milestone.id % 2 !== 0 && (
<>
<Card {...milestone} />
<LineWithDot />
<EmptyCard />
</>
)}
</Flex>
))}
</Container>
);
};
interface CardProps {
id: number;
title: string;
description: string;
date: string;
}
const Card = ({ id, title, description, date }: CardProps) => {
// For even id show card on left side
// For odd id show card on right side
const isEvenId = id % 2 == 0;
let borderWidthValue = isEvenId ? '15px 15px 15px 0' : '15px 0 15px 15px';
let leftValue = isEvenId ? '-15px' : 'unset';
let rightValue = isEvenId ? 'unset' : '-15px';
const isMobile = useBreakpointValue({ base: true, md: false });
if (isMobile) {
leftValue = '-15px';
rightValue = 'unset';
borderWidthValue = '15px 15px 15px 0';
}
return (
<HStack
flex={1}
p={{ base: 3, sm: 6 }}
bg={useColorModeValue('gray.100', 'gray.800')}
spacing={5}
rounded="lg"
alignItems="center"
pos="relative"
_before={{
content: `""`,
w: '0',
h: '0',
borderColor: `transparent ${useColorModeValue('#edf2f6', '#1a202c')} transparent`,
borderStyle: 'solid',
borderWidth: borderWidthValue,
position: 'absolute',
left: leftValue,
right: rightValue,
display: 'block'
}}
>
<Box>
<Text fontSize="lg" color={isEvenId ? 'teal.400' : 'blue.400'}>
{date}
</Text>
<VStack spacing={2} mb={3} textAlign="left">
<chakra.h1 fontSize="2xl" lineHeight={1.2} fontWeight="bold" w="100%">
{title}
</chakra.h1>
<Text fontSize="md">{description}</Text>
</VStack>
</Box>
</HStack>
);
};
const LineWithDot = () => {
return (
<Flex
pos="relative"
alignItems="center"
mr={{ base: '40px', md: '40px' }}
ml={{ base: '0', md: '40px' }}
>
<chakra.span
position="absolute"
left="50%"
height="calc(100% + 10px)"
border="1px solid"
borderColor={useColorModeValue('gray.200', 'gray.700')}
top="0px"
></chakra.span>
<Box pos="relative" p="10px">
<Box
pos="absolute"
top="0"
left="0"
bottom="0"
right="0"
width="100%"
height="100%"
backgroundSize="cover"
backgroundRepeat="no-repeat"
backgroundPosition="center center"
bg={useColorModeValue('gray.600', 'gray.200')}
borderRadius="100px"
backgroundImage="none"
opacity={1}
></Box>
</Box>
</Flex>
);
};
const EmptyCard = () => {
return <Box flex={{ base: 0, md: 1 }} p={{ base: 0, md: 6 }} bg="transparent"></Box>;
};
export default Milestones;
Articles
import React from 'react';
import {
Box,
chakra,
Container,
Link,
Text,
HStack,
VStack,
Flex,
Icon,
useColorModeValue
} from '@chakra-ui/react';
// Here we have used react-icons package for the icons
import { FaRegNewspaper } from 'react-icons/fa';
import { BsGithub } from 'react-icons/bs';
import { IconType } from 'react-icons';
const milestones = [
{
id: 1,
categories: ['Article'],
title: 'Wrote first article on Medium',
icon: FaRegNewspaper,
description: `Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum is simply dummy text of the printing and typesetting industry. `,
date: 'MARCH 30, 2022'
},
{
id: 2,
categories: ['Web Dev', 'OSS'],
title: 'First open source contribution',
icon: BsGithub,
description: `Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.`,
date: 'July 30, 2022'
}
];
const Milestones = () => {
return (
<Container maxWidth="4xl" p={{ base: 2, sm: 10 }}>
<chakra.h3 fontSize="4xl" fontWeight="bold" mb={18} textAlign="center">
Articles
</chakra.h3>
{milestones.map((milestone, index) => (
<Flex key={index} mb="10px">
<LineWithDot />
<Card {...milestone} />
</Flex>
))}
</Container>
);
};
interface CardProps {
title: string;
categories: string[];
description: string;
icon: IconType;
date: string;
}
const Card = ({ title, categories, description, icon, date }: CardProps) => {
return (
<HStack
p={{ base: 3, sm: 6 }}
bg={useColorModeValue('gray.100', 'gray.800')}
spacing={5}
rounded="lg"
alignItems="center"
pos="relative"
_before={{
content: `""`,
w: '0',
h: '0',
borderColor: `transparent ${useColorModeValue('#edf2f6', '#1a202c')} transparent`,
borderStyle: 'solid',
borderWidth: '15px 15px 15px 0',
position: 'absolute',
left: '-15px',
display: 'block'
}}
>
<Icon as={icon} w={12} h={12} color="teal.400" />
<Box>
<HStack spacing={2} mb={1}>
{categories.map((cat) => (
<Text fontSize="sm" key={cat}>
{cat}
</Text>
))}
</HStack>
<VStack spacing={2} mb={3} textAlign="left">
<chakra.h1
as={Link}
_hover={{ color: 'teal.400' }}
fontSize="2xl"
lineHeight={1.2}
fontWeight="bold"
w="100%"
>
{title}
</chakra.h1>
<Text fontSize="md" noOfLines={2}>
{description}
</Text>
</VStack>
<Text fontSize="sm">{date}</Text>
</Box>
</HStack>
);
};
const LineWithDot = () => {
return (
<Flex pos="relative" alignItems="center" mr="40px">
<chakra.span
position="absolute"
left="50%"
height="calc(100% + 10px)"
border="1px solid"
borderColor={useColorModeValue('gray.200', 'gray.700')}
top="0px"
></chakra.span>
<Box pos="relative" p="10px">
<Box
pos="absolute"
width="100%"
height="100%"
bottom="0"
right="0"
top="0"
left="0"
backgroundSize="cover"
backgroundRepeat="no-repeat"
backgroundPosition="center center"
backgroundColor="rgb(255, 255, 255)"
borderRadius="100px"
border="3px solid rgb(4, 180, 180)"
backgroundImage="none"
opacity={1}
></Box>
</Box>
</Flex>
);
};
export default Milestones;
With icons
import {
VStack,
Heading,
Box,
Link,
Container,
BoxProps,
Circle,
Flex,
useColorModeValue
} from '@chakra-ui/react';
import { FaTools } from 'react-icons/fa';
// Here we have used react-icons package for the icons
import { FiPackage, FiHome, FiBarChart2, FiCheckCircle } from 'react-icons/fi';
const Milestones = () => {
const linkColor = 'blue.400';
const linkHoverColor = 'blue.600';
return (
<Container maxW="7xl" p={{ base: 2, sm: 10 }}>
<VStack textAlign="start" align="start" mb={5}>
<Box zIndex={5}>
<Heading fontSize="4xl" fontWeight="600" my={5}>
2021
</Heading>
<Box>
<MilestoneItem icon={FaTools}>
Learnt{' '}
<Link
href="https://www.typescriptlang.org"
color={linkColor}
_hover={{ color: linkHoverColor }}
isExternal
>
Typescript
</Link>{' '}
and{' '}
<Link
href="https://nextjs.org"
color={linkColor}
_hover={{ color: linkHoverColor }}
isExternal
>
Next.js
</Link>
</MilestoneItem>
<MilestoneItem icon={FiPackage}>
Published 3 posts on my portfolio website{' '}
<Link
href="https://mahmad.me/blog"
color={linkColor}
_hover={{ color: linkHoverColor }}
isExternal
>
Blog
</Link>
</MilestoneItem>
<MilestoneItem icon={FiPackage}>
Published or contributed to{' '}
<Link
href="https://mahmad.me/open-source"
color={linkColor}
_hover={{ color: linkHoverColor }}
isExternal
>
20+ open-source repositories
</Link>
</MilestoneItem>
<MilestoneItem icon={FiBarChart2}>
Collected 34k+ posts views and 1.5k+ total reactions on{' '}
<Link
href="https://dev.to/m_ahmad"
color={linkColor}
_hover={{ color: linkHoverColor }}
isExternal
>
Dev.to
</Link>
</MilestoneItem>
<MilestoneItem icon={FiHome} skipTrail>
Rebuilt my portfolio website with React, ChakraUI and Framer-motion,{' '}
<Link
href="https://github.com/MA-Ahmad/myPortfolio"
color={linkColor}
_hover={{ color: linkHoverColor }}
isExternal
>
source on Github
</Link>
.
</MilestoneItem>
</Box>
</Box>
</VStack>
</Container>
);
};
interface MilestoneItemProps extends BoxProps {
icon?: any;
boxProps?: BoxProps;
skipTrail?: boolean;
}
const MilestoneItem: React.FC<MilestoneItemProps> = ({
icon = FiCheckCircle,
boxProps = {},
skipTrail = false,
children,
...props
}) => {
const color = useColorModeValue('gray.700', 'gray.500');
return (
<Flex minH={20} {...props}>
<Flex flexDir="column" alignItems="center" mr={4} pos="relative">
<Circle
size={12}
bg={useColorModeValue('gray.600', 'gray.500')}
opacity={useColorModeValue(0.07, 0.15)}
/>
<Box as={icon} size="1.25rem" color={color} pos="absolute" left="0.875rem" top="0.875rem" />
{!skipTrail && <Box w="1px" flex={1} bg={color} my={1} />}
</Flex>
<Box pt={{ base: 1, sm: 3 }} {...boxProps}>
{children}
</Box>
</Flex>
);
};
export default Milestones;