Nav hardening: app-safe deep-link Back + stale-load guard on Today
Per Codex audit follow-ups: * Track in-app navigation depth (forward goto/link increments, popstate unwinds, clamped at 0) and base the in-page Back on it instead of history.length. A direct deep link (email/social/article) now sends the in-page Back to Highlights rather than out of the site. * Apply the same stale-load guard to the Today/Highlights path that feed views have, and only scroll-to-top when the load is still current — avoids stale error/scroll state during quick navigation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -236,9 +236,13 @@
|
||||
if (source) sourceNames = { ...sourceNames, [source.id]: source.name };
|
||||
navigate(key);
|
||||
}
|
||||
// How many forward in-app navigations deep we are from the landing entry, so
|
||||
// the in-page Back stays INSIDE the app even when someone deep-links in from
|
||||
// email/social/an article (history.length can't tell us that).
|
||||
let appNavDepth = 0;
|
||||
function goBack() {
|
||||
if (typeof history !== 'undefined' && history.length > 1) history.back();
|
||||
else goto(urlForView('today'));
|
||||
if (appNavDepth > 0 && typeof history !== 'undefined') history.back();
|
||||
else goto(urlForView('today')); // landed here directly → app-safe Highlights
|
||||
}
|
||||
|
||||
// Load the data for a view. Called by afterNavigate (URL-driven: in-app goto,
|
||||
@@ -251,6 +255,7 @@
|
||||
try {
|
||||
if (key === 'today') {
|
||||
await loadToday(fresh);
|
||||
if (seq !== loadSeq) return; // a newer navigation superseded this one
|
||||
} else {
|
||||
const items = (await getJSON(feedUrl(key, 0))).items;
|
||||
if (seq !== loadSeq) return;
|
||||
@@ -264,13 +269,17 @@
|
||||
} catch (e) {
|
||||
if (seq === loadSeq) error = 'Something went quiet — could not reach the feed.';
|
||||
}
|
||||
if (typeof window !== 'undefined') window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
if (seq === loadSeq && typeof window !== 'undefined') window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
// Every URL change (in-app goto, browser back/forward, link) reloads the view.
|
||||
// The initial 'enter' is handled by onMount, after its data deps are fetched.
|
||||
afterNavigate((nav) => {
|
||||
if (nav.type === 'enter') return;
|
||||
// Forward in-app nav deepens the stack; back/forward (popstate) unwinds it.
|
||||
// Clamped at 0, so an out-of-app landing keeps Back app-safe (→ Highlights).
|
||||
if (nav.type === 'goto' || nav.type === 'link') appNavDepth += 1;
|
||||
else if (nav.type === 'popstate') appNavDepth = Math.max(0, appNavDepth - 1);
|
||||
loadView(selected);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user