feat: redesign site as a modern developer portfolio
- New home page: hero, stats, about, focus areas, stack, projects, contact - Light/dark theme with system default and persisted toggle - Content centralised in data/profile.js - Restyle /rates to match; remove it from nav and projects - Afriex: log a clear error now that its API requires a device id Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5c40a64c42
commit
3bb0a5e4a9
@@ -0,0 +1,37 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// Fades children in when they scroll into view.
|
||||
export default function Reveal({ as: Tag = 'div', delay = 0, className = '', children, ...rest }) {
|
||||
const ref = useRef(null);
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const node = ref.current;
|
||||
if (!node || typeof IntersectionObserver === 'undefined') {
|
||||
setVisible(true);
|
||||
return;
|
||||
}
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
setVisible(true);
|
||||
observer.disconnect();
|
||||
}
|
||||
},
|
||||
{ rootMargin: '0px 0px -10% 0px' }
|
||||
);
|
||||
observer.observe(node);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Tag
|
||||
ref={ref}
|
||||
className={`reveal ${visible ? 'is-visible' : ''} ${className}`}
|
||||
style={{ transitionDelay: `${delay}ms` }}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user