ai generated solutions to our ai generated problems
This commit is contained in:
+60
-53
@@ -1,9 +1,13 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||
import L from 'leaflet'
|
||||
import { gsap } from 'gsap'
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import Tree, { prewarmTreeCanvas } from '../Tree/Tree'
|
||||
import FallingLeaves from '../Tree/FallingLeaves'
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger)
|
||||
|
||||
const numberFormat = new Intl.NumberFormat('en-GB')
|
||||
const dateFormat = new Intl.DateTimeFormat('en-GB', {
|
||||
dateStyle: 'medium',
|
||||
@@ -593,53 +597,51 @@ function themeToggleDockPosition(navPill) {
|
||||
}
|
||||
}
|
||||
|
||||
function ThemeToggleMover({ position, theme, onThemeChange }) {
|
||||
const previousPositionRef = useRef(position)
|
||||
const [motion, setMotion] = useState(() => ({
|
||||
from: position,
|
||||
to: position,
|
||||
mid: position,
|
||||
key: 0,
|
||||
animate: false,
|
||||
}))
|
||||
function ThemeToggleMover({ dockPosition, homePosition, isHome, theme, onThemeChange }) {
|
||||
const moverRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
const from = previousPositionRef.current
|
||||
const to = position
|
||||
if (from.x === to.x && from.y === to.y) return
|
||||
useLayoutEffect(() => {
|
||||
const mover = moverRef.current
|
||||
if (!mover) return undefined
|
||||
|
||||
const distance = Math.hypot(to.x - from.x, to.y - from.y)
|
||||
const lift = Math.min(96, Math.max(24, distance * 0.16))
|
||||
const mid = {
|
||||
x: Math.round((from.x + to.x) / 2),
|
||||
y: Math.round(Math.min(from.y, to.y) - lift),
|
||||
if (!isHome) {
|
||||
gsap.to(mover, {
|
||||
x: dockPosition.x,
|
||||
y: dockPosition.y,
|
||||
duration: 0.56,
|
||||
ease: 'power3.out',
|
||||
overwrite: true,
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
|
||||
previousPositionRef.current = to
|
||||
setMotion((current) => ({
|
||||
from,
|
||||
to,
|
||||
mid,
|
||||
key: current.key + 1,
|
||||
animate: true,
|
||||
}))
|
||||
}, [position])
|
||||
const tween = gsap.fromTo(
|
||||
mover,
|
||||
{ x: homePosition.x, y: homePosition.y },
|
||||
{
|
||||
x: dockPosition.x,
|
||||
y: dockPosition.y,
|
||||
ease: 'none',
|
||||
overwrite: true,
|
||||
scrollTrigger: {
|
||||
end: '+=96',
|
||||
scrub: 0.35,
|
||||
start: 'top top',
|
||||
trigger: document.documentElement,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
return () => {
|
||||
tween.scrollTrigger?.kill()
|
||||
tween.kill()
|
||||
}
|
||||
}, [dockPosition.x, dockPosition.y, homePosition.x, homePosition.y, isHome])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`theme-toggle-mover fixed left-0 top-0 z-[60] ${
|
||||
motion.animate ? 'theme-toggle-mover-arc' : ''
|
||||
}`}
|
||||
key={motion.key}
|
||||
style={{
|
||||
'--from-x': `${motion.from.x}px`,
|
||||
'--from-y': `${motion.from.y}px`,
|
||||
'--mid-x': `${motion.mid.x}px`,
|
||||
'--mid-y': `${motion.mid.y}px`,
|
||||
'--to-x': `${motion.to.x}px`,
|
||||
'--to-y': `${motion.to.y}px`,
|
||||
transform: `translate3d(${motion.to.x}px, ${motion.to.y}px, 0)`,
|
||||
}}
|
||||
className="theme-toggle-mover fixed left-0 top-0 z-[60]"
|
||||
ref={moverRef}
|
||||
>
|
||||
<ThemeToggle theme={theme} onThemeChange={onThemeChange} />
|
||||
</div>
|
||||
@@ -821,7 +823,10 @@ function AppContent() {
|
||||
const [analyticsPreferences, setAnalyticsPreferences] = useState(() => storedAnalyticsPreferences())
|
||||
const [theme, setTheme] = useState(() => storedThemePreference())
|
||||
const [showFloatingNav, setShowFloatingNav] = useState(() => window.scrollY > 40)
|
||||
const [themeTogglePosition, setThemeTogglePosition] = useState(() => defaultThemeTogglePosition())
|
||||
const [themeTogglePositions, setThemeTogglePositions] = useState(() => {
|
||||
const position = defaultThemeTogglePosition()
|
||||
return { dock: position, home: position }
|
||||
})
|
||||
const [teamQuery, setTeamQuery] = useState('')
|
||||
const [searchHint, setSearchHint] = useState({ status: 'idle', name: '' })
|
||||
const [teamSearchResults, setTeamSearchResults] = useState([])
|
||||
@@ -1476,24 +1481,24 @@ function AppContent() {
|
||||
useEffect(() => {
|
||||
let frame = 0
|
||||
|
||||
function updateThemeTogglePosition() {
|
||||
function updateThemeTogglePositions() {
|
||||
window.cancelAnimationFrame(frame)
|
||||
frame = window.requestAnimationFrame(() => {
|
||||
setThemeTogglePosition(
|
||||
shouldShowFloatingNav
|
||||
? themeToggleDockPosition(navPillRef.current)
|
||||
: defaultThemeTogglePosition(),
|
||||
)
|
||||
setThemeTogglePositions({
|
||||
dock: themeToggleDockPosition(navPillRef.current),
|
||||
home: defaultThemeTogglePosition(),
|
||||
})
|
||||
ScrollTrigger.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
updateThemeTogglePosition()
|
||||
window.addEventListener('resize', updateThemeTogglePosition)
|
||||
updateThemeTogglePositions()
|
||||
window.addEventListener('resize', updateThemeTogglePositions)
|
||||
return () => {
|
||||
window.cancelAnimationFrame(frame)
|
||||
window.removeEventListener('resize', updateThemeTogglePosition)
|
||||
window.removeEventListener('resize', updateThemeTogglePositions)
|
||||
}
|
||||
}, [route.page, shouldShowFloatingNav])
|
||||
}, [route.page])
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-bg text-text">
|
||||
@@ -1533,7 +1538,9 @@ function AppContent() {
|
||||
</div>
|
||||
</header>
|
||||
<ThemeToggleMover
|
||||
position={themeTogglePosition}
|
||||
dockPosition={themeTogglePositions.dock}
|
||||
homePosition={themeTogglePositions.home}
|
||||
isHome={route.page === 'home'}
|
||||
theme={theme}
|
||||
onThemeChange={chooseTheme}
|
||||
/>
|
||||
|
||||
+2
-16
@@ -477,8 +477,8 @@ h3 {
|
||||
0 1px 3px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.theme-toggle-mover-arc {
|
||||
animation: themeToggleArc 560ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
.theme-toggle-mover {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
:root.theme-transition,
|
||||
@@ -535,20 +535,6 @@ h3 {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes themeToggleArc {
|
||||
0% {
|
||||
transform: translate3d(var(--from-x), var(--from-y), 0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translate3d(var(--mid-x), var(--mid-y), 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate3d(var(--to-x), var(--to-y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes celestialPathExit {
|
||||
0% {
|
||||
offset-distance: 0%;
|
||||
|
||||
Reference in New Issue
Block a user