feat: directional scroll restoration (only on back navigation)
This commit is contained in:
parent
80e05b54e1
commit
b3b6815ee0
1 changed files with 58 additions and 49 deletions
107
js/app.js
107
js/app.js
|
|
@ -958,46 +958,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
// Session-based scroll positions (transient, cleared on refresh)
|
// Session-based scroll positions (transient, cleared on refresh)
|
||||||
const scrollPositions = new Map();
|
const scrollPositions = new Map();
|
||||||
|
|
||||||
const handleRouter = async (e) => {
|
|
||||||
// Save scroll position for the previous page if available
|
|
||||||
if (e && e.oldURL) {
|
|
||||||
try {
|
|
||||||
const url = new URL(e.oldURL);
|
|
||||||
const oldHash = url.hash || '#home';
|
|
||||||
const content = document.querySelector('.main-content');
|
|
||||||
if (content) {
|
|
||||||
scrollPositions.set(oldHash, content.scrollTop);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Ignore URL parsing errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the new page
|
|
||||||
await router();
|
|
||||||
|
|
||||||
// Restore scroll position for the new page
|
|
||||||
const newHash = window.location.hash || '#home';
|
|
||||||
const content = document.querySelector('.main-content');
|
|
||||||
if (content) {
|
|
||||||
const savedScroll = scrollPositions.get(newHash);
|
|
||||||
if (savedScroll !== undefined) {
|
|
||||||
// Small timeout to ensure DOM layout is stable after render
|
|
||||||
setTimeout(() => {
|
|
||||||
content.scrollTop = savedScroll;
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initial load
|
|
||||||
await handleRouter(null);
|
|
||||||
window.addEventListener('hashchange', handleRouter);
|
|
||||||
|
|
||||||
// Simple Navigation History
|
|
||||||
const navStack = [window.location.hash];
|
const navStack = [window.location.hash];
|
||||||
let navIndex = 0;
|
let navIndex = 0;
|
||||||
|
let isGoingBack = false;
|
||||||
|
|
||||||
const updateNavButtons = () => {
|
const updateNavButtons = () => {
|
||||||
const backBtn = document.getElementById('nav-back');
|
const backBtn = document.getElementById('nav-back');
|
||||||
|
|
@ -1006,21 +969,67 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (fwdBtn) fwdBtn.disabled = navIndex >= navStack.length - 1;
|
if (fwdBtn) fwdBtn.disabled = navIndex >= navStack.length - 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('hashchange', () => {
|
const handleRouter = async (e) => {
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
if (hash === navStack[navIndex]) return;
|
|
||||||
|
|
||||||
if (navIndex > 0 && hash === navStack[navIndex - 1]) {
|
// 1. Update history state and determine direction
|
||||||
navIndex--; // User went back
|
if (e && e.oldURL) {
|
||||||
} else if (navIndex < navStack.length - 1 && hash === navStack[navIndex + 1]) {
|
try {
|
||||||
navIndex++; // User went forward
|
const url = new URL(e.oldURL);
|
||||||
} else {
|
const oldHash = url.hash || '#home';
|
||||||
navIndex++;
|
|
||||||
navStack.splice(navIndex); // Truncate forward history
|
// Save scroll position for the old page
|
||||||
navStack.push(hash);
|
const content = document.querySelector('.main-content');
|
||||||
|
if (content) {
|
||||||
|
scrollPositions.set(oldHash, content.scrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hash !== navStack[navIndex]) {
|
||||||
|
if (navIndex > 0 && hash === navStack[navIndex - 1]) {
|
||||||
|
navIndex--;
|
||||||
|
isGoingBack = true;
|
||||||
|
} else if (navIndex < navStack.length - 1 && hash === navStack[navIndex + 1]) {
|
||||||
|
navIndex++;
|
||||||
|
isGoingBack = false;
|
||||||
|
} else {
|
||||||
|
navIndex++;
|
||||||
|
navStack.splice(navIndex);
|
||||||
|
navStack.push(hash);
|
||||||
|
isGoingBack = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
isGoingBack = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Render the new page
|
||||||
|
await router();
|
||||||
updateNavButtons();
|
updateNavButtons();
|
||||||
});
|
|
||||||
|
// 3. Handle scroll restoration
|
||||||
|
const content = document.querySelector('.main-content');
|
||||||
|
if (content) {
|
||||||
|
if (isGoingBack) {
|
||||||
|
const savedScroll = scrollPositions.get(hash || '#home');
|
||||||
|
if (savedScroll !== undefined) {
|
||||||
|
setTimeout(() => {
|
||||||
|
content.scrollTop = savedScroll;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For forward or new clicks, ensure we start at the top
|
||||||
|
content.scrollTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset flag
|
||||||
|
isGoingBack = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial load
|
||||||
|
await handleRouter(null);
|
||||||
|
window.addEventListener('hashchange', handleRouter);
|
||||||
updateNavButtons();
|
updateNavButtons();
|
||||||
|
|
||||||
audioPlayer.addEventListener('play', () => {
|
audioPlayer.addEventListener('play', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue