2 Commits

Author SHA1 Message Date
Arnie 302d3aa4ab Update tsconfig
continuous-integration/drone/tag Build is failing
2024-10-25 10:22:16 +02:00
Arnie 0d74fd01bc Change the nav sticky behavior
continuous-integration/drone/tag Build is passing
2024-10-24 14:35:43 +02:00
5 changed files with 83 additions and 85 deletions
@@ -23,7 +23,7 @@ const Nav = styled("nav")({
flex: "0 0 280px", flex: "0 0 280px",
width: 280, width: 280,
minHeight: "100%", minHeight: "100%",
padding: "2rem 2rem 2rem", padding: "0 2rem 2rem",
[hideNavigationMQ]: { [hideNavigationMQ]: {
display: "none", display: "none",
@@ -18,21 +18,15 @@ const ProfileImg = styled("img")({
width: 150, width: 150,
}); });
const getTopOffset = (input: HTMLElement) => { const navBottomPadding = 50;
let el: HTMLElement | Element | null = input;
let o = 0;
do {
if (!(el instanceof HTMLElement)) {
break;
}
if (!isNaN(el.offsetTop)) { const TopSpacer = styled("div")({
o += el.offsetTop; height: 40,
} });
} while ((el = el.offsetParent));
return o; const StickyWrapper = styled("div")({
}; position: "sticky",
});
const MainNavigation: React.FC = () => { const MainNavigation: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
@@ -45,64 +39,30 @@ const MainNavigation: React.FC = () => {
return; return;
} }
d.style.top = "0px";
let { height } = d.getBoundingClientRect(); let { height } = d.getBoundingClientRect();
const listener = () => {
const visibleArea = navBottomPadding + height;
if (window.innerHeight > visibleArea) {
d.style.top = "0px";
} else {
d.style.top = `${window.innerHeight - visibleArea}px`;
}
};
const ro = new ResizeObserver((entries) => { const ro = new ResizeObserver((entries) => {
if (entries[0]) { if (entries[0]) {
height = entries[0].contentRect.height; height = entries[0].contentRect.height;
listener();
} }
}); });
ro.observe(d); ro.observe(d);
let scrollPrev = window.scrollY; window.addEventListener("scroll", listener, { passive: true });
window.addEventListener("resize", listener, { passive: true });
const listener = () => {
const down = scrollPrev < window.scrollY;
scrollPrev = window.scrollY;
const top = getTopOffset(d);
console.log({
"window.innerHeight": window.innerHeight,
height,
top,
down,
});
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;
console.log({ delta, wDelta, "window.scrollY": window.scrollY, diff });
if (diff > 0) {
const sizeDelta = Math.min(window.innerHeight - height, 0);
d.style.marginTop = `${Math.max(top + diff + sizeDelta, 0)}px`;
console.log({
sizeDelta,
marginTop: Math.max(top + diff + sizeDelta, 0),
});
}
} else {
const delta = top;
const wDelta = window.scrollY;
const diff = wDelta - delta;
console.log({ delta, wDelta, "window.scrollY": window.scrollY, diff });
if (diff < 0) {
console.log({ marginTop: Math.max(top + diff, 0) });
d.style.marginTop = `${Math.max(top + diff, 0)}px`;
}
}
};
window.addEventListener("scroll", listener);
return () => { return () => {
window.removeEventListener("scroll", listener); window.removeEventListener("scroll", listener);
@@ -111,7 +71,8 @@ const MainNavigation: React.FC = () => {
}, []); }, []);
return ( return (
<div ref={ref}> <StickyWrapper ref={ref}>
<TopSpacer />
<ProfileImg src={profile} alt="profile picture" /> <ProfileImg src={profile} alt="profile picture" />
<NavigationHeadline> <NavigationHeadline>
@@ -177,7 +138,7 @@ const MainNavigation: React.FC = () => {
id: "Navigation.experience", id: "Navigation.experience",
})} })}
</NavigationHeadline> </NavigationHeadline>
</div> </StickyWrapper>
); );
}; };
+28
View File
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"composite": true,
"allowSyntheticDefaultImports": true,
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2021", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}
+5 -21
View File
@@ -1,23 +1,7 @@
{ {
"compilerOptions": { "files": [],
"target": "ES2020", "references": [
"useDefineForClassFields": true, { "path": "./tsconfig.app.json" },
"lib": ["ES2020", "DOM", "DOM.Iterable"], { "path": "./tsconfig.node.json" }
"module": "ESNext", ]
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
} }
+25
View File
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"composite": true,
"allowSyntheticDefaultImports": true,
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}