Add a sticky navigation
This commit is contained in:
parent
e7f6b2be79
commit
75325472b8
@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { defineMessages, useIntl } from "react-intl";
|
import { defineMessages, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { CONTACT_EMAIL, CONTACT_PHONE } from "../../config/environment";
|
import { CONTACT_EMAIL, CONTACT_PHONE } from "../../config/environment";
|
||||||
@ -30,10 +30,85 @@ const messages = defineMessages({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getTopOffset = (input: HTMLElement) => {
|
||||||
|
let el: HTMLElement | Element | null = input;
|
||||||
|
let o = 0;
|
||||||
|
do {
|
||||||
|
if (!(el instanceof HTMLElement)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNaN(el.offsetTop)) {
|
||||||
|
o += el.offsetTop;
|
||||||
|
}
|
||||||
|
} while ((el = el.offsetParent));
|
||||||
|
|
||||||
|
return o;
|
||||||
|
};
|
||||||
|
|
||||||
const MainNavigation: React.FC = () => {
|
const MainNavigation: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const d = ref.current;
|
||||||
|
if (!d) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { height } = d.getBoundingClientRect();
|
||||||
|
|
||||||
|
const ro = new ResizeObserver((entries) => {
|
||||||
|
if (entries[0]) {
|
||||||
|
height = entries[0].contentRect.height;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ro.observe(d);
|
||||||
|
|
||||||
|
let scrollPrev = window.scrollY;
|
||||||
|
|
||||||
|
const listener = () => {
|
||||||
|
const down = scrollPrev < window.scrollY;
|
||||||
|
scrollPrev = window.scrollY;
|
||||||
|
const top = getTopOffset(d);
|
||||||
|
|
||||||
|
if (window.innerHeight > height) {
|
||||||
|
d.style.marginTop = `${Math.max(window.scrollY, 0)}px`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (down) {
|
||||||
|
const delta = top + height;
|
||||||
|
const wDelta = window.scrollY + window.innerHeight;
|
||||||
|
|
||||||
|
const diff = wDelta - delta;
|
||||||
|
if (diff > 0) {
|
||||||
|
const sizeDelta = Math.min(window.innerHeight - height, 0);
|
||||||
|
d.style.marginTop = `${Math.max(top + diff + sizeDelta, 0)}px`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const delta = top;
|
||||||
|
const wDelta = window.scrollY;
|
||||||
|
|
||||||
|
const diff = wDelta - delta;
|
||||||
|
if (diff < 0) {
|
||||||
|
d.style.marginTop = `${Math.max(top + diff, 0)}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("scroll", listener);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("scroll", listener);
|
||||||
|
ro.disconnect();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div ref={ref}>
|
||||||
<NavigationHeadline>
|
<NavigationHeadline>
|
||||||
{intl.formatMessage(messages.contact)}
|
{intl.formatMessage(messages.contact)}
|
||||||
</NavigationHeadline>
|
</NavigationHeadline>
|
||||||
@ -79,7 +154,7 @@ const MainNavigation: React.FC = () => {
|
|||||||
<NavigationHeadline href="#experience">
|
<NavigationHeadline href="#experience">
|
||||||
{intl.formatMessage(messages.experience)}
|
{intl.formatMessage(messages.experience)}
|
||||||
</NavigationHeadline>
|
</NavigationHeadline>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user