╭ changed ──────────╮ │src/embed/script.js│ ╰───────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │63 // restore focus across the swap. │ │64 grid.innerHTML = html; │ │65 }, │ │66 - _pushState: function (ptr, len) { │ │66 + _replaceState: function (ptr, len) { │ │67 const url = readWasmString(ptr, len); │ │68 - // idempotent: wasm tells us its current page every tick after a│ │69 - // change, but we don't want to add history entries for a URL │ │70 - // the browser is already on (e.g., right after the page loaded │ │71 - // from a server-side render of the same route). │ │68 + // passive same-page URL changes. replaceState changes the URL │ │69 + // without adding a history entry, so the back button isn't │ │70 + // cluttered with unnecessary entries. │ │71 if (window.location.pathname !== url) { │ │73 - history.pushState({}, "", url); │ │72 + history.replaceState({}, "", url); │ │73 } │ │74 }, │ │75 _setOverlay: function (ptr, len) { │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/main_wasm.zig│ ╰─────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │61 .max_size = .{ .width = max_width, .height = null }, │ │62 }, root_ptr.getFocus()); │ │63 │ │64 - // mirror the page Header settled on into the browser URL. _pushState │ │65 - // is idempotent on the JS side (it bails when pathname already matches) │ │66 - // so the first tick after _init is a no-op even though we always send │ │67 - // something through. │ │64 + // mirror the page Header settled on into the browser URL. these are │ │65 + // passive same-page changes, like moving down the commits list, so we │ │66 + // replace the URL in place rather than pushing a history entry. real │ │67 + // cross-page navigations go through _navigate. │ │68 const current_page = session.data.current_page; │ │69 const should_push = if (last_pushed_page_maybe) |lp| !lp.eql(current_page) else true;│ │70 if (should_push) { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────╮ │71 last_pushed_page_maybe = current_page; │ │72 const url = try current_page.urlAlloc(&page_arena);│ │73 - _pushState(url.ptr, @intCast(url.len)); │ │73 + _replaceState(url.ptr, @intCast(url.len)); │ │74 } │ │75 │ │76 const html = try web.generateHtml(allocator, root_ptr);│ ╰───────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │175 extern fn _consoleLog(arg: [*]const u8, len: u32) void; │ │176 extern fn _setHtml(arg: [*]const u8, len: u32) void; │ │177 extern fn _setOverlay(arg: [*]const u8, len: u32) void; │ │178 -extern fn _pushState(arg: [*]const u8, len: u32) void; │ │178 +extern fn _replaceState(arg: [*]const u8, len: u32) void; │ │179 extern fn _focusInput(focus_id: u32) void; │ │180 extern fn _navigate(arg: [*]const u8, len: u32) void; │ │181 extern fn _scrollToRect(x: u32, y: u32, width: u32, height: u32) void;│ ╰───────────────────────────────────────────────────────────────────────────╯