Skip to content

Commit

Permalink
use gsap
Browse files Browse the repository at this point in the history
  • Loading branch information
ashharrison90 committed Nov 18, 2023
1 parent c40f959 commit 5179005
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 153 deletions.
1 change: 1 addition & 0 deletions components/Footer/Footer.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
display: flex;
flex-direction: column;
min-height: 60px;
position: relative;
}

.socialLink {
Expand Down
13 changes: 3 additions & 10 deletions components/Layout/Layout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@
width: 100%;
}

.parallaxContainer {
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
perspective: 1px;
perspective-origin: bottom right;
width: 100%;
}

.foreground {
display: flex;
flex-direction: column;
Expand All @@ -29,17 +20,19 @@
}

.foregroundContentRef {
box-shadow: inset 0 0 60px 0 black;
display: flex;
flex-direction: column;
position: relative;
width: 100%;
}

.contentContainer {
align-items: center;
background-color: var(--background);
display: flex;
flex: 1;
flex-direction: column;
position: relative;
}

.content {
Expand Down
95 changes: 36 additions & 59 deletions components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import classnames from 'classnames'
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'
import Head from 'next/head'
import { useEffect, useRef, useState, ReactNode } from 'react'
import { ReactNode, useEffect, useRef, useState } from 'react'

import Footer from '../Footer/Footer'
import Header from '../Header/Header'
Expand All @@ -23,90 +25,65 @@ let prevScrollTop = 0
export default function Layout({
backgroundContent,
backgroundHeight = 0,
blurBackground,
children,
foregroundContent,
hideHeaderUntilScroll = false,
metaDescription,
metaTitle,
}: Props) {
const [showHeader, setShowHeader] = useState(!hideHeaderUntilScroll)
const [backgroundContentFade, setBackgroundContentFade] = useState(0)
const containerRef = useRef<HTMLDivElement>(null)
const foregroundContentRef = useRef<HTMLDivElement>(null)
const headerRef = useRef<HTMLElement>(null)
useEffect(() => {
gsap.to('[data-speed]', {
y: (i, el) =>
(1 - parseFloat(el.getAttribute('data-speed'))) *
ScrollTrigger.maxScroll(window),
ease: 'none',
scrollTrigger: {
start: 0,
end: 'max',
scrub: true,
},
})

const handleScroll = () => {
if (containerRef.current) {
if (hideHeaderUntilScroll) {
setShowHeader(containerRef.current.scrollTop > 0)
} else {
setShowHeader(containerRef.current.scrollTop < prevScrollTop)
prevScrollTop = containerRef.current.scrollTop
}
}
// doing this all the time wouldn't be very good for perfomance
// let's split it into intervals of 0.1
// and stop once we're past 1
if (foregroundContent && foregroundContentRef.current) {
const height =
foregroundContentRef.current.getBoundingClientRect().height
const top = foregroundContentRef.current.getBoundingClientRect().top
const scrollScaleFactor = Math.round(10 * (Math.abs(top) / height)) / 10
setBackgroundContentFade(Math.min(scrollScaleFactor, 1))
if (hideHeaderUntilScroll) {
setShowHeader(window.scrollY > 0)
} else {
setShowHeader(window.scrollY < prevScrollTop)
prevScrollTop = window.scrollY
}
}

headerRef.current?.addEventListener('focusin', () => setShowHeader(true))
containerRef.current?.addEventListener('scroll', handleScroll)
}, [foregroundContent, hideHeaderUntilScroll])

document.addEventListener('scroll', handleScroll)
}, [hideHeaderUntilScroll])
return (
<div className={styles.container}>
<Head>
<title>{metaTitle}</title>
<meta name='description' content={metaDescription} />
</Head>
<Header show={showHeader} ref={headerRef} />
<div className={styles.parallaxContainer} ref={containerRef} role='main'>
{backgroundContent}
{backgroundContent}
<div
style={{
height: `${backgroundHeight}%`,
}}
className={styles.foregroundContentRef}
>
{foregroundContent}
</div>
<div className={styles.contentContainer} role='main'>
<div
data-testid='backgroundOverlay'
className={classnames(styles.foreground, {
[styles.blur]: blurBackground,
className={classnames(styles.content, {
[styles.padContent]: !foregroundContent && !hideHeaderUntilScroll,
})}
style={{
backgroundColor: `rgba(var(--hero-background-rgb), ${
Math.max(0, backgroundContentFade - 0.2) * 0.5
})`,
backdropFilter: `blur(${
Math.max(0, backgroundContentFade - 0.2) * 20
}px)`,
}}
>
<div
ref={foregroundContentRef}
style={{
height: `${backgroundHeight}%`,
minHeight: `${backgroundHeight}%`,
}}
className={styles.foregroundContentRef}
>
{foregroundContent}
</div>
<div className={styles.contentContainer}>
<div
className={classnames(styles.content, {
[styles.padContent]:
!foregroundContent && !hideHeaderUntilScroll,
})}
>
{children}
</div>
</div>
<Footer />
{children}
</div>
</div>
<Footer />
</div>
)
}
6 changes: 0 additions & 6 deletions components/PostLayout/PostLayout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@
object-fit: cover;
object-position: top;
position: absolute;

// why is this scale so weird?
// because windows doesn't calculate the scale properly.
// so we have to overscale slightly to prevent an ugly gap
transform: translateZ(-4px) scale(5.1);
transform-origin: bottom right;
width: 100%;
}

Expand Down
11 changes: 8 additions & 3 deletions components/PostLayout/PostLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function PostLayout({ children, metadata }: Props) {
hljs.highlightAll()
gsap.from(`.${layoutStyles.foregroundContentRef}`, {
duration: 0.5,
minHeight: '100%',
height: '100%',
ease: 'back',
delay: 0.1,
})
Expand Down Expand Up @@ -65,14 +65,19 @@ export default function PostLayout({ children, metadata }: Props) {
const { coverImage, date, excerpt, tags, title } = metadata

const backgroundContent = (
<img alt='' className={styles.coverImage} src={coverImage} />
<img
alt=''
data-speed='0.15'
className={styles.coverImage}
src={coverImage}
/>
)
const foregroundContent = <div className={styles.padder} />

return (
<Layout
backgroundContent={backgroundContent}
backgroundHeight={50}
backgroundHeight={65}
foregroundContent={foregroundContent}
metaDescription={excerpt}
metaTitle={title}
Expand Down
7 changes: 7 additions & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'
import { AppProps } from 'next/app'
import dynamic from 'next/dynamic'
import '../styles/globals.scss'
import { useEffect } from 'react'

// Turn off SSR for the theme context so we can access window immediately
const ThemeContextProvider = dynamic(
Expand All @@ -11,6 +14,10 @@ const ThemeContextProvider = dynamic(
)

function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
gsap.registerPlugin(ScrollTrigger)
}, [])

return (
<ThemeContextProvider>
<Component {...pageProps} />
Expand Down
45 changes: 14 additions & 31 deletions pages/about.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useRef } from 'react'
import { gsap } from 'gsap'
import { useEffect } from 'react'
import Typewriter from 'typewriter-effect'

import JobSummary from '../components/JobSummary/JobSummary'
Expand Down Expand Up @@ -30,34 +31,20 @@ const skills = [
]

export default function About() {
const grafanaRef = useRef<HTMLDivElement>(null)
const ibmRef = useRef<HTMLDivElement>(null)
const qinetiqRef = useRef<HTMLDivElement>(null)
const durhamRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const intersectionObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const target = entry.target
if (target instanceof HTMLElement) {
target.style.opacity = '1'
target.style.transform = 'none'
}
}
})
},
{
threshold: 0.5,
},
)
;[grafanaRef, ibmRef, qinetiqRef, durhamRef].forEach((ref) => {
if (ref.current) {
intersectionObserver.observe(ref.current)
}
const jobSummaries = gsap.utils.toArray<string>(`.${styles.jobSummary}`)
jobSummaries.forEach((jobSummary) => {
gsap.from(jobSummary, {
scrollTrigger: {
trigger: jobSummary,
start: 'center bottom',
},
opacity: 0,
x: '-5%',
duration: 1,
ease: 'power3.out',
})
})
return () => intersectionObserver.disconnect()
}, [])

return (
Expand Down Expand Up @@ -96,7 +83,6 @@ export default function About() {
<p>But did Mark Twain ever develop software? No. Stupid.</p>

<JobSummary
ref={grafanaRef}
className={styles.jobSummary}
company='Grafana'
icon={<Grafana />}
Expand Down Expand Up @@ -133,7 +119,6 @@ export default function About() {
</JobSummary>

<JobSummary
ref={ibmRef}
className={styles.jobSummary}
company='IBM'
icon={<Ibm />}
Expand Down Expand Up @@ -202,7 +187,6 @@ export default function About() {
</JobSummary>

<JobSummary
ref={qinetiqRef}
className={styles.jobSummary}
company='QinetiQ'
icon={<Qinetiq />}
Expand All @@ -227,7 +211,6 @@ export default function About() {
</JobSummary>

<JobSummary
ref={durhamRef}
className={styles.jobSummary}
company='Durham'
icon={<Durham />}
Expand Down
19 changes: 6 additions & 13 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import classnames from 'classnames'
import { useState, useEffect } from 'react'
import { useState } from 'react'
import Typewriter from 'typewriter-effect'

import Button, { ButtonType } from '../components/Button/Button'
Expand All @@ -15,20 +15,11 @@ export interface Props {

export default function Home({ allPosts }: Props) {
const [pageLoaded, setPageLoaded] = useState(false)
useEffect(() => {
function handlePageLoad() {
setPageLoaded(true)
}
if (document.readyState === 'complete') {
handlePageLoad()
} else {
window.addEventListener('load', handlePageLoad)
return () => window.removeEventListener('load', handlePageLoad)
}
}, [])

const backgroundContent = (
<>
<img
data-speed='0.15'
alt=''
src='/assets/home/hero-fallback.webp'
data-testid='heroFallback'
Expand All @@ -37,6 +28,8 @@ export default function Home({ allPosts }: Props) {
})}
/>
<img
data-speed='0.15'
onLoad={() => setPageLoaded(true)}
alt='A nice background'
src='/assets/home/hero-background.webp'
data-testid='heroBackground'
Expand All @@ -45,6 +38,7 @@ export default function Home({ allPosts }: Props) {
})}
/>
<img
data-speed='0.30'
alt='Me'
src='/assets/home/hero-cutout.webp'
data-testid='heroCutout'
Expand Down Expand Up @@ -77,7 +71,6 @@ export default function Home({ allPosts }: Props) {
return (
<Layout
hideHeaderUntilScroll
blurBackground={!pageLoaded}
backgroundContent={backgroundContent}
backgroundHeight={100}
foregroundContent={foregroundContent}
Expand Down
5 changes: 0 additions & 5 deletions styles/About.module.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
.jobSummary {
margin-top: 3em;
opacity: 0;
transform: translateX(-10%);
transition:
opacity 0.5s ease-out,
transform 0.5s ease-out;
}

.typewriter {
Expand Down
Loading

0 comments on commit 5179005

Please sign in to comment.