Skip to content

Commit

Permalink
use useLayoutEffect and gsap context everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
ashharrison90 committed Nov 19, 2023
1 parent 28d1b71 commit 57e821c
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 80 deletions.
144 changes: 87 additions & 57 deletions components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import classnames from 'classnames'
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'
import Head from 'next/head'
import { ReactNode, useEffect, useRef, useState } from 'react'
import {
ReactNode,
forwardRef,
useImperativeHandle,
useLayoutEffect,
useRef,
useState,
} from 'react'

import Footer from '../Footer/Footer'
import Header from '../Header/Header'
Expand All @@ -20,66 +27,89 @@ export interface Props {

let prevScrollTop = 0

export default function Layout({
children,
heroContent,
heroHeight = 0,
hideHeaderUntilScroll = false,
metaDescription,
metaTitle,
}: Props) {
const [showHeader, setShowHeader] = useState(!hideHeaderUntilScroll)
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 Layout = forwardRef<HTMLDivElement, Props>(
(
{
children,
heroContent,
heroHeight = 0,
hideHeaderUntilScroll = false,
metaDescription,
metaTitle,
},
ref,
) => {
const [showHeader, setShowHeader] = useState(!hideHeaderUntilScroll)
const headerRef = useRef<HTMLElement>(null)
const containerRef = useRef<HTMLDivElement>(null)

const handleScroll = () => {
if (hideHeaderUntilScroll) {
setShowHeader(window.scrollY > 0)
} else {
setShowHeader(window.scrollY < prevScrollTop)
prevScrollTop = window.scrollY
useImperativeHandle(ref, () => containerRef.current!)

useLayoutEffect(() => {
const ctx = gsap.context(() => {
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,
},
})
}, containerRef)

const handleScroll = () => {
if (hideHeaderUntilScroll) {
setShowHeader(window.scrollY > 0)
} else {
setShowHeader(window.scrollY < prevScrollTop)
prevScrollTop = window.scrollY
}
}
}

headerRef.current?.addEventListener('focusin', () => setShowHeader(true))
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
style={{
height: `${heroHeight}%`,
}}
className={styles.heroContent}
>
{heroContent}
</div>
<div className={styles.contentContainer} role='main'>
const handleFocus = () => setShowHeader(true)

const header = headerRef.current

header?.addEventListener('focusin', handleFocus)
document.addEventListener('scroll', handleScroll)

return () => {
ctx.revert()
header?.removeEventListener('focusin', handleFocus)
document.removeEventListener('scroll', handleScroll)
}
}, [hideHeaderUntilScroll])
return (
<div ref={containerRef} className={styles.container}>
<Head>
<title>{metaTitle}</title>
<meta name='description' content={metaDescription} />
</Head>
<Header show={showHeader} ref={headerRef} />
<div
className={classnames(styles.content, {
[styles.padContent]: !heroContent && !hideHeaderUntilScroll,
})}
style={{
height: `${heroHeight}%`,
}}
className={styles.heroContent}
>
{children}
{heroContent}
</div>
<div className={styles.contentContainer} role='main'>
<div
className={classnames(styles.content, {
[styles.padContent]: !heroContent && !hideHeaderUntilScroll,
})}
>
{children}
</div>
</div>
<Footer />
</div>
<Footer />
</div>
)
}
)
},
)

export default Layout
28 changes: 20 additions & 8 deletions components/PostLayout/PostLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import json from 'highlight.js/lib/languages/json'
import python from 'highlight.js/lib/languages/python'
import scss from 'highlight.js/lib/languages/scss'
import typescript from 'highlight.js/lib/languages/typescript'
import { ReactNode, useContext, useEffect, useRef } from 'react'
import {
ReactNode,
useContext,
useEffect,
useLayoutEffect,
useRef,
} from 'react'

import { ThemeContext } from '../../context/ThemeContext/ThemeContext'
import { PostMetadata } from '../../lib/postsApi'
Expand All @@ -30,15 +36,20 @@ export interface Props {
export default function PostLayout({ children, metadata }: Props) {
const { theme } = useContext(ThemeContext)
const commentsContainer = useRef<HTMLDivElement>(null)
const layoutRef = useRef<HTMLDivElement>(null)

useEffect(() => {
useLayoutEffect(() => {
hljs.highlightAll()
gsap.from(`.${layoutStyles.heroContent}`, {
duration: 0.5,
height: '100%',
ease: 'back',
delay: 0.1,
})
const ctx = gsap.context(() => {
gsap.from(`.${layoutStyles.heroContent}`, {
duration: 0.5,
height: '100%',
ease: 'back',
delay: 0.1,
})
}, layoutRef)

return () => ctx.revert()
}, [])

useEffect(() => {
Expand Down Expand Up @@ -79,6 +90,7 @@ export default function PostLayout({ children, metadata }: Props) {
heroHeight={65}
metaDescription={excerpt}
metaTitle={title}
ref={layoutRef}
>
<PostTitle date={date} excerpt={excerpt} tags={tags} title={title} />
<div className={styles.postLayout}>{children}</div>
Expand Down
40 changes: 25 additions & 15 deletions pages/about.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { gsap } from 'gsap'
import { useEffect } from 'react'
import { useLayoutEffect, useRef } from 'react'
import Typewriter from 'typewriter-effect'

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

export default function About() {
useEffect(() => {
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',
const layoutRef = useRef<HTMLDivElement>(null)

useLayoutEffect(() => {
const ctx = gsap.context(() => {
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',
})
})
})
}, layoutRef)

return () => ctx.revert()
}, [])

return (
<Layout metaDescription='More about my career so far.' metaTitle='About'>
<Layout
ref={layoutRef}
metaDescription='More about my career so far.'
metaTitle='About'
>
<h1>about</h1>

<p>
Expand Down

0 comments on commit 57e821c

Please sign in to comment.