Skip to content

Commit d429f3c

Browse files
Format timeline into calendar view (#6349)
* format timeline into calendar view * ... but make it responsive * also when it's big tho * scroll * add all months and gradient to overflowing lists * initial scroll / button placement * mobile improvements --------- Co-authored-by: Eli Kinsey <[email protected]>
1 parent b188e77 commit d429f3c

File tree

2 files changed

+127
-81
lines changed

2 files changed

+127
-81
lines changed

src/components/CompensationCalculator/compensation_data/sf_benchmark.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const sfBenchmark: Record<string, number> = {
1414
'Product Designer': 186000,
1515
'Product Manager': 213600,
1616
'Product Marketer': 195000,
17-
'Recruiter': 173000,
17+
Recruiter: 173000,
1818
'Site Reliability Engineer': 236000,
1919
'Talent Partner': 173000,
2020
// 'Technical Writer': 150000,

src/components/Home/Timeline.js

+126-80
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { CallToAction } from 'components/CallToAction'
21
import { graphql, useStaticQuery } from 'gatsby'
3-
import Link from 'components/Link'
4-
import { heading, section } from './classes'
2+
import { heading } from './classes'
53
import groupBy from 'lodash.groupby'
6-
import React from 'react'
4+
import React, { useEffect, useRef, useState } from 'react'
5+
import { ArrowLeft, ArrowRight } from '@posthog/icons'
6+
import { useBreakpoint } from 'gatsby-plugin-breakpoints'
77

88
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
99
const categories = {
@@ -12,7 +12,42 @@ const categories = {
1212
'Something cool happened': 'milestone',
1313
}
1414

15+
export const Items = ({ items }) => {
16+
const ref = useRef(null)
17+
const [isOverflowing, setIsOverflowing] = useState(false)
18+
19+
useEffect(() => {
20+
setIsOverflowing(ref?.current?.scrollHeight > ref?.current?.getBoundingClientRect()?.height)
21+
}, [])
22+
23+
return (
24+
<div
25+
className={`relative ${
26+
isOverflowing
27+
? 'after:absolute after:h-[30px] after:w-full after:bottom-0 after:left-0 after:bg-gradient-to-t after:from-accent dark:after:from-accent-dark after:to-transparent'
28+
: ''
29+
}`}
30+
>
31+
<ul ref={ref} className={`m-0 p-0 h-[110px] overflow-auto ${isOverflowing ? 'pb-[30px]' : ''}`}>
32+
{items?.map(({ title, category }) => {
33+
return (
34+
<li
35+
key={title}
36+
className="relative list-none text-sm text-left pl-4 content-none before:inline-block before:absolute before:w-[10px] before:h-[10px] before:left-0 before:top-[5px] before:rounded-full before:mr-2 mt-1 first:mt-0"
37+
data-type={categories[category]}
38+
>
39+
{title}
40+
</li>
41+
)
42+
})}
43+
</ul>
44+
</div>
45+
)
46+
}
47+
1548
export default function Timeline() {
49+
const breakpoints = useBreakpoint()
50+
const listRef = useRef(null)
1651
const {
1752
allSqueakRoadmap: { nodes },
1853
} = useStaticQuery(graphql`
@@ -49,8 +84,12 @@ export default function Timeline() {
4984
}
5085
)
5186

87+
useEffect(() => {
88+
listRef?.current?.scrollBy({ left: listRef?.current?.scrollWidth })
89+
}, [])
90+
5291
return (
53-
<section className="px-4 mb-12 md:mb-20">
92+
<section className="px-4 mb-12 md:mb-20 overflow-hidden">
5493
<h2 className={heading()}>
5594
We ship <br className="sm:hidden" />
5695
<span className="text-orange">weirdly fast</span>
@@ -73,82 +112,89 @@ export default function Timeline() {
73112
</div>
74113
</div>
75114
</div>
76-
77-
<div className="max-w-screen-2xl mx-auto mdlg:grid grid-cols-2 xl:grid-cols-4 border border-light dark:border-dark divide-x divide-light dark:divide-dark">
78-
{Object.keys(pastEvents).map((year) => {
79-
const pastMonths = groupBy(pastEvents[year], (node) => {
80-
const date = new Date(node.dateCompleted || node.projectedCompletion)
81-
return months[date.getUTCMonth()]
82-
})
83-
const futureQuarters = groupBy(futureEvents[year], (node) => {
84-
const date = node.dateCompleted || node.projectedCompletion
85-
return Math.floor(new Date(date).getUTCMonth() / 3 + 1)
86-
})
87-
return (
88-
<div
89-
key={year}
90-
className="bg-accent dark:bg-accent-dark w-full mb-4 lg:mb-0 last:border-r border-light dark:border-dark"
91-
>
92-
<h4 className="text-base py-1 font-bold text-center bg-light dark:bg-dark border-y xl:border-t-0 border-light dark:border-dark">
93-
{year}
94-
</h4>
95-
<div className="px-8">
96-
<ul role="list" className="py-1 px-0">
97-
{Object.keys(pastMonths).map((month) => {
98-
return (
99-
<li
100-
key={month}
101-
className="timeline-entry list-none border-light dark:border-dark border-b last:border-none flex py-2 gap-3 items-start"
102-
>
103-
<p className="text-[14px] text-gray capitalize w-[30px] flex-shrink-0 m-0">
104-
{month}
105-
</p>
106-
<ul className="list-none m-0 p-0">
107-
{pastMonths[month].map(({ title, category }) => {
108-
return (
109-
<li
110-
key={title}
111-
className="flex-auto relative text-[14px] text-left pl-4 content-none before:inline-block before:absolute before:w-[10px] before:h-[10px] before:left-0 before:top-[5px] before:rounded-full before:mr-2 mt-1 first:mt-0"
112-
data-type={categories[category]}
113-
>
114-
{title}
115-
</li>
116-
)
117-
})}
118-
</ul>
119-
</li>
120-
)
121-
})}
122-
{Object.keys(futureQuarters).map((quarter) => {
123-
return (
124-
<li
125-
key={quarter}
126-
className="timeline-entry list-none flex py-2 gap-3 items-start"
127-
>
128-
<p className="text-[14px] text-gray capitalize w-[30px] flex-shrink-0 m-0">
129-
Q{quarter}
130-
</p>
131-
<ul className="list-none m-0 p-0">
132-
{futureQuarters[quarter].map(({ title, category }) => {
133-
return (
134-
<li
135-
key={title}
136-
className="flex-auto relative text-[14px] text-left pl-4 text-gray content-none before:inline-block before:absolute before:w-[10px] before:h-[10px] before:left-0 before:top-[5px] before:rounded-full before:mr-2 mt-1 first:mt-0"
137-
data-type={categories[category]}
138-
>
139-
{title}
140-
</li>
141-
)
142-
})}
143-
</ul>
144-
</li>
145-
)
146-
})}
147-
</ul>
115+
<div className="relative -mx-4 pr-4">
116+
<div className="md:block hidden absolute z-20 top-1/2 left-0 -translate-y-1/2">
117+
<button
118+
onClick={() => listRef?.current?.scrollBy({ left: -50, behavior: 'smooth' })}
119+
className="relative hover:scale-[1.01] hover:top-[-1px] active:top-[.5px] active:scale-[.99] md:z-30 px-2 py-8"
120+
>
121+
<ArrowLeft className="w-10" />
122+
</button>
123+
</div>
124+
<div
125+
ref={listRef}
126+
className="-mr-4 px-4 md:px-16 snap-x snap-mandatory flex flex-nowrap gap-4 overflow-auto relative"
127+
>
128+
{Object.keys(pastEvents).map((year, index) => {
129+
const pastMonths = groupBy(pastEvents[year], (node) => {
130+
const date = new Date(node.dateCompleted || node.projectedCompletion)
131+
return months[date.getUTCMonth()]
132+
})
133+
const futureQuarters = groupBy(futureEvents[year], (node) => {
134+
const date = node.dateCompleted || node.projectedCompletion
135+
return Math.floor(new Date(date).getUTCMonth() / 3 + 1)
136+
})
137+
return (
138+
<div key={year} className="w-[80vw] md:w-[90vw] max-w-5xl shrink-0 mb-4 snap-center">
139+
<h4 className="text-2xl py-1 font-bold text-center">{year}</h4>
140+
<div className="p-4 bg-white dark:bg-dark border border-light dark:border-dark sm:h-auto h-96 overflow-auto snap-x">
141+
<ul role="list" className="py-1 px-0 grid sm:grid-cols-2 md:grid-cols-4 gap-4">
142+
{months.map((month) => {
143+
const items = pastMonths[month]
144+
if (breakpoints.sm && !items) return null
145+
return (
146+
<li
147+
key={month}
148+
className="timeline-entry bg-accent dark:bg-accent-dark list-none px-4 pb-4 text-center min-h-[6rem] md:min-h-[8rem] lg:min-h-[10rem]"
149+
>
150+
<p
151+
className={`text-lg font-bold border-b border-light dark:border-dark capitalize py-2 mb-2`}
152+
>
153+
{month}
154+
</p>
155+
<Items items={items} />
156+
</li>
157+
)
158+
})}
159+
{Object.keys(futureQuarters).map((quarter) => {
160+
return (
161+
<li
162+
key={quarter}
163+
className="timeline-entry list-none bg-accent dark:bg-accent-dark px-4 pb-4"
164+
>
165+
<p className="text-lg font-bold border-b border-light dark:border-dark capitalize py-2 mb-2 text-center">
166+
Q{quarter}
167+
</p>
168+
<ul className="list-none m-0 p-0">
169+
{futureQuarters[quarter].map(({ title, category }) => {
170+
return (
171+
<li
172+
key={title}
173+
className="flex-auto relative text-[14px] text-left pl-4 content-none before:inline-block before:absolute before:w-[10px] before:h-[10px] before:left-0 before:top-[5px] before:rounded-full before:mr-2 mt-1 first:mt-0"
174+
data-type={categories[category]}
175+
>
176+
{title}
177+
</li>
178+
)
179+
})}
180+
</ul>
181+
</li>
182+
)
183+
})}
184+
</ul>
185+
</div>
148186
</div>
149-
</div>
150-
)
151-
})}
187+
)
188+
})}
189+
</div>
190+
<div className="absolute top-1/2 right-0 -translate-y-1/2">
191+
<button
192+
onClick={() => listRef?.current?.scrollBy({ left: 50, behavior: 'smooth' })}
193+
className="md:block hidden relative hover:scale-[1.01] hover:top-[-1px] active:top-[.5px] active:scale-[.99] md:z-30 px-2 py-8"
194+
>
195+
<ArrowRight className="w-10" />
196+
</button>
197+
</div>
152198
</div>
153199
</section>
154200
)

0 commit comments

Comments
 (0)