Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 45 additions & 4 deletions src/routes/blog/[[page]]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@

let articlesHeader: HTMLElement;

let previousPage: number | null = null;
function getBlogPageNumber(pageParam: string | undefined): number {
const pageNumber = parseInt(pageParam ?? '1', 10);
return Number.isNaN(pageNumber) ? 1 : pageNumber;
}

onNavigate(async ({ from, to, type }) => {
const fromPage = getBlogPageNumber(from?.params?.page);
const toPage = getBlogPageNumber(to?.params?.page);
const isPaginationNavigation =
type === 'link' && fromPage !== toPage && from?.url.search === to?.url.search;

onNavigate(async ({ from, type }) => {
previousPage = type === 'link' ? parseInt(from?.params?.page ?? '1') : null;
if (!articlesHeader || !previousPage) return;
if (!articlesHeader || !isPaginationNavigation) return;

await tick();
articlesHeader.scrollIntoView();
Expand Down Expand Up @@ -88,6 +95,35 @@

const { debounce, reset } = createDebounce();

async function handleCategoryClick(event: MouseEvent, category?: string) {
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
return;
}

event.preventDefault();
event.stopPropagation();
const scrollPosition = {
left: window.scrollX,
top: window.scrollY
};

const url = new URL('/blog', page.url);

if (category) {
url.searchParams.set('category', category);
}

await goto(url.toString(), {
noScroll: true,
keepFocus: true
});

await tick();
window.scrollTo(scrollPosition);
requestAnimationFrame(() => window.scrollTo(scrollPosition));
setTimeout(() => window.scrollTo(scrollPosition), 100);
Comment on lines +121 to +124
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Redundant and fragile triple scroll restoration

After goto with noScroll: true, the function fires window.scrollTo three separate times: once immediately, once in a requestAnimationFrame, and once in a setTimeout 100 ms later. The 100 ms timer is the problematic one — if the user intentionally scrolls within that window after clicking a category, the timer forcibly snaps them back to the pre-click position. Since goto is already called with noScroll: true, a single restore after await tick() should be sufficient; the duplicate RAF and timeout calls are fighting browser behavior empirically rather than addressing the root cause.

}

const search = (node: HTMLInputElement) => {
const inputHandler = () => debounce(() => handleSearch());
const keydownHandler = (event: KeyboardEvent) => {
Expand Down Expand Up @@ -335,8 +371,10 @@
<li class="flex items-center">
<a
href={base + '/blog'}
data-sveltekit-noscroll
class="web-interactive-tag web-caption-400 cursor-pointer"
class:is-selected={selectedCategory === 'Latest'}
onclick={(event) => handleCategoryClick(event)}
>
Latest
</a>
Expand All @@ -348,8 +386,11 @@
href={base +
'/blog?category=' +
encodeURIComponent(category.name)}
data-sveltekit-noscroll
class="web-interactive-tag web-caption-400 cursor-pointer"
class:is-selected={selectedCategory === category.name}
onclick={(event) =>
handleCategoryClick(event, category.name)}
>
{category.name}
</a>
Expand Down