mirror of https://github.com/mkrhere/pw2
Muthu Kumar
1 year ago
5 changed files with 270 additions and 157 deletions
@ -0,0 +1,101 @@ |
|||||
|
import { css } from "@emotion/css"; |
||||
|
import React from "react"; |
||||
|
import { setupDynamicGradient } from "../../util"; |
||||
|
import { Experience } from "./types"; |
||||
|
|
||||
|
const Circle: React.FC = () => ( |
||||
|
<div className="timeline-segment" aria-hidden> |
||||
|
<div |
||||
|
className={css` |
||||
|
width: 200vw; |
||||
|
height: 1px; |
||||
|
background: #333333; |
||||
|
left: -50vw; |
||||
|
position: absolute; |
||||
|
top: calc(-3rem + 0.2rem / 2); |
||||
|
z-index: 0; |
||||
|
`}></div>
|
||||
|
<div |
||||
|
className={css` |
||||
|
width: 0.25rem; |
||||
|
height: 0.25rem; |
||||
|
background: #333333; |
||||
|
background: #ffffff; |
||||
|
border-radius: 100%; |
||||
|
position: absolute; |
||||
|
top: -3rem; |
||||
|
left: 0; |
||||
|
z-index: 100; |
||||
|
`}></div>
|
||||
|
</div> |
||||
|
); |
||||
|
|
||||
|
const btn = css` |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 0.6rem; |
||||
|
cursor: pointer; |
||||
|
padding: 1rem var(--item-padding); |
||||
|
border-radius: 0.5rem; |
||||
|
position: relative; |
||||
|
height: max-content; |
||||
|
width: 100%; |
||||
|
|
||||
|
background-color: transparent; |
||||
|
border: none; |
||||
|
text-align: left; |
||||
|
display: inherit; |
||||
|
|
||||
|
& > * { |
||||
|
z-index: 10; |
||||
|
} |
||||
|
|
||||
|
@media (pointer: fine) { |
||||
|
&:hover { |
||||
|
background-color: var(--card-hover); |
||||
|
z-index: 1000; |
||||
|
box-shadow: 0 0 25rem 2rem rgba(190, 190, 190, 0.1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
& .timeline-segment { |
||||
|
position: absolute; |
||||
|
} |
||||
|
|
||||
|
& .position { |
||||
|
color: var(--text-colour); |
||||
|
} |
||||
|
|
||||
|
& .year, |
||||
|
& h5 { |
||||
|
font-size: 0.8rem; |
||||
|
font-weight: 300; |
||||
|
color: var(--text-subdued); |
||||
|
} |
||||
|
|
||||
|
& h5 { |
||||
|
font-weight: 400; |
||||
|
margin-block-start: 0.2rem; |
||||
|
} |
||||
|
`;
|
||||
|
|
||||
|
export const Content = ({ |
||||
|
onClick, |
||||
|
title, |
||||
|
year, |
||||
|
position, |
||||
|
location, |
||||
|
}: Experience) => { |
||||
|
return ( |
||||
|
<button className={btn} onClick={onClick} ref={setupDynamicGradient}> |
||||
|
<div className="dynamic-gradient" /> |
||||
|
<Circle /> |
||||
|
<h4> |
||||
|
{title} |
||||
|
<span className="year"> · ({year})</span> |
||||
|
</h4> |
||||
|
<span className="position">{position}</span> |
||||
|
<h5>{location}</h5> |
||||
|
</button> |
||||
|
); |
||||
|
}; |
@ -0,0 +1,66 @@ |
|||||
|
import React from "react"; |
||||
|
import { css, cx } from "@emotion/css"; |
||||
|
import { Experience } from "./types"; |
||||
|
|
||||
|
const story = css` |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
border-radius: 0.5rem; |
||||
|
display: flex; |
||||
|
|
||||
|
overflow: hidden; |
||||
|
|
||||
|
& .contents { |
||||
|
padding: 1.5rem; |
||||
|
line-height: 1.25rem; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
align-items: flex-start; |
||||
|
gap: 2rem; |
||||
|
margin-block-start: 1rem; |
||||
|
height: var(--story-height); |
||||
|
|
||||
|
& ul { |
||||
|
max-height: 100%; |
||||
|
margin: 0; |
||||
|
column-count: 3; |
||||
|
column-gap: 2rem; |
||||
|
color: var(--text-subdued); |
||||
|
font-weight: 400; |
||||
|
|
||||
|
& li + li { |
||||
|
margin-block-start: 0.5rem; |
||||
|
} |
||||
|
|
||||
|
& li::marker { |
||||
|
content: ""; |
||||
|
font-weight: 800; |
||||
|
padding-top: 1rem; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
`;
|
||||
|
|
||||
|
export const Story = ({ description, logo }: Experience) => { |
||||
|
return ( |
||||
|
<div className={cx(story, "story")}> |
||||
|
<div className="contents"> |
||||
|
<img |
||||
|
src={`/assets/logos/` + logo} |
||||
|
className={cx( |
||||
|
"story-logo", |
||||
|
css` |
||||
|
height: 4rem; |
||||
|
width: 4rem; |
||||
|
|
||||
|
background: rgba(40, 40, 40); |
||||
|
border-radius: 100%; |
||||
|
`,
|
||||
|
)} |
||||
|
/> |
||||
|
<ul>{description}</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
@ -0,0 +1,70 @@ |
|||||
|
import React from "react"; |
||||
|
import { css, cx } from "@emotion/css"; |
||||
|
import { Story } from "./Story"; |
||||
|
import { Experience } from "./types"; |
||||
|
import { Content } from "./Content"; |
||||
|
|
||||
|
const expUnit = css` |
||||
|
--final-height: 20rem; |
||||
|
--unit-height: 9rem; |
||||
|
--story-height: calc(var(--final-height) - var(--unit-height)); |
||||
|
--transition-time: 300ms; |
||||
|
|
||||
|
& > * { |
||||
|
line-height: 1em; |
||||
|
font-size: 1rem; |
||||
|
} |
||||
|
|
||||
|
& button { |
||||
|
border: 1px solid transparent; |
||||
|
transition: all calc(var(--transition-time) * 2); |
||||
|
} |
||||
|
|
||||
|
&.active button { |
||||
|
background-color: var(--card-active); |
||||
|
border: 1px solid var(--card-active-border); |
||||
|
box-shadow: 0 0 50rem 0 rgba(190, 190, 190, 0.5); |
||||
|
z-index: 800; |
||||
|
|
||||
|
& .year, |
||||
|
& h5 { |
||||
|
color: var(--text-colour); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
margin-block-end: 0.5rem; |
||||
|
|
||||
|
/* -- Animation stuff -- */ |
||||
|
|
||||
|
height: var(--unit-height); |
||||
|
transition: height var(--transition-time) ease-in-out; |
||||
|
|
||||
|
& .story { |
||||
|
opacity: 0; |
||||
|
transition: opacity var(--transition-time) ease-in-out; |
||||
|
transition-delay: 0; |
||||
|
} |
||||
|
|
||||
|
&.active { |
||||
|
height: var(--final-height); |
||||
|
transition-delay: 0; |
||||
|
transition-delay: var(--transition-time); |
||||
|
|
||||
|
.story { |
||||
|
opacity: 1; |
||||
|
transition: opacity calc(var(--transition-time) * 2) ease-in-out; |
||||
|
transition-delay: var(--transition-time); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* -- */ |
||||
|
`;
|
||||
|
|
||||
|
export const ExpUnit = (props: Experience) => { |
||||
|
return ( |
||||
|
<div className={cx(expUnit, { active: props.active })}> |
||||
|
<Content {...props} /> |
||||
|
<Story {...props} /> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
@ -0,0 +1,10 @@ |
|||||
|
export interface Experience { |
||||
|
active: boolean; |
||||
|
title: string; |
||||
|
location: string; |
||||
|
position: string; |
||||
|
year: string; |
||||
|
description: React.ReactElement | string; |
||||
|
logo: string; |
||||
|
onClick?: (e: React.MouseEvent) => void; |
||||
|
} |
Loading…
Reference in new issue