mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(site): preserve scroll position on framework switch (pagereveal) (#608)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
1c6293ea39
commit
420742e7c9
@@ -15,39 +15,55 @@ const { docsSidebarId } = Astro.props;
|
||||
const STORAGE_KEY = 'vjs-sidebar-state';
|
||||
|
||||
window.addEventListener('pagereveal', () => {
|
||||
// Restore sidebar state
|
||||
const aside = document.getElementById(docsSidebarId);
|
||||
if (!aside) return;
|
||||
const stored = sessionStorage.getItem(STORAGE_KEY);
|
||||
if (aside) {
|
||||
const stored = sessionStorage.getItem(STORAGE_KEY);
|
||||
|
||||
if (stored) {
|
||||
try {
|
||||
const state = JSON.parse(stored);
|
||||
if (stored) {
|
||||
try {
|
||||
const state = JSON.parse(stored);
|
||||
|
||||
if (state.sidebarScroll !== undefined) {
|
||||
aside.scrollTop = state.sidebarScroll;
|
||||
if (state.sidebarScroll !== undefined) {
|
||||
aside.scrollTop = state.sidebarScroll;
|
||||
}
|
||||
|
||||
if (state.detailsState) {
|
||||
document.querySelectorAll(`#${docsSidebarId} details[id]`).forEach((details) => {
|
||||
const savedState = state.detailsState[details.id];
|
||||
if (savedState !== undefined) {
|
||||
details.open = savedState;
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Sidebar] Failed to restore state', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.detailsState) {
|
||||
document.querySelectorAll(`#${docsSidebarId} details[id]`).forEach((details) => {
|
||||
const savedState = state.detailsState[details.id];
|
||||
if (savedState !== undefined) {
|
||||
details.open = savedState;
|
||||
}
|
||||
});
|
||||
// Auto-expand sections containing active link (override saved state)
|
||||
const activeLink = aside.querySelector('a[aria-current="page"]');
|
||||
if (activeLink) {
|
||||
let parent = activeLink.closest('details');
|
||||
while (parent && aside.contains(parent)) {
|
||||
parent.open = true;
|
||||
parent = parent.parentElement?.closest('details') ?? null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Sidebar] Failed to restore state', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-expand sections containing active link (override saved state)
|
||||
const activeLink = aside.querySelector('a[aria-current="page"]');
|
||||
if (activeLink) {
|
||||
let parent = activeLink.closest('details');
|
||||
while (parent && aside.contains(parent)) {
|
||||
parent.open = true;
|
||||
parent = parent.parentElement?.closest('details') ?? null;
|
||||
// Restore page scroll position (set by framework switch)
|
||||
try {
|
||||
const scrollData = sessionStorage.getItem('vjs-page-scroll');
|
||||
if (scrollData) {
|
||||
sessionStorage.removeItem('vjs-page-scroll');
|
||||
const { url, scrollY } = JSON.parse(scrollData);
|
||||
if (url.replace(/\/$/, '') === window.location.pathname.replace(/\/$/, '')) {
|
||||
window.scrollTo(0, scrollY);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore storage errors
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -35,10 +35,20 @@ export function Selectors({ currentFramework, currentSlug }: SelectorProps) {
|
||||
});
|
||||
|
||||
if (shouldReplace) {
|
||||
// Maintaining the current slug, navigate without pushing onto the history stack
|
||||
// Base UI's scroll lock transfers html.scrollTop → body.scrollTop
|
||||
const scrollLocked = document.documentElement.hasAttribute('data-base-ui-scroll-locked');
|
||||
const scrollY = scrollLocked ? document.body.scrollTop : window.scrollY;
|
||||
|
||||
try {
|
||||
sessionStorage.setItem(
|
||||
'vjs-page-scroll',
|
||||
JSON.stringify({ url: new URL(url, window.location.origin).pathname, scrollY })
|
||||
);
|
||||
} catch {
|
||||
// Ignore storage errors
|
||||
}
|
||||
window.location.replace(url);
|
||||
} else {
|
||||
// Changing slug, use normal navigation
|
||||
window.location.href = url;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,7 +17,6 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function JSPickerClient({ currentFramework, currentStyle, currentSlug }: Props) {
|
||||
// TODO: use astro view transitions to preserve scroll position when switching from the same slug to the same slug
|
||||
const handleFrameworkChange = (newFramework: SupportedFramework | null) => {
|
||||
if (newFramework === null) return;
|
||||
if (!isValidFramework(newFramework)) return;
|
||||
@@ -30,10 +29,20 @@ export default function JSPickerClient({ currentFramework, currentStyle, current
|
||||
});
|
||||
|
||||
if (shouldReplace) {
|
||||
// Maintaining the current slug, navigate without pushing onto the history stack
|
||||
// Base UI's scroll lock transfers html.scrollTop → body.scrollTop
|
||||
const scrollLocked = document.documentElement.hasAttribute('data-base-ui-scroll-locked');
|
||||
const scrollY = scrollLocked ? document.body.scrollTop : window.scrollY;
|
||||
|
||||
try {
|
||||
sessionStorage.setItem(
|
||||
'vjs-page-scroll',
|
||||
JSON.stringify({ url: new URL(url, window.location.origin).pathname, scrollY })
|
||||
);
|
||||
} catch {
|
||||
// Ignore storage errors
|
||||
}
|
||||
window.location.replace(url);
|
||||
} else {
|
||||
// Changing slug, use normal navigation
|
||||
window.location.href = url;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user