ai generated solutions to our ai generated problems

This commit is contained in:
2026-06-15 08:45:24 +01:00
parent c94a09f46c
commit efe233667f
5 changed files with 100 additions and 74 deletions
+60 -53
View File
@@ -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
View File
@@ -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%;